输入设备的按键事件,在Android设备中会被转换为KeyEvent对象。而游戏手柄中的摇杆则会产生对应的MotionEvent对象。
关于事件分发机制
先大概看下事件的分发机制。简单来说,比如按键事件,分发按键事件的方法叫 dispatchKeyEvent()
。
一个事件首先被顶层DecorView分发给Activity,然后Activity会调用 dispatchKeyEvent()
方法将事件分发给ViewGroup层,在经过层层传递后,最终事件会到达我们想接受事件的View。View接受到事件后也会调用自己的 dispatchKeyEvent()
方法,然后就开始处理事件。默认情况下,会首先查看是否有给View设 OnKeyListener
。如果没有,或者有但是返回结果为false,那么事件还会继续交给View的 onKeyDown()
onKeyUp()
等方法。如果为true,则事件立刻被消耗掉,后面不会再给其他方法了。其次,在交给 View
的 onKeyDown()
和onKeyUp()
方法后,如果这些方法又返回了false,那么事件不会被消耗掉,会进一步交给上层,最终在Activity的 onKeyDown()
onKeyUp()
方法中处理。而如果返回了true,则事件被消耗掉,事件处理就此结束。
监听事件
对于按键事件,有以下方法可以来处理
onKeyDown()
: 按键按下
onKeyUp()
: 按下之后松开
onKeyLongPress()
:长按
onKeyMultiple()
:多次重复事件
onKeyShortCut()
:快捷键事件
在长按的时候,首先会调 onKeyDown()
,然后一般会连续调用onKeyDown()
多次,或在调两次之后直接调用一次onKeyLongPress()
方法一次就停止,这个可能与输入设备和按键有关。
不过,如果是要在Webview中监听按键事件,因为给Webview loadurl之后,KeyEvent就被消耗了,重写onKeyDown()等方法是接收不到事件的。所以还是建议直接重写 dispatchKeyEvent()
方法,这样可以从一开始就截获事件,不必担心不必要的麻烦。
对于游戏手柄中的摇杆事件,可以通过重写 dispatchGenericMotionEvent
方法来监听。
事件对象
事件对象,包括按键事件 KeyEvent
和摇杆事件MotionEvent
。
KeyEvent
一个KeyEvent
对象,有以下属性:
action
: 按键的动作。有DOWN UP等
keyCode
: 按键代码,跟前面单独的KeyCode一样
scanCode
: 按键事件的原始设备扫描码,最终会转换为keyCode
metaState
: 当前按键的metaState
flags
: 当前按键事件的flags
repeatCount
: 按键事件重复的次数。有的按键在长按的时候,会连续产生多个DOWN事件,这个时候除第一个DOWN事件的repeatCount为0,之后的DOWN事件的repeatCount会递增。之所以是部分按键,是因为我发现键盘上的按键长按时,会被识别为 DOWN UP DOWN UP序列,而长按比如手机的虚拟按键时,事件序列是 DOWN DOWN UP
eventTime
: 这个事件发生的时间,是一个从开机到现在的毫秒数。
downTime
: 这个按键按下的时间,是一个从开机到现在的毫秒数。如果同一个按键先按下再弹起,那么他有两个事件,UP和DOWN,且这两个事件的downTime是一样的
deviceId
: 产生按键事件的设备deviceid
source
: 输入源,具体可以参考 InputDevice类
这里keyCode有很多,除了基础的Android手机的几个虚拟按键外,还有整个键盘按键、游戏手柄按键、电视遥控器等,具体在官网有讲,也有一些靠谱的翻译:
摇杆事件
一个MotionEvent
对象,表示摇杆相关状态,常用的一些值,需要用 getAxisValue()
方法通过传入不同的参数来获取当前值,此外有一些类似方法可以获取历史值。
AXIS_X
参数,获取到x值,表示水平方向移动距离,向右为正,向左为负
AXIS_Y
参数,获取到y值,表示垂直方向移动距离,向下为正,向上为负
AXIS_Z
参数,获取到z值,表示水平方向移动距离,向右为正,向左为负
AXIS_RZ
参数,获取到rz值,表示垂直方向移动距离,向下为正,向上为负
AXIS_BRAKE
参数,获取到break值,表示肩键状态,1为按住 0为释放
AXIS_GAS
参数,获取到gas值,表示肩键状态,1为按住 0为释放负
键位映射
键盘
在接入键盘时,每个按键在按下、弹起时都有对应的 KeyEvent
对象,对应着一个事件,可以使用。
手柄
在接入手柄时,有两种事件,分别是按键事件 KeyEvent
和移动事件MotionEvent
。
手柄中的常规按键,都会对应一个或多个 KeyEvent
,而操作摇杆时,或者按下左右侧的L2 R2键时,会产生MotionEvent
。其中按键事件不一定是一对一的,部分键是一次操作有多种按键事件。而移动事件可以获取当前摇杆的移动情况,用坐标形式来模拟,具体映射如下:
X : 按下一次会产生两个按键事件,对应的 KeyCode
依次为 KEYCODE_BUTTON_X
和 KEYCODE_DEL
。长按会继续产生 KEYCODE_DEL
按键事件。
Y : 按下一次会产生两个按键事件,对应的 KeyCode
依次为 KEYCODE_BUTTON_Y
和 KEYCODE_SPACE
。长按会继续产生 KEYCODE_SPACE
按键事件。
A : 按下一次会产生两个按键事件,对应的 KeyCode
依次为 KEYCODE_BUTTON_A
和 KEYCODE_DPAD_CENTER
。长按会继续产生 KEYCODE_DPAD_CENTER
按键事件。
B : 按下一次会产生两个按键事件,对应的 KeyCode
依次为 KEYCODE_BUTTON_B
和 KEYCODE_BACK
。长按会继续产生 KEYCODE_BACK
按键事件。
↑ : 按下会先产生一个摇杆事件,坐标移动量为0。之后会产生一个按键事件,对应 KeyCode
为 KEYCODE_DPAD_UP
。如果是长按,则会继续产生相同的按键事件,直到松开。
↓ : 按下会先产生一个摇杆事件,坐标移动量为0。之后会产生一个按键事件,对应 KeyCode
为 KEYCODE_DPAD_DOWN
。如果是长按,则会继续产生相同的按键事件,直到松开。
← : 按下会先产生一个摇杆动事件,坐标移动量为0。之后会产生一个按键事件,对应 KeyCode
为 KEYCODE_DPAD_LEFT
。如果是长按,则会继续产生相同的按键事件,直到松开。
→ : 按下会先产生一个摇杆事件,坐标移动量为0。之后会产生一个按键事件,对应 KeyCode
为 KEYCODE_DPAD_RIGHT
。如果是长按,则会继续产生相同的按键事件,直到松开。
L1 : 按下会产生一个按键事件,对应 KeyCode
为 KEYCODE_BUTTON_L1
,长按继续产生相同事件。
R1 : 按下会产生一个按键事件,对应 KeyCode
为 KEYCODE_BUTTON_L2
,长按继续产生相同事件。
L2 : 按下会产生一个按键事件,对应 KeyCode
为 KEYCODE_BUTTON_L2
,之后再产生一个摇杆事件,坐标移动量为0。长按继续产生相同的按键事件。松开后坐标移动量中 break 会变为1
R2 : 按下会产生一个按键事件,对应 KeyCode
为 KEYCODE_BUTTON_R2
,之后再产生一个移动事件,坐标移动量为0。长按继续产生相同的按键事件。松开后坐标移动量中 gas 会变为1。
左摇杆 :按下一次会产生两个按键事件,对应的 KeyCode
依次为 KEYCODE_BUTTON_THUMBL
和 KEYCODE_DPAD_CENTER
。长按会继续产生 KEYCODE_DPAD_CENTER
按键事件。拨动摇杆时,会连续产生多个移动事件。移动事件的x y值表示当前拨动的距离。
右摇杆 :按下一次会产生两个按键事件,对应的 KeyCode
依次为 KEYCODE_BUTTON_THUMBL
和 KEYCODE_DPAD_CENTER
。长按会继续产生 KEYCODE_DPAD_CENTER
按键事件。拨动摇杆时,会连续产生多个移动事件。移动事件的z zr值表示当前拨动的距离。
手柄的适配情况,在主流的Xbox360类手柄上是完全适配的,Switch Pro类手柄的L2 R2键没有KeyEvent事件
网友评论