From 92c3b72b17574d1a59870f98e9f4972efdf9fe6b Mon Sep 17 00:00:00 2001 From: BeZide93 Date: Sat, 6 Sep 2025 02:13:53 -0500 Subject: [PATCH] fixed L3+R3 on physical controllers, added L3/R3 on virtual Controllers --- .../org/kenjinx/android/GameController.kt | 87 ++++++++-- .../android/PhysicalControllerManager.kt | 159 ++++++++---------- 2 files changed, 137 insertions(+), 109 deletions(-) diff --git a/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/GameController.kt b/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/GameController.kt index 6fb0a4f64..362dba3c8 100644 --- a/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/GameController.kt +++ b/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/GameController.kt @@ -238,8 +238,8 @@ private fun generateConfig(isLeft: Boolean): GamePadConfig { if (isLeft) { return GamePadConfig( - 12, - PrimaryDialConfig.Stick( + /* ringSegments = */ 12, + /* Primary (Stick) */ PrimaryDialConfig.Stick( GamePadButtonInputId.LeftStick.ordinal, GamePadButtonInputId.LeftStickButton.ordinal, setOf(), @@ -247,10 +247,11 @@ private fun generateConfig(isLeft: Boolean): GamePadConfig { null ), listOf( + // D-Pad (unchanged) SecondaryDialConfig.Cross( - 10, - 3, - 2.5f, + /* sector */ 10, + /* size */ 3, + /* gap */ 2.5f, distance, CrossConfig( GamePadButtonInputId.DpadUp.ordinal, @@ -263,8 +264,10 @@ private fun generateConfig(isLeft: Boolean): GamePadConfig { ), SecondaryDialConfig.RotationProcessor() ), + + // Minus (unchanged) SecondaryDialConfig.SingleButton( - 1, + /* sector */ 1, buttonScale, distance, ButtonConfig( @@ -280,8 +283,10 @@ private fun generateConfig(isLeft: Boolean): GamePadConfig { null, SecondaryDialConfig.RotationProcessor() ), + + // L-Bumper (unchanged, DoubleButton means wider target) SecondaryDialConfig.DoubleButton( - 2, + /* sector */ 2, distance, ButtonConfig( GamePadButtonInputId.LeftShoulder.ordinal, @@ -296,8 +301,10 @@ private fun generateConfig(isLeft: Boolean): GamePadConfig { null, SecondaryDialConfig.RotationProcessor() ), + + // ZL-Trigger (unchanged) SecondaryDialConfig.SingleButton( - 9, + /* sector */ 9, buttonScale, distance, ButtonConfig( @@ -313,12 +320,31 @@ private fun generateConfig(isLeft: Boolean): GamePadConfig { null, SecondaryDialConfig.RotationProcessor() ), + + // *** NEW: L3 as a separate button (top of the left pad) *** + SecondaryDialConfig.SingleButton( + /* sector */ 1, + buttonScale, + 1.5f, + ButtonConfig( + GamePadButtonInputId.LeftStickButton.ordinal, + "L3", + true, + null, + "LeftStickButton", + setOf(), + true, + null + ), + null, + SecondaryDialConfig.RotationProcessor() + ), ) ) } else { return GamePadConfig( - 12, - PrimaryDialConfig.PrimaryButtons( + /* ringSegments = */ 12, + /* Primary (ABXY) */ PrimaryDialConfig.PrimaryButtons( listOf( ButtonConfig( GamePadButtonInputId.A.ordinal, @@ -367,10 +393,11 @@ private fun generateConfig(isLeft: Boolean): GamePadConfig { null ), listOf( + // Right stick (unchanged) SecondaryDialConfig.Stick( - 7, - 2, - 2f, + /* sector */ 7, + /* size */ 2, + /* gap */ 2f, distance, GamePadButtonInputId.RightStick.ordinal, GamePadButtonInputId.RightStickButton.ordinal, @@ -379,8 +406,10 @@ private fun generateConfig(isLeft: Boolean): GamePadConfig { "RightStick", SecondaryDialConfig.RotationProcessor() ), + + // Plus (unchanged) SecondaryDialConfig.SingleButton( - 6, + /* sector */ 6, buttonScale, distance, ButtonConfig( @@ -396,8 +425,10 @@ private fun generateConfig(isLeft: Boolean): GamePadConfig { null, SecondaryDialConfig.RotationProcessor() ), + + // R-Bumper (unchanged) SecondaryDialConfig.DoubleButton( - 3, + /* sector */ 3, distance, ButtonConfig( GamePadButtonInputId.RightShoulder.ordinal, @@ -412,8 +443,10 @@ private fun generateConfig(isLeft: Boolean): GamePadConfig { null, SecondaryDialConfig.RotationProcessor() ), + + // ZR-Trigger (unchanged) SecondaryDialConfig.SingleButton( - 9, + /* sector */ 9, buttonScale, distance, ButtonConfig( @@ -428,8 +461,28 @@ private fun generateConfig(isLeft: Boolean): GamePadConfig { ), null, SecondaryDialConfig.RotationProcessor() - ) + ), + + // *** NEW: R3 as a separate button (top of the right pad) *** + SecondaryDialConfig.SingleButton( + /* sector */ 5, + buttonScale, + 1.5f, + ButtonConfig( + GamePadButtonInputId.RightStickButton.ordinal, + "R3", + true, + null, + "RightStickButton", + setOf(), + true, + null + ), + null, + SecondaryDialConfig.RotationProcessor() + ), ) ) } } + diff --git a/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/PhysicalControllerManager.kt b/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/PhysicalControllerManager.kt index 62b7ad890..ec05d45e3 100644 --- a/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/PhysicalControllerManager.kt +++ b/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/PhysicalControllerManager.kt @@ -9,119 +9,80 @@ class PhysicalControllerManager(val activity: MainActivity) { private var controllerId: Int = -1 fun onKeyEvent(event: KeyEvent): Boolean { + // Make sure we are connected + if (controllerId == -1) { + controllerId = KenjinxNative.inputConnectGamepad(0) + } + val id = getGamePadButtonInputId(event.keyCode) if (id != GamePadButtonInputId.None) { val isNotFallback = (event.flags and KeyEvent.FLAG_FALLBACK) == 0 - if (/*controllerId != -1 &&*/ isNotFallback) { + // Many gamepads send additional fallback events – we suppress them. + if (isNotFallback) { when (event.action) { KeyEvent.ACTION_UP -> { KenjinxNative.inputSetButtonReleased(id.ordinal, controllerId) } - KeyEvent.ACTION_DOWN -> { KenjinxNative.inputSetButtonPressed(id.ordinal, controllerId) } } - return true - } //else if (!isNotFallback) { - return true -// } + } + return true } return false } fun onMotionEvent(ev: MotionEvent) { -// if (true) { - if (ev.action == MotionEvent.ACTION_MOVE) { - val leftStickX = ev.getAxisValue(MotionEvent.AXIS_X) - val leftStickY = ev.getAxisValue(MotionEvent.AXIS_Y) - val rightStickX = ev.getAxisValue(MotionEvent.AXIS_Z) - val rightStickY = ev.getAxisValue(MotionEvent.AXIS_RZ) - KenjinxNative.inputSetStickAxis( - 1, - leftStickX, - -leftStickY, - controllerId - ) - KenjinxNative.inputSetStickAxis( - 2, - rightStickX, - -rightStickY, - controllerId - ) + if (ev.action == MotionEvent.ACTION_MOVE) { + if (controllerId == -1) { + controllerId = KenjinxNative.inputConnectGamepad(0) + } - ev.device?.apply { - if (sources and InputDevice.SOURCE_DPAD != InputDevice.SOURCE_DPAD) { - // Controller uses HAT - val dPadHor = ev.getAxisValue(MotionEvent.AXIS_HAT_X) - val dPadVert = ev.getAxisValue(MotionEvent.AXIS_HAT_Y) - if (dPadVert == 0.0f) { - KenjinxNative.inputSetButtonReleased( - GamePadButtonInputId.DpadUp.ordinal, - controllerId - ) - KenjinxNative.inputSetButtonReleased( - GamePadButtonInputId.DpadDown.ordinal, - controllerId - ) - } - if (dPadHor == 0.0f) { - KenjinxNative.inputSetButtonReleased( - GamePadButtonInputId.DpadLeft.ordinal, - controllerId - ) - KenjinxNative.inputSetButtonReleased( - GamePadButtonInputId.DpadRight.ordinal, - controllerId - ) - } + val leftStickX = ev.getAxisValue(MotionEvent.AXIS_X) + val leftStickY = ev.getAxisValue(MotionEvent.AXIS_Y) + val rightStickX = ev.getAxisValue(MotionEvent.AXIS_Z) + val rightStickY = ev.getAxisValue(MotionEvent.AXIS_RZ) - if (dPadVert < 0.0f) { - KenjinxNative.inputSetButtonPressed( - GamePadButtonInputId.DpadUp.ordinal, - controllerId - ) - KenjinxNative.inputSetButtonReleased( - GamePadButtonInputId.DpadDown.ordinal, - controllerId - ) - } - if (dPadHor < 0.0f) { - KenjinxNative.inputSetButtonPressed( - GamePadButtonInputId.DpadLeft.ordinal, - controllerId - ) - KenjinxNative.inputSetButtonReleased( - GamePadButtonInputId.DpadRight.ordinal, - controllerId - ) - } + KenjinxNative.inputSetStickAxis(1, leftStickX, -leftStickY, controllerId) + KenjinxNative.inputSetStickAxis(2, rightStickX, -rightStickY, controllerId) - if (dPadVert > 0.0f) { - KenjinxNative.inputSetButtonReleased( - GamePadButtonInputId.DpadUp.ordinal, - controllerId - ) - KenjinxNative.inputSetButtonPressed( - GamePadButtonInputId.DpadDown.ordinal, - controllerId - ) - } - if (dPadHor > 0.0f) { - KenjinxNative.inputSetButtonReleased( - GamePadButtonInputId.DpadLeft.ordinal, - controllerId - ) - KenjinxNative.inputSetButtonPressed( - GamePadButtonInputId.DpadRight.ordinal, - controllerId - ) - } + ev.device?.apply { + if (sources and InputDevice.SOURCE_DPAD != InputDevice.SOURCE_DPAD) { + // Controller uses HAT instead of “real” DPAD + val dPadHor = ev.getAxisValue(MotionEvent.AXIS_HAT_X) + val dPadVert = ev.getAxisValue(MotionEvent.AXIS_HAT_Y) + + if (dPadVert == 0.0f) { + KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadUp.ordinal, controllerId) + KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadDown.ordinal, controllerId) + } + if (dPadHor == 0.0f) { + KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadLeft.ordinal, controllerId) + KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadRight.ordinal, controllerId) + } + + if (dPadVert < 0.0f) { + KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadUp.ordinal, controllerId) + KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadDown.ordinal, controllerId) + } + if (dPadHor < 0.0f) { + KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadLeft.ordinal, controllerId) + KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadRight.ordinal, controllerId) + } + + if (dPadVert > 0.0f) { + KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadUp.ordinal, controllerId) + KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadDown.ordinal, controllerId) + } + if (dPadHor > 0.0f) { + KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadLeft.ordinal, controllerId) + KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadRight.ordinal, controllerId) } } } -// } + } } fun connect(): Int { @@ -136,22 +97,36 @@ class PhysicalControllerManager(val activity: MainActivity) { private fun getGamePadButtonInputId(keycode: Int): GamePadButtonInputId { val quickSettings = QuickSettings(activity) return when (keycode) { + // ABXY (Switch/Xbox layout switchable) KeyEvent.KEYCODE_BUTTON_A -> if (!quickSettings.useSwitchLayout) GamePadButtonInputId.A else GamePadButtonInputId.B KeyEvent.KEYCODE_BUTTON_B -> if (!quickSettings.useSwitchLayout) GamePadButtonInputId.B else GamePadButtonInputId.A KeyEvent.KEYCODE_BUTTON_X -> if (!quickSettings.useSwitchLayout) GamePadButtonInputId.X else GamePadButtonInputId.Y KeyEvent.KEYCODE_BUTTON_Y -> if (!quickSettings.useSwitchLayout) GamePadButtonInputId.Y else GamePadButtonInputId.X + + // Shoulder buttons KeyEvent.KEYCODE_BUTTON_L1 -> GamePadButtonInputId.LeftShoulder KeyEvent.KEYCODE_BUTTON_L2 -> GamePadButtonInputId.LeftTrigger KeyEvent.KEYCODE_BUTTON_R1 -> GamePadButtonInputId.RightShoulder KeyEvent.KEYCODE_BUTTON_R2 -> GamePadButtonInputId.RightTrigger - KeyEvent.KEYCODE_BUTTON_THUMBL -> GamePadButtonInputId.LeftStick - KeyEvent.KEYCODE_BUTTON_THUMBR -> GamePadButtonInputId.RightStick + + // **L3 / R3 (Stick-Click) – CORRECT: *_Button** + KeyEvent.KEYCODE_BUTTON_THUMBL -> GamePadButtonInputId.LeftStickButton + KeyEvent.KEYCODE_BUTTON_THUMBR -> GamePadButtonInputId.RightStickButton + + // Additional fallback keycodes for some pads (optional) + KeyEvent.KEYCODE_BUTTON_11 -> GamePadButtonInputId.LeftStickButton // isolated L3 + KeyEvent.KEYCODE_BUTTON_12 -> GamePadButtonInputId.RightStickButton // isolated R3 + + // D-Pad KeyEvent.KEYCODE_DPAD_UP -> GamePadButtonInputId.DpadUp KeyEvent.KEYCODE_DPAD_DOWN -> GamePadButtonInputId.DpadDown KeyEvent.KEYCODE_DPAD_LEFT -> GamePadButtonInputId.DpadLeft KeyEvent.KEYCODE_DPAD_RIGHT -> GamePadButtonInputId.DpadRight + + // Plus/Minus KeyEvent.KEYCODE_BUTTON_START -> GamePadButtonInputId.Plus KeyEvent.KEYCODE_BUTTON_SELECT -> GamePadButtonInputId.Minus + else -> GamePadButtonInputId.None } }