Android输入事件的源头是位于/dev/input/下的设备节点,而输入系统的终点是由WMS管理的某个窗口。最初的输入事件为内核生成的原始事件,而最终交付给窗口的则是KeyEvent或MotionEvent对象。因此Android输入系统的主要工作是读取设备节点中的原始事件,将其加工封装,然后派发给一个特定的窗口以及窗口中的控件。这个过程由InputManagerService(以下简称IMS)系统服务为核心的多个参与者共同完成。
(1)键扫描码
ScanCode是由linux的Input驱动框架定义的整数类型,可参考input.h头文件,即getevent得到的键值。
(2) 键盘布局文件(*.kl)
将input event报的键值转换成具体键盘对应的按键供android上层使用,时通过键盘布局文件(*.kl)完成转换的。放在/system/usr/keylayout/下面
而qwert.kl中定义如下:
其中ScanCode 是驱动报的值(即驱动input.h中定义的键值 )
(3) 添加kl文件:
abcxxxx.kl(文件名须与input 的device设备的name一致)
[199为 驱动定义的scanCode ,CAMERA 为Android中 KEYCODES[]定义按键对应的keylabel字符]
注:
1)kl文件须与键盘输入的input的devic的名称一致,否则EventHub在加载设备时因找不到对应的kl而加载默认的qwert.kl,导致键值转换错误
2)kl中的scanCode和android中定义的keylabel字符必须对应,否则会转换错误。keyMapper在转换时是根据scanCode,来确定对应的按键字符,再根据此字符在KEYCODES中的位置来确定对应android中的键值
(4) kl文件添加到system
将kl文件(通常)放在/device/mtk/XXX/(XXX为项目名称)
添加AndroidBoard.mk :
在/device/mtk/common/base.mk添加
①IR硬件扫描码在驱动里面被映射为 include/uapi/linux/input.h 里面定义的某个键值,但这个键值只在linux系统(内核)中使用。
②Android通过源码目录下的 device/xxx/xxx.kl(keylayout) 文件完成linux键值到Android系统要使用的键值映射。
以HID设备为例,首先内核中的键值转换在drivers/hid/hid-input.c 中进行映射,键值通道也有多种类型,例如:keyboard、consumer 等等;
//keyboard通道键值则是在如下数组添加修改:
//consumer通道键值则是在如下添加修改:
通过 map_key_clear 宏将原始键值(usage->hid & HID_USAGE)转换成内核的定义,映射函数的具体实现可看内核源码,
以上键值的定义在 include/uapi/linux/input-event-codes.h (内核代码,较新版本定义整合进了input.h),对应到Android系统层的头文件则是 bionic/libc/kernel/uapi/linux/input-event-codes.h:
可通过 getevent 指令查看上报的键值,键值为十六进制显示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U7UstaUe-1597307827051)(assets/821933-20180816205242760-1243866432.png)]
如上我的设备名是:“Smart Remote” , VID PID信息是:Vendor=0030 Product=001D ,则对应 /system/usr/keylayout/Vendor_0030_Product_001D.kl,如果该目录下没有对应VID PID的.kl则默认使用 Generic.kl,根据系统差异可能另外有 /data/system/devices/keylayout/Vendor_XXXX_Product_XXXX_Version_XXXX.kl ,此外还有键值对应字符的转换表:/system/usr/keychars/Generic.kcm 。
所以上面通过getevent获得的原始键值是0x44(十进制:68),然后由 hid-input.c 可知 hid_keyboard[68]=87 而 input.h 中定义是 #define KEY_F11 87,所以Android系统层获取到内核转换后的键值为<87>,然后通过加载Generic.kl解析<87>的含义是"F11"(一般都是和内核头文件定义相匹配,也可以自己修改使其映射成其他含义):
键值从底层上报到上层的流程简图如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kUMPvATC-1597307827054)(assets/821933-20180816202424670-516556732.png)]
图2:键值上报流程
从上图可以看到,framework层通过.kl文件将获取的键值转换成实际按键含义后,又会通过KeycodeLabel转换成相应的keycode,具体文件在:frameworks ativeincludeinputKeycodeLabels.h(android 4.4.4源码):
然后app可以通过如下方法获得对应键按下时的keyCode值,即“F11”对应获得的keyCode即为上面自定义的<546>:
1、Kernel层:
① include/uapi/linux/input.h 中添加: #define KEY_LXL 123
② drivers/hid/hid-input.c 中添加: case 0x188: map_key_clear(KEY_LXL); break; //其中0x188是HID设备上报的原始键值
2、Android系统层:
(1)定义按键对应的key label**
在KEYCODES[]数组的最后添加按键的key label,即:
位置:
Android 4.4 以前版本 frameworks/base/include/ui/KeycodeLabels.h 的KEYCODES[]数组中添加: { “LXL”, 666 },
Android 4.4 在framework/native/include/input/KeyCodelabels.h
Android5.0 以后在framework/native/include/input/InputEventLabels.h
(2)定义keyCode
A: native 定义(keycodes.h)
注:
1)位置:frameworks/base/include/android/keycodes.h
2)此处keycode的定义的值即是 上面key label定义在KEYCODES数组中的位置(index),否则会映射错误
B JAVA定义(KeyEvent.java定义键值)
修改LAST_KEYCODE
注:
位置:frameworks/base/core/java/android/view/KeyEvent.java
此处的key code必须与native定义的一致
C :资源文件(attrs.xml)添加keycode
注:
- 位置:frameworksbasecore es esvaluesattrs.xml
影响到API则需要调用 make update-api 然后就可以使用了
经过如上的步骤就将Linux驱动向上层抛出的"123"键值和Android系统中的KEYCODE_LXL <666>对应起来了,然后可以在Android的framework层的键值处理函数中,捕获按键事件,并进行相应自定义处理,具体在frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java 的**interceptKeyBeforeQueueing()**函数中实现。
dumpsys input
这个命令可以查看到输入设备映射到了哪一个kl文件 kl文件映射
getevent getevent -ltr
这个命令可以查看到输入的具体键值时多少,输出的是16进制。
input keyevent
模拟键值输入,input keyevent android键值 例如:
注意这里的android 键值就是前面KeyEvent.java 里面对应的键值
cat /proc/bus/input/devices
查看设备信息,详见上文
},**
Android 4.4 在framework/native/include/input/KeyCodelabels.h
Android5.0 以后在framework/native/include/input/InputEventLabels.h
(2)定义keyCode
A: native 定义(keycodes.h)
注:
1)位置:frameworks/base/include/android/keycodes.h
2)此处keycode的定义的值即是 上面key label定义在KEYCODES数组中的位置(index),否则会映射错误
B JAVA定义(KeyEvent.java定义键值)
修改LAST_KEYCODE
注:
位置:frameworks/base/core/java/android/view/KeyEvent.java
此处的key code必须与native定义的一致
C :资源文件(attrs.xml)添加keycode
注:
- 位置:frameworksbasecore es esvaluesattrs.xml
影响到API则需要调用 make update-api 然后就可以使用了
经过如上的步骤就将Linux驱动向上层抛出的"123"键值和Android系统中的KEYCODE_LXL <666>对应起来了,然后可以在Android的framework层的键值处理函数中,捕获按键事件,并进行相应自定义处理,具体在frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java 的**interceptKeyBeforeQueueing()**函数中实现。
dumpsys input
这个命令可以查看到输入设备映射到了哪一个kl文件 kl文件映射
getevent getevent -ltr
这个命令可以查看到输入的具体键值时多少,输出的是16进制。
input keyevent
模拟键值输入,input keyevent android键值 例如:
注意这里的android 键值就是前面KeyEvent.java 里面对应的键值
cat /proc/bus/input/devices