From ff344cfc30d692f210ba9e3b866f2f38579d8627 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Thu, 19 Feb 2015 18:49:53 -0500 Subject: [PATCH 1/5] Add support for multiple controllers --- src/com/limelight/input/EvdevHandler.java | 52 ++++++++++++++++++++-- src/com/limelight/input/EvdevReader.java | 2 + src/com/limelight/input/GamepadMapper.java | 5 +++ 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/src/com/limelight/input/EvdevHandler.java b/src/com/limelight/input/EvdevHandler.java index 9c3858c..7a8f679 100644 --- a/src/com/limelight/input/EvdevHandler.java +++ b/src/com/limelight/input/EvdevHandler.java @@ -1,5 +1,6 @@ package com.limelight.input; +import com.limelight.LimeLog; import com.limelight.nvstream.NvConnection; import com.limelight.nvstream.input.ControllerPacket; import com.limelight.nvstream.input.KeyboardPacket; @@ -20,11 +21,16 @@ public class EvdevHandler extends EvdevReader { /* GFE's prefix for every key code */ public static final short KEY_PREFIX = (short) 0x80; + /* Global controller ID state */ + private static int assignedControllerIds = 0; + private static Object controllerIdLock = new Object(); + /* Gamepad state */ private short buttonFlags; private byte leftTrigger, rightTrigger; private short leftStickX, leftStickY, rightStickX, rightStickY; private boolean gamepadSynced; + private short controllerId = -1; private short mouseDeltaX, mouseDeltaY; private byte mouseScroll; @@ -41,9 +47,6 @@ public class EvdevHandler extends EvdevReader { this.conn = conn; this.mapping = mapping; - // We want limelight-common to scale the axis values to match Xinput values - ControllerPacket.enableAxisScaling = true; - absLX = new EvdevAbsolute(device, mapping.abs_x, mapping.reverse_x); absLY = new EvdevAbsolute(device, mapping.abs_y, !mapping.reverse_y); absRX = new EvdevAbsolute(device, mapping.abs_rx, mapping.reverse_rx); @@ -57,6 +60,30 @@ public class EvdevHandler extends EvdevReader { gamepadSynced = true; } + private void assignNewControllerId() { + synchronized (controllerIdLock) { + for (short i = 0; i < 4; i++) { + if ((assignedControllerIds & (1 << i)) == 0) { + // Assign this unused value to this input device + assignedControllerIds |= (1 << i); + controllerId = i; + LimeLog.info("Assigning controller ID "+i); + return; + } + } + } + + // All IDs have been assigned so use controller 0 for the rest + controllerId = 0; + } + + private void releaseControllerId() { + LimeLog.info("Releasing controller ID "+controllerId); + synchronized (controllerIdLock) { + assignedControllerIds &= ~(1 << controllerId); + } + } + @Override protected void parseEvent(ByteBuffer buffer) { if (buffer.limit()==EvdevConstants.MAX_STRUCT_SIZE_BYTES) { @@ -73,7 +100,16 @@ public class EvdevHandler extends EvdevReader { if (type==EvdevConstants.EV_SYN) { if (!gamepadSynced) { - conn.sendControllerInput(buttonFlags, leftTrigger, rightTrigger, leftStickX, leftStickY, rightStickX, rightStickY); + // Assign a controller ID if one hasn't been assigned yet. + // Note that we're only assigning IDs to things that actually send + // some form of controller input to avoid falsely reserving IDs for + // devices that aren't actually controllers or are inactive controllers. + if (controllerId < 0) { + assignNewControllerId(); + } + + conn.sendControllerInput(controllerId, buttonFlags, leftTrigger, rightTrigger, + leftStickX, leftStickY, rightStickX, rightStickY); gamepadSynced = true; } if (mouseDeltaX != 0 || mouseDeltaY != 0) { @@ -222,6 +258,14 @@ public class EvdevHandler extends EvdevReader { gamepadSynced &= !gamepadModified; } + @Override + protected void deviceRemoved() { + // Release this device's controller ID (if it has one) + if (controllerId >= 0) { + releaseControllerId(); + } + } + private short accountForDeadzone(short value) { return Math.abs(value) > mapping.abs_deadzone?value:0; } diff --git a/src/com/limelight/input/EvdevReader.java b/src/com/limelight/input/EvdevReader.java index e9b3de7..3b3f791 100644 --- a/src/com/limelight/input/EvdevReader.java +++ b/src/com/limelight/input/EvdevReader.java @@ -43,6 +43,7 @@ public abstract class EvdevReader implements Runnable { } protected abstract void parseEvent(ByteBuffer buffer); + protected abstract void deviceRemoved(); @Override public void run() { @@ -54,6 +55,7 @@ public abstract class EvdevReader implements Runnable { } } catch (IOException e) { LimeLog.warning("Input device removed"); + deviceRemoved(); } } diff --git a/src/com/limelight/input/GamepadMapper.java b/src/com/limelight/input/GamepadMapper.java index 0e0d705..20b7dfe 100644 --- a/src/com/limelight/input/GamepadMapper.java +++ b/src/com/limelight/input/GamepadMapper.java @@ -75,6 +75,11 @@ public class GamepadMapper extends EvdevReader { notify(); } } + + @Override + protected void deviceRemoved() { + // Nothing for us to do + } public synchronized void readKey(String key, String name) throws InterruptedException { System.out.println(name); From a695b4f3e34e8a073744e4d40527de2965210ec1 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Thu, 19 Feb 2015 19:27:29 -0500 Subject: [PATCH 2/5] Correctly fetch more than one watcher event list --- src/com/limelight/input/EvdevLoader.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/com/limelight/input/EvdevLoader.java b/src/com/limelight/input/EvdevLoader.java index a4ddff8..c8ee221 100644 --- a/src/com/limelight/input/EvdevLoader.java +++ b/src/com/limelight/input/EvdevLoader.java @@ -90,14 +90,16 @@ public class EvdevLoader implements Runnable { WatchService watcher = evdev.getFileSystem().newWatchService(); evdev.register(watcher, StandardWatchEventKinds.ENTRY_CREATE); - WatchKey watckKey = watcher.take(); - List> events = watckKey.pollEvents(); - for (WatchEvent event:events) { - if (event.kind() == StandardWatchEventKinds.ENTRY_CREATE) { - String name = event.context().toString(); - if (filter.accept(input, name)) { - LimeLog.info("Input " + name + " added"); - new EvdevHandler(conn, new File(input, name).getAbsolutePath(), mapping).start(); + for (;;) { + WatchKey watckKey = watcher.take(); + List> events = watckKey.pollEvents(); + for (WatchEvent event:events) { + if (event.kind() == StandardWatchEventKinds.ENTRY_CREATE) { + String name = event.context().toString(); + if (filter.accept(input, name)) { + LimeLog.info("Input " + name + " added"); + new EvdevHandler(conn, new File(input, name).getAbsolutePath(), mapping).start(); + } } } } From 5b20f16d4419e75b2d1f9211d3493ddf68adf841 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Thu, 19 Feb 2015 19:38:08 -0500 Subject: [PATCH 3/5] Reset the watch key after processing events. watckKey -> watchKey --- src/com/limelight/input/EvdevLoader.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/com/limelight/input/EvdevLoader.java b/src/com/limelight/input/EvdevLoader.java index c8ee221..83d3eb8 100644 --- a/src/com/limelight/input/EvdevLoader.java +++ b/src/com/limelight/input/EvdevLoader.java @@ -91,8 +91,8 @@ public class EvdevLoader implements Runnable { evdev.register(watcher, StandardWatchEventKinds.ENTRY_CREATE); for (;;) { - WatchKey watckKey = watcher.take(); - List> events = watckKey.pollEvents(); + WatchKey watchKey = watcher.take(); + List> events = watchKey.pollEvents(); for (WatchEvent event:events) { if (event.kind() == StandardWatchEventKinds.ENTRY_CREATE) { String name = event.context().toString(); @@ -102,6 +102,10 @@ public class EvdevLoader implements Runnable { } } } + + if (!watchKey.reset()) { + break; + } } } catch (IOException | InterruptedException ex) { LimeLog.severe(ex.getMessage()); From 4c332d3199771592d712b77f9c4ab2b7395598cf Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Thu, 19 Feb 2015 19:42:43 -0500 Subject: [PATCH 4/5] Fix build.xml --- build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.xml b/build.xml index dca1a53..ebbdb6a 100644 --- a/build.xml +++ b/build.xml @@ -107,7 +107,7 @@ - java + From b8213276dcd67aafbff5ad2a16032a81bc134bc6 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Thu, 19 Feb 2015 20:31:07 -0500 Subject: [PATCH 5/5] Fix analog stick axis overflow issue causing full positive axis input to invert on Xbox 360 controllers --- src/com/limelight/input/EvdevAbsolute.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/com/limelight/input/EvdevAbsolute.java b/src/com/limelight/input/EvdevAbsolute.java index 1801a39..a053cef 100644 --- a/src/com/limelight/input/EvdevAbsolute.java +++ b/src/com/limelight/input/EvdevAbsolute.java @@ -53,7 +53,9 @@ public class EvdevAbsolute { return reverse?Short.MAX_VALUE:Short.MIN_VALUE; else { value += value