Android input键值从底层到应用层映射流程与修改方法

   日期:2024-12-27    作者:huihaohuagong 移动:http://mip.riyuangf.com/mobile/quote/62437.html

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

 

  1. 位置:frameworks/base/core/java/android/view/KeyEvent.java

  2. 此处的key code必须与native定义的一致

C :资源文件(attrs.xml)添加keycode

  1. 位置: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

 

  1. 位置:frameworks/base/core/java/android/view/KeyEvent.java

  2. 此处的key code必须与native定义的一致

C :资源文件(attrs.xml)添加keycode

  1. 位置: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


特别提示:本信息由相关用户自行提供,真实性未证实,仅供参考。请谨慎采用,风险自负。


举报收藏 0评论 0
0相关评论
相关最新动态
推荐最新动态
点击排行
{
网站首页  |  关于我们  |  联系方式  |  使用协议  |  隐私政策  |  版权隐私  |  网站地图  |  排名推广  |  广告服务  |  积分换礼  |  网站留言  |  RSS订阅  |  违规举报  |  鄂ICP备2020018471号