From eed4327d26d6b8cf69df3ca7e7493dfe66479412 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 24 Jun 2023 19:09:10 -0500 Subject: [PATCH] Add controller touchpad support --- app/src/main/java/com/limelight/Game.java | 4 + .../binding/input/ControllerHandler.java | 91 +++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java index 916b20ec..9168225e 100644 --- a/app/src/main/java/com/limelight/Game.java +++ b/app/src/main/java/com/limelight/Game.java @@ -1454,11 +1454,15 @@ public class Game extends Activity implements SurfaceHolder.Callback, } int eventSource = event.getSource(); + int deviceSources = event.getDevice() != null ? event.getDevice().getSources() : 0; if ((eventSource & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) { if (controllerHandler.handleMotionEvent(event)) { return true; } } + else if ((deviceSources & InputDevice.SOURCE_CLASS_JOYSTICK) != 0 && controllerHandler.tryHandleTouchpadEvent(event)) { + return true; + } else if ((eventSource & InputDevice.SOURCE_CLASS_POINTER) != 0 || (eventSource & InputDevice.SOURCE_CLASS_POSITION) != 0 || eventSource == InputDevice.SOURCE_MOUSE_RELATIVE) 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 3dc72a44..93e363a0 100644 --- a/app/src/main/java/com/limelight/binding/input/ControllerHandler.java +++ b/app/src/main/java/com/limelight/binding/input/ControllerHandler.java @@ -547,6 +547,10 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD context.hasSelect = buttons[1] || buttons[2]; } + context.touchpadXRange = dev.getMotionRange(MotionEvent.AXIS_X, InputDevice.SOURCE_TOUCHPAD); + context.touchpadYRange = dev.getMotionRange(MotionEvent.AXIS_Y, InputDevice.SOURCE_TOUCHPAD); + context.touchpadPressureRange = dev.getMotionRange(MotionEvent.AXIS_PRESSURE, InputDevice.SOURCE_TOUCHPAD); + context.leftStickXAxis = MotionEvent.AXIS_X; context.leftStickYAxis = MotionEvent.AXIS_Y; if (getMotionRangeForJoystickAxis(dev, context.leftStickXAxis) != null && @@ -1262,6 +1266,89 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD sendControllerInputPacket(context); } + // Normalize the given raw float value into a 0.0-1.0f range + private float normalizeRawValueWithRange(float value, InputDevice.MotionRange range) { + value = Math.max(value, range.getMin()); + value = Math.min(value, range.getMax()); + + value -= range.getMin(); + + return value / range.getRange(); + } + + public boolean tryHandleTouchpadEvent(MotionEvent event) { + // Bail if this is not a touchpad event + if (event.getSource() != InputDevice.SOURCE_TOUCHPAD) { + return false; + } + + // Only get a context if one already exists. We want to ensure we don't report non-gamepads. + InputDeviceContext context = inputDeviceContexts.get(event.getDeviceId()); + if (context == null) { + return false; + } + + byte touchType; + switch (event.getActionMasked()) { + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_POINTER_DOWN: + touchType = MoonBridge.LI_TOUCH_EVENT_DOWN; + break; + + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_POINTER_UP: + if ((event.getFlags() & MotionEvent.FLAG_CANCELED) != 0) { + touchType = MoonBridge.LI_TOUCH_EVENT_CANCEL; + } + else { + touchType = MoonBridge.LI_TOUCH_EVENT_UP; + } + break; + + case MotionEvent.ACTION_MOVE: + touchType = MoonBridge.LI_TOUCH_EVENT_MOVE; + break; + + case MotionEvent.ACTION_CANCEL: + touchType = MoonBridge.LI_TOUCH_EVENT_CANCEL; + break; + + case MotionEvent.ACTION_BUTTON_PRESS: + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && event.getActionButton() == MotionEvent.BUTTON_PRIMARY) { + context.inputMap |= ControllerPacket.TOUCHPAD_FLAG; + sendControllerInputPacket(context); + return true; + } + return false; + + case MotionEvent.ACTION_BUTTON_RELEASE: + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && event.getActionButton() == MotionEvent.BUTTON_PRIMARY) { + context.inputMap &= ~ControllerPacket.TOUCHPAD_FLAG; + sendControllerInputPacket(context); + return true; + } + return false; + + default: + return false; + } + + // If we don't have X and Y ranges, we can't process this event + if (context.touchpadXRange == null || context.touchpadYRange == null) { + return false; + } + + float normalizedX = normalizeRawValueWithRange(event.getX(event.getActionIndex()), context.touchpadXRange); + float normalizedY = normalizeRawValueWithRange(event.getY(event.getActionIndex()), context.touchpadYRange); + float normalizedPressure = context.touchpadPressureRange != null ? + normalizeRawValueWithRange(event.getPressure(event.getActionIndex()), context.touchpadPressureRange) + : 0; + + return conn.sendControllerTouchEvent((byte)context.controllerNumber, touchType, + event.getPointerId(event.getActionIndex()), + normalizedX, normalizedY, normalizedPressure) != MoonBridge.LI_ERR_UNSUPPORTED; + } + public boolean handleMotionEvent(MotionEvent event) { InputDeviceContext context = getContextForEvent(event); if (context == null) { @@ -2126,6 +2213,10 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD public int hatYAxis = -1; public boolean hatXAxisUsed, hatYAxisUsed; + InputDevice.MotionRange touchpadXRange; + InputDevice.MotionRange touchpadYRange; + InputDevice.MotionRange touchpadPressureRange; + public boolean isNonStandardDualShock4; public boolean usesLinuxGamepadStandardFaceButtons; public boolean isNonStandardXboxBtController;