如何区分D-pad运动和摇杆运动?

5
我需要有两种不同的行为,一种是针对D-pad,另一种是针对模拟摇杆(在同一个游戏手柄上)。
问题在于,在onGenericMotionEvent回调中,两者在MotionEvent上具有相同的信息,我无法区分它们。
// 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 }

能否识别正在使用的输入方式?如何实现?


你有找到解决方案吗?我也遇到了同样的问题,但似乎没有办法区分这两种输入方法。这真的很烦人... - grill2010
似乎 DS4 手柄在使用 DPAD 时不会声明 DPAD 源。相反,你会得到一个带有 Hat 值的 Joystick 源事件,这些值根据你按下的按钮而设置为最小/最大。为了支持 DS4,看起来需要查询 X 和 XHat,确定哪个更大(绝对值),然后使用它。 - Halsafar
3个回答

4
我遇到了相同的问题,不得不翻阅这位有用的Git用户的项目才能弄清楚他是如何做到的。你区分不同的摇杆(和D-pad)的方法是使用每个方向的特定
如果你仔细阅读Android文档页面(我没有注意到),它确实显示了如何区分各种摇杆及其方向:

Android documentation for different axis/labels

这张图片显示左侧摇杆使用轴 AXIS_X AXIS_Y ,而右侧摇杆使用 AXIS_Z AXIS_RZ 。对于D-pad,我使用了 AXIS_HAT_X AXIS_HAT_Y 。以下是我的Kotlin代码片段,展示如何单独访问每个输入:

注意:我的拖动条也设置为0-100的范围,这就是为什么在 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)
    }
}

0

来自Android文档(https://developer.android.com/training/game-controllers/controller-input):

Android将D-pad向上和向下的按键事件报告为AXIS_HAT_Y事件,范围从-1.0 (向上)到1.0(向下),将D-pad左或右的按键事件报告为AXIS_HAT_X事件,范围从-1.0(左)到1.0(右)。

一些控制器会使用一个按键代码代替D-pad按键事件。如果你的游戏关心D-pad按键事件,那么你应该将帽子轴事件和D-pad按键代码视为相同的输入事件,如表2所推荐的。

我使用过的两个控制器(NVIDIA SHIELD蓝牙和Microsoft XBOX360有线控制器)都会产生AXIS_HAT_*移动事件。


DS4也一样。DPad始终是MotionEvent,源=Joystick,必须从XHat/YHat值中读取DPad。 - Halsafar

0

根据您提供的信息,它们看起来来自同一来源,即手柄(0x1000010)。您可以在输入设备对象上检查这些信息。

以下信息来自处理控制器操作

要验证连接的输入设备是否为游戏控制器,请调用getSources()以获取该设备支持的输入源类型的组合位字段。
源类型SOURCE_GAMEPAD表示输入设备具有游戏手柄按钮(例如BUTTON_A)。请注意,此源类型并不严格指示游戏控制器是否具有D-pad按钮,尽管大多数游戏手柄通常都有方向控制。
源类型SOURCE_DPAD表示输入设备具有D-pad按钮(例如DPAD_UP)。
源类型SOURCE_JOYSTICK表示输入设备具有模拟控制杆(例如记录沿AXIS_XAXIS_Y移动的操纵杆)。
您还可以查看支持多个控制器输入

我需要区分来自同一个操纵杆源的两个不同输入(dpad和模拟),而不是两个不同的来源。 - thiagolr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接