committed by
bunnei
6 changed files with 510 additions and 11 deletions
-
42src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
-
38src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt
-
16src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt
-
323src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/InputHandler.kt
-
90src/android/app/src/main/jni/native.cpp
-
12src/android/app/src/main/jni/native.h
@ -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) |
||||
|
) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue