Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 295
thiagolr Avatar asked Sep 26 '22 19:09

thiagolr


1 Answers

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:

Android documentation for different axis/labels

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)
    }
}
like image 51
ConcernedHobbit Avatar answered Oct 08 '22 19:10

ConcernedHobbit