I need to have two different behaviors, one for D-pad and another for the analog Joystick (on the same gamepad).
The problem is that on the onGenericMotionEvent
callback, both have the same information on the MotionEvent
and I am not able to distinguish them.
// d-pad
MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=-1.5259255E-5, y[0]=-1.5259255E-5, toolType[0]=TOOL_TYPE_UNKNOWN, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=151637936, downTime=0, deviceId=5, source=0x1000010 }
// analog joystick
MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=0.64507514, y[0]=0.710811, toolType[0]=TOOL_TYPE_UNKNOWN, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=151650802, downTime=0, deviceId=5, source=0x1000010 }
Is it possible to identify which kind of input is being used? How?
I ran into this same issue, and I had to dig through this helpful Git user's project to figure out how he did it. The way you differentiate between the different joysticks (and the D-pad) is to use each direction's specific axis.
If you read the Android documentation's page very carefully (I didn't pick up on it), it does show how you can differentiate between the various joysticks and their directions:
This image shows that the left joystick uses axes AXIS_X and AXIS_Y, whereas the right joystick uses AXIS_Z and and AXIS_RZ. For the D-pad, I used AXIS_HAT_X and AXIS_HAT_Y. The following snippet from my code (in Kotlin) shows how you can access each of these individually:
Note: I also had my seek bars set to a range of 0-100, which is why I have the conversion math at the bottom of processJoystickInput()
.
private fun processJoystickInput(event: MotionEvent, historyPos: Int) {
val inputDevice = event.device
val newJoystickValues = floatArrayOf(
getCenteredAxis(event, inputDevice, MotionEvent.AXIS_X, historyPos),
getCenteredAxis(event, inputDevice, MotionEvent.AXIS_Y, historyPos),
getCenteredAxis(event, inputDevice, MotionEvent.AXIS_Z, historyPos),
getCenteredAxis(event, inputDevice, MotionEvent.AXIS_RZ, historyPos),
getCenteredAxis(event, inputDevice, MotionEvent.AXIS_HAT_X, historyPos),
getCenteredAxis(event, inputDevice, MotionEvent.AXIS_HAT_Y, historyPos))
// Update based on the new x and y values
val throttleSeekBar = findViewById<SeekBar>(R.id.throttle_seekBar)
val yawSeekBar = findViewById<SeekBar>(R.id.yaw_seekBar)
val pitchSeekBar = findViewById<SeekBar>(R.id.pitch_seekBar)
val rollSeekBar = findViewById<SeekBar>(R.id.roll_seekBar)
val dpadXSeekBar = findViewById<SeekBar>(R.id.dpadX_seekBar)
val dpadYSeekBar = findViewById<SeekBar>(R.id.dpadY_seekBar)
// Convert the float range (-1.00 to 1.00) to Int (0 to 100)
yawSeekBar.progress = ((newJoystickValues[0] + 1) * 50).toInt()
throttleSeekBar.progress = ((newJoystickValues[1] + 1) * 50).toInt()
rollSeekBar.progress = ((newJoystickValues[2] + 1) * 50).toInt()
pitchSeekBar.progress = ((newJoystickValues[3] + 1) * 50).toInt()
dpadXSeekBar.progress = ((newJoystickValues[4] + 1) * 50).toInt()
dpadYSeekBar.progress = ((newJoystickValues[5] + 1) * 50).toInt()
}
override fun onGenericMotionEvent(event: MotionEvent): Boolean {
// Check that the event came from a game controller
return if (event.source and(InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK
&& event.action == MotionEvent.ACTION_MOVE) {
// Process the movements starting from the
// earliest historical position in the batch
(0 until event.historySize).forEach { i ->
// Process the event at historical position i
processJoystickInput(event, i)
}
// Process the current movement sample in the batch (position -1)
processJoystickInput(event, -1)
true
} else {
super.onGenericMotionEvent(event)
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With