From da7904a767c332e76e0890bf852a3724d745c984 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sun, 1 Feb 2015 15:06:18 -0500 Subject: [PATCH 1/8] Add multiple controller support --- app/src/main/java/com/limelight/Game.java | 2 +- .../binding/input/ControllerHandler.java | 443 +++++++++--------- .../preferences/PreferenceConfiguration.java | 5 +- app/src/main/res/values/strings.xml | 2 + app/src/main/res/xml/preferences.xml | 13 +- 5 files changed, 248 insertions(+), 217 deletions(-) diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java index ed0f88c5..b7d714b7 100644 --- a/app/src/main/java/com/limelight/Game.java +++ b/app/src/main/java/com/limelight/Game.java @@ -193,7 +193,7 @@ public class Game extends Activity implements SurfaceHolder.Callback, // Initialize the connection conn = new NvConnection(host, uniqueId, Game.this, config, PlatformBinding.getCryptoProvider(this)); keybTranslator = new KeyboardTranslator(conn); - controllerHandler = new ControllerHandler(conn, this, prefConfig.deadzonePercentage); + controllerHandler = new ControllerHandler(conn, this, prefConfig.multiController, prefConfig.deadzonePercentage); SurfaceHolder sh = sv.getHolder(); if (prefConfig.stretchVideo || !decoderRenderer.isHardwareAccelerated()) { diff --git a/app/src/main/java/com/limelight/binding/input/ControllerHandler.java b/app/src/main/java/com/limelight/binding/input/ControllerHandler.java index df9f13a3..2ede0647 100644 --- a/app/src/main/java/com/limelight/binding/input/ControllerHandler.java +++ b/app/src/main/java/com/limelight/binding/input/ControllerHandler.java @@ -14,25 +14,9 @@ import com.limelight.ui.GameGestures; import com.limelight.utils.Vector2d; public class ControllerHandler { - private short inputMap = 0x0000; - private byte leftTrigger = 0x00; - private byte rightTrigger = 0x00; - private short rightStickX = 0x0000; - private short rightStickY = 0x0000; - private short leftStickX = 0x0000; - private short leftStickY = 0x0000; - private int emulatingButtonFlags = 0; - - // Used for OUYA bumper state tracking since they force all buttons - // up when the OUYA button goes down. We watch the last time we get - // a bumper up and compare that to our maximum delay when we receive - // a Start button press to see if we should activate one of our - // emulated button combos. - private long lastLbUpTime = 0; - private long lastRbUpTime = 0; + private static final int MAXIMUM_BUMPER_UP_DELAY_MS = 100; - private long startDownTime = 0; private static final int START_DOWN_TIME_KEYB_MS = 750; private static final int MINIMUM_BUTTON_DOWN_TIME_MS = 25; @@ -45,17 +29,21 @@ public class ControllerHandler { private Vector2d inputVector = new Vector2d(); - private HashMap mappings = new HashMap(); + private HashMap contexts = new HashMap(); private NvConnection conn; private double stickDeadzone; - private final ControllerMapping defaultMapping = new ControllerMapping(); + private final ControllerContext defaultContext = new ControllerContext(); private GameGestures gestures; private boolean hasGameController; + + private boolean multiControllerEnabled; + private short nextControllerNumber; - public ControllerHandler(NvConnection conn, GameGestures gestures, int deadzonePercentage) { + public ControllerHandler(NvConnection conn, GameGestures gestures, boolean multiControllerEnabled, int deadzonePercentage) { this.conn = conn; this.gestures = gestures; + this.multiControllerEnabled = multiControllerEnabled; // HACK: For now we're hardcoding a 10% deadzone. Some deadzone // is required for controller batching support to work. @@ -82,15 +70,16 @@ public class ControllerHandler { this.stickDeadzone = (double)deadzonePercentage / 100.0; - // Initialize the default mapping for events with no device - defaultMapping.leftStickXAxis = MotionEvent.AXIS_X; - defaultMapping.leftStickYAxis = MotionEvent.AXIS_Y; - defaultMapping.leftStickDeadzoneRadius = (float) stickDeadzone; - defaultMapping.rightStickXAxis = MotionEvent.AXIS_Z; - defaultMapping.rightStickYAxis = MotionEvent.AXIS_RZ; - defaultMapping.rightStickDeadzoneRadius = (float) stickDeadzone; - defaultMapping.leftTriggerAxis = MotionEvent.AXIS_BRAKE; - defaultMapping.rightTriggerAxis = MotionEvent.AXIS_GAS; + // Initialize the default context for events with no device + defaultContext.leftStickXAxis = MotionEvent.AXIS_X; + defaultContext.leftStickYAxis = MotionEvent.AXIS_Y; + defaultContext.leftStickDeadzoneRadius = (float) stickDeadzone; + defaultContext.rightStickXAxis = MotionEvent.AXIS_Z; + defaultContext.rightStickYAxis = MotionEvent.AXIS_RZ; + defaultContext.rightStickDeadzoneRadius = (float) stickDeadzone; + defaultContext.leftTriggerAxis = MotionEvent.AXIS_BRAKE; + defaultContext.rightTriggerAxis = MotionEvent.AXIS_GAS; + defaultContext.controllerNumber = (short) 0; } private static InputDevice.MotionRange getMotionRangeForJoystickAxis(InputDevice dev, int axis) { @@ -106,19 +95,19 @@ public class ControllerHandler { return range; } - private ControllerMapping createMappingForDevice(InputDevice dev) { - ControllerMapping mapping = new ControllerMapping(); + private ControllerContext createContextForDevice(InputDevice dev) { + ControllerContext context = new ControllerContext(); String devName = dev.getName(); - LimeLog.info("Creating controller mapping for device: "+devName); + LimeLog.info("Creating controller context for device: "+devName); - mapping.leftStickXAxis = MotionEvent.AXIS_X; - mapping.leftStickYAxis = MotionEvent.AXIS_Y; - if (getMotionRangeForJoystickAxis(dev, mapping.leftStickXAxis) != null && - getMotionRangeForJoystickAxis(dev, mapping.leftStickYAxis) != null) { + context.leftStickXAxis = MotionEvent.AXIS_X; + context.leftStickYAxis = MotionEvent.AXIS_Y; + if (getMotionRangeForJoystickAxis(dev, context.leftStickXAxis) != null && + getMotionRangeForJoystickAxis(dev, context.leftStickYAxis) != null) { // This is a gamepad hasGameController = true; - mapping.hasJoystickAxes = true; + context.hasJoystickAxes = true; } InputDevice.MotionRange leftTriggerRange = getMotionRangeForJoystickAxis(dev, MotionEvent.AXIS_LTRIGGER); @@ -128,14 +117,14 @@ public class ControllerHandler { if (leftTriggerRange != null && rightTriggerRange != null) { // Some controllers use LTRIGGER and RTRIGGER (like Ouya) - mapping.leftTriggerAxis = MotionEvent.AXIS_LTRIGGER; - mapping.rightTriggerAxis = MotionEvent.AXIS_RTRIGGER; + context.leftTriggerAxis = MotionEvent.AXIS_LTRIGGER; + context.rightTriggerAxis = MotionEvent.AXIS_RTRIGGER; } else if (brakeRange != null && gasRange != null) { // Others use GAS and BRAKE (like Moga) - mapping.leftTriggerAxis = MotionEvent.AXIS_BRAKE; - mapping.rightTriggerAxis = MotionEvent.AXIS_GAS; + context.leftTriggerAxis = MotionEvent.AXIS_BRAKE; + context.rightTriggerAxis = MotionEvent.AXIS_GAS; } else { @@ -144,34 +133,34 @@ public class ControllerHandler { if (rxRange != null && ryRange != null && devName != null) { if (devName.contains("Xbox") || devName.contains("XBox") || devName.contains("X-Box")) { // Xbox controllers use RX and RY for right stick - mapping.rightStickXAxis = MotionEvent.AXIS_RX; - mapping.rightStickYAxis = MotionEvent.AXIS_RY; + context.rightStickXAxis = MotionEvent.AXIS_RX; + context.rightStickYAxis = MotionEvent.AXIS_RY; // Xbox controllers use Z and RZ for triggers - mapping.leftTriggerAxis = MotionEvent.AXIS_Z; - mapping.rightTriggerAxis = MotionEvent.AXIS_RZ; - mapping.triggersIdleNegative = true; - mapping.isXboxController = true; + context.leftTriggerAxis = MotionEvent.AXIS_Z; + context.rightTriggerAxis = MotionEvent.AXIS_RZ; + context.triggersIdleNegative = true; + context.isXboxController = true; } else { // DS4 controller uses RX and RY for triggers - mapping.leftTriggerAxis = MotionEvent.AXIS_RX; - mapping.rightTriggerAxis = MotionEvent.AXIS_RY; - mapping.triggersIdleNegative = true; + context.leftTriggerAxis = MotionEvent.AXIS_RX; + context.rightTriggerAxis = MotionEvent.AXIS_RY; + context.triggersIdleNegative = true; - mapping.isDualShock4 = true; + context.isDualShock4 = true; } } } - if (mapping.rightStickXAxis == -1 && mapping.rightStickYAxis == -1) { + if (context.rightStickXAxis == -1 && context.rightStickYAxis == -1) { InputDevice.MotionRange zRange = getMotionRangeForJoystickAxis(dev, MotionEvent.AXIS_Z); InputDevice.MotionRange rzRange = getMotionRangeForJoystickAxis(dev, MotionEvent.AXIS_RZ); // Most other controllers use Z and RZ for the right stick if (zRange != null && rzRange != null) { - mapping.rightStickXAxis = MotionEvent.AXIS_Z; - mapping.rightStickYAxis = MotionEvent.AXIS_RZ; + context.rightStickXAxis = MotionEvent.AXIS_Z; + context.rightStickYAxis = MotionEvent.AXIS_RZ; } else { InputDevice.MotionRange rxRange = getMotionRangeForJoystickAxis(dev, MotionEvent.AXIS_RX); @@ -179,8 +168,8 @@ public class ControllerHandler { // Try RX and RY now if (rxRange != null && ryRange != null) { - mapping.rightStickXAxis = MotionEvent.AXIS_RX; - mapping.rightStickYAxis = MotionEvent.AXIS_RY; + context.rightStickXAxis = MotionEvent.AXIS_RX; + context.rightStickYAxis = MotionEvent.AXIS_RY; } } } @@ -189,30 +178,30 @@ public class ControllerHandler { InputDevice.MotionRange hatXRange = getMotionRangeForJoystickAxis(dev, MotionEvent.AXIS_HAT_X); InputDevice.MotionRange hatYRange = getMotionRangeForJoystickAxis(dev, MotionEvent.AXIS_HAT_Y); if (hatXRange != null && hatYRange != null) { - mapping.hatXAxis = MotionEvent.AXIS_HAT_X; - mapping.hatYAxis = MotionEvent.AXIS_HAT_Y; + context.hatXAxis = MotionEvent.AXIS_HAT_X; + context.hatYAxis = MotionEvent.AXIS_HAT_Y; } - if (mapping.leftStickXAxis != -1 && mapping.leftStickYAxis != -1) { - mapping.leftStickDeadzoneRadius = (float) stickDeadzone; + if (context.leftStickXAxis != -1 && context.leftStickYAxis != -1) { + context.leftStickDeadzoneRadius = (float) stickDeadzone; } - if (mapping.rightStickXAxis != -1 && mapping.rightStickYAxis != -1) { - mapping.rightStickDeadzoneRadius = (float) stickDeadzone; + if (context.rightStickXAxis != -1 && context.rightStickYAxis != -1) { + context.rightStickDeadzoneRadius = (float) stickDeadzone; } - if (mapping.leftTriggerAxis != -1 && mapping.rightTriggerAxis != -1) { - InputDevice.MotionRange ltRange = getMotionRangeForJoystickAxis(dev, mapping.leftTriggerAxis); - InputDevice.MotionRange rtRange = getMotionRangeForJoystickAxis(dev, mapping.rightTriggerAxis); + if (context.leftTriggerAxis != -1 && context.rightTriggerAxis != -1) { + InputDevice.MotionRange ltRange = getMotionRangeForJoystickAxis(dev, context.leftTriggerAxis); + InputDevice.MotionRange rtRange = getMotionRangeForJoystickAxis(dev, context.rightTriggerAxis); // It's important to have a valid deadzone so controller packet batching works properly - mapping.triggerDeadzone = Math.max(Math.abs(ltRange.getFlat()), Math.abs(rtRange.getFlat())); + context.triggerDeadzone = Math.max(Math.abs(ltRange.getFlat()), Math.abs(rtRange.getFlat())); // For triggers without (valid) deadzones, we'll use 13% (around XInput's default) - if (mapping.triggerDeadzone < 0.13f || - mapping.triggerDeadzone > 0.30f) + if (context.triggerDeadzone < 0.13f || + context.triggerDeadzone > 0.30f) { - mapping.triggerDeadzone = 0.13f; + context.triggerDeadzone = 0.13f; } } @@ -226,71 +215,82 @@ public class ControllerHandler { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) { boolean[] hasStartKey = dev.hasKeys(KeyEvent.KEYCODE_BUTTON_START, KeyEvent.KEYCODE_MENU, 0); if (!hasStartKey[0] && !hasStartKey[1]) { - mapping.backIsStart = true; + context.backIsStart = true; } } // The ASUS Gamepad has triggers that sit far forward and are prone to false presses // so we increase the deadzone on them to minimize this - mapping.triggerDeadzone = 0.30f; + context.triggerDeadzone = 0.30f; } // Classify this device as a remote by name else if (devName.contains("Fire TV Remote") || devName.contains("Nexus Remote")) { // It's only a remote if it doesn't any sticks - if (!mapping.hasJoystickAxes) { - mapping.isRemote = true; + if (!context.hasJoystickAxes) { + context.isRemote = true; } } // NYKO Playpad has a fake hat that mimics the left stick for some reason else if (devName.contains("NYKO PLAYPAD")) { - mapping.hatXAxis = -1; - mapping.hatYAxis = -1; + context.hatXAxis = -1; + context.hatYAxis = -1; } } - LimeLog.info("Analog stick deadzone: "+mapping.leftStickDeadzoneRadius+" "+mapping.rightStickDeadzoneRadius); - LimeLog.info("Trigger deadzone: "+mapping.triggerDeadzone); - - return mapping; + LimeLog.info("Analog stick deadzone: "+context.leftStickDeadzoneRadius+" "+context.rightStickDeadzoneRadius); + LimeLog.info("Trigger deadzone: "+context.triggerDeadzone); + + if (multiControllerEnabled) { + context.controllerNumber = nextControllerNumber; + nextControllerNumber = (short)((nextControllerNumber + 1) % 4); + } + else { + context.controllerNumber = 0; + } + LimeLog.info("Assigned as controller "+context.controllerNumber); + + return context; } - private ControllerMapping getMappingForDevice(InputDevice dev) { - // Unknown devices use the default mapping + private ControllerContext getContextForDevice(InputDevice dev) { + // Unknown devices use the default context if (dev == null) { - return defaultMapping; + return defaultContext; } String descriptor = dev.getDescriptor(); - // Return the existing mapping if it exists - ControllerMapping mapping = mappings.get(descriptor); - if (mapping != null) { - return mapping; + // Return the existing context if it exists + ControllerContext context = contexts.get(descriptor); + if (context != null) { + return context; } - // Otherwise create a new mapping - mapping = createMappingForDevice(dev); - mappings.put(descriptor, mapping); + // Otherwise create a new context + context = createContextForDevice(dev); + contexts.put(descriptor, context); - return mapping; + return context; } - private void sendControllerInputPacket() { - conn.sendControllerInput(inputMap, leftTrigger, rightTrigger, - leftStickX, leftStickY, rightStickX, rightStickY); + private void sendControllerInputPacket(ControllerContext context) { + conn.sendControllerInput(context.controllerNumber, context.inputMap, + context.leftTrigger, context.rightTrigger, + context.leftStickX, context.leftStickY, + context.rightStickX, context.rightStickY); } // Return a valid keycode, 0 to consume, or -1 to not consume the event // Device MAY BE NULL - private int handleRemapping(ControllerMapping mapping, KeyEvent event) { + private int handleRemapping(ControllerContext context, KeyEvent event) { // For remotes, don't capture the back button - if (mapping.isRemote) { + if (context.isRemote) { if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) { return -1; } } - if (mapping.isDualShock4) { + if (context.isDualShock4) { switch (event.getKeyCode()) { case KeyEvent.KEYCODE_BUTTON_Y: return KeyEvent.KEYCODE_BUTTON_L1; @@ -329,7 +329,7 @@ public class ControllerHandler { } } - if (mapping.hatXAxis != -1 && mapping.hatYAxis != -1) { + if (context.hatXAxis != -1 && context.hatYAxis != -1) { switch (event.getKeyCode()) { // These are duplicate dpad events for hat input case KeyEvent.KEYCODE_DPAD_LEFT: @@ -340,9 +340,9 @@ public class ControllerHandler { return 0; } } - else if (mapping.hatXAxis == -1 && - mapping.hatYAxis == -1 && - mapping.isXboxController && + else if (context.hatXAxis == -1 && + context.hatYAxis == -1 && + context.isXboxController && event.getKeyCode() == KeyEvent.KEYCODE_UNKNOWN) { // If there's not a proper Xbox controller mapping, we'll translate the raw d-pad // scan codes into proper key codes @@ -375,9 +375,9 @@ public class ControllerHandler { if (keyCode == KeyEvent.KEYCODE_BUTTON_START || keyCode == KeyEvent.KEYCODE_MENU) { // Ensure that we never use back as start if we have a real start - mapping.backIsStart = false; + context.backIsStart = false; } - else if (mapping.backIsStart && keyCode == KeyEvent.KEYCODE_BACK) { + else if (context.backIsStart && keyCode == KeyEvent.KEYCODE_BACK) { // Emulate the start button with back return KeyEvent.KEYCODE_BUTTON_START; } @@ -402,101 +402,101 @@ public class ControllerHandler { // evaluates the deadzone. } - private void handleAxisSet(ControllerMapping mapping, float lsX, float lsY, float rsX, + private void handleAxisSet(ControllerContext context, float lsX, float lsY, float rsX, float rsY, float lt, float rt, float hatX, float hatY) { - if (mapping.leftStickXAxis != -1 && mapping.leftStickYAxis != -1) { + if (context.leftStickXAxis != -1 && context.leftStickYAxis != -1) { Vector2d leftStickVector = populateCachedVector(lsX, lsY); - handleDeadZone(leftStickVector, mapping.leftStickDeadzoneRadius); + handleDeadZone(leftStickVector, context.leftStickDeadzoneRadius); - leftStickX = (short) (leftStickVector.getX() * 0x7FFE); - leftStickY = (short) (-leftStickVector.getY() * 0x7FFE); + context.leftStickX = (short) (leftStickVector.getX() * 0x7FFE); + context.leftStickY = (short) (-leftStickVector.getY() * 0x7FFE); } - if (mapping.rightStickXAxis != -1 && mapping.rightStickYAxis != -1) { + if (context.rightStickXAxis != -1 && context.rightStickYAxis != -1) { Vector2d rightStickVector = populateCachedVector(rsX, rsY); - handleDeadZone(rightStickVector, mapping.rightStickDeadzoneRadius); + handleDeadZone(rightStickVector, context.rightStickDeadzoneRadius); - rightStickX = (short) (rightStickVector.getX() * 0x7FFE); - rightStickY = (short) (-rightStickVector.getY() * 0x7FFE); + context.rightStickX = (short) (rightStickVector.getX() * 0x7FFE); + context.rightStickY = (short) (-rightStickVector.getY() * 0x7FFE); } - if (mapping.leftTriggerAxis != -1 && mapping.rightTriggerAxis != -1) { - if (mapping.triggersIdleNegative) { + if (context.leftTriggerAxis != -1 && context.rightTriggerAxis != -1) { + if (context.triggersIdleNegative) { lt = (lt + 1) / 2; rt = (rt + 1) / 2; } - if (lt <= mapping.triggerDeadzone) { + if (lt <= context.triggerDeadzone) { lt = 0; } - if (rt <= mapping.triggerDeadzone) { + if (rt <= context.triggerDeadzone) { rt = 0; } - leftTrigger = (byte)(lt * 0xFF); - rightTrigger = (byte)(rt * 0xFF); + context.leftTrigger = (byte)(lt * 0xFF); + context.rightTrigger = (byte)(rt * 0xFF); } - if (mapping.hatXAxis != -1 && mapping.hatYAxis != -1) { - inputMap &= ~(ControllerPacket.LEFT_FLAG | ControllerPacket.RIGHT_FLAG); + if (context.hatXAxis != -1 && context.hatYAxis != -1) { + context.inputMap &= ~(ControllerPacket.LEFT_FLAG | ControllerPacket.RIGHT_FLAG); if (hatX < -0.5) { - inputMap |= ControllerPacket.LEFT_FLAG; + context.inputMap |= ControllerPacket.LEFT_FLAG; } else if (hatX > 0.5) { - inputMap |= ControllerPacket.RIGHT_FLAG; + context.inputMap |= ControllerPacket.RIGHT_FLAG; } - inputMap &= ~(ControllerPacket.UP_FLAG | ControllerPacket.DOWN_FLAG); + context.inputMap &= ~(ControllerPacket.UP_FLAG | ControllerPacket.DOWN_FLAG); if (hatY < -0.5) { - inputMap |= ControllerPacket.UP_FLAG; + context.inputMap |= ControllerPacket.UP_FLAG; } else if (hatY > 0.5) { - inputMap |= ControllerPacket.DOWN_FLAG; + context.inputMap |= ControllerPacket.DOWN_FLAG; } } - sendControllerInputPacket(); + sendControllerInputPacket(context); } public boolean handleMotionEvent(MotionEvent event) { - ControllerMapping mapping = getMappingForDevice(event.getDevice()); + ControllerContext context = getContextForDevice(event.getDevice()); float lsX = 0, lsY = 0, rsX = 0, rsY = 0, rt = 0, lt = 0, hatX = 0, hatY = 0; // We purposefully ignore the historical values in the motion event as it makes // the controller feel sluggish for some users. - if (mapping.leftStickXAxis != -1 && mapping.leftStickYAxis != -1) { - lsX = event.getAxisValue(mapping.leftStickXAxis); - lsY = event.getAxisValue(mapping.leftStickYAxis); + if (context.leftStickXAxis != -1 && context.leftStickYAxis != -1) { + lsX = event.getAxisValue(context.leftStickXAxis); + lsY = event.getAxisValue(context.leftStickYAxis); } - if (mapping.rightStickXAxis != -1 && mapping.rightStickYAxis != -1) { - rsX = event.getAxisValue(mapping.rightStickXAxis); - rsY = event.getAxisValue(mapping.rightStickYAxis); + if (context.rightStickXAxis != -1 && context.rightStickYAxis != -1) { + rsX = event.getAxisValue(context.rightStickXAxis); + rsY = event.getAxisValue(context.rightStickYAxis); } - if (mapping.leftTriggerAxis != -1 && mapping.rightTriggerAxis != -1) { - lt = event.getAxisValue(mapping.leftTriggerAxis); - rt = event.getAxisValue(mapping.rightTriggerAxis); + if (context.leftTriggerAxis != -1 && context.rightTriggerAxis != -1) { + lt = event.getAxisValue(context.leftTriggerAxis); + rt = event.getAxisValue(context.rightTriggerAxis); } - if (mapping.hatXAxis != -1 && mapping.hatYAxis != -1) { + if (context.hatXAxis != -1 && context.hatYAxis != -1) { hatX = event.getAxisValue(MotionEvent.AXIS_HAT_X); hatY = event.getAxisValue(MotionEvent.AXIS_HAT_Y); } - handleAxisSet(mapping, lsX, lsY, rsX, rsY, lt, rt, hatX, hatY); + handleAxisSet(context, lsX, lsY, rsX, rsY, lt, rt, hatX, hatY); return true; } public boolean handleButtonUp(KeyEvent event) { - ControllerMapping mapping = getMappingForDevice(event.getDevice()); + ControllerContext context = getContextForDevice(event.getDevice()); - int keyCode = handleRemapping(mapping, event); + int keyCode = handleRemapping(context, event); if (keyCode == 0) { return true; } @@ -515,78 +515,78 @@ public class ControllerHandler { switch (keyCode) { case KeyEvent.KEYCODE_BUTTON_MODE: - inputMap &= ~ControllerPacket.SPECIAL_BUTTON_FLAG; + context.inputMap &= ~ControllerPacket.SPECIAL_BUTTON_FLAG; break; case KeyEvent.KEYCODE_BUTTON_START: case KeyEvent.KEYCODE_MENU: - if (SystemClock.uptimeMillis() - startDownTime > ControllerHandler.START_DOWN_TIME_KEYB_MS) { + if (SystemClock.uptimeMillis() - context.startDownTime > ControllerHandler.START_DOWN_TIME_KEYB_MS) { gestures.showKeyboard(); } - inputMap &= ~ControllerPacket.PLAY_FLAG; + context.inputMap &= ~ControllerPacket.PLAY_FLAG; break; case KeyEvent.KEYCODE_BACK: case KeyEvent.KEYCODE_BUTTON_SELECT: - inputMap &= ~ControllerPacket.BACK_FLAG; + context.inputMap &= ~ControllerPacket.BACK_FLAG; break; case KeyEvent.KEYCODE_DPAD_LEFT: - inputMap &= ~ControllerPacket.LEFT_FLAG; + context.inputMap &= ~ControllerPacket.LEFT_FLAG; break; case KeyEvent.KEYCODE_DPAD_RIGHT: - inputMap &= ~ControllerPacket.RIGHT_FLAG; + context.inputMap &= ~ControllerPacket.RIGHT_FLAG; break; case KeyEvent.KEYCODE_DPAD_UP: - inputMap &= ~ControllerPacket.UP_FLAG; + context.inputMap &= ~ControllerPacket.UP_FLAG; break; case KeyEvent.KEYCODE_DPAD_DOWN: - inputMap &= ~ControllerPacket.DOWN_FLAG; + context.inputMap &= ~ControllerPacket.DOWN_FLAG; break; case KeyEvent.KEYCODE_BUTTON_B: - inputMap &= ~ControllerPacket.B_FLAG; + context.inputMap &= ~ControllerPacket.B_FLAG; break; case KeyEvent.KEYCODE_DPAD_CENTER: case KeyEvent.KEYCODE_BUTTON_A: - inputMap &= ~ControllerPacket.A_FLAG; + context.inputMap &= ~ControllerPacket.A_FLAG; break; case KeyEvent.KEYCODE_BUTTON_X: - inputMap &= ~ControllerPacket.X_FLAG; + context.inputMap &= ~ControllerPacket.X_FLAG; break; case KeyEvent.KEYCODE_BUTTON_Y: - inputMap &= ~ControllerPacket.Y_FLAG; + context.inputMap &= ~ControllerPacket.Y_FLAG; break; case KeyEvent.KEYCODE_BUTTON_L1: - inputMap &= ~ControllerPacket.LB_FLAG; - lastLbUpTime = SystemClock.uptimeMillis(); + context.inputMap &= ~ControllerPacket.LB_FLAG; + context.lastLbUpTime = SystemClock.uptimeMillis(); break; case KeyEvent.KEYCODE_BUTTON_R1: - inputMap &= ~ControllerPacket.RB_FLAG; - lastRbUpTime = SystemClock.uptimeMillis(); + context.inputMap &= ~ControllerPacket.RB_FLAG; + context.lastRbUpTime = SystemClock.uptimeMillis(); break; case KeyEvent.KEYCODE_BUTTON_THUMBL: - inputMap &= ~ControllerPacket.LS_CLK_FLAG; + context.inputMap &= ~ControllerPacket.LS_CLK_FLAG; break; case KeyEvent.KEYCODE_BUTTON_THUMBR: - inputMap &= ~ControllerPacket.RS_CLK_FLAG; + context.inputMap &= ~ControllerPacket.RS_CLK_FLAG; break; case KeyEvent.KEYCODE_BUTTON_L2: - leftTrigger = 0; + context.leftTrigger = 0; break; case KeyEvent.KEYCODE_BUTTON_R2: - rightTrigger = 0; + context.rightTrigger = 0; break; default: return false; } // Check if we're emulating the select button - if ((emulatingButtonFlags & ControllerHandler.EMULATING_SELECT) != 0) + if ((context.emulatingButtonFlags & ControllerHandler.EMULATING_SELECT) != 0) { // If either start or LB is up, select comes up too - if ((inputMap & ControllerPacket.PLAY_FLAG) == 0 || - (inputMap & ControllerPacket.LB_FLAG) == 0) + if ((context.inputMap & ControllerPacket.PLAY_FLAG) == 0 || + (context.inputMap & ControllerPacket.LB_FLAG) == 0) { - inputMap &= ~ControllerPacket.BACK_FLAG; - - emulatingButtonFlags &= ~ControllerHandler.EMULATING_SELECT; + context.inputMap &= ~ControllerPacket.BACK_FLAG; + + context.emulatingButtonFlags &= ~ControllerHandler.EMULATING_SELECT; try { Thread.sleep(EMULATED_SELECT_UP_DELAY_MS); @@ -595,16 +595,16 @@ public class ControllerHandler { } // Check if we're emulating the special button - if ((emulatingButtonFlags & ControllerHandler.EMULATING_SPECIAL) != 0) + if ((context.emulatingButtonFlags & ControllerHandler.EMULATING_SPECIAL) != 0) { // If either start or select and RB is up, the special button comes up too - if ((inputMap & ControllerPacket.PLAY_FLAG) == 0 || - ((inputMap & ControllerPacket.BACK_FLAG) == 0 && - (inputMap & ControllerPacket.RB_FLAG) == 0)) + if ((context.inputMap & ControllerPacket.PLAY_FLAG) == 0 || + ((context.inputMap & ControllerPacket.BACK_FLAG) == 0 && + (context.inputMap & ControllerPacket.RB_FLAG) == 0)) { - inputMap &= ~ControllerPacket.SPECIAL_BUTTON_FLAG; - - emulatingButtonFlags &= ~ControllerHandler.EMULATING_SPECIAL; + context.inputMap &= ~ControllerPacket.SPECIAL_BUTTON_FLAG; + + context.emulatingButtonFlags &= ~ControllerHandler.EMULATING_SPECIAL; try { Thread.sleep(EMULATED_SPECIAL_UP_DELAY_MS); @@ -612,112 +612,112 @@ public class ControllerHandler { } } - sendControllerInputPacket(); + sendControllerInputPacket(context); return true; } public boolean handleButtonDown(KeyEvent event) { - ControllerMapping mapping = getMappingForDevice(event.getDevice()); + ControllerContext context = getContextForDevice(event.getDevice()); - int keyCode = handleRemapping(mapping, event); + int keyCode = handleRemapping(context, event); if (keyCode == 0) { return true; } switch (keyCode) { case KeyEvent.KEYCODE_BUTTON_MODE: - inputMap |= ControllerPacket.SPECIAL_BUTTON_FLAG; + context.inputMap |= ControllerPacket.SPECIAL_BUTTON_FLAG; break; case KeyEvent.KEYCODE_BUTTON_START: case KeyEvent.KEYCODE_MENU: if (event.getRepeatCount() == 0) { - startDownTime = SystemClock.uptimeMillis(); + context.startDownTime = SystemClock.uptimeMillis(); } - inputMap |= ControllerPacket.PLAY_FLAG; + context.inputMap |= ControllerPacket.PLAY_FLAG; break; case KeyEvent.KEYCODE_BACK: case KeyEvent.KEYCODE_BUTTON_SELECT: - inputMap |= ControllerPacket.BACK_FLAG; + context.inputMap |= ControllerPacket.BACK_FLAG; break; case KeyEvent.KEYCODE_DPAD_LEFT: - inputMap |= ControllerPacket.LEFT_FLAG; + context.inputMap |= ControllerPacket.LEFT_FLAG; break; case KeyEvent.KEYCODE_DPAD_RIGHT: - inputMap |= ControllerPacket.RIGHT_FLAG; + context.inputMap |= ControllerPacket.RIGHT_FLAG; break; case KeyEvent.KEYCODE_DPAD_UP: - inputMap |= ControllerPacket.UP_FLAG; + context.inputMap |= ControllerPacket.UP_FLAG; break; case KeyEvent.KEYCODE_DPAD_DOWN: - inputMap |= ControllerPacket.DOWN_FLAG; + context.inputMap |= ControllerPacket.DOWN_FLAG; break; case KeyEvent.KEYCODE_BUTTON_B: - inputMap |= ControllerPacket.B_FLAG; + context.inputMap |= ControllerPacket.B_FLAG; break; case KeyEvent.KEYCODE_DPAD_CENTER: case KeyEvent.KEYCODE_BUTTON_A: - inputMap |= ControllerPacket.A_FLAG; + context.inputMap |= ControllerPacket.A_FLAG; break; case KeyEvent.KEYCODE_BUTTON_X: - inputMap |= ControllerPacket.X_FLAG; + context.inputMap |= ControllerPacket.X_FLAG; break; case KeyEvent.KEYCODE_BUTTON_Y: - inputMap |= ControllerPacket.Y_FLAG; + context.inputMap |= ControllerPacket.Y_FLAG; break; case KeyEvent.KEYCODE_BUTTON_L1: - inputMap |= ControllerPacket.LB_FLAG; + context.inputMap |= ControllerPacket.LB_FLAG; break; case KeyEvent.KEYCODE_BUTTON_R1: - inputMap |= ControllerPacket.RB_FLAG; + context.inputMap |= ControllerPacket.RB_FLAG; break; case KeyEvent.KEYCODE_BUTTON_THUMBL: - inputMap |= ControllerPacket.LS_CLK_FLAG; + context.inputMap |= ControllerPacket.LS_CLK_FLAG; break; case KeyEvent.KEYCODE_BUTTON_THUMBR: - inputMap |= ControllerPacket.RS_CLK_FLAG; + context.inputMap |= ControllerPacket.RS_CLK_FLAG; break; case KeyEvent.KEYCODE_BUTTON_L2: - leftTrigger = (byte)0xFF; + context.leftTrigger = (byte)0xFF; break; case KeyEvent.KEYCODE_BUTTON_R2: - rightTrigger = (byte)0xFF; + context.rightTrigger = (byte)0xFF; break; default: return false; } // Start+LB acts like select for controllers with one button - if ((inputMap & ControllerPacket.PLAY_FLAG) != 0 && - ((inputMap & ControllerPacket.LB_FLAG) != 0 || - SystemClock.uptimeMillis() - lastLbUpTime <= MAXIMUM_BUMPER_UP_DELAY_MS)) + if ((context.inputMap & ControllerPacket.PLAY_FLAG) != 0 && + ((context.inputMap & ControllerPacket.LB_FLAG) != 0 || + SystemClock.uptimeMillis() - context.lastLbUpTime <= MAXIMUM_BUMPER_UP_DELAY_MS)) { - inputMap &= ~(ControllerPacket.PLAY_FLAG | ControllerPacket.LB_FLAG); - inputMap |= ControllerPacket.BACK_FLAG; - - emulatingButtonFlags |= ControllerHandler.EMULATING_SELECT; + context.inputMap &= ~(ControllerPacket.PLAY_FLAG | ControllerPacket.LB_FLAG); + context.inputMap |= ControllerPacket.BACK_FLAG; + + context.emulatingButtonFlags |= ControllerHandler.EMULATING_SELECT; } // We detect select+start or start+RB as the special button combo - if (((inputMap & ControllerPacket.RB_FLAG) != 0 || - (SystemClock.uptimeMillis() - lastRbUpTime <= MAXIMUM_BUMPER_UP_DELAY_MS) || - (inputMap & ControllerPacket.BACK_FLAG) != 0) && - (inputMap & ControllerPacket.PLAY_FLAG) != 0) + if (((context.inputMap & ControllerPacket.RB_FLAG) != 0 || + (SystemClock.uptimeMillis() - context.lastRbUpTime <= MAXIMUM_BUMPER_UP_DELAY_MS) || + (context.inputMap & ControllerPacket.BACK_FLAG) != 0) && + (context.inputMap & ControllerPacket.PLAY_FLAG) != 0) { - inputMap &= ~(ControllerPacket.BACK_FLAG | ControllerPacket.PLAY_FLAG | ControllerPacket.RB_FLAG); - inputMap |= ControllerPacket.SPECIAL_BUTTON_FLAG; - - emulatingButtonFlags |= ControllerHandler.EMULATING_SPECIAL; + context.inputMap &= ~(ControllerPacket.BACK_FLAG | ControllerPacket.PLAY_FLAG | ControllerPacket.RB_FLAG); + context.inputMap |= ControllerPacket.SPECIAL_BUTTON_FLAG; + + context.emulatingButtonFlags |= ControllerHandler.EMULATING_SPECIAL; } // Send a new input packet if this is the first instance of a button down event // or anytime if we're emulating a button - if (event.getRepeatCount() == 0 || emulatingButtonFlags != 0) { - sendControllerInputPacket(); + if (event.getRepeatCount() == 0 || context.emulatingButtonFlags != 0) { + sendControllerInputPacket(context); } return true; } - class ControllerMapping { + class ControllerContext { public int leftStickXAxis = -1; public int leftStickYAxis = -1; public float leftStickDeadzoneRadius; @@ -739,5 +739,26 @@ public class ControllerHandler { public boolean backIsStart; public boolean isRemote; public boolean hasJoystickAxes; + + public short controllerNumber; + + public short inputMap = 0x0000; + public byte leftTrigger = 0x00; + public byte rightTrigger = 0x00; + public short rightStickX = 0x0000; + public short rightStickY = 0x0000; + public short leftStickX = 0x0000; + public short leftStickY = 0x0000; + public int emulatingButtonFlags = 0; + + // Used for OUYA bumper state tracking since they force all buttons + // up when the OUYA button goes down. We watch the last time we get + // a bumper up and compare that to our maximum delay when we receive + // a Start button press to see if we should activate one of our + // emulated button combos. + public long lastLbUpTime = 0; + public long lastRbUpTime = 0; + + public long startDownTime = 0; } } diff --git a/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java b/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java index b9a9df67..7b7bb109 100644 --- a/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java +++ b/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java @@ -16,6 +16,7 @@ public class PreferenceConfiguration { private static final String LANGUAGE_PREF_STRING = "list_languages"; private static final String LIST_MODE_PREF_STRING = "checkbox_list_mode"; private static final String SMALL_ICONS_PREF_STRING = "checkbox_small_icon_mode"; + private static final String MULTI_CONTROLLER_PREF_STRING = "checkbox_multi_controller"; private static final int BITRATE_DEFAULT_720_30 = 5; private static final int BITRATE_DEFAULT_720_60 = 10; @@ -32,6 +33,7 @@ public class PreferenceConfiguration { private static final int DEFAULT_DEADZONE = 15; public static final String DEFAULT_LANGUAGE = "default"; private static final boolean DEFAULT_LIST_MODE = false; + private static final boolean DEFAULT_MULTI_CONTROLLER = true; public static final int FORCE_HARDWARE_DECODER = -1; public static final int AUTOSELECT_DECODER = 0; @@ -43,7 +45,7 @@ public class PreferenceConfiguration { public int deadzonePercentage; public boolean stretchVideo, enableSops, playHostAudio, disableWarnings; public String language; - public boolean listMode, smallIconMode; + public boolean listMode, smallIconMode, multiController; public static int getDefaultBitrate(String resFpsString) { if (resFpsString.equals("720p30")) { @@ -156,6 +158,7 @@ public class PreferenceConfiguration { config.playHostAudio = prefs.getBoolean(HOST_AUDIO_PREF_STRING, DEFAULT_HOST_AUDIO); config.listMode = prefs.getBoolean(LIST_MODE_PREF_STRING, DEFAULT_LIST_MODE); config.smallIconMode = prefs.getBoolean(SMALL_ICONS_PREF_STRING, getDefaultSmallMode(context)); + config.multiController = prefs.getBoolean(MULTI_CONTROLLER_PREF_STRING, DEFAULT_MULTI_CONTROLLER); return config; } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d5258ef4..1301092f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -95,6 +95,8 @@ Disable on-screen connection warning messages while streaming Gamepad Settings + Enable multiple controller support + When unchecked, all controllers appear as controller one Adjust analog stick deadzone % diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index b56f0d15..678d0b7e 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -26,14 +26,19 @@ android:summary="@string/summary_checkbox_disable_warnings" android:defaultValue="false" /> - + android:title="@string/title_seekbar_deadzone"/--> + + Date: Sun, 1 Feb 2015 15:06:27 -0500 Subject: [PATCH 2/8] Update common --- app/libs/limelight-common.jar | Bin 956815 -> 958347 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/app/libs/limelight-common.jar b/app/libs/limelight-common.jar index 63660c373a81e7edda5f5c7bd1ef4f2930331972..3a47834487c285d570a17a303b16b8fd41fcd0a0 100644 GIT binary patch delta 18330 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 delta 16584 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 K7x) Date: Sun, 1 Feb 2015 18:07:03 -0500 Subject: [PATCH 3/8] Trap Shield's back button as controller 0 --- .../com/limelight/binding/input/ControllerHandler.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/limelight/binding/input/ControllerHandler.java b/app/src/main/java/com/limelight/binding/input/ControllerHandler.java index 2ede0647..55f81cb9 100644 --- a/app/src/main/java/com/limelight/binding/input/ControllerHandler.java +++ b/app/src/main/java/com/limelight/binding/input/ControllerHandler.java @@ -101,6 +101,8 @@ public class ControllerHandler { LimeLog.info("Creating controller context for device: "+devName); + context.name = devName; + context.leftStickXAxis = MotionEvent.AXIS_X; context.leftStickYAxis = MotionEvent.AXIS_Y; if (getMotionRangeForJoystickAxis(dev, context.leftStickXAxis) != null && @@ -240,7 +242,11 @@ public class ControllerHandler { LimeLog.info("Analog stick deadzone: "+context.leftStickDeadzoneRadius+" "+context.rightStickDeadzoneRadius); LimeLog.info("Trigger deadzone: "+context.triggerDeadzone); - if (multiControllerEnabled) { + if (devName != null && devName.equals("gpio-keys")) { + // This is the back button on Shield portable consoles + context.controllerNumber = 0; + } + else if (multiControllerEnabled) { context.controllerNumber = nextControllerNumber; nextControllerNumber = (short)((nextControllerNumber + 1) % 4); } @@ -718,6 +724,8 @@ public class ControllerHandler { } class ControllerContext { + public String name; + public int leftStickXAxis = -1; public int leftStickYAxis = -1; public float leftStickDeadzoneRadius; From f0b22f9119159f9c1eacfc9c32e70cf9c5ce9dc6 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sun, 1 Feb 2015 18:20:39 -0500 Subject: [PATCH 4/8] Don't use small mode on TVs --- .../com/limelight/preferences/PreferenceConfiguration.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java b/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java index 7b7bb109..c5ad6055 100644 --- a/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java +++ b/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java @@ -2,6 +2,7 @@ package com.limelight.preferences; import android.content.Context; import android.content.SharedPreferences; +import android.content.pm.PackageManager; import android.preference.PreferenceManager; public class PreferenceConfiguration { @@ -67,6 +68,12 @@ public class PreferenceConfiguration { } public static boolean getDefaultSmallMode(Context context) { + PackageManager manager = context.getPackageManager(); + if (manager != null && manager.hasSystemFeature(PackageManager.FEATURE_TELEVISION)) { + // TVs shouldn't use small mode by default + return false; + } + // Use small mode on anything smaller than a 7" tablet return context.getResources().getConfiguration().smallestScreenWidthDp < 600; } From 5c812eed6c8ab8280b353867498b8f18366853e8 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sun, 1 Feb 2015 18:20:55 -0500 Subject: [PATCH 5/8] Beta 2 version update --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 2ac98b95..74780e17 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,8 +11,8 @@ android { minSdkVersion 16 targetSdkVersion 21 - versionName "3.1-beta1" - versionCode = 50 + versionName "3.1-beta2" + versionCode = 51 } productFlavors { From 256fa897a7347cd7e47d4e414ca85b837e4520bd Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sun, 1 Feb 2015 18:31:34 -0500 Subject: [PATCH 6/8] Fix build issues --- app/src/main/res/values-it/strings.xml | 2 ++ app/src/main/res/values/strings.xml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 269435e5..21992302 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -95,6 +95,8 @@ Disabilita i messaggi di warning sullo schermo durante lo streaming Impostazioni Gamepad + Enable multiple controller support + When unchecked, all controllers appear as one Aggiusta deadzone degli stick analogici % diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1301092f..689efad3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -96,7 +96,7 @@ Gamepad Settings Enable multiple controller support - When unchecked, all controllers appear as controller one + When unchecked, all controllers appear as one Adjust analog stick deadzone % From b8065227517c0b50de138b347983518b9bc9c18c Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Mon, 2 Feb 2015 02:13:27 -0500 Subject: [PATCH 7/8] Unassign the controller number when a device is removed --- app/src/main/java/com/limelight/Game.java | 7 +++ .../binding/input/ControllerHandler.java | 57 +++++++++++++++++-- 2 files changed, 58 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java index b7d714b7..44e11471 100644 --- a/app/src/main/java/com/limelight/Game.java +++ b/app/src/main/java/com/limelight/Game.java @@ -25,6 +25,7 @@ import android.app.Activity; import android.content.Context; import android.content.res.Configuration; import android.graphics.Point; +import android.hardware.input.InputManager; import android.media.AudioManager; import android.net.ConnectivityManager; import android.net.wifi.WifiManager; @@ -194,6 +195,9 @@ public class Game extends Activity implements SurfaceHolder.Callback, conn = new NvConnection(host, uniqueId, Game.this, config, PlatformBinding.getCryptoProvider(this)); keybTranslator = new KeyboardTranslator(conn); controllerHandler = new ControllerHandler(conn, this, prefConfig.multiController, prefConfig.deadzonePercentage); + + InputManager inputManager = (InputManager) getSystemService(Context.INPUT_SERVICE); + inputManager.registerInputDeviceListener(controllerHandler, null); SurfaceHolder sh = sv.getHolder(); if (prefConfig.stretchVideo || !decoderRenderer.isHardwareAccelerated()) { @@ -277,6 +281,9 @@ public class Game extends Activity implements SurfaceHolder.Callback, SpinnerDialog.closeDialogs(this); Dialog.closeDialogs(); + + InputManager inputManager = (InputManager) getSystemService(Context.INPUT_SERVICE); + inputManager.unregisterInputDeviceListener(controllerHandler); displayedFailureDialog = true; stopConnection(); diff --git a/app/src/main/java/com/limelight/binding/input/ControllerHandler.java b/app/src/main/java/com/limelight/binding/input/ControllerHandler.java index 55f81cb9..fd882335 100644 --- a/app/src/main/java/com/limelight/binding/input/ControllerHandler.java +++ b/app/src/main/java/com/limelight/binding/input/ControllerHandler.java @@ -1,7 +1,10 @@ package com.limelight.binding.input; import java.util.HashMap; +import java.util.Map; +import android.content.Context; +import android.hardware.input.InputManager; import android.os.SystemClock; import android.view.InputDevice; import android.view.KeyEvent; @@ -13,7 +16,7 @@ import com.limelight.nvstream.input.ControllerPacket; import com.limelight.ui.GameGestures; import com.limelight.utils.Vector2d; -public class ControllerHandler { +public class ControllerHandler implements InputManager.InputDeviceListener { private static final int MAXIMUM_BUMPER_UP_DELAY_MS = 100; @@ -38,7 +41,7 @@ public class ControllerHandler { private boolean hasGameController; private boolean multiControllerEnabled; - private short nextControllerNumber; + private short currentControllers; public ControllerHandler(NvConnection conn, GameGestures gestures, boolean multiControllerEnabled, int deadzonePercentage) { this.conn = conn; @@ -94,6 +97,47 @@ public class ControllerHandler { return range; } + + private short assignNewControllerNumber() { + for (short i = 0; i < 4; i++) { + if ((currentControllers & (1 << i)) == 0) { + // Found an unused controller value + currentControllers |= (1 << i); + return i; + } + } + + return 0; + } + + @Override + public void onInputDeviceAdded(int deviceId) { + // Nothing happening here yet + } + + @Override + public void onInputDeviceRemoved(int deviceId) { + for (Map.Entry device : contexts.entrySet()) { + if (device.getValue().id == deviceId) { + LimeLog.info("Removed controller: "+device.getValue().name); + releaseControllerNumber(device.getValue().controllerNumber); + contexts.remove(device.getKey()); + return; + } + } + } + + @Override + public void onInputDeviceChanged(int deviceId) { + // Remove and re-add + onInputDeviceRemoved(deviceId); + onInputDeviceAdded(deviceId); + } + + private void releaseControllerNumber(int controllerNumber) { + LimeLog.info("Controller number "+controllerNumber+" is now available"); + currentControllers &= ~(1 << controllerNumber); + } private ControllerContext createContextForDevice(InputDevice dev) { ControllerContext context = new ControllerContext(); @@ -102,6 +146,7 @@ public class ControllerHandler { LimeLog.info("Creating controller context for device: "+devName); context.name = devName; + context.id = dev.getId(); context.leftStickXAxis = MotionEvent.AXIS_X; context.leftStickYAxis = MotionEvent.AXIS_Y; @@ -247,8 +292,7 @@ public class ControllerHandler { context.controllerNumber = 0; } else if (multiControllerEnabled) { - context.controllerNumber = nextControllerNumber; - nextControllerNumber = (short)((nextControllerNumber + 1) % 4); + context.controllerNumber = assignNewControllerNumber(); } else { context.controllerNumber = 0; @@ -722,9 +766,10 @@ public class ControllerHandler { } return true; } - - class ControllerContext { + + class ControllerContext { public String name; + public int id; public int leftStickXAxis = -1; public int leftStickYAxis = -1; From 4d3a69cf6a786beb46d7256ed89df511abb0fd29 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Mon, 2 Feb 2015 18:10:18 -0500 Subject: [PATCH 8/8] Fix GFE 2.1.x controller regression --- app/libs/limelight-common.jar | Bin 958347 -> 958435 bytes app/src/main/res/values/strings.xml | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/app/libs/limelight-common.jar b/app/libs/limelight-common.jar index 3a47834487c285d570a17a303b16b8fd41fcd0a0..654e0ca406c9cb3f7251966ab6c868ef57fecfa6 100644 GIT binary patch delta 20018 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 on-screen connection warning messages while streaming Gamepad Settings - Enable multiple controller support + Multiple controller support When unchecked, all controllers appear as one Adjust analog stick deadzone %