diff --git a/src/com/limelight/Limelight.java b/src/com/limelight/Limelight.java index 4d01e2f..d7ec424 100644 --- a/src/com/limelight/Limelight.java +++ b/src/com/limelight/Limelight.java @@ -4,6 +4,7 @@ import java.io.IOException; import com.limelight.binding.PlatformBinding; import com.limelight.input.EvdevHandler; +import com.limelight.input.GamepadMapping; import com.limelight.nvstream.NvConnection; import com.limelight.nvstream.NvConnectionListener; import com.limelight.nvstream.StreamConfiguration; @@ -59,10 +60,12 @@ public class Limelight implements NvConnectionListener { for (String event:events) inputs.add(new File(input, event).getAbsolutePath()); } + + GamepadMapping mapping = new GamepadMapping(); for (String input:inputs) { try { - new EvdevHandler(conn, input).start(); + new EvdevHandler(conn, input, mapping).start(); } catch (FileNotFoundException ex) { displayError("Input", "Input (" + input + ") could not be found"); return; diff --git a/src/com/limelight/input/EvdevConstants.java b/src/com/limelight/input/EvdevConstants.java new file mode 100644 index 0000000..5c1c8ff --- /dev/null +++ b/src/com/limelight/input/EvdevConstants.java @@ -0,0 +1,180 @@ +package com.limelight.input; + +import java.awt.event.KeyEvent; + +/** + * + * @author iwan + */ +public class EvdevConstants { + + public static final int MAX_STRUCT_SIZE_BYTES = 24; + + public static final short KEY_CODES[] = { + 0, //KeyEvent.VK_RESERVED + KeyEvent.VK_ESCAPE, + KeyEvent.VK_1, + KeyEvent.VK_2, + KeyEvent.VK_3, + KeyEvent.VK_4, + KeyEvent.VK_5, + KeyEvent.VK_6, + KeyEvent.VK_7, + KeyEvent.VK_8, + KeyEvent.VK_9, + KeyEvent.VK_0, + KeyEvent.VK_MINUS, + KeyEvent.VK_EQUALS, + KeyEvent.VK_BACK_SPACE, + KeyEvent.VK_TAB, + KeyEvent.VK_Q, + KeyEvent.VK_W, + KeyEvent.VK_E, + KeyEvent.VK_R, + KeyEvent.VK_T, + KeyEvent.VK_Y, + KeyEvent.VK_U, + KeyEvent.VK_I, + KeyEvent.VK_O, + KeyEvent.VK_P, + 0, //KeyEvent.VK_LEFTBRACE, + 0, //KeyEvent.VK_RIGHTBRACE, + KeyEvent.VK_ENTER, + KeyEvent.VK_CONTROL, // Left control */ + KeyEvent.VK_A, + KeyEvent.VK_S, + KeyEvent.VK_D, + KeyEvent.VK_F, + KeyEvent.VK_G, + KeyEvent.VK_H, + KeyEvent.VK_J, + KeyEvent.VK_K, + KeyEvent.VK_L, + KeyEvent.VK_SEMICOLON, + 0, //KeyEvent.VK_APOSTROPHE, + 0, //KeyEvent.VK_GRAVE, + 0, //KeyEvent.VK_LEFTSHIFT, + 0, //KeyEvent.VK_BACKSLASH, + KeyEvent.VK_Z, + KeyEvent.VK_X, + KeyEvent.VK_C, + KeyEvent.VK_V, + KeyEvent.VK_B, + KeyEvent.VK_N, + KeyEvent.VK_M, + KeyEvent.VK_COMMA, + 0, //KeyEvent.VK_DOT, + KeyEvent.VK_SLASH, + 0, //KeyEvent.VK_RIGHTSHIFT, + 0, //KeyEvent.VK_KPASTERISK, + 0, //KeyEvent.VK_LEFTALT, + KeyEvent.VK_SPACE, + 0, //KeyEvent.VK_CAPSLOCK, + KeyEvent.VK_F1, + KeyEvent.VK_F2, + KeyEvent.VK_F3, + KeyEvent.VK_F4, + KeyEvent.VK_F5, + KeyEvent.VK_F6, + KeyEvent.VK_F7, + KeyEvent.VK_F8, + KeyEvent.VK_F9, + KeyEvent.VK_F10, + KeyEvent.VK_NUM_LOCK, + KeyEvent.VK_SCROLL_LOCK, + KeyEvent.VK_NUMPAD7, + KeyEvent.VK_NUMPAD8, + KeyEvent.VK_NUMPAD9, + 0, //KeyEvent.VK_NUMPAD_MINUS, + KeyEvent.VK_NUMPAD4, + KeyEvent.VK_NUMPAD5, + KeyEvent.VK_NUMPAD6, + 0, //KeyEvent.VK_NUMPADPLUS, + KeyEvent.VK_NUMPAD1, + KeyEvent.VK_NUMPAD2, + KeyEvent.VK_NUMPAD3, + KeyEvent.VK_NUMPAD0, + 0, //KeyEvent.VK_NUMPADDOT, + 0, + 0, //KeyEvent.VK_ZENKAKUHANKAKU, + 0, //KeyEvent.VK_102ND, + KeyEvent.VK_F11, + KeyEvent.VK_F12, + 0, //KeyEvent.VK_RO, + KeyEvent.VK_KATAKANA, + KeyEvent.VK_HIRAGANA, + 0, //KeyEvent.VK_HENKAN, + 0, //KeyEvent.VK_KATAKANAHIRAGANA, + 0, //KeyEvent.VK_MUHENKAN, + 0, //KeyEvent.VK_KPJPCOMMA, + 0, //KeyEvent.VK_KPENTER, + 0, //KeyEvent.VK_RIGHTCTRL, + 0, //KeyEvent.VK_KPSLASH, + 0, //KeyEvent.VK_SYSRQ, + 0, //KeyEvent.VK_RIGHTALT, + 0, //KeyEvent.VK_LINEFEED, + KeyEvent.VK_HOME, + KeyEvent.VK_UP, + KeyEvent.VK_PAGE_UP, + KeyEvent.VK_LEFT, + KeyEvent.VK_RIGHT, + KeyEvent.VK_END, + KeyEvent.VK_DOWN, + KeyEvent.VK_PAGE_DOWN, + KeyEvent.VK_INSERT, + KeyEvent.VK_DELETE, + 0, //KeyEvent.VK_MACRO, + 0, //KeyEvent.VK_MUTE, + 0, //KeyEvent.VK_VOLUMEDOWN, + 0, //KeyEvent.VK_VOLUMEUP, + 0, //KeyEvent.VK_POWER, /* SC System Power Down */ + 0, //KeyEvent.VK_KPEQUAL, + 0, //KeyEvent.VK_KPPLUSMINUS, + KeyEvent.VK_PAUSE, + 0, //KeyEvent.VK_SCALE, /* AL Compiz Scale (Expose) */ + }; + + /* Mouse constants */ + public static final short REL_X = 0x00; + public static final short REL_Y = 0x01; + + public static final short BTN_LEFT = 0x110; + public static final short BTN_RIGHT = 0x111; + public static final short BTN_MIDDLE = 0x112; + + /* Gamepad constants */ + public static final short ABS_X = 0x00; + public static final short ABS_Y = 0x01; + public static final short ABS_RX = 0x03; + public static final short ABS_RY = 0x04; + + public static final short ABS_THROTTLE = 0x06; + public static final short ABS_RUDDER = 0x07; + + public static final short BTN_SOUTH = 0x130; + public static final short BTN_EAST = 0x131; + public static final short BTN_NORTH = 0x133; + public static final short BTN_WEST = 0x134; + + public static final short BTN_SELECT = 0x13a; + public static final short BTN_START = 0x13b; + public static final short BTN_MODE = 0x13c; + public static final short BTN_THUMBL = 0x13d; + public static final short BTN_THUMBR = 0x13e; + public static final short BTN_TL = 0x136; + public static final short BTN_TR = 0x137; + + public static final short BTN_DPAD_UP = 0x220; + public static final short BTN_DPAD_DOWN = 0x221; + public static final short BTN_DPAD_LEFT = 0x222; + public static final short BTN_DPAD_RIGHT = 0x223; + + /* Event types */ + public static final short EV_KEY = 0x01; + public static final short EV_REL = 0x02; + public static final short EV_ABS = 0x03; + + /* Events */ + public static final int KEY_RELEASED = 0; + public static final int KEY_PRESSED = 1; +} diff --git a/src/com/limelight/input/EvdevHandler.java b/src/com/limelight/input/EvdevHandler.java index 013e137..e096fcd 100644 --- a/src/com/limelight/input/EvdevHandler.java +++ b/src/com/limelight/input/EvdevHandler.java @@ -1,9 +1,9 @@ package com.limelight.input; import com.limelight.nvstream.NvConnection; +import com.limelight.nvstream.input.ControllerPacket; import com.limelight.nvstream.input.KeyboardPacket; import com.limelight.nvstream.input.MouseButtonPacket; -import java.awt.event.KeyEvent; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -20,155 +20,21 @@ public class EvdevHandler implements Runnable { private static KeyboardTranslator translator; - private static final short KEY_CODES[] = { - 0, //KeyEvent.VK_RESERVED - KeyEvent.VK_ESCAPE, - KeyEvent.VK_1, - KeyEvent.VK_2, - KeyEvent.VK_3, - KeyEvent.VK_4, - KeyEvent.VK_5, - KeyEvent.VK_6, - KeyEvent.VK_7, - KeyEvent.VK_8, - KeyEvent.VK_9, - KeyEvent.VK_0, - KeyEvent.VK_MINUS, - KeyEvent.VK_EQUALS, - KeyEvent.VK_BACK_SPACE, - KeyEvent.VK_TAB, - KeyEvent.VK_Q, - KeyEvent.VK_W, - KeyEvent.VK_E, - KeyEvent.VK_R, - KeyEvent.VK_T, - KeyEvent.VK_Y, - KeyEvent.VK_U, - KeyEvent.VK_I, - KeyEvent.VK_O, - KeyEvent.VK_P, - 0, //KeyEvent.VK_LEFTBRACE, - 0, //KeyEvent.VK_RIGHTBRACE, - KeyEvent.VK_ENTER, - KeyEvent.VK_CONTROL, // Left control */ - KeyEvent.VK_A, - KeyEvent.VK_S, - KeyEvent.VK_D, - KeyEvent.VK_F, - KeyEvent.VK_G, - KeyEvent.VK_H, - KeyEvent.VK_J, - KeyEvent.VK_K, - KeyEvent.VK_L, - KeyEvent.VK_SEMICOLON, - 0, //KeyEvent.VK_APOSTROPHE, - 0, //KeyEvent.VK_GRAVE, - 0, //KeyEvent.VK_LEFTSHIFT, - 0, //KeyEvent.VK_BACKSLASH, - KeyEvent.VK_Z, - KeyEvent.VK_X, - KeyEvent.VK_C, - KeyEvent.VK_V, - KeyEvent.VK_B, - KeyEvent.VK_N, - KeyEvent.VK_M, - KeyEvent.VK_COMMA, - 0, //KeyEvent.VK_DOT, - KeyEvent.VK_SLASH, - 0, //KeyEvent.VK_RIGHTSHIFT, - 0, //KeyEvent.VK_KPASTERISK, - 0, //KeyEvent.VK_LEFTALT, - KeyEvent.VK_SPACE, - 0, //KeyEvent.VK_CAPSLOCK, - KeyEvent.VK_F1, - KeyEvent.VK_F2, - KeyEvent.VK_F3, - KeyEvent.VK_F4, - KeyEvent.VK_F5, - KeyEvent.VK_F6, - KeyEvent.VK_F7, - KeyEvent.VK_F8, - KeyEvent.VK_F9, - KeyEvent.VK_F10, - KeyEvent.VK_NUM_LOCK, - KeyEvent.VK_SCROLL_LOCK, - KeyEvent.VK_NUMPAD7, - KeyEvent.VK_NUMPAD8, - KeyEvent.VK_NUMPAD9, - 0, //KeyEvent.VK_NUMPAD_MINUS, - KeyEvent.VK_NUMPAD4, - KeyEvent.VK_NUMPAD5, - KeyEvent.VK_NUMPAD6, - 0, //KeyEvent.VK_NUMPADPLUS, - KeyEvent.VK_NUMPAD1, - KeyEvent.VK_NUMPAD2, - KeyEvent.VK_NUMPAD3, - KeyEvent.VK_NUMPAD0, - 0, //KeyEvent.VK_NUMPADDOT, - 0, - 0, //KeyEvent.VK_ZENKAKUHANKAKU, - 0, //KeyEvent.VK_102ND, - KeyEvent.VK_F11, - KeyEvent.VK_F12, - 0, //KeyEvent.VK_RO, - KeyEvent.VK_KATAKANA, - KeyEvent.VK_HIRAGANA, - 0, //KeyEvent.VK_HENKAN, - 0, //KeyEvent.VK_KATAKANAHIRAGANA, - 0, //KeyEvent.VK_MUHENKAN, - 0, //KeyEvent.VK_KPJPCOMMA, - 0, //KeyEvent.VK_KPENTER, - 0, //KeyEvent.VK_RIGHTCTRL, - 0, //KeyEvent.VK_KPSLASH, - 0, //KeyEvent.VK_SYSRQ, - 0, //KeyEvent.VK_RIGHTALT, - 0, //KeyEvent.VK_LINEFEED, - KeyEvent.VK_HOME, - KeyEvent.VK_UP, - KeyEvent.VK_PAGE_UP, - KeyEvent.VK_LEFT, - KeyEvent.VK_RIGHT, - KeyEvent.VK_END, - KeyEvent.VK_DOWN, - KeyEvent.VK_PAGE_DOWN, - KeyEvent.VK_INSERT, - KeyEvent.VK_DELETE, - 0, //KeyEvent.VK_MACRO, - 0, //KeyEvent.VK_MUTE, - 0, //KeyEvent.VK_VOLUMEDOWN, - 0, //KeyEvent.VK_VOLUMEUP, - 0, //KeyEvent.VK_POWER, /* SC System Power Down */ - 0, //KeyEvent.VK_KPEQUAL, - 0, //KeyEvent.VK_KPPLUSMINUS, - KeyEvent.VK_PAUSE, - 0, //KeyEvent.VK_SCALE, /* AL Compiz Scale (Expose) */ - }; - - private static final int MAX_STRUCT_SIZE_BYTES = 24; - /* GFE's prefix for every key code */ public static final short KEY_PREFIX = (short) 0x80; - /* Event types */ - public static final short EV_KEY = 0x01; - public static final short EV_REL = 0x02; - - public static final short REL_X = 0x00; - public static final short REL_Y = 0x01; - - public static final short BTN_LEFT = 0x110; - public static final short BTN_RIGHT = 0x111; - public static final short BTN_MIDDLE = 0x112; - - /* Events */ - public static final int KEY_RELEASED = 0; - public static final int KEY_PRESSED = 1; + /* Gamepad state */ + private short buttonFlags; + private byte leftTrigger, rightTrigger; + private short leftStickX, leftStickY, rightStickX, rightStickY; private NvConnection conn; private FileChannel deviceInput; private ByteBuffer inputBuffer; - public EvdevHandler(NvConnection conn, String device) throws FileNotFoundException, IOException { + private GamepadMapping mapping; + + public EvdevHandler(NvConnection conn, String device, GamepadMapping mapping) throws FileNotFoundException, IOException { this.conn = conn; File file = new File(device); if (!file.exists()) @@ -178,7 +44,7 @@ public class EvdevHandler implements Runnable { FileInputStream in = new FileInputStream(file); deviceInput = in.getChannel(); - inputBuffer = ByteBuffer.allocate(MAX_STRUCT_SIZE_BYTES); + inputBuffer = ByteBuffer.allocate(EvdevConstants.MAX_STRUCT_SIZE_BYTES); inputBuffer.order(ByteOrder.nativeOrder()); translator = new KeyboardTranslator(conn); @@ -192,7 +58,7 @@ public class EvdevHandler implements Runnable { } private void parseEvent(ByteBuffer buffer) { - if (buffer.limit()==MAX_STRUCT_SIZE_BYTES) { + if (buffer.limit()==EvdevConstants.MAX_STRUCT_SIZE_BYTES) { long time_sec = buffer.getLong(); long time_usec = buffer.getLong(); } else { @@ -203,45 +69,89 @@ public class EvdevHandler implements Runnable { short code = buffer.getShort(); int value = buffer.getInt(); - if (type==EV_KEY) { - if (code0) { - if (value==KEY_PRESSED) + if (value==EvdevConstants.KEY_PRESSED) conn.sendMouseButtonDown(mouseButton); - else if (value==KEY_RELEASED) + else if (value==EvdevConstants.KEY_RELEASED) conn.sendMouseButtonUp(mouseButton); + } else if (gamepadButton>0) { + if (value==EvdevConstants.KEY_PRESSED) { + buttonFlags |= gamepadButton; + } else if (value==EvdevConstants.KEY_RELEASED){ + buttonFlags &= ~gamepadButton; + } + conn.sendControllerInput(buttonFlags, leftTrigger, rightTrigger, leftStickX, leftStickY, rightStickX, rightStickY); } } - } else if (type==EV_REL) { - switch (code) { - case REL_X: - conn.sendMouseMove((short) value, (short) 0); - break; - case REL_Y: - conn.sendMouseMove((short) 0, (short) value); - break; - } + } else if (type==EvdevConstants.EV_REL) { + if (code==EvdevConstants.REL_X) + conn.sendMouseMove((short) value, (short) 0); + else if (code==EvdevConstants.REL_Y) + conn.sendMouseMove((short) 0, (short) value); + } else if (type==EvdevConstants.EV_ABS) { + if (code==mapping.abs_x) + leftStickX = (short) value; + else if (code==mapping.abs_y) + leftStickY = (short) value; + else if (code==mapping.abs_rx) + rightStickX = (short) value; + else if (code==mapping.abs_ry) + rightStickY = (short) value; + else if (code==mapping.abs_throttle) + leftTrigger = (byte) value; + else if (code==mapping.abs_rudder) + rightTrigger = (byte) value; + + conn.sendControllerInput(buttonFlags, leftTrigger, rightTrigger, leftStickX, leftStickY, rightStickX, rightStickY); } } @@ -249,7 +159,7 @@ public class EvdevHandler implements Runnable { public void run() { try { while (true) { - while(inputBuffer.remaining()==MAX_STRUCT_SIZE_BYTES) + while(inputBuffer.remaining()==EvdevConstants.MAX_STRUCT_SIZE_BYTES) deviceInput.read(inputBuffer); inputBuffer.flip(); diff --git a/src/com/limelight/input/GamepadMapping.java b/src/com/limelight/input/GamepadMapping.java new file mode 100644 index 0000000..1c0dbb8 --- /dev/null +++ b/src/com/limelight/input/GamepadMapping.java @@ -0,0 +1,35 @@ +package com.limelight.input; + +/** + * Mapping between gamepad and gamestream input + * @author Iwan Timmer + */ +public class GamepadMapping { + + public short abs_x = EvdevConstants.ABS_X; + public short abs_y = EvdevConstants.ABS_Y; + public short abs_rx = EvdevConstants.ABS_RX; + public short abs_ry = EvdevConstants.ABS_RY; + + public short abs_throttle = EvdevConstants.ABS_THROTTLE; + public short abs_rudder = EvdevConstants.ABS_RUDDER; + + public short btn_south = EvdevConstants.BTN_SOUTH; + public short btn_easth = EvdevConstants.BTN_EAST; + public short btn_north = EvdevConstants.BTN_NORTH; + public short btn_west = EvdevConstants.BTN_WEST; + + public short btn_select = EvdevConstants.BTN_SELECT; + public short btn_start = EvdevConstants.BTN_START; + public short btn_mode = EvdevConstants.BTN_MODE; + public short btn_thumbl = EvdevConstants.BTN_THUMBL; + public short btn_thumbr = EvdevConstants.BTN_THUMBR; + public short btn_tl = EvdevConstants.BTN_TL; + public short btn_tr = EvdevConstants.BTN_TR; + + public short btn_dpad_up = EvdevConstants.BTN_DPAD_UP; + public short btn_dpad_down = EvdevConstants.BTN_DPAD_DOWN; + public short btn_dpad_left = EvdevConstants.BTN_DPAD_LEFT; + public short btn_dpad_right = EvdevConstants.BTN_DPAD_RIGHT; + +}