How to differentiate a D-pad movement from a Joystick movement?

微笑、不失礼 提交于 2019-12-23 09:56:10

问题


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 along AXIS_X and AXIS_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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!