问题
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?
回答1:
Looking into your provided information, they look like from the same source, which is Joystick (0x1000010). You can check these information on Input Device object.
The following information were from Handling Controller Actions:
To verify that a connected input device is a game controller, call
getSources()
to obtain a combined bit field of input source types supported on that device.A source type of
SOURCE_GAMEPAD
indicates that the input device has gamepad buttons (for example,BUTTON_A
). Note that this source type does not strictly indicate if the game controller has D-pad buttons, although most gamepads typically have directional controls.A source type of
SOURCE_DPAD
indicates that the input device has D-pad buttons (for example,DPAD_UP
).A source type of
SOURCE_JOYSTICK
indicates that the input device has analog control sticks (for example, a joystick that records movements alongAXIS_X
andAXIS_Y
).
You may also want to check Supporting Multiple Controller Input.
回答2:
From the Android docs (https://developer.android.com/training/game-controllers/controller-input):
Android reports D-pad UP and DOWN presses as AXIS_HAT_Y events with a range from -1.0 (up) to 1.0 (down), and D-pad LEFT or RIGHT presses as AXIS_HAT_X events with a range from -1.0 (left) to 1.0 (right).
Some controllers instead report D-pad presses with a key code. If your game cares about D-pad presses, you should treat the hat axis events and the D-pad key codes as the same input events, as recommended in table 2.
The two controllers I've worked with (NVIDIA SHIELD BlueTooth and Microsoft XBOX360 wired) both generate AXIS_HAT_* movement events.
回答3:
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)
}
}
来源:https://stackoverflow.com/questions/34536195/how-to-differentiate-a-d-pad-movement-from-a-joystick-movement