android: Implement gamepad input
parent
f5c48f92f2
commit
6dfe4240ac
@ -0,0 +1,323 @@
|
|||||||
|
package org.yuzu.yuzu_emu.utils
|
||||||
|
|
||||||
|
import android.view.InputDevice
|
||||||
|
import android.view.KeyEvent
|
||||||
|
import android.view.MotionEvent
|
||||||
|
import org.yuzu.yuzu_emu.NativeLibrary
|
||||||
|
|
||||||
|
class InputHandler {
|
||||||
|
fun initialize() {
|
||||||
|
// Connect first controller
|
||||||
|
NativeLibrary.onGamePadConnectEvent(getPlayerNumber(NativeLibrary.Player1Device));
|
||||||
|
}
|
||||||
|
|
||||||
|
fun dispatchKeyEvent(event: KeyEvent): Boolean {
|
||||||
|
val button: Int = when (event.device.vendorId) {
|
||||||
|
0x045E -> getInputXboxButtonKey(event.keyCode)
|
||||||
|
0x054C -> getInputDS5ButtonKey(event.keyCode)
|
||||||
|
0x057E -> getInputJoyconButtonKey(event.keyCode)
|
||||||
|
0x1532 -> getInputRazerButtonKey(event.keyCode)
|
||||||
|
else -> getInputGenericButtonKey(event.keyCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
val action = when (event.action) {
|
||||||
|
KeyEvent.ACTION_DOWN -> NativeLibrary.ButtonState.PRESSED
|
||||||
|
KeyEvent.ACTION_UP -> NativeLibrary.ButtonState.RELEASED
|
||||||
|
else -> return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore invalid buttons
|
||||||
|
if (button < 0) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return NativeLibrary.onGamePadButtonEvent(
|
||||||
|
getPlayerNumber(event.device.controllerNumber),
|
||||||
|
button,
|
||||||
|
action
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun dispatchGenericMotionEvent(event: MotionEvent): Boolean {
|
||||||
|
val device = event.device
|
||||||
|
// Check every axis input available on the controller
|
||||||
|
for (range in device.motionRanges) {
|
||||||
|
val axis = range.axis;
|
||||||
|
when (device.vendorId) {
|
||||||
|
0x045E -> setGenericAxisInput(event, axis)
|
||||||
|
0x054C -> setGenericAxisInput(event, axis)
|
||||||
|
0x057E -> setJoyconAxisInput(event, axis)
|
||||||
|
0x1532 -> setRazerAxisInput(event, axis)
|
||||||
|
else -> setGenericAxisInput(event, axis)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getPlayerNumber(index: Int): Int {
|
||||||
|
// TODO: Joycons are handled as different controllers. Find a way to merge them.
|
||||||
|
return when (index) {
|
||||||
|
2 -> NativeLibrary.Player2Device
|
||||||
|
3 -> NativeLibrary.Player3Device
|
||||||
|
4 -> NativeLibrary.Player4Device
|
||||||
|
5 -> NativeLibrary.Player5Device
|
||||||
|
6 -> NativeLibrary.Player6Device
|
||||||
|
7 -> NativeLibrary.Player7Device
|
||||||
|
8 -> NativeLibrary.Player8Device
|
||||||
|
else -> if (NativeLibrary.isHandheldOnly()) NativeLibrary.ConsoleDevice else NativeLibrary.Player1Device
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getAxisToButton(axis: Float): Int {
|
||||||
|
return if (axis > 0.5f) NativeLibrary.ButtonState.PRESSED else NativeLibrary.ButtonState.RELEASED
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setAxisDpadState(playerNumber: Int, xAxis: Float, yAxis: Float) {
|
||||||
|
NativeLibrary.onGamePadButtonEvent(
|
||||||
|
playerNumber,
|
||||||
|
NativeLibrary.ButtonType.DPAD_UP,
|
||||||
|
getAxisToButton(-yAxis)
|
||||||
|
)
|
||||||
|
NativeLibrary.onGamePadButtonEvent(
|
||||||
|
playerNumber,
|
||||||
|
NativeLibrary.ButtonType.DPAD_DOWN,
|
||||||
|
getAxisToButton(yAxis)
|
||||||
|
)
|
||||||
|
NativeLibrary.onGamePadButtonEvent(
|
||||||
|
playerNumber,
|
||||||
|
NativeLibrary.ButtonType.DPAD_LEFT,
|
||||||
|
getAxisToButton(-xAxis)
|
||||||
|
)
|
||||||
|
NativeLibrary.onGamePadButtonEvent(
|
||||||
|
playerNumber,
|
||||||
|
NativeLibrary.ButtonType.DPAD_RIGHT,
|
||||||
|
getAxisToButton(xAxis)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getInputDS5ButtonKey(key: Int): Int {
|
||||||
|
// The missing ds5 buttons are axis
|
||||||
|
return when (key) {
|
||||||
|
KeyEvent.KEYCODE_BUTTON_A -> NativeLibrary.ButtonType.BUTTON_B
|
||||||
|
KeyEvent.KEYCODE_BUTTON_B -> NativeLibrary.ButtonType.BUTTON_A
|
||||||
|
KeyEvent.KEYCODE_BUTTON_X -> NativeLibrary.ButtonType.BUTTON_Y
|
||||||
|
KeyEvent.KEYCODE_BUTTON_Y -> NativeLibrary.ButtonType.BUTTON_X
|
||||||
|
KeyEvent.KEYCODE_BUTTON_L1 -> NativeLibrary.ButtonType.TRIGGER_L
|
||||||
|
KeyEvent.KEYCODE_BUTTON_R1 -> NativeLibrary.ButtonType.TRIGGER_R
|
||||||
|
KeyEvent.KEYCODE_BUTTON_THUMBL -> NativeLibrary.ButtonType.STICK_L
|
||||||
|
KeyEvent.KEYCODE_BUTTON_THUMBR -> NativeLibrary.ButtonType.STICK_R
|
||||||
|
KeyEvent.KEYCODE_BUTTON_START -> NativeLibrary.ButtonType.BUTTON_PLUS
|
||||||
|
KeyEvent.KEYCODE_BUTTON_SELECT -> NativeLibrary.ButtonType.BUTTON_MINUS
|
||||||
|
else -> -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getInputJoyconButtonKey(key: Int): Int {
|
||||||
|
// Joycon support is half dead. A lot of buttons can't be mapped
|
||||||
|
return when (key) {
|
||||||
|
KeyEvent.KEYCODE_BUTTON_A -> NativeLibrary.ButtonType.BUTTON_B
|
||||||
|
KeyEvent.KEYCODE_BUTTON_B -> NativeLibrary.ButtonType.BUTTON_A
|
||||||
|
KeyEvent.KEYCODE_BUTTON_X -> NativeLibrary.ButtonType.BUTTON_X
|
||||||
|
KeyEvent.KEYCODE_BUTTON_Y -> NativeLibrary.ButtonType.BUTTON_Y
|
||||||
|
KeyEvent.KEYCODE_DPAD_UP -> NativeLibrary.ButtonType.DPAD_UP
|
||||||
|
KeyEvent.KEYCODE_DPAD_DOWN -> NativeLibrary.ButtonType.DPAD_DOWN
|
||||||
|
KeyEvent.KEYCODE_DPAD_LEFT -> NativeLibrary.ButtonType.DPAD_LEFT
|
||||||
|
KeyEvent.KEYCODE_DPAD_RIGHT -> NativeLibrary.ButtonType.DPAD_RIGHT
|
||||||
|
KeyEvent.KEYCODE_BUTTON_L1 -> NativeLibrary.ButtonType.TRIGGER_L
|
||||||
|
KeyEvent.KEYCODE_BUTTON_R1 -> NativeLibrary.ButtonType.TRIGGER_R
|
||||||
|
KeyEvent.KEYCODE_BUTTON_L2 -> NativeLibrary.ButtonType.TRIGGER_ZL
|
||||||
|
KeyEvent.KEYCODE_BUTTON_R2 -> NativeLibrary.ButtonType.TRIGGER_ZR
|
||||||
|
KeyEvent.KEYCODE_BUTTON_THUMBL -> NativeLibrary.ButtonType.STICK_L
|
||||||
|
KeyEvent.KEYCODE_BUTTON_THUMBR -> NativeLibrary.ButtonType.STICK_R
|
||||||
|
KeyEvent.KEYCODE_BUTTON_START -> NativeLibrary.ButtonType.BUTTON_PLUS
|
||||||
|
KeyEvent.KEYCODE_BUTTON_SELECT -> NativeLibrary.ButtonType.BUTTON_MINUS
|
||||||
|
else -> -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getInputXboxButtonKey(key: Int): Int {
|
||||||
|
// The missing xbox buttons are axis
|
||||||
|
return when (key) {
|
||||||
|
KeyEvent.KEYCODE_BUTTON_A -> NativeLibrary.ButtonType.BUTTON_A
|
||||||
|
KeyEvent.KEYCODE_BUTTON_B -> NativeLibrary.ButtonType.BUTTON_B
|
||||||
|
KeyEvent.KEYCODE_BUTTON_X -> NativeLibrary.ButtonType.BUTTON_X
|
||||||
|
KeyEvent.KEYCODE_BUTTON_Y -> NativeLibrary.ButtonType.BUTTON_Y
|
||||||
|
KeyEvent.KEYCODE_BUTTON_L1 -> NativeLibrary.ButtonType.TRIGGER_L
|
||||||
|
KeyEvent.KEYCODE_BUTTON_R1 -> NativeLibrary.ButtonType.TRIGGER_R
|
||||||
|
KeyEvent.KEYCODE_BUTTON_THUMBL -> NativeLibrary.ButtonType.STICK_L
|
||||||
|
KeyEvent.KEYCODE_BUTTON_THUMBR -> NativeLibrary.ButtonType.STICK_R
|
||||||
|
KeyEvent.KEYCODE_BUTTON_START -> NativeLibrary.ButtonType.BUTTON_PLUS
|
||||||
|
KeyEvent.KEYCODE_BUTTON_SELECT -> NativeLibrary.ButtonType.BUTTON_MINUS
|
||||||
|
else -> -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getInputRazerButtonKey(key: Int): Int {
|
||||||
|
// The missing xbox buttons are axis
|
||||||
|
return when (key) {
|
||||||
|
KeyEvent.KEYCODE_BUTTON_A -> NativeLibrary.ButtonType.BUTTON_B
|
||||||
|
KeyEvent.KEYCODE_BUTTON_B -> NativeLibrary.ButtonType.BUTTON_A
|
||||||
|
KeyEvent.KEYCODE_BUTTON_X -> NativeLibrary.ButtonType.BUTTON_Y
|
||||||
|
KeyEvent.KEYCODE_BUTTON_Y -> NativeLibrary.ButtonType.BUTTON_X
|
||||||
|
KeyEvent.KEYCODE_BUTTON_L1 -> NativeLibrary.ButtonType.TRIGGER_L
|
||||||
|
KeyEvent.KEYCODE_BUTTON_R1 -> NativeLibrary.ButtonType.TRIGGER_R
|
||||||
|
KeyEvent.KEYCODE_BUTTON_THUMBL -> NativeLibrary.ButtonType.STICK_L
|
||||||
|
KeyEvent.KEYCODE_BUTTON_THUMBR -> NativeLibrary.ButtonType.STICK_R
|
||||||
|
KeyEvent.KEYCODE_BUTTON_START -> NativeLibrary.ButtonType.BUTTON_PLUS
|
||||||
|
KeyEvent.KEYCODE_BUTTON_SELECT -> NativeLibrary.ButtonType.BUTTON_MINUS
|
||||||
|
else -> -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getInputGenericButtonKey(key: Int): Int {
|
||||||
|
return when (key) {
|
||||||
|
KeyEvent.KEYCODE_BUTTON_A -> NativeLibrary.ButtonType.BUTTON_A
|
||||||
|
KeyEvent.KEYCODE_BUTTON_B -> NativeLibrary.ButtonType.BUTTON_B
|
||||||
|
KeyEvent.KEYCODE_BUTTON_X -> NativeLibrary.ButtonType.BUTTON_X
|
||||||
|
KeyEvent.KEYCODE_BUTTON_Y -> NativeLibrary.ButtonType.BUTTON_Y
|
||||||
|
KeyEvent.KEYCODE_DPAD_UP -> NativeLibrary.ButtonType.DPAD_UP
|
||||||
|
KeyEvent.KEYCODE_DPAD_DOWN -> NativeLibrary.ButtonType.DPAD_DOWN
|
||||||
|
KeyEvent.KEYCODE_DPAD_LEFT -> NativeLibrary.ButtonType.DPAD_LEFT
|
||||||
|
KeyEvent.KEYCODE_DPAD_RIGHT -> NativeLibrary.ButtonType.DPAD_RIGHT
|
||||||
|
KeyEvent.KEYCODE_BUTTON_L1 -> NativeLibrary.ButtonType.TRIGGER_L
|
||||||
|
KeyEvent.KEYCODE_BUTTON_R1 -> NativeLibrary.ButtonType.TRIGGER_R
|
||||||
|
KeyEvent.KEYCODE_BUTTON_L2 -> NativeLibrary.ButtonType.TRIGGER_ZL
|
||||||
|
KeyEvent.KEYCODE_BUTTON_R2 -> NativeLibrary.ButtonType.TRIGGER_ZR
|
||||||
|
KeyEvent.KEYCODE_BUTTON_THUMBL -> NativeLibrary.ButtonType.STICK_L
|
||||||
|
KeyEvent.KEYCODE_BUTTON_THUMBR -> NativeLibrary.ButtonType.STICK_R
|
||||||
|
KeyEvent.KEYCODE_BUTTON_START -> NativeLibrary.ButtonType.BUTTON_PLUS
|
||||||
|
KeyEvent.KEYCODE_BUTTON_SELECT -> NativeLibrary.ButtonType.BUTTON_MINUS
|
||||||
|
else -> -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setGenericAxisInput(event: MotionEvent, axis: Int) {
|
||||||
|
val playerNumber = getPlayerNumber(event.device.controllerNumber)
|
||||||
|
|
||||||
|
when (axis) {
|
||||||
|
MotionEvent.AXIS_X, MotionEvent.AXIS_Y ->
|
||||||
|
NativeLibrary.onGamePadJoystickEvent(
|
||||||
|
playerNumber,
|
||||||
|
NativeLibrary.StickType.STICK_L,
|
||||||
|
event.getAxisValue(MotionEvent.AXIS_X),
|
||||||
|
-event.getAxisValue(MotionEvent.AXIS_Y)
|
||||||
|
)
|
||||||
|
MotionEvent.AXIS_RX, MotionEvent.AXIS_RY ->
|
||||||
|
NativeLibrary.onGamePadJoystickEvent(
|
||||||
|
playerNumber,
|
||||||
|
NativeLibrary.StickType.STICK_R,
|
||||||
|
event.getAxisValue(MotionEvent.AXIS_RX),
|
||||||
|
-event.getAxisValue(MotionEvent.AXIS_RY)
|
||||||
|
)
|
||||||
|
MotionEvent.AXIS_Z, MotionEvent.AXIS_RZ ->
|
||||||
|
NativeLibrary.onGamePadJoystickEvent(
|
||||||
|
playerNumber,
|
||||||
|
NativeLibrary.StickType.STICK_R,
|
||||||
|
event.getAxisValue(MotionEvent.AXIS_Z),
|
||||||
|
-event.getAxisValue(MotionEvent.AXIS_RZ)
|
||||||
|
)
|
||||||
|
MotionEvent.AXIS_LTRIGGER ->
|
||||||
|
NativeLibrary.onGamePadButtonEvent(
|
||||||
|
playerNumber,
|
||||||
|
NativeLibrary.ButtonType.TRIGGER_ZL,
|
||||||
|
getAxisToButton(event.getAxisValue(MotionEvent.AXIS_LTRIGGER))
|
||||||
|
)
|
||||||
|
MotionEvent.AXIS_BRAKE ->
|
||||||
|
NativeLibrary.onGamePadButtonEvent(
|
||||||
|
playerNumber,
|
||||||
|
NativeLibrary.ButtonType.TRIGGER_ZL,
|
||||||
|
getAxisToButton(event.getAxisValue(MotionEvent.AXIS_BRAKE))
|
||||||
|
)
|
||||||
|
MotionEvent.AXIS_RTRIGGER ->
|
||||||
|
NativeLibrary.onGamePadButtonEvent(
|
||||||
|
playerNumber,
|
||||||
|
NativeLibrary.ButtonType.TRIGGER_ZR,
|
||||||
|
getAxisToButton(event.getAxisValue(MotionEvent.AXIS_RTRIGGER))
|
||||||
|
)
|
||||||
|
MotionEvent.AXIS_GAS ->
|
||||||
|
NativeLibrary.onGamePadButtonEvent(
|
||||||
|
playerNumber,
|
||||||
|
NativeLibrary.ButtonType.TRIGGER_ZR,
|
||||||
|
getAxisToButton(event.getAxisValue(MotionEvent.AXIS_GAS))
|
||||||
|
)
|
||||||
|
MotionEvent.AXIS_HAT_X, MotionEvent.AXIS_HAT_Y ->
|
||||||
|
setAxisDpadState(
|
||||||
|
playerNumber,
|
||||||
|
event.getAxisValue(MotionEvent.AXIS_HAT_X),
|
||||||
|
event.getAxisValue(MotionEvent.AXIS_HAT_Y)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun setJoyconAxisInput(event: MotionEvent, axis: Int) {
|
||||||
|
// Joycon support is half dead. Right joystick doesn't work
|
||||||
|
val playerNumber = getPlayerNumber(event.device.controllerNumber)
|
||||||
|
|
||||||
|
when (axis) {
|
||||||
|
MotionEvent.AXIS_X, MotionEvent.AXIS_Y ->
|
||||||
|
NativeLibrary.onGamePadJoystickEvent(
|
||||||
|
playerNumber,
|
||||||
|
NativeLibrary.StickType.STICK_L,
|
||||||
|
event.getAxisValue(MotionEvent.AXIS_X),
|
||||||
|
-event.getAxisValue(MotionEvent.AXIS_Y)
|
||||||
|
)
|
||||||
|
MotionEvent.AXIS_Z, MotionEvent.AXIS_RZ ->
|
||||||
|
NativeLibrary.onGamePadJoystickEvent(
|
||||||
|
playerNumber,
|
||||||
|
NativeLibrary.StickType.STICK_R,
|
||||||
|
event.getAxisValue(MotionEvent.AXIS_Z),
|
||||||
|
-event.getAxisValue(MotionEvent.AXIS_RZ)
|
||||||
|
)
|
||||||
|
MotionEvent.AXIS_RX, MotionEvent.AXIS_RY ->
|
||||||
|
NativeLibrary.onGamePadJoystickEvent(
|
||||||
|
playerNumber,
|
||||||
|
NativeLibrary.StickType.STICK_R,
|
||||||
|
event.getAxisValue(MotionEvent.AXIS_RX),
|
||||||
|
-event.getAxisValue(MotionEvent.AXIS_RY)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setRazerAxisInput(event: MotionEvent, axis: Int) {
|
||||||
|
val playerNumber = getPlayerNumber(event.device.controllerNumber)
|
||||||
|
|
||||||
|
when (axis) {
|
||||||
|
MotionEvent.AXIS_X, MotionEvent.AXIS_Y ->
|
||||||
|
NativeLibrary.onGamePadJoystickEvent(
|
||||||
|
playerNumber,
|
||||||
|
NativeLibrary.StickType.STICK_L,
|
||||||
|
event.getAxisValue(MotionEvent.AXIS_X),
|
||||||
|
-event.getAxisValue(MotionEvent.AXIS_Y)
|
||||||
|
)
|
||||||
|
MotionEvent.AXIS_Z, MotionEvent.AXIS_RZ ->
|
||||||
|
NativeLibrary.onGamePadJoystickEvent(
|
||||||
|
playerNumber,
|
||||||
|
NativeLibrary.StickType.STICK_R,
|
||||||
|
event.getAxisValue(MotionEvent.AXIS_Z),
|
||||||
|
-event.getAxisValue(MotionEvent.AXIS_RZ)
|
||||||
|
)
|
||||||
|
MotionEvent.AXIS_BRAKE ->
|
||||||
|
NativeLibrary.onGamePadButtonEvent(
|
||||||
|
playerNumber,
|
||||||
|
NativeLibrary.ButtonType.TRIGGER_ZL,
|
||||||
|
getAxisToButton(event.getAxisValue(MotionEvent.AXIS_BRAKE))
|
||||||
|
)
|
||||||
|
MotionEvent.AXIS_GAS ->
|
||||||
|
NativeLibrary.onGamePadButtonEvent(
|
||||||
|
playerNumber,
|
||||||
|
NativeLibrary.ButtonType.TRIGGER_ZR,
|
||||||
|
getAxisToButton(event.getAxisValue(MotionEvent.AXIS_GAS))
|
||||||
|
)
|
||||||
|
MotionEvent.AXIS_HAT_X, MotionEvent.AXIS_HAT_Y ->
|
||||||
|
setAxisDpadState(
|
||||||
|
playerNumber,
|
||||||
|
event.getAxisValue(MotionEvent.AXIS_HAT_X),
|
||||||
|
event.getAxisValue(MotionEvent.AXIS_HAT_Y)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue