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 zcmeC*Y}LKriZ{TUnMH(wgM))%PKo12UTG%g?OFDlwV4{2nAKDqH?Lz+U46`fr&{-o%SS=E8@C4O z=CYn;Ig%6|o%8nIqS!5K@7~*7`*rWPuUl)+M^)ahe>Ydvkn`a8D|bH6uRgb5|G9m6 z&BwRtegYSR{>^o>^eO&3ao?hl>+B__Bemy?u5uq#| z{7`T4{S};&59iG~Yh9k$c=D=rXQD>lIi0P?*Cy;pH@&Q~f2+P!|CXqU{}K*tnK8}0 z|IkWvx&CV=%kP=|J0GcwvplirC!5 zC>yCwoBcadzSTE7I2y?K9tnP7x_II0Sj{IBGE+aePWRxdznJmEt-kkG#O0Yc^=`N+ z3CM_VyA=^U{U%?IZo*n_Nn1m;Z-%0pY`JL?+ujgn6U#m7@l?UWHav0p=i@7Q$%-jF@UIqnt4eP292N|tVZ%cD@jUM)0D(PHsC zSz~D}>xm`225Z}kGW-0DGxdV=TvMO3B+XhLEccXqi-UUa9j4G%CXJs=SEa3z$Uj!G zqU#yQr=+KbJ-|b=5ms8L6y&C$Z6DQEAHsRx91*q6#9XjW{nK+PrZN`=Zzt zm$g>82EG!!E#ZInb_MveT)ww&+1@&1t)`b(6yD8{sds&_ zAVT8bUD;_5&0X)P&AoQ9YE9}9R&LGAf_eT&KD{i_oT?PN_R6Uz&k}Crcz$_1#pkZ1 zk!qlFo${5;2*;V$`mrDHDNL%qR}rIl)nv-IxPA9G+BNq~=1C6;3W|KW?PP}*r^zj= zCpjBFyDdIFW7T;jE0b4Fq4M=286}pNHDKBOwp)Ugn^)#| zSR4?4ojcuCXYL=C{UQr8ejVDlL-5<-JX7V6iHRSl`zCKScy(=Md(}g$l`axmHB;w) zs+;b&TXh9@P~ajalltw4(r1~mMfNIn{8^}%BYq&q_)w$A{Psg8?s6BD)F!TIo%nL! zh7J8kl>_TNzt_#>T6w~``lVFwx88UACiZF0T{rc{dE+v-H9G`$`z=q>`gnoY>CG|2 z&b^PX2>qE|dMR^Jd!Fc@+X0H_o}Cb5dVe)j$oJa?S*HhoSA?dQW+(?fNYsuK?_DKx zciqMI2`PfBm#5{&Ys}(k&H6R{O3rKUtxP$lYi49FUF@}Z_sn{)Df$bh=NDf)wAZKj zSl7*I|9E9(*9P(1ExPRfGTFl{;GOx}T@D9~l23dtepA3b`=gY++_~zOtF|Tk=dkk| zM2afE|G8hLJl$ey%irUrRUL9|M^5yYsczA~)4O7heO4P!rK*bE%FB$3fiu)DW=0uC zoO71_qB+;jw_mBKIfL_Cecrom!pEO4J3eF2x4iuM8?}=vf9I;?TL^u3TewTIPdq@q zHf;Ivmz*Wb8WVJ+jK1YI1%|{2SWRk~d+757zxm7c4SYLP%Z^=PvI%(jxmV-=pjD46fbzrja!hvV1d*{jay#J zUWzJPTvFT}We|7eW%QR^3q85a@;&xTlU(lCPv5ux;`ayF7yeX!meKd+#TVv4xv%@I zA1#w#SRZ8lX_?Ob^p;)9Ve=(7q}F+=)JmFW$E=(@@rT^6PCxsl^B3-SV%sX^7-C$} z@bZ!%XYbV4O+B%*dkpp@PhFn5u)S((-NK9KXX;g$|FHTyDXy76>UB-7Z*Ovp#<6LK zeD|l#x|;EgU9eH>{KgcvJ=GW1R5%Kn-rZuerMGVN<@ZPGTYnmGbnU$HBL3;s*FM_k zZ)xcMRbaeV@8D7LWmX)^r0c%*E(OabsY!%ss&HS*;M`q*{iVIiZ*|8eHtXfrq-!&{ z|NGQmd|^K`ZT`fie*aa|x81&WP+VYB{pFYMzuedGUBTOF7c3jnF}*OpTYLNNm%aw^ z=`79$F*c93aw=|Bw5ZQ{*sEw7`Zl%7dwKn(+biC#aQ(QeV8Km~mcM(o)}5=F(_6dZ zhS}OX?;Pc4EjFC5xb9l{Y-xjSGdF7dGB>_lQ@n15$D@5GHz`evnRI8)@sjykg?)PW zY~6JBD7*_zx88DZ=Xve7o6Q$6WiB)q`^XmfvuDGPqUA4Vu#~Rn+_uI{+@I*nH;^w zY5OY|otu2*zN+HW7t=iU=nC>BtJf?otXB-upKSR}lr=qgzM%hZ=2eO|r;ZEDW}HZl zeA{&Sg9W?2&8n=bDy!W;dFD9kU!RaN!@6&Sb?{$F-CIkpeKMK5{4)E+2`iR#xZSmx zywYs4|0&%U_P?4Zx>zx#-*(SX65D?LWBjS9PM24I&Y9P|W*hJNO;sNwQ?{D8#PluJ zRc`aG*R&5A$#lhd5TdtT^dhb&LH_98}cI`_6?KLQMx!Yj5%q#m5Gn{l1Uo&dSirE!WW zwng0BQi@Mz?b#RbJoJ^;;((>n6AfRlYUUP-S2-1PCZ&E(t5I^zhf_JzF6#<<*Bb@O zm;Df$dv38&*u++f!@h zyEJph)sJo)9gHuF{F%~@8`E%_`0YrBqXlREdF4Q z)@pT!7VVOKlh!*im|f4!&AhQ;@w%;3GjHxzQ2VvVJ>9v=M>p+Q^n|?`yKb&8cG&mU zr|0ChvW@d!C5HFB+H5$Z!+gfYQ-0G=y=%H<_i(rO^SiIAosMvwh}4)}|EuH|Lv6r< zjwS1w)?KSy$$L~_z1bC|{<^v5$)~DU#yzfG*}a+Tc*)MATJftt*JVDjv3NMwyZJ@M z-gD+DB{>ey#f=_kJyn~VKW!@0)}-ssmG!I7ZTD;v|G9ay-z~elF*xLY<&8LLhIF+@!(7iRV;@B3TNX*IPkeWv;Qbvz+uS$`HP#(%P^Y81QhBX3#d z;|uF*I@{krs$QyBGh<~^jNvk^KXd;CI{uQl^&+R*wD~EA)6( zBnP|M!wOS#*I$O`S7+o;ci7u3f9WS11RSqts=UVfLdp>+A8SAP;< z+x=&JcjiR?+;;AMpv1mu*Vf9;{C@xP&)=Wwf}-84 zU-$8r>h`{ser0A>fASK4>A#6iFTa?YS^AjNX?}fp<(=l$^7o~V#v%cCcexoan7{Cp z!%v}Qx{rHaZ~j?pmNMt*{B_)?@>yMPx`=Ue zS{!W`4|6`zarBAJ>ENxNkMH-~d(c~8?0$IGzS);^VkC+?GnAg5;18;AD0=c-!_=?f znVeR@;=WiTzeOjrbe1TYiUoH{U3|PkFt%UnBKu0gSdPGj?uXbv8x_p)-2CB-(8Fhw zxa(YIuV%|E3;oJ4HGJw*-V1+LwK9hUmd;tVi;eTaqE*W?FD_zSHF4t^Q-{+m7GB!y z8DAYgU3oVBsrpNy-?5JwaxHj1J+BYejrGYsn6UUy3*X1itP`%@3vL9h*ucZ2->#sY z!MHYLcXp;}EYlpfgslOxrp(FBx^lUPq=P2R=oD39I~8~#E#OROfcA@>A}VQTnD^S; za>~7Nvv2!mjprs3PqL3lm9F@2WqNDb#j?tcX7bzOSPhF_aOIRWo{icl#BwT7r@Om; zy^WW(S(xa>UQeUdlSFEQA|piREMduDS^V|GWPi@}%-Ztj1->Ren|Oa~&hFr?LUUF; zuxL$ulrd?Y-4wOd*V{cOPRR8sob_7a-usSCY{&fOsPyxA-fB+VZ+mT&7!s)~j@dmgTB@v9WX4%$h*F|P02rqp63s1f^MyKHv&q3H07ty`Gg zj4x?5?ta`~rn)x!(vi-i6S#YOlC3_To?9~AV@|bh8b?aqUyHk!RTV#()JizBJ~phM z@Gg7Zw8%+vcS80Wc+Ss=ESdDhwY7WlmlMt*N$=Nd{ySr6HN$ylyV%oP-k!hi1pa!& z6~0pYfAGxMdggQMf~J4d5M6qYPi}FtWyq^4r%0Ju6N{$0oUAmOUi*{z%Ns{6fdJ-; zIrCm?{X3;#8~@7d()Gz-&My8kx7lR-wWk+CUfUn}wMb>|p-qRwMSgq~ta@rJIk9eP z)TVeH?@RfUzUXgVXLOyr%xvk3zj9YLeV?QCZ+rQLy2p%F5xuDb^{@TeGnOrywPe4Y z$MvNW|NOtzZGAua%e+-tjsFT)n61~*_gvon<0Nuw5E{Xf4<-aWU%bcDaMXf)?N>~%O%#@gW!@9A` zA>|Oatwzh<70iyi7%aYSkrq*^zv39^vaofk#62~G+s@Z7o1SR=Thg#@vH#`XFP6JR zZSoeczxeix)ZXcJzVDZt3v~W>(D^s{-J{MDbMeczHG+3fXTM0^)A#OqSyjXOMeLR? z^3M%y&s@Kx{zJ^FA?&;0zS(k5-Cr2mH5E?a`(#)(XMfx2L;WuV_PfMCn14a=AFFNs z(e;5rPn~CrWY^t2+5Wj;o>-&&<(xSeRkirVK7?0rEr@xsdA9e&L_H7d$=g0yK5431 z|6ym1+=AN^e4}^peD&J2sudkrYc{i_cHYw$`V(GEUA*O_D&te@n;e_&bf+rDEnOs; z_8S0lmu{zpwe~~3mr1qtwKIa%iPdO-ui#~buIA*2SO@(mt!%f|>Gau#7 zXI>tl5r2sD@1{wQWTa0|bXs0xH-Gwsf=DZ->1(;#7z_X1d$l3b%)xwR(K+!OhfnED z+m;`9aON+qh`%z&|LAYZDm`UxSu|CqF>>CmtqfWx-YhMXwkL6dzU+d(uUdb1&VyGcR>pu>$YKc#k?mjV1dR$^MkywRnGe zWlq$s6bSGa|xv56Oi8>nC11-#5aA*;Wvw>&hg*+ zgZl%^t)p_UoY!_QWcgAo_|{$MUPDxcbk>940iW%T1P3lozfk*TX?um)s}C|)ZtgTW z@cE_WlIPqW$HjMc)t$NeMfgKiZ}yA+n!2#A{q+xbteWBX>FtVlJdyLBfB*FR!ISm} z*K}*zFEg86SaSKqFB_4-FaMq&ZCz?VJE*^%O)+&`dTbv;yTr!amn3sO%FW= z4~w05tQXDlyQx1d?E`C(?6ksLUsURCE(@;8I%Ie0M^I6*vFOKTYrNv;Oj|rd{+a)c zT*G>yfL)h%AN<6?7dZQAnNCNCt8;|f&)~zBd5rFJmU(P&x;JZTOTBAmpX(oudbX6! zKWxg}?AY5szhs*K_CYc0j~L51yZ+C@eDfFYDDydBk-UO4eabGc&t9Lsw+59@vY-Ai zv-$?h`MeKrTopNkG~X{WI&isi`=k0+UxTytZ1wjxzTx@Tv}uh)e2dRct}3Ak-j3}X zXDwf#-0(^Ci->}+qd#*I|J9`W0~a3&h}~Hw)W61c(&WRX8x}b8SgB+PeGle*zp$9m z-&NM*yW`6yP7lv@TH7YYObu48T-W4MG`*?M!pbLj(sS(>nM<9gJ#oL-adVP;qgsdR zVHN*R#)oZdbye>1cdmDDxi=wH+v`%$v=5v6rl|f=bw4F!w{XdsNB{0fE`D?RaAo~{ zo_pIHzUOvqy6xV%X+2-(Ca3K+dSyTM=&e^t?EmmNR{iAHC#e=Gem1XfMwGVf?{hx9 z_ou>6y~9tWXFOT1cK^^41KZs)#^G6?VtqaZO_onsbaV2$cwt7z7wjrkD2Y7v+mH0*`@WtbLZ__*`?Q=@rbQA-j3IJanwGY z{@^Wva%VF&K5LYG?!OpvJL>#op>9Kezd2{F-g;(aeUw$h{^|VQh9Enc)HJbE+J7FF zFW~vKy1jkjo|)HF*=zUN)OW_kOP!6`=l!#H$7HLY;n}BOg#I)AUzU6GKU07=JBLAJ z>cWen3=FCU{0s~M@X_M!S@x6jLo_xYkiEkU9x|S<*vbfEO#k4|sIl2!`5c%xxzIvm z`utix;pslLe0-ZTRpY^`r}vdGg2g2_^Js2>2r(KmYE1uI%O|^;MRzr`;PxzgHwGl& zIGvH5QEGa89iP@@7Q=5~s|39nH9#U_o2`w~S-?Ud+o$W-^NDYMV%7zA!sbE?4=`i$ zMRtwJ1`ceK9|W*%{$ME#*07n)?mt9U=cLAF1BaiG0dO7XVos2GlOI0Tm|oM!C%pNt z&n2)sC+j%tO@0t?9xN+fsXe)&gnPPu6Q9WDKY;}h&G{i0*g?|M!R}LN;S2F&2_%_chQ2~pC zJU89Gl}~8%uTm+9A>x%#7w3m)Piy0o-E30Z%MUUYY{q2!O1|j@ZG3#2IeG;U&V>oH zZ;qJq0Bp`={w$DoZjfTO&E+#1xxi-d%Q9+AwyzY}Y`pjw#04;QKim0uHrp+gg!m2= zA(QPZIj67h;A7o9VU;4-(9K)co@WD@v$<`HIuD339TfkQ?JkH-U(m_NzWM8c8n8mR z@a9cN${{hPbMiSvtJnoLu$s;Cm-h>R%-H>^vU%3CJg_vFWB=+K*p-_t z-t3S9sh!R*%c#3uft~RZSO+*oPEL5kI$eRCk#D;J7vmivkh1OkvW%O+Dkkfk)R^AT z$0s^nvyV?`yRZV|8i;s)2v}TUJC`zJJ49%{B3MXd`vq0TV6dwvi&tuZjrZ*5ligmR z#i$8(&h|OljFZ87KpxfGo}kA#56s=pXviqe#5`HW5tN0dP2gi^Da|R#oNn*UC|)1@ zHt4pSh;6rhN)Lxtf{>GwkXNUUoexLu6F8uaRzW)C&>jqvEl^%nfEq5;W zB+rlPyKDE+c&>T+zVw;PC3k<0y?);2wbj1Z`U2~H&#n5NhMu{WeR{e;YQX=``-T3q z<+QDssQr>hdHpAzo;or}jzC`q2A%d+RDMW?Wd`WN~9x!o|3x)lYB8-oBsKvErpvX=FkFnm~g)69k>- zBsy)k4hxu^XeQg87*rm;EZEp~_U(nn`$XF$gI8az+2`fIYnlrSw^821WUe*SE}6>x z5SA34V7W`%nKK~jnEQ+;8Ii|A8p2Y2*mp}xu4K47*-&`FZ=?EkPRlm@>-7DU^Xh*+ z!=@6kebL)(S10W&jrrX1aMr5&?0tsDvbWDZx&JF{Uv*7RWn|nB=M+_&MeqJQT72l! z@joUe7i_RMMWX8ChKPHbPfzh&{uO2$9ZJj<|gwfZ{sA6Fm#NjExWvA|K$ZuztJ;Q7U` z!g)5oTCJ$F%j2w?bJmGxF1NY#=jD~&`qwGpzbozJs@q?quB|(p{_fY(Ba&^7CGX$0_c|>Sz9He7Y<0|M-j93$ol-ZYx~nxM+^% z8E!U>OS*UX9{=@}i+j0j*_r=M*0*B#yKnW%P1`ctc14udt>$G*lWf;ytgPVAj`Dhy z80)QCb>qi`z{UF-T~FP&_!b|s8k7$YQe*76?s#gN1Cfv>nWI zbZKKokNVt#kgJk)_fpF9H{F@Qzv-ZEZ;+#u$04pu4wD5mB~mV{G;}&}XqfNbep2=K z)4RJBSLkL0YG-UszHRtm%Vn#%OSaiB__TCx;F{27b6;8{-;RIVGk4`**ZQr-bEhTx z%r7qAd^4kibLL6g_m%t4{oW)0{NCTc>iPRv6Kvxy1gLPh)=&BvaHeavVRpd@PF1%{ zeYsK}CrtH7opWJZ%At*uH_piXzT?f**CrJ#qV2tc$|A->%?s}-ep<{l-#BGy_&wkD zx!j*_I9(3YPPEKz`dZ4pC3dg-gPYTOW-S%ax%9C0e1FoEmlrlf1jH;CIc2@J<>uT@ z{uyQK4F!x@L+76C5WJmSe`DIM=QHG39X8}8Dz1rfXE<7>_RyWd+w=;Dl=u^e6& z7Ub9OD-os@@qX9bUHBXluRGaj!e3 zyw!Jg5AN%;4HBP*>=Iz;Y zZ{%ivGgx|W6GtycW`y>N_=cH%yARfcxPO`yceyW`^RS_1`u3}$PxjZEBrTi5rtUcP zo1Col2hql~rMDkzK3`$Y^xHH?#N^D(JN4^Q)N;#I-OuE7dR=T;|0<(x*0~ju#XYr5 zF9YA4wYs(JX6>shx>ozz*6J*KI%C^Im6^+D?K-rK=lKtx6SX(iEu5?TBXVWm@4If^ z2EV-w*DQAS-FV*YagWbNtJ0F4KiYaq%&-2r(Ro*@j8n{Ced+0fwi25Lxkdfbi<$Cc zE%sQgsV|YgvQho?_B)MtmoMi3z5I5;-UkPqZWrWzZQ7UKYa;VN*SuWS$nf|qJC*EJ z4;2r#RUX@VwLr;vPF#7{UyBasS5_u0()R4P*0}GUTPh$Z8(8q~^yQh2JD!%zcHi_U z`rEGfO4%!hOO#e`^8L!Sp=ZX|6_%ym9DJ`O!k+4FzLdyUzce>JXbvN9;la0;zv>A* zeeUQSwBg9rjguCBIJc+a?UYlj`_leRP5vzW`_s9d{7a);`P}N}v1Hq;+ZwC)+lg6v z9`CqoZd&?Ka*kb*P8{E6U-A6a?pJzc=W6*@mPHHrM4s9ZS`&OP{mo133zpvJUQ}fA zU0?qC#JW9GUwwYicu22a)Z}dWtF#hx*{f%2rpx>K?mfT#%%nxveoo)x%X;&1!R6E? zG1H~?8D9+!j<-9hd~@?3+mk)AhTEgFgnxVy-57RrgVftj51pB5Z(^4jPw9D85f__( zZ_8n+4P}XO-@k2}G0|^!rcU~A@z2J-T3T1ac~>g^%hpibKjn(rJJI9&m;I|}lApd{ zesSq3(eqO;80%l*3bM*Py4Gdt>G-Cjk^1xaE7`(-KHpKZ=b6o)>4CL^@jDLr$-6Jm zKE3m^O_=GP#x|unr&q7B@2$VOzj>Kq%n4 z3p2Lb{Dj#J_hxTh@GNRQN0v#x-b&tS7Y^4i+}7YOxVC+kjaOy6gKoU|oOw0+FKWwW zq~_;e-`BM1)Z-O-&ii=J$q|rhof%yMzaUKMtu$Xx1Ow&JuJ^O@A72*zQ=o=-lTWzt>?L~{_UUM z%X7}(MCzTsX`Q%dlM;X7xzyT>JzRgUTim!_z{y{3&Q|-SP>?x!Mc65>P3HVJA3J^9 z^SkWvZ;i~H9Ub`^|G(yake+4Bda!yK_Y~3dVSBqb9J7lo>$43x6Su;RhyPLfj0At5 z2jcIlc>f=(pD;o8)22Cz@pC51?|j`dXX^En`?cgxw0j&_T>s0bYeTDl>#3{n??B z{ZMh5*L1BzoX27hn^yk|zVhm9V4RKb&1?>__m>2AH+u1&R^KQ&i%oImLeCv~mpRzK z`)ty!F=oyBe5O=ndhT@T6_b9aPAcF^=yesD8)4MBRO8gAM$fuq&t$)5TUeAH;XN8r zCmVV_@YcMqF_#=a|4;0UTDSXV{k6TE{*Oe$`HTO{?0bE${?WbWKfmokwQTr8hWX~~ z3=GWt=(Vh%H>1V$`&Nv+^%0ykGS?&j+rQ0nkLrE0_03n+n_)SpBV+H~=)7yOX==o$ ziMb_LCq32Z^SriOIrGugbw<{&7w0-@v~IieRI6pN?(_z>72YZ{cWlWFW-476vviB1 zZmZmdWdRyrT5kQ>Z@zi;)u%U(*uVY#Z14Mh_r4c>y;UsFu))1ldPTqskEd#n>m{o% zox1T@IM1e9@4Z!6kx^dya<05R>eEZ-#;7G*I#=Cx2vGbK@hQe=o@d(e$IR(+n}gOl z6%;)9v7yOJz=Ew7S$+JyO z6Blv3W~$usZQTMc$u!NQ=TfU}?)Z6~(q2>l?rK+xuDRV5@3~u3>?deXxN7zO$ho8J zTzYRmOnF{7HTnCEVBu+t1+H3%Khk{uXv*yF>f0_WFHYn4pP=M>wEB7P*KZv{*EH5^ zN3eQdxhBDS{oIjE?^O>h!mjmxzjbqS*e+}5qi^2qIHsEVb%O0Y-(9TjEz0J;6$z^6 zD;&K}yicePs$S6Tl=bpo;iWS1W5=H9_NKq=d)K}0X>PY(Z54Ew-061bn81-JH=dmEj=O7W6LXw{O-0IPbtJ_~7;cfu2#na=^GNO1 zg>xQi#wim^UY_9H=yH0K8rSJqHM68(({~5tn0HHFVC`V8_lvT)*SY&e-@79l-TS`C z`^mftkGQ>CWPPy6?es^cJE9jFsYi3=ZhUGGe(kxOFz=%NLyW?v2CE(BueU2n(YSZ{ zuJHTwylR&-f2sETKEP!A5Jl%gp%acHmx&|HTh^IvwXIR zRPvU9iHh1!BlP^OcsJzV+4jJ|K6UA%&f;cIb<511Iktbq43*XV9yxyUvGSW_)4Xw7 z@ZCh7hl(fn1lx4XeU&FEczv$f$J&Y(jY(Iy?rv;(K6}qmlP!0<3kCOPc-ME^PLVwS zF*~WK@r&QXSuUpzNUFVb+Vt;EfTC&OBI_c>RNv0sK1-HLh4~r^J{9+&S_ z3(G0p`*ttpiruHoo@u`}wV1b$-sJy>WJ4Gb)+$b;`7-)g&z_NqXRE zResS{^q6qm{@;wkTUQu=Xy%&jWx@HcqN4p$=J8X{m(Hs@afJV|?xowh&*wb-p}utX zI*;e|?>7hU<;W5%apKkx;2}|mj?9(0{|0sOVbBr(9l~U)}LhG2l*XKq4%M&aA)6^N-v7ztgC7J67^bIfP zXT{s`%7o5CG#VXSeNfivr&?%yMCnl1J7*pLU!5cN&dU_9?JgT*BL)$U*Jre z$;B}@ccwh5-4uM*F3Hj_(d)fkc9L6JbN|yfYkt(6JCf=<p7o2j|Xyc|`i})ie-^TS9Z!NfXhPP%-gm=`} zO>E0Qh^yH(@OyRt_ZF^i-M`GMb>$X0=0k@LCNG>Dn)KGU#C7Q*%eiIuCf2{K<>~1) zlsXe0zqL~MOV5+DVdhf3)A*8v&QAZZsj)udXI`vR>LcSHI=)54>bdUzW~a{y%Dq27 z^N0GM&EY9>m4TUl37k6(_9r~*{vq_!@>-?!>C7_UH8lnwXLN@Dzj|c;!^Md)topaY zKjgFRJ0+O0)5`SY`yW!1-`HH9#wB&D{`sQw+CTh-`>$m4 z+zGij<4e^+DrPL}u zbmotGF}u_i2G-YjZ+;OqTDNyf_*SEn-d8W_Z(KO(+#jppg1a%_GSn>3bvyAEswemE zJltn%r#E@^%Z>?`(j)lVW2{TR9sJZEI4SeUqrjWu=ap7Yvb*=?!S2oa;U|n^T^kSY z{2ZC7D|41-Yp3wf-rhOtI#N3VO}iRrryi(Y5k1??vcLZ5%gTudgoA%&efs{Z=()~9 zk>wIy=O=v&pRRA>`to+jW{>ow_Df;MeC;Aw+-gtGF+TTXlHaZKvnM?1?Z|rk_(9vE zt`=9%wX2*}KHe3!%8q?<;h=<|#hI`PpMI5IP0`Ekzxn8Cs48=N(4%_iyOqJ~zHaDN z`o3bXQW3N2)31*HZS{p`Pk+{$`lxsRW4_kl?KQpkPId3l$oT%>`-1Kt`Q}9nY`OUF zuUZhD{oAW_=8x){u2hpL+7_CxSLo)d?V9mcuTa=_{(?<@{%SMNM_1lCRwlzB@NDx| zA;mh$KdT%>_pd&^@9>|;p92riQT%%9q38OV8!x9O_r(2NrgpcAH~)dWeEkurybG_T z=9wlL*KcRYnq=hiZ}QsW8@H-hZ@WF;kj!>=?dp$LQt#L`^T}7qKiYi5y7}+gT;mrx zYwar}zn^>Hp>k;RzHi&o3v_qC_&J+R%6A@bGFsNC0YkKA|rU4CI( z+LjOZ^|pLoxR0A%@Oa=GwX<@cc1@o1PN{$IlP&!H!jGBW9dmv2oZ)JxjOE?+e}Ai- zmuELoi3@vjnWg>TDuw9^p9(l{N@)pH#W+9bh`n;5(n;K7ujth4nJ%r2sS`}=CmrYM z`FQ?WeY~2-F>%RHTzlr7`1F;HlSwi}h^@Ao)!%^OzJ2rZ7blmmd*Hh`#(MtI*{@eW z`*7{5>GbrEi;INj9QEJEWzao;=0R({mp{7duT2y!&|kZwf1YIvU&-Z1a=EKta(>JW zHL9qJbeP)wD@R?lqH4;@52uYQ)Nk(J{O|7OAEk^+3nTy3_c3h#vG?euzKNgZ4PVbw zUavjn*FU37Ywt_{7O1?2I(V!+{=eH|j*mLGj%{MMbL_S|`RKpN+N#df zKSteOjcuwWbAQYUd!XmfVb>#Ga;YpM)MCFeqrKCLrjXY!dc{wc3*SCGzrIL+#ae#l zfLh+{DM?vjCj=sw~m*=?biU(_!@7uFfdR^8IA1yO#SL zO80vd#$Q@hT6tt?)vb>G3nzIw*RKv0ej$8^JLARsEm>@@(muZ27WwC~qt=faar1BIAAP=5U->Qnn(hf_%Zo4O&M|oQL0|pl*Xkze%!AYQ z3xCW03ryJj@rBMlCF{*U`n^TA&pmp{)4$^5jm6UMw0lm4-z?ehrn=v+{-5~9eU5wb zH+j~~e)?5*+V$@RO=k=rsQy#Tc*(^{NRp=LZ{eN~{&7u`M z{8*dncQx)=GDRm`HAF`8uS_-f{w?oUlzq;)-=4bAdSC6Pzpa@qx8i>+2%y9Ci=E#dn7c~yyMWz_yzAHO-ed-B z+UC9X^V+wU%EB`=9!1|?`j#(i#l7v@yl=~1x)7DS)*-1p^y0f`U+3grTg|)gu6t?a zrZ<_Fj$KSRJSXeJ+Yh%Ido%)aSA@PzjSLOHw6Sm7UXM7h+}OtS1lD=w6Q0+<3x9ZX zN!Rt$3YBa%^KQTRWw|w3a$fbx;`z^RK1rPZ@y^TNoBZyst6dr5v-QUv|Cep7Ym~l+ zalV<872o#PR^^*oPZ49?^if^Xx<#ErT1(5O#}vCb9oRap>08ew-Ev*! zXK^!L?K3)mW!jOB(l0(sy!N`?eY-hF%)c;Z>au%(;&k@h-j->W;xy^+m3mFj=Sh>= zj3)V&CV1YycT)DE)|Fdk%lYD>T>d^)GS$jx|8s9SU*>6%dDqMy{AU1l^Mro-K3vMn zz_3>axtj-?uAHx^F>L}L+w{JPd?MRLJs5v7F+Wyx1Wksy)z=0~g^L`UFD)W)-6Leu zjTzTWa=RjyKAWnd#>L^aiEHZD)?3ro?Ra!-s_%7Gp4`Mm0Pw$JC;{`vVmzn)=7?_U8u4xcM;_AW_%Cpj(he&OWa@Zal_ zUsQW;{gP;~yKQ<$U>8f?|L2pAE_*s_`E^bf@uHVI?`%5I+S}tW zeVX11roBr`zE%3I&YBwJ=ODuJYe&)jtJ3dQ<(c*}@K;UEzI=7hta-~_XL^Z*7|nB% zn!2UVW%DGh_Ad_)O9y2vEivI#ykHz26a9*#XTST|r(63Dyihvb`m;4z)ki$5KHXf= zRVd)9l@^gX)$&`02S*>8UHL_q}WLW+#81)U@9JrRcI_cMZR@ zPI~o!Rehb?o#(f*mnBd6a(&v`e9oBO)%st;t2QOxI(a7h`U#Wm+j*aF^f@l2rMSj; zvpP@LxoHnIey~ZGEE6;FJsVo=UEKO*(t!!T@-H73tZC2UxWC!y+zroz{1;evHXxABJM>`aUo5#IBAL*X8%7u-3}%^LY2Ya7xX|e&5T-=TFT4{X^_0xBT&w$##Adj@Rlu{(tGX@Eh|)A0^MH z+FGWY{@m$dtLG1Ay4VrM>E6C2-teke-6gGsFSuH*_gC<}`}kc<_{_1BCEp90yZ^M! zIKrrwHi0odv0=J|htT)EqMKIQIjq|IFg`~3nekMP80npIue(Z*H*LI7ZR1lPlbvW~ zc!c{iy={S7(n7JWg{?w^fT%Mx+c;%Chv!|^yy|!ts-w?FPyz->y$+9C#laRQkyrceiF+5DzihPoC$^gXM_GOE`IXE$>w4AiCH`W#eJ|k|gZ>`JZy6Kp zXKBgsURmsTQF_l&*_Y2OK6$3e+GI*py4juAj!W3b-Sb28-KQ=73yRVNUFVhe?l<~% zx;_21%l>wP#&7#vjz2FVEg^-~yFZ%qb6FS| z1dBM(N~`T3{23R6XM!ioUj~(1+|$=j;uF|@Gl=mxSQtECJUu~=k##!%WImzoFG3lG znVB_}96=M?APsDwxni#AW|54-^>ahK{iV}IY#*z)DO#vBs?2CvzVYl~-hfLYQgND` zycbq2%X11pY+xwdW+-)xrSxj*^t&Nh%Arnow{VN;p3(>k{mTAD{mc50RaNiInG+{_ zoJ>1sd;R{M_jiil|9JoZ-w*Bs7II4jFB@cDD?i=0H`}r-_qP6S_TT%`C3mOZzMEbD z#OZ@fhyiHFxcID5u?msvAculCR z&EJ>t zOYpd;toX%+ig6lY#uo}g-Gx^2tW%!uHofiR_Wcg-Qocdj>Zy6JPArIg;k&TbD$41W zdPzXLoSd9U)P;*umzpjl%8EN#>6G}mM|&JM*|PS=I#H`lc{x_o+P+QQm1z-rcyp`! z$(H@O#SX#w^=7Y3PaCXV7`kQ~uX;|e_gB5X>=QF?PunT{&VN(^f9o~`}0Ej`M6+l!NXkL@ z)=L~su@))P71`#p!u{tp4tCR81t;vGS1>a z21~d>C*PR`!ru!-w^wXZ7O6kDe;%iU>*R|0Ldi+#DqrQLCMwvyIVGz&)8d@1yHQ!7TiE#dl@~hBTB(=IvSb;00UL3lbPPw@1e^z5*96+dUE(%fX9mrh6nX zI&5c3XIu$c&I4Md15zx${cR3o5?Bdn9T-SRXnIdEmUiz+tnJ>D*xJ1(vA26q;%N7t#M$mW ziL2dv5_h}zB%bZwlXzb~XP#5yINiL8Zv)tZS5>_|#M!-4H9*rcbZt z^Hcz>B>VM}f9fJ;28M2S1_pDaRb>neZ)7JQG?1KpKvrS8Wepz>Shdtf#)F!S3=A?% z3=D=Ssy{12Rf|ktR?jB{R-H60AapJx1H&OE1_nJ8)z!*i)&9!jIsx8{Od<@Boz@@+ zIhpG#yD~E{XmBzxSfFSsQ3Yv&FPeiaR?4j9lV+0FgvqFaEzbW~Tsx7Of#DDv1A_^Q z8N#}g4;si!tK(AxhmmF-pEMJj;pBq`&eJ>Vpq`vLLzms1g@GZ0i-ExyMR%al&rjoure^L<3?ARoiI5t zMsNC!Ha=mn=R2GEq?s(zz=Btrp@OeKg2`Ev17mcjTeL%C(6fb4nrUaz|+G?PRxT$*)yK^q^$>Rymk{uERx zc0?Gw1IhQ#K$T}h_}sUhPnyYpFrJ=qhL)1kp5-g* zGBGezu%Kr_(pWOq^7#lz`?(EYAr|?OFmuD)lGs;cp z?1e@`R7~ZkJwgl&$J7}Z3{d>%$%UeaZ@K{&BOAD61Uqucy=B$DObiU3EDQ`*C>oPx z5gKh|8Re#*?}fVZUN0yYD1fD>!xoy#fm4-NAD=Xnm@-@nQY@|qiM~*Ui;7IYpvuTL z{eK_SK)!xHX{IVIusqmvp8b59;K;pxZ@-Zv69dC876t}&6z6@IKCz$A3~cEskoGn` zu=Z&a_%y+SIurP$nL-U=f^5_E4H?C!*MrLR$tsR+$V=H!tF?S%m>$GRRxwa=7iF7~7l#(xWszI+l?Sk(9R|@stx|V_^8g%fMiU5;Yf7LF!$=3H~+f zcH<6K28IT1bXDFtAXSFbmra4zP20n50Tqs@zQZG4u=Ttsba8Nx2nPT4x5xrN>C_Y_p8lM)^zJ9of z(DeK+Mvm#d)1aAT&NM!0ru!2i@^w9olG9(qq<&4~lV-j$opE~fBu3@w*3GP-aIWVm(o&In-pCi-J^yw-y`0SaAw5F%d;Im~a_n5u}#NXsI{pk!o xbEYpf)8%IJ`KpxG^D*e9XO?89=j9ir26(fwfkHHbA%bDMJOjhNdOijQ1^`jVRAm4F delta 16584 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 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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 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 689efad3..c871dcec 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -95,7 +95,7 @@ Disable 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 %