package vafusion.mt4j; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; import java.net.InetSocketAddress; import java.net.Socket; import java.util.Arrays; import org.mt4j.MTApplication; import org.mt4j.input.inputData.InputCursor; import org.mt4j.input.inputData.MTFingerInputEvt; import org.mt4j.input.inputSources.AbstractInputSource; public class LinuxHIDInputSource extends AbstractInputSource { private boolean success; private final static int struct_size = 24; private Socket sock; private Touch previous = null; private Touch current = null; public LinuxHIDInputSource(MTApplication mtApp) { super(mtApp); success = false; //start the daemon here... //daemon should be started int port = 9999; if((sock = openSocket(port)) == null) return; success = true; } public boolean isSuccessfullySetup() { return success; } @Override public void pre() { if(success) { MTHIDEvent evt; while(true) { evt = pollEvent(); switch(evt.type) { // case 0x00: //EV_SYN // if(evt.code == 2) //SYN_MT_REPORT // ; // else // System.err.println("Unrecognized event from HID device"); // break; case 0x01: //EV_KEY if(evt.code == 0x14a) { //BTN_TOUCH // A touch event has been recorded if(evt.value == 0) { //release // MTHIDEvent idEvt = pollEvent(), xEvt = pollEvent(), yEvt = pollEvent(); // the next three events // // should be the id and (x, y) coordinates // // of the touch this.enqueueInputEvent(new MTFingerInputEvt(this, current.x, current.y, MTFingerInputEvt.INPUT_ENDED, current.cursor)); current = previous = null; continue; } } else System.err.println("Unrecognized event from HID device"); break; case 0x03: //EV_ABS if(evt.code == 0x00) { //ABS_X if(previous == null) //we're getting data about the last touch, but we don't have it's id so we can't track it continue; previous.x = evt.value; evt = pollEvent(); previous.y = evt.value; this.enqueueInputEvent(new MTFingerInputEvt(this, previous.x, previous.y, MTFingerInputEvt.INPUT_UPDATED, previous.cursor)); continue; } else if(evt.code == 0x39) { //ABS_MT_TRACKING_ID int id; if(current == null) { current = new Touch(evt.value, (evt = pollEvent()).value, (evt = pollEvent()).value); if((evt = pollEvent()).type != 0x00 && evt.code == 2) //EV_SYN and SYN_MT_REPORT, this is a synch point System.err.println("Incorrect event sequence!!!"); this.enqueueInputEvent(new MTFingerInputEvt(this, current.x, current.y, MTFingerInputEvt.INPUT_DETECTED, current.cursor)); evt = pollEvent(); // this should be the btn_touch touch down event } else { if(current.id == (id = evt.value)) { current.x = (evt = pollEvent()).value; current.y = (evt = pollEvent()).value; this.enqueueInputEvent(new MTFingerInputEvt(this, current.x, current.y, MTFingerInputEvt.INPUT_UPDATED, current.cursor)); } else if(previous.id == (id = evt.value)) { previous.x = (evt = pollEvent()).value; previous.y = (evt = pollEvent()).value; this.enqueueInputEvent(new MTFingerInputEvt(this, previous.x, previous.y, MTFingerInputEvt.INPUT_UPDATED, previous.cursor)); } else { previous = current; current = new Touch(id, (evt = pollEvent()).value, (evt = pollEvent()).value); this.enqueueInputEvent(new MTFingerInputEvt(this, current.x, current.y, MTFingerInputEvt.INPUT_DETECTED, current.cursor)); } if((evt = pollEvent()).type != 0x00 && evt.code == 2) //EV_SYN and SYN_MT_REPORT, this is a synch point System.err.println("Incorrect event sequence!!!"); } } break; default: System.err.println("Unrecognized event from HID device"); } } } } private Socket openSocket(int port) { try { return new Socket(new InetSocketAddress("localhost", port).getAddress(), port); } catch (IOException e) { System.err.println("Error: Unable to open socket to HID daemon."); } return null; } private MTHIDEvent pollEvent() { try { InputStream is = sock.getInputStream(); byte[] stream = new byte[struct_size]; int readCount = is.read(stream, 0, struct_size); if(readCount < struct_size) return null; return new MTHIDEvent(stream); } catch (IOException e) { System.err.println("Failed to poll for event."); } return null; } } class MTHIDEvent { double time; int type; int code; int value; MTHIDEvent(byte[] stream) { time = read(stream, 0, 8) + read(stream, 8, 8) / 1000000; type = read(stream, 16, 2); code = read(stream, 18, 2); value = read(stream, 20, 4); } private int read(byte[] stream, int offset, int count) { byte[] b = Arrays.copyOfRange(stream, offset, offset + count); BigInteger i = new BigInteger(b); return i.intValue(); } } class Touch { int id, x, y; InputCursor cursor; Touch(int id, int x, int y) { this.id = id; this.x = x; this.y = y; cursor = new InputCursor(); } }