在实际开发中我们有时会遇到处理外部设备输入的响应操作,例如:键盘、鼠标、游戏手柄和电视机遥控器等。
外部设备不同于常见的触屏设备,触屏设备是在不指定控件焦点的情况下可以直接拿到事件。但物理性的外部设备就不行了,首先需要让控件获取焦点,可以调用View类的requestFocus方法获取焦点,不然后续的外设事件是收不到的。
然后通过View的setOnGenericMotionListener方法和setOnKeyListener方法来监听我们想要的外设事件。一般来说这两个监听器都要给View设置。
public void setOnGenericMotionListener(OnGenericMotionListener l) {
getListenerInfo().mOnGenericMotionListener = l;
}
public void setOnKeyListener(OnKeyListener l) {
getListenerInfo().mOnKeyListener = l;
}
- OnGenericMotionListener主要是用来接收鼠标或手柄的摇杆事件。
- OnKeyListener主要是用于接收外设的按键事件。有此按键会同时触发两种监听事件,比如鼠标的点击事件。
这两个方法分别需要传入两个接口OnGenericMotionListener和OnKeyListener,接口定义如下:
public interface OnGenericMotionListener {
boolean onGenericMotion(View v, MotionEvent event);
}
public interface OnKeyListener {
boolean onKey(View v, int keyCode, KeyEvent event);
}
这两个接口都只有一个方法需要实现,且方法都会返回一个布尔值,这个布尔值的表示是否消费掉该事件。原理和onTouch事件是一样的,这里就不多说了。
具体的代码实现也很简单,我们可以按如下方式实现:
// 先获取焦点,不然后续的事件无法获取得到
viewTouch.setFocusable(true);
viewTouch.requestFocus();
viewTouch.setOnGenericMotionListener(new View.OnGenericMotionListener() {
@Override
public boolean onGenericMotion(View v, MotionEvent event) {
// 需要处理的响应事件
return false;
}
});
viewTouch.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
// 需要处理的响应事件
return false;
}
});
现在来说一下事件响应类MotionEvent和KeyEvent,首先它们都继承自InputEvent类。我们可以通过这两个类来获取事件来自哪种设备和事件的具体数值等信息。
- MotionEvent封装了和移动操作相关的数据,比如鼠标的各种操作(包括按键)或手柄的摇杆。
- KeyEvent封装了和按键相关的数据。
有时对一个外设的操作可能会同时触发这两种事件。
设备动作状态
MotionEvent和KeyEvent都会有一个getAction方法,用于表示当前外设处于哪种动作状态,常见的动作为:
- ACTION_DOWN:按键被按下
- ACTION_UP:按键释放
- ACTION_CANCEL:按键被长时间按下后释放
- ACTION_HOVER_ENTER:指针移入到窗口或者View区域,但没有按下。
- ACTION_HOVER_MOVE:指针在窗口或者View区域移动,但没有按下。
- ACTION_HOVER_EXIT:指针移出到窗口或者View区域,但没有按下。
- ACTION_SCROLL: 滚轮滚动,可以触发水平滚动(AXIS_HSCROLL)或者垂直滚动(AXIS_VSCROLL)
事件源的设备信息
MotinEvent和KeyEvent都有一个名为getDevice的方法,该方法属于InputEvent的抽象方法,方法返回一个InputDevice对象,此对象包含了发送事件的设备信息。InputDevice有几个常用的方法:
- 获取设备的类型getSource:
此方法会返回一个int类型的常量,用于表示设备的类型,并且在InputDevice类中已经列出一部分常见的设备类型:
SOURCE_MOUSE:鼠标
SOURCE_KEYBOARD:键盘
SOURCE_JOYSTICK:游戏手柄
SOURCE_GAMEPAD:游戏手柄
但在实际开发中有很多设备的类型并没有对应的常量,或常量名称定义的很笼统,建议直接获取getSource的返回值而不要和InputDevice的常量比较。
除了上述方法外也可以通过MotionEvent的getToolType方法来判断部分的设备类型:
TOOL_TYPE_MOUSE:鼠标
TOOL_TYPE_STYLUS:手写笔
-
获取设备的名称和描述getName、getDescriptor:
getName用于返回设备的名称,但有时看名称也不知道是什么设备的时候就需要用getDescriptor进一步说明这是什么设备了。 -
获取设备的编号getId:
此方法用于返回设备的ID号,主要在相同类型的设备之间做区分。
关于Android外部设备的事件处理就说到这里,整个过程并没有什么难点,最后再强调下控件一定要获取焦点,不然收受不到事件响应,因为平时触屏手机APP做习惯了往往会乎视这个问题。
关于手柄的一些资料可以参见:Android蓝牙手柄开发
点击链接加入群聊【口袋里的安卓】:https://jq.qq.com/?_wv=1027&k=5z4fzdT
或关注微信公众号:
网友评论