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. typedefenumKeyCode {
2. kKeyCodeUnknown = 0,
3. kKeyCodeSoftLeft = 1,
4. kKeyCodeSoftRight = 2,
5. kKeyCodeHome = 3,
6. kKeyCodeBack = 4,
7. // ...... 省略中间按键码
8. } KeyCode;
进而在定义了KeycodeLabels.h 中定义了从字符串到整数的映射关系,数组KEYCODES ,定义如下所示:
1. static constKeycodeLabel KEYCODES[] = {
// {字符串,整数}  2. { "SOFT_LEFT", 1 },
3. { "SOFT_RIGHT", 2 },
4. { "HOME", 3 },
5. { "BACK", 4 },
6. { "CALL", 5 },
7. { "ENDCALL", 6 },
8. { "0", 7 },                                // ...... 数字按键
ScanCode(整签Keycodelabels(字符按键码keycode (整数型)
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. staticconstKeycodeLabel 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. classKeyCharacterMap
2. {
3. public:
4. ~KeyCharacterMap();
5. unsigned short get(intkeycode, int meta);
6. unsigned short getNumber(intkeycode);
7. unsigned short getMatch(intkeycode, const unsigned short* chars,
8. intcharsize, uint32_t modifiers);
9. unsigned short getDisplayLabel(intkeycode);
10. boolgetKeyData(intkeycode, unsigned short *displayLabel,
11. unsigned short *number, unsigned short* results);
12. inline unsigned intgetKeyboardType() { return m_type; }
13. boolgetEvents(uint16_t* chars, size_tlen,
14. Vector<int32_t>* keys, Vector<uint32_t>* modifiers);
15. staticKeyCharacterMap* 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可以在应用程序中使用这个类。hod中有各种Linstener,可以之间监听KeyCharacterMap相关的信息。DigitsKeyListenerNumberKeyListenerTextKeyListener。
以上关于按键码和按键字符映射的内容是在代码中实现的内容,还需要配合动态的配置文件来使用。在实现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 fncaps_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.android11系统更新包下载
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中基本的处理
Libui库中frameworks/base/libs/ui中的EventHub.cpp文件是用户输入系统的中枢,主要的功能都是在这个文件中实现的。
EventHub.cpp中定义设备节点所在的路径,内容如下所示:
1. static const char *device_path = "/dev/input"; // 输入设备的目录