mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-11-23 00:59:17 +01:00
Don't ignore HAT axes input events
Capture HAT axes events ourselves instead of relying on the android framework to turn them into KeyCodes. Fixes handling of DPAD button presses on most controllers.
This commit is contained in:
parent
f1ec771944
commit
3a657c44cc
@ -44,6 +44,8 @@ data class MotionHostEvent(override val descriptor : String = "", val axis : Int
|
||||
MotionEvent.AXIS_Y,
|
||||
MotionEvent.AXIS_Z,
|
||||
MotionEvent.AXIS_RZ,
|
||||
MotionEvent.AXIS_HAT_X,
|
||||
MotionEvent.AXIS_HAT_Y,
|
||||
MotionEvent.AXIS_LTRIGGER,
|
||||
MotionEvent.AXIS_RTRIGGER,
|
||||
MotionEvent.AXIS_THROTTLE,
|
||||
|
@ -5,7 +5,6 @@
|
||||
|
||||
package emu.skyline.input
|
||||
|
||||
import android.graphics.PointF
|
||||
import android.view.InputDevice
|
||||
import android.view.KeyEvent
|
||||
import android.view.MotionEvent
|
||||
@ -120,58 +119,47 @@ class InputHandler(private val inputManager : InputManager, private val preferen
|
||||
*/
|
||||
private val axesHistory = arrayOfNulls<Float>(MotionHostEvent.axes.size)
|
||||
|
||||
/**
|
||||
* The last value of the HAT axes so it can be ignored in [onGenericMotionEvent] so they are handled by [dispatchKeyEvent] instead
|
||||
*/
|
||||
private var oldHat = PointF()
|
||||
|
||||
/**
|
||||
* Handles translating any [MotionHostEvent]s to a [GuestEvent] that is passed into libskyline
|
||||
*/
|
||||
fun handleMotionEvent(event : MotionEvent) : Boolean {
|
||||
if ((event.isFromSource(InputDevice.SOURCE_CLASS_JOYSTICK) || event.isFromSource(InputDevice.SOURCE_CLASS_BUTTON)) && event.action == MotionEvent.ACTION_MOVE) {
|
||||
val hat = PointF(event.getAxisValue(MotionEvent.AXIS_HAT_X), event.getAxisValue(MotionEvent.AXIS_HAT_Y))
|
||||
for (axisItem in MotionHostEvent.axes.withIndex()) {
|
||||
val axis = axisItem.value
|
||||
var value = event.getAxisValue(axis)
|
||||
|
||||
if (hat == oldHat) {
|
||||
for (axisItem in MotionHostEvent.axes.withIndex()) {
|
||||
val axis = axisItem.value
|
||||
var value = event.getAxisValue(axis)
|
||||
if ((event.historySize != 0 && value != event.getHistoricalAxisValue(axis, 0)) || (axesHistory[axisItem.index]?.let { it == value } == false)) {
|
||||
var polarity = value > 0 || (value == 0f && axesHistory[axisItem.index]?.let { it >= 0 } == true)
|
||||
|
||||
if ((event.historySize != 0 && value != event.getHistoricalAxisValue(axis, 0)) || (axesHistory[axisItem.index]?.let { it == value } == false)) {
|
||||
var polarity = value > 0 || (value == 0f && axesHistory[axisItem.index]?.let { it >= 0 } == true)
|
||||
|
||||
val guestEvent = MotionHostEvent(event.device.descriptor, axis, polarity).let { hostEvent ->
|
||||
inputManager.eventMap[hostEvent] ?: if (value == 0f) {
|
||||
polarity = false
|
||||
inputManager.eventMap[hostEvent.copy(polarity = false)]
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
when (guestEvent) {
|
||||
is ButtonGuestEvent -> {
|
||||
if (guestEvent.button != ButtonId.Menu)
|
||||
setButtonState(guestEvent.id, guestEvent.button.value(), if (abs(value) >= guestEvent.threshold) ButtonState.Pressed.state else ButtonState.Released.state)
|
||||
}
|
||||
|
||||
is AxisGuestEvent -> {
|
||||
value = guestEvent.value(value)
|
||||
value = if (polarity) abs(value) else -abs(value)
|
||||
value = if (guestEvent.axis == AxisId.LX || guestEvent.axis == AxisId.RX) value else -value
|
||||
|
||||
setAxisValue(guestEvent.id, guestEvent.axis.ordinal, (value * Short.MAX_VALUE).toInt())
|
||||
}
|
||||
val guestEvent = MotionHostEvent(event.device.descriptor, axis, polarity).let { hostEvent ->
|
||||
inputManager.eventMap[hostEvent] ?: if (value == 0f) {
|
||||
polarity = false
|
||||
inputManager.eventMap[hostEvent.copy(polarity = false)]
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
axesHistory[axisItem.index] = value
|
||||
when (guestEvent) {
|
||||
is ButtonGuestEvent -> {
|
||||
val action = if (abs(value) >= guestEvent.threshold) ButtonState.Pressed.state else ButtonState.Released.state
|
||||
if (guestEvent.button != ButtonId.Menu)
|
||||
setButtonState(guestEvent.id, guestEvent.button.value(), action)
|
||||
}
|
||||
|
||||
is AxisGuestEvent -> {
|
||||
value = guestEvent.value(value)
|
||||
value = if (polarity) abs(value) else -abs(value)
|
||||
value = if (guestEvent.axis == AxisId.LX || guestEvent.axis == AxisId.RX) value else -value
|
||||
setAxisValue(guestEvent.id, guestEvent.axis.ordinal, (value * Short.MAX_VALUE).toInt())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
} else {
|
||||
oldHat = hat
|
||||
axesHistory[axisItem.index] = value
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
|
@ -101,10 +101,6 @@ class ButtonDialog @JvmOverloads constructor(private val item : ControllerButton
|
||||
var axisRunnable : Runnable? = null // The Runnable that is used for counting down till an axis is selected
|
||||
val axisHandler = Handler(Looper.getMainLooper()) // The handler responsible for handling posting [axisRunnable]
|
||||
|
||||
// The last values of the HAT axes so that they can be ignored in [View.OnGenericMotionListener] so they are passed onto [DialogInterface.OnKeyListener] as [KeyEvent]s
|
||||
var oldDpadX = 0.0f
|
||||
var oldDpadY = 0.0f
|
||||
|
||||
dialog?.setOnKeyListener { _, _, event ->
|
||||
// We want all input events from Joysticks and Buttons except for [KeyEvent.KEYCODE_BACK] as that will should be processed elsewhere
|
||||
if (((event.isFromSource(InputDevice.SOURCE_CLASS_BUTTON) && event.keyCode != KeyEvent.KEYCODE_BACK) || event.isFromSource(InputDevice.SOURCE_CLASS_JOYSTICK)) && event.repeatCount == 0) {
|
||||
@ -155,23 +151,18 @@ class ButtonDialog @JvmOverloads constructor(private val item : ControllerButton
|
||||
}
|
||||
}
|
||||
|
||||
val axes = arrayOf(MotionEvent.AXIS_X, MotionEvent.AXIS_Y, MotionEvent.AXIS_Z, MotionEvent.AXIS_RZ, MotionEvent.AXIS_HAT_X, MotionEvent.AXIS_HAT_Y, MotionEvent.AXIS_LTRIGGER, MotionEvent.AXIS_RTRIGGER, MotionEvent.AXIS_THROTTLE, MotionEvent.AXIS_RUDDER, MotionEvent.AXIS_WHEEL, MotionEvent.AXIS_GAS, MotionEvent.AXIS_BRAKE).plus(IntRange(MotionEvent.AXIS_GENERIC_1, MotionEvent.AXIS_GENERIC_16).toList())
|
||||
|
||||
val axes = MotionHostEvent.axes
|
||||
val axesHistory = arrayOfNulls<Float>(axes.size) // The last recorded value of an axis, this is used to eliminate any stagnant axes
|
||||
|
||||
view.setOnGenericMotionListener { _, event ->
|
||||
// We retrieve the value of the HAT axes so that we can check for change and ignore any input from them so it'll be passed onto the [KeyEvent] handler
|
||||
val dpadX = event.getAxisValue(MotionEvent.AXIS_HAT_X)
|
||||
val dpadY = event.getAxisValue(MotionEvent.AXIS_HAT_Y)
|
||||
|
||||
// We want all input events from Joysticks and Buttons that are [MotionEvent.ACTION_MOVE] and not from the D-pad
|
||||
if ((event.isFromSource(InputDevice.SOURCE_CLASS_JOYSTICK) || event.isFromSource(InputDevice.SOURCE_CLASS_BUTTON)) && event.action == MotionEvent.ACTION_MOVE && dpadX == oldDpadX && dpadY == oldDpadY) {
|
||||
if ((event.isFromSource(InputDevice.SOURCE_CLASS_JOYSTICK) || event.isFromSource(InputDevice.SOURCE_CLASS_BUTTON)) && event.action == MotionEvent.ACTION_MOVE) {
|
||||
// We iterate over every axis to check if any of them pass the selection threshold and if they do then select them by setting [deviceId], [inputId] and [axisPolarity]
|
||||
for (axisItem in axes.withIndex()) {
|
||||
val axis = axisItem.value
|
||||
val value = event.getAxisValue(axis)
|
||||
|
||||
// This checks the history of the axis so it we can ignore any stagnant axis
|
||||
// This checks the history of the axis so we can ignore any stagnant axis
|
||||
if ((event.historySize == 0 || value == event.getHistoricalAxisValue(axis, 0)) && (axesHistory[axisItem.index]?.let { it == value } != false)) {
|
||||
axesHistory[axisItem.index] = value
|
||||
continue
|
||||
@ -246,9 +237,6 @@ class ButtonDialog @JvmOverloads constructor(private val item : ControllerButton
|
||||
|
||||
true
|
||||
} else {
|
||||
oldDpadX = dpadX
|
||||
oldDpadY = dpadY
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user