|
|
@@ -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)
|
|
|
+ )
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+}
|