mirror of
https://git.ryujinx.app/kenji-nx/ryujinx.git
synced 2025-12-13 13:37:08 +00:00
Merge branch 'libryujinx_bionic_L2R2_XBox' into 'libryujinx_bionic'
Fixed L2/R2 on XBox controllers See merge request kenji-nx/ryujinx!10
This commit is contained in:
commit
cc00dc2967
1 changed files with 119 additions and 58 deletions
|
|
@ -4,10 +4,17 @@ import android.view.InputDevice
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import org.kenjinx.android.viewmodels.QuickSettings
|
import org.kenjinx.android.viewmodels.QuickSettings
|
||||||
|
import kotlin.math.abs
|
||||||
|
|
||||||
class PhysicalControllerManager(val activity: MainActivity) {
|
class PhysicalControllerManager(val activity: MainActivity) {
|
||||||
private var controllerId: Int = -1
|
private var controllerId: Int = -1
|
||||||
|
|
||||||
|
// Trigger debouncing (analog → digital)
|
||||||
|
private var leftTriggerPressed = false
|
||||||
|
private var rightTriggerPressed = false
|
||||||
|
private val pressThreshold = 0.65f
|
||||||
|
private val releaseThreshold = 0.45f
|
||||||
|
|
||||||
fun onKeyEvent(event: KeyEvent): Boolean {
|
fun onKeyEvent(event: KeyEvent): Boolean {
|
||||||
// Make sure we are connected
|
// Make sure we are connected
|
||||||
if (controllerId == -1) {
|
if (controllerId == -1) {
|
||||||
|
|
@ -17,40 +24,88 @@ class PhysicalControllerManager(val activity: MainActivity) {
|
||||||
val id = getGamePadButtonInputId(event.keyCode)
|
val id = getGamePadButtonInputId(event.keyCode)
|
||||||
if (id != GamePadButtonInputId.None) {
|
if (id != GamePadButtonInputId.None) {
|
||||||
val isNotFallback = (event.flags and KeyEvent.FLAG_FALLBACK) == 0
|
val isNotFallback = (event.flags and KeyEvent.FLAG_FALLBACK) == 0
|
||||||
// Many gamepads send additional fallback events – we suppress them.
|
|
||||||
if (isNotFallback) {
|
if (isNotFallback) {
|
||||||
when (event.action) {
|
when (event.action) {
|
||||||
KeyEvent.ACTION_UP -> {
|
KeyEvent.ACTION_UP -> KenjinxNative.inputSetButtonReleased(id.ordinal, controllerId)
|
||||||
KenjinxNative.inputSetButtonReleased(id.ordinal, controllerId)
|
KeyEvent.ACTION_DOWN -> KenjinxNative.inputSetButtonPressed(id.ordinal, controllerId)
|
||||||
}
|
|
||||||
KeyEvent.ACTION_DOWN -> {
|
|
||||||
KenjinxNative.inputSetButtonPressed(id.ordinal, controllerId)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onMotionEvent(ev: MotionEvent) {
|
fun onMotionEvent(ev: MotionEvent) {
|
||||||
if (ev.action == MotionEvent.ACTION_MOVE) {
|
if (ev.action != MotionEvent.ACTION_MOVE) return
|
||||||
|
|
||||||
if (controllerId == -1) {
|
if (controllerId == -1) {
|
||||||
controllerId = KenjinxNative.inputConnectGamepad(0)
|
controllerId = KenjinxNative.inputConnectGamepad(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
val leftStickX = ev.getAxisValue(MotionEvent.AXIS_X)
|
val device = ev.device
|
||||||
val leftStickY = ev.getAxisValue(MotionEvent.AXIS_Y)
|
val source = InputDevice.SOURCE_JOYSTICK
|
||||||
val rightStickX = ev.getAxisValue(MotionEvent.AXIS_Z)
|
|
||||||
val rightStickY = ev.getAxisValue(MotionEvent.AXIS_RZ)
|
fun hasAxis(axis: Int): Boolean =
|
||||||
|
device?.getMotionRange(axis, source) != null
|
||||||
|
|
||||||
|
fun axisValue(axis: Int): Float = ev.getAxisValue(axis)
|
||||||
|
|
||||||
|
// --- Sticks (prefer RX/RY on the right, fallback to Z/RZ) ---
|
||||||
|
val rightXaxis = if (hasAxis(MotionEvent.AXIS_RX)) MotionEvent.AXIS_RX else MotionEvent.AXIS_Z
|
||||||
|
val rightYaxis = if (hasAxis(MotionEvent.AXIS_RY)) MotionEvent.AXIS_RY else MotionEvent.AXIS_RZ
|
||||||
|
|
||||||
|
val leftStickX = if (hasAxis(MotionEvent.AXIS_X)) axisValue(MotionEvent.AXIS_X) else 0f
|
||||||
|
val leftStickY = if (hasAxis(MotionEvent.AXIS_Y)) axisValue(MotionEvent.AXIS_Y) else 0f
|
||||||
|
val rightStickX = if (hasAxis(rightXaxis)) axisValue(rightXaxis) else 0f
|
||||||
|
val rightStickY = if (hasAxis(rightYaxis)) axisValue(rightYaxis) else 0f
|
||||||
|
|
||||||
KenjinxNative.inputSetStickAxis(1, leftStickX, -leftStickY, controllerId)
|
KenjinxNative.inputSetStickAxis(1, leftStickX, -leftStickY, controllerId)
|
||||||
KenjinxNative.inputSetStickAxis(2, rightStickX, -rightStickY, controllerId)
|
KenjinxNative.inputSetStickAxis(2, rightStickX, -rightStickY, controllerId)
|
||||||
|
|
||||||
ev.device?.apply {
|
// --- Read triggers (with fallbacks) ---
|
||||||
|
// Preferred: LTRIGGER/RTRIGGER, then BRAKE/GAS.
|
||||||
|
// If the right stick uses RX/RY (standard on Xbox), Z/RZ are free → use as an additional fallback.
|
||||||
|
// If the stick uses Z/RZ, do NOT use them for triggers (to avoid conflicts).
|
||||||
|
val rightStickUsesZ = (rightXaxis == MotionEvent.AXIS_Z)
|
||||||
|
val rightStickUsesRZ = (rightYaxis == MotionEvent.AXIS_RZ)
|
||||||
|
|
||||||
|
val rawLT = when {
|
||||||
|
hasAxis(MotionEvent.AXIS_LTRIGGER) -> axisValue(MotionEvent.AXIS_LTRIGGER)
|
||||||
|
hasAxis(MotionEvent.AXIS_BRAKE) -> axisValue(MotionEvent.AXIS_BRAKE)
|
||||||
|
!rightStickUsesZ && hasAxis(MotionEvent.AXIS_Z) -> axisValue(MotionEvent.AXIS_Z)
|
||||||
|
else -> 0f
|
||||||
|
}
|
||||||
|
val rawRT = when {
|
||||||
|
hasAxis(MotionEvent.AXIS_RTRIGGER) -> axisValue(MotionEvent.AXIS_RTRIGGER)
|
||||||
|
hasAxis(MotionEvent.AXIS_GAS) -> axisValue(MotionEvent.AXIS_GAS)
|
||||||
|
!rightStickUsesRZ && hasAxis(MotionEvent.AXIS_RZ) -> axisValue(MotionEvent.AXIS_RZ)
|
||||||
|
else -> 0f
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some pads report slight offsets — normalize
|
||||||
|
val lt = if (abs(rawLT) < 0.02f) 0f else rawLT.coerceIn(0f, 1f)
|
||||||
|
val rt = if (abs(rawRT) < 0.02f) 0f else rawRT.coerceIn(0f, 1f)
|
||||||
|
|
||||||
|
// Analog → digital with hysteresis
|
||||||
|
if (!leftTriggerPressed && lt >= pressThreshold) {
|
||||||
|
leftTriggerPressed = true
|
||||||
|
KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.LeftTrigger.ordinal, controllerId)
|
||||||
|
} else if (leftTriggerPressed && lt <= releaseThreshold) {
|
||||||
|
leftTriggerPressed = false
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.LeftTrigger.ordinal, controllerId)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rightTriggerPressed && rt >= pressThreshold) {
|
||||||
|
rightTriggerPressed = true
|
||||||
|
KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.RightTrigger.ordinal, controllerId)
|
||||||
|
} else if (rightTriggerPressed && rt <= releaseThreshold) {
|
||||||
|
rightTriggerPressed = false
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.RightTrigger.ordinal, controllerId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- DPAD as HAT (as before) ---
|
||||||
|
device?.apply {
|
||||||
if (sources and InputDevice.SOURCE_DPAD != InputDevice.SOURCE_DPAD) {
|
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 dPadHor = ev.getAxisValue(MotionEvent.AXIS_HAT_X)
|
||||||
val dPadVert = ev.getAxisValue(MotionEvent.AXIS_HAT_Y)
|
val dPadVert = ev.getAxisValue(MotionEvent.AXIS_HAT_Y)
|
||||||
|
|
||||||
|
|
@ -83,7 +138,6 @@ class PhysicalControllerManager(val activity: MainActivity) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fun connect(): Int {
|
fun connect(): Int {
|
||||||
controllerId = KenjinxNative.inputConnectGamepad(0)
|
controllerId = KenjinxNative.inputConnectGamepad(0)
|
||||||
|
|
@ -92,30 +146,37 @@ class PhysicalControllerManager(val activity: MainActivity) {
|
||||||
|
|
||||||
fun disconnect() {
|
fun disconnect() {
|
||||||
controllerId = -1
|
controllerId = -1
|
||||||
|
// If a trigger was "stuck" on disconnect, release it just in case
|
||||||
|
if (leftTriggerPressed) {
|
||||||
|
leftTriggerPressed = false
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.LeftTrigger.ordinal, controllerId)
|
||||||
|
}
|
||||||
|
if (rightTriggerPressed) {
|
||||||
|
rightTriggerPressed = false
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.RightTrigger.ordinal, controllerId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getGamePadButtonInputId(keycode: Int): GamePadButtonInputId {
|
private fun getGamePadButtonInputId(keycode: Int): GamePadButtonInputId {
|
||||||
val quickSettings = QuickSettings(activity)
|
val quickSettings = QuickSettings(activity)
|
||||||
return when (keycode) {
|
return when (keycode) {
|
||||||
// ABXY (Switch/Xbox layout switchable)
|
// ABXY (Switch/Xbox layout)
|
||||||
KeyEvent.KEYCODE_BUTTON_A -> if (!quickSettings.useSwitchLayout) GamePadButtonInputId.A else GamePadButtonInputId.B
|
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_B -> if (!quickSettings.useSwitchLayout) GamePadButtonInputId.B else GamePadButtonInputId.A
|
||||||
KeyEvent.KEYCODE_BUTTON_X -> if (!quickSettings.useSwitchLayout) GamePadButtonInputId.X else GamePadButtonInputId.Y
|
KeyEvent.KEYCODE_BUTTON_X -> if (!quickSettings.useSwitchLayout) GamePadButtonInputId.X else GamePadButtonInputId.Y
|
||||||
KeyEvent.KEYCODE_BUTTON_Y -> if (!quickSettings.useSwitchLayout) GamePadButtonInputId.Y else GamePadButtonInputId.X
|
KeyEvent.KEYCODE_BUTTON_Y -> if (!quickSettings.useSwitchLayout) GamePadButtonInputId.Y else GamePadButtonInputId.X
|
||||||
|
|
||||||
// Shoulder buttons
|
// Shoulder & Trigger (if a pad sends them as key events)
|
||||||
KeyEvent.KEYCODE_BUTTON_L1 -> GamePadButtonInputId.LeftShoulder
|
KeyEvent.KEYCODE_BUTTON_L1 -> GamePadButtonInputId.LeftShoulder
|
||||||
KeyEvent.KEYCODE_BUTTON_L2 -> GamePadButtonInputId.LeftTrigger
|
KeyEvent.KEYCODE_BUTTON_L2 -> GamePadButtonInputId.LeftTrigger
|
||||||
KeyEvent.KEYCODE_BUTTON_R1 -> GamePadButtonInputId.RightShoulder
|
KeyEvent.KEYCODE_BUTTON_R1 -> GamePadButtonInputId.RightShoulder
|
||||||
KeyEvent.KEYCODE_BUTTON_R2 -> GamePadButtonInputId.RightTrigger
|
KeyEvent.KEYCODE_BUTTON_R2 -> GamePadButtonInputId.RightTrigger
|
||||||
|
|
||||||
// **L3 / R3 (Stick-Click) – CORRECT: *_Button**
|
// L3 / R3
|
||||||
KeyEvent.KEYCODE_BUTTON_THUMBL -> GamePadButtonInputId.LeftStickButton
|
KeyEvent.KEYCODE_BUTTON_THUMBL -> GamePadButtonInputId.LeftStickButton
|
||||||
KeyEvent.KEYCODE_BUTTON_THUMBR -> GamePadButtonInputId.RightStickButton
|
KeyEvent.KEYCODE_BUTTON_THUMBR -> GamePadButtonInputId.RightStickButton
|
||||||
|
KeyEvent.KEYCODE_BUTTON_11 -> GamePadButtonInputId.LeftStickButton
|
||||||
// Additional fallback keycodes for some pads (optional)
|
KeyEvent.KEYCODE_BUTTON_12 -> GamePadButtonInputId.RightStickButton
|
||||||
KeyEvent.KEYCODE_BUTTON_11 -> GamePadButtonInputId.LeftStickButton // isolated L3
|
|
||||||
KeyEvent.KEYCODE_BUTTON_12 -> GamePadButtonInputId.RightStickButton // isolated R3
|
|
||||||
|
|
||||||
// D-Pad
|
// D-Pad
|
||||||
KeyEvent.KEYCODE_DPAD_UP -> GamePadButtonInputId.DpadUp
|
KeyEvent.KEYCODE_DPAD_UP -> GamePadButtonInputId.DpadUp
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue