安卓系统遥控器的映射具体过程相关文档
1.处理的内容和流程
按键处理的过程,从驱动程序到Android的Java层受到的信息,键表示方式经过了两次转化,如下图所示。
键扫描码Scancode是由Linux的Input驱动框架定义的整数类型。键扫描码Scancode经过一次转化后,形成按键的标签KeycodeLabel,是一个字符串的表示形式。按键的标签KeycodeLabel经过转换后,再次形成整数型的按键码keycode。在Android应用程序层,主要使用按键码keycode来区分。
在本地框架层F:\XPcode\lib_Hi3716C_V100R002C00SPC010\froyo\frameworks\base\include\ui的文件夹中KeycodeLabels.h,按键码为整数值的格式,其定义KeyCode(枚举值)如下所示:
1. typedef enum KeyCode {
2. kKeyCodeUnknown = 0,
3. kKeyCodeSoftLeft = 1,
4. kKeyCodeSoftRight = 2,
5. kKeyCodeHome = 3,
6. kKeyCodeBack = 4,
7. // ...... 省略中间按键码
8. } KeyCode;
进而在定义了KeycodeLabels.h中定义了从字符串到整数的映射关系,数组KEYCODES,定义如下所示:
1. static const KeycodeLabel KEYCODES[] = { // {字符串,整数}
2. { "SOFT_LEFT", 1 },
3. { "SOFT_RIGHT", 2 },
4. { "HOME", 3 },
5. { "BACK", 4 },
6. { "CALL", 5 },
7. { "ENDCALL", 6 },
8. { "0", 7 }, // ...... 数字按键
9. { "1", 8 },
10. { "2", 9 },
11. { "3", 10 },
12. { "4", 11 },
13. { "5", 12 },
14. { "6", 13 },
15. { "7", 14 },
16. { "8", 15 },
17. { "9", 16 },
18. { "STAR", 17 },
19. // ...... 省略中间按键映射
20. { "MENU", 82 },
21. // ...... 省略中间按键映射
22. { NULL, 0 }
23. };
数组KEYCODES表示的映射关系,左列的内容即表示按键标签KeyCodeLabel,右列的内容为按键码KeyCode(与KeyCode的数值对应)。实际上,在按键信息第二次转化的时候就是将字符串类型KeyCodeLabel转化成整数的KeyCode。
KeycodeLabel的Flags的定义如下所示:
1. static const KeycodeLabel FLAGS[] = {
2. { "WAKE", 0x00000001 }, // 可以唤醒睡眠,并通知应用层
3. { "WAKE_DROPPED", 0x00000002 }, // 可以唤醒睡眠,不通知应用层
4. { "SHIFT", 0x00000004 }, // 自动附加SHIFT
5. { "CAPS_LOCK", 0x00000008 }, // 自动附加CAPS_LOCK
6. { "ALT", 0x00000010 }, // 自动附加ALT
7. { "ALT_GR", 0x00000020 },
8. { "MENU", 0x00000040 },
9. { "LAUNCHER", 0x00000080 },
10. { NULL, 0 }
11. };
KeycodeLabel表示按键的附属标识。
提示: frameworks/base/core/Java/android/view/KeyEvent.Java中定义了类android.view. KeyEvent类,其中定义整数类型的数值与KeycodeLabels.h中定义的KeyCode枚举值是对应的。
在本地框架层的\frameworks\base\include\ui中KeyCharacterMap.h,定义了按键的字符映射关系,KeyCharacterMap类的定义如下所示:
1. class KeyCharacterMap
2. {
3. public:
4. ~KeyCharacterMap();
5. unsigned short get(int keycode, int meta);
6. unsigned short getNumber(int keycode);
7. unsigned short getMatch(int keycode, const unsigned short* chars,
8. int charsize, uint32_t modifiers);
9. unsigned short getDisplayLabel(int keycode);
10. bool getKeyData(int keycode, unsigned short *displayLabel,
11. unsigned short *number, unsigned short* results);
12. inline unsigned int getKeyboardType() { return m_type; }
13. bool getEvents(uint16_t* chars, size_t len,
14. Vector<int32_t>* keys, Vector<uint32_t>* modifiers);
15. static KeyCharacterMap* load(int id);
16. enum {
17. NUMERIC = 1,
18. Q14 = 2,
19. QWERTY = 3 // or AZERTY or whatever
20. };
21. }
KeyCharacterMap用于将按键的码映射为文本可识别的字符串(例如,显示的标签等)。KeyCharacterMap是一个辅助的功能:由于按键码只是一个与UI无关整数,通常用程序对其进行捕获处理,然而如果将按键事件转换为用户可见的内容,就需要经过这个层次的转换了。
KeyCharacterMap需要从本地层传送到Java层,JNI的代码路径如下所示:
frameworks/base/core/jni/android_text_KeyCharacterMap.cpp
KeyCharacterMap Java框架层次的代码如下所示:
frameworks/base/core/Java/android/view/KeyCharacterMap.Java
android.view.KeyCharacterMap类是Android平台的API可以在应用程序中使用这个类。
android.text.method中有各种Linstener,可以之间监听KeyCharacterMap相关的信息。DigitsKeyListener NumberKeyListener TextKeyListener。
以上关于按键码和按键字符映射的内容是在代码中实现的内容,还需要配合动态的配置文件来使用。在实现Android系统的时候,有可能需要更改这两种文件。
动态的配置文件包括:
•KL(Keycode Layout): 后缀名为kl的配置文件
•KCM(KeyCharacterMap):后缀名为kcm的配置文件
配置文件的路径为:
sdk/emulator/keymaps/
这些配置文件经过系统生成后,将被放置在目标文件系统的/system/usr/keylayout/目录中。
kl文件将被直接复职到目标文件系统中;由于尺寸较大,kcm文件放置在目标文件系统中之前,需要经过压缩处理。KeyLayoutMap.cpp负责解析处理kl文件,KeyCharacterMap.cpp负责解析kcm文件。
2.kl:按键布局文件
Android默认提供的按键布局文件主要包括qwerty.kl和AVRCP.kl。qwerty.kl为全键盘的布局文件,是系统中主要按键使用的布局文件;AVRCP.kl用于多媒体的控制,ACRCP的含义为Audio/Video Remote Control Profile。
qwerty.kl文件的片断如下所示:
1. key 399 GRAVE
2. key 2 1
3. key 3 2
4. key 4 3
5. key 5 4
6. key 6 5
7. key 7 6
8. key 8 7
9. key 10 9
10. key 11 0
11. key 158 BACK WAKE_DROPPED
12. key 230 SOFT_RIGHT WAKE
13. key 60 SOFT_RIGHT WAKE
14. key 107 ENDCALL WAKE_DROPPED
15. key 62 ENDCALL WAKE_DROPPED
16. key 229 MENU WAKE_DROPPED
17. # 省略部分按键的对应内容
18. key 16 Q
19. key 17 W
20. key 18 E
21. key 19 R
22. key 20 T
23. key 115 VOLUME_UP
24. key 114 VOLUME_DOWN
在按键布局文件中,第1列为按键的扫描码,是一个整数值;第2列为按键的标签,是一个字符串。即完成了按键信息的第1次转化,将整型的扫描码,转换成字符串类型的按键标签。第3列表示按键的Flag,带有WAKE字符,表示这个按键可以唤醒系统。
扫描码来自驱动程序,显然不同的扫描码可以对应一个按键标签。表示物理上的两个按键可以对应同一个功能按键。
例如,上面的扫描码为158的时候,对应的标签为 BACK ,再经过第二次转换,根据KeycodeLabels.h的KEYCODES数组,其对应的按键码为4。
提示:按键布局文件其实同时兼顾了input驱动程序的定义和Android中按键的定义。例如:input驱动程序中定义的数字扫描码KEY_1的数值为2,这里2对应的按键标签也为“1”;input驱动程序中定义字母扫描码KEY_Q的数值为16,这里对应的按键标签也为“Q”。然而移动电话的全键盘毕竟有所不同,因此有一些按键是和input驱动程序的定义没有对应关系的。
kl文件将以原始的文本文件的形式,放置于目标文件系统的/system/usr/keylayout/目录或者/system/usr/keychars/目录中。
3.kcm:按键字符映射文件
kcm表示按键字符的映射关系,主要功能是将整数类型按键码(keycode)转化成可以显示的字符。
qwerty.kcm表示全键盘的字符映射关系,其片断如下所示:
1. [type=QWERTY]
2. # keycode display number base caps fn caps_fn
3.
4. A 'A' '2' 'a' 'A' '#' 0x00
5.
6. B 'B' '2' 'b' 'B' '<' 0x00
7.
8. C 'C' '2' 'c' 'C' '9' 0x00E7
9.
10. D 'D' '3' 'd' 'D' '5' 0x00
11.
12. E 'E' '3' 'e' 'E' '2' 0x0301
13.
14. F 'F' '3' 'f' 'F' '6' 0x00A5
15.
16. G 'G' '4' 'g' 'G' '-' '_'
17.
18. H 'H' '4' 'h' 'H' '[' '{'
19.
20. I 'I' '4' 'i' 'I' '$' 0x0302
21.
22. J 'J' '5' 'j' 'J' ']' '}'
23.
24. K 'K' '5' 'k' 'K' '"' '~'
25.
26. L 'L' '5' 'l' 'L' ''' '`'
27.
28. M 'M' '6' 'm' 'M' '!' 0x00
29.
30. N 'N' '6' 'n' 'N' '>' 0x0303
第一列是转换之前的按键码,第二列之后分别表示转换成为的显示内容(display),数字(number)等内容。这些转化的内容和KeyCharacterMap.h中定义的getDisplayLabel(),getNumber()等函数相对应。
这里的类型,除了QWERTY之外,还可以是Q14(单键多字符对应的键盘),NUMERIC(12键的数字键盘)。
kcm文件将被makekcharmap工具转化成二进制的格式
4.EventHub中基本的处理
Lib ui库中frameworks/base/libs/ui中的EventHub.cpp文件是用户输入系统的中枢,主要的功能都是在这个文件中实现的。
EventHub.cpp中定义设备节点所在的路径,内容如下所示:
1. static const char *device_path = "/dev/input"; // 输入设备的目录
在处理过程中,将搜索路径下面的所有Input驱动的设备节点,这在openPlatformInput()中通过调用scan_dir()来实现,scan_dir()将会从目录中查找设备,找到后调用open_device()将其打开。
1. bool EventHub::openPlatformInput(void)
2.
3. {
4.
5. // ...... 省略
6.
7. res = scan_dir(device_path);
8.
9. return true;
10.
11. }
EventHub的getEvent()函数负责处理中完成,处理过程是在一个无限循环之内,调用阻塞的函数等待事件到来。
1. bool EventHub::getEvent(int32_t* outDeviceId, int32_t* outType,
2.
3. int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags,
4.
5. int32_t* outValue, nsecs_t* outWhen)
6.
7. {
8.
9. while(1) {
10.
11. // ...... 省略部分内容
12.
13. pollres = poll(mFDs, mFDCount, -1); // 使用poll处理设备节点,进行阻塞
14.
15. // ...... 省略部分内容
16.
17. for(i = 1; i < mFDCount; i++) {
18.
19. if(mFDs[i].revents) {
20.
21. if(mFDs[i].revents & POLLIN) {
22.
23. res = read(mFDs[i].fd, &iev, sizeof(iev)); // 读取信息
24.
25. // ...... 省略部分内容
26.
27. }
28.
29. }
30.
31. }
32.
33. }
poll()函数将会阻塞程序的运行,此时为等待状态,无开销,直到Input设备的相应事件发生,事件发生后poll()将返回,然后通过read()函数读取Input设备发生的事件代码。
注意,EventHub默认情况可以在/dev/input之中扫描各个设备进行处理,通常情况下所有的输入设备均在这个目录中。
实际上,系统中可能有一些input设备可能不需要被Android整个系统使用,也就是说不需要经过EventHub的处理,在这种情况下可以根据EventHub中open_device()函数的处理,设置驱动程序中的一些标志,屏蔽一些设备。open_device()中处理了键盘,轨迹球和触摸屏等几种设备,对其他设备可以略过。另外一个简单的方法就是将不需要EventHub处理的设备的设备节点不放置在/dev/input之中。
open_device()函数还将打开system/usr/keylayout/中的kl文件来处理,处理的过程如下所示:
1. int EventHub::open_device(const char *deviceName) {
2.
3. // ...... 省略部分内容
4.
5. const char* root = getenv("ANDROID_ROOT");
6.
7. snprintf(keylayoutFilename, sizeof(keylayoutFilename),
8.
9. "%s/usr/keylayout/%s.kl", root, tmpfn);
10.
11. bool defaultKeymap = false;
12.
13. if (access(keylayoutFilename, R_OK)) {
14.
15. snprintf(keylayoutFilename, sizeof(keylayoutFilename),
16.
17. "%s/usr/keylayout/%s", root, "qwerty.kl");
18.
19. defaultKeymap = true;
20.
21. }
22.
23. // ...... 省略部分内容
24.
25. }
由此可见,默认情况下使用的就是qwerty.kl,这里只是扫描各个后缀名为kl的文件,然后交由KeyLayoutMap去解析处理,KeyLayoutMap是一个内部使用的类。
4.按键的增加
Android已经定义了比较丰富、完整的标准按键。在一般情况下,不需要为Android系统增加按键,只需要根据kl配置按键即可。在系统中有比较奇特按键的时候,需要更改Android系统的框架层来更改按键。
增加按键需要更改的文件较多,主要的文件如下所示。
• frameworks/base/include/ui/KeycodeLabels.h:中的KeyCode枚举数值和KeycodeLabel 类型Code数组(以NULL为结尾)
• frameworks/base/core/Java/android/view/KeyEvent.Java:定义整数值,作为平台的API供Java应用程序使用
• frameworks/base/core/res/res/values/attrs.xml:表示属性的资源文件,需要修改其中的name="keycode"的attr。
框架层增加完成后,只需要更改kl文件,增加按键的映射关系即可。
安卓系统遥控器的映射具体过程相关文档相关推荐
- 【ember zigbee】序章:协议栈相关文档学习笔记
原文地址:https://blog.csdn.net/tainjau/article/details/90648114 文章目录 写在前面 一.材料出处 二.文档解析 2.1.EZSP Protoco ...
- 软件是计算机什么及相关文档的总称,1冯-诺依曼原理的基本思想是什么.doc
文档介绍: 2.什么是计算机硬件.计算机软件?各由哪几部分组成?它们之间有何联系? 答:人们通常把构成计算机的物理装置称为计算机的硬件,其主要功能是:存放控制计算机运行的程序和数据,对信息进行加工处理 ...
- 【Windows 逆向】CheatEngine 工具 ( CheatEngine 简介 | 使用 Lazarus 编译 CE 源码 | CheatEngine 相关文档资料 )
文章目录 一.CheatEngine 简介 二.使用 Lazarus 编译 CE 源码 三.CheatEngine 相关文档资料 一.CheatEngine 简介 CheatEngine 简称 CE ...
- pageadmin 修改默认的html,PageAdmin系统为什么没有首页文件(默认文档)
问题: 最近经常有客户问这个问题,首页文件是什么,怎么设置首页文档? 答案: 从4.0后,pageadmin采用了mvc架构重新开发了系统,MVC全名是Model View Controller,是模 ...
- 软件测试质量过程检测文档_如何编写实际上有效的质量检查文档
软件测试质量过程检测文档 A software product is like an airplane: it must undergo a technical check before launch ...
- 【Android 逆向】substrate 框架 ( substrate 简介 | substrate 相关文档资料 )
文章目录 一.substrate 简介 二.substrate 相关文档资料 一.substrate 简介 substrate 官网 : http://www.cydiasubstrate.com s ...
- turbo c相关文档
无意中在网上找到的turbo c 2.0相关文档,有reference guide 和user guide.下载地址见(镜像一 ,镜像二 ,镜像三 ,镜像四 ).这些网站还有很多其他各类软件相关文档, ...
- 织梦dedecms 相关文档标签(likearticle)实现关联整站文档
注意:本教程适用于 DedeCMS V5.7 其他版本楼主未测试 默认情况下,相关文档(likearticle)的关联,在只能调用当前栏目(包括顶级栏目下的下级栏目)的文档,那么我们如何来实现关联网站 ...
- ❤️MVC三层架构及相关文档(建议收藏)❤️
MVC三层架构 什么是MVC:Model .View.Controller:模型.视图.控制器 Model 业务处理:业务逻辑(Servlet) 数据持久层:CRUD(Dao) View 展示数据 提 ...
最新文章
- [物理学与PDEs]第1章第7节 媒质中的 Maxwell 方程组 7.2 媒质交界面上的条件
- Java反射 - 动态类加载和重载
- Programming Computer Vision with Python (学习笔记十一)
- OS / Linux / 主线程退出了,子线程会退出吗?
- QT 4.8.5支持电容触摸屏 和 鼠标
- java 跨站点脚本编制_AppScan跨站点脚本编制修复
- Jq将字符串复制粘贴到剪贴板
- 3个技巧让你正能量满满
- Windows下Zookeeper启动zkServer.cmd闪退问题的解决方案
- GPU驱动“后摩尔定律时代” 为HPC和深度学习提供强大加速动力
- [译] Subject 和 Observable + Observer 的混淆指北[ Android RxJava2 ] ( 这什么鬼系列 ) 第八话...
- 【转】状态压缩动态规划
- JavaScript的NaN-唯一 一个自己不等于自己的对象!!
- 编译原理第三版王生原pdf_CS143:编译原理 | 环境搭建HelloWorld
- sed 、awk用法
- eclipse打包成jar_SpringBoot系列(三)- 用 jar的方式运行springboot项目
- liblinear参数及使用方法(原创)
- 关于Matpower用于攻击检测仿真方法的文献摘录
- 【Excel】下拉填充相同的数据
- 案例分享:Qt西门子PLC调试模拟工具(包含PLC上位机通讯,PLC服务器,读写Byte、Int、DInt、Real)(持续更新,当前v1.6.0)
热门文章
- NoSQL之Redis配置与数据库常用命令
- SLIC——代码、改进
- python简单程序
- python中文居中对齐处理
- Angular入门到精通系列教程(1) - Angular,Vue,React 选型
- python入门代码示例
- 虚拟机(一)虚拟机安装Mysql
- 安装mysql 配置环境变量
- 单代号网络图计算例题_还在熬夜计算工期?不会优化工期?学会双代号网络图效率提高80%,升职加薪其实不难...
- 穿越存在吗?诺奖得主基普·S·索恩:人类穿梭时间可能摧毁自己