按键从Linux到Android -USB篇<4>

android下的按键布局和映射
这个笔记整理一下使用usb键盘遇到的问题,比如添加usb键盘的keylayout,添加按键,修改按键映射等。
本文参考了: http://blog.csdn.net/kieven2008/archive/2011/03/26/6279975.aspx http://blog.csdn.net/skdev/archive/2010/03/08/5355542.aspx
Android的用户输入系统,自下而上,分成如下部分:
1.驱动程序:/dev/input目录。负责report键值到上层。其中键值定义在input.h中; 2.根文件系统中,KeyLayout(按键布局)和KeyCharacterMap(按键字符映射):后缀名称分别为kl和kcm;如果使用usb全键盘,则使用/system/usr/keylayout/qwerty.kl. 3.EventHub: libui的一部分,实现了对驱动程序的控制。目录 android/frameworks/base/libs/ui/,读取RawEvent事件。 4.Java框架层的处理:有KeyInputDevice等类来处理EventHub传递上来的信息,这些信息通过RawInputEvent和KeyEvent来表示。 一般情况下,对于按键事件,以后者的形式传送给应用程序,而触摸屏和轨迹球事件以前者的形式转换形成MotionEvent事件传送给应用程序; 5.Android应用程序层:通过重载onKeyDown()和onkeyUp()等方法接收KeyEvent(按键事件),通过重载onTouchEvent()和onTrackballEvent()等方法接收MotionEvent(运动事件);
keyEvent的处理流程: 1、生成 存在这样一个线程,它不断地从driver读取Event,并把它放到RawEvent队列中。这个队列中的RawEvent既有按键,也有触摸、轨迹球等事件。 RawEvent队列中的每个RawEvent最后都会通过一系列转化,最终变为KeyEvent被发送给另外一个线程,即输入线程,也就是一个Activity的主线程。 2、传递 KeyEvent传递过程主要可以划分为三步:过滤器、View树、Activity 过滤器部分 主要对应着PhoneWindowManager.java中的interceptKeyTq和interceptKeyTi这两个方法。 它们的代码可以在frameworks/base/policy/base/phone/com/android/internal/policy/impl/PhoneWindowManager.java中看到。 这两个过滤器最大的不同就是interceptKeyTq用于RawEvent,而interceptKeyTi用于KeyEvent。
在一个没有实体键盘的机器上,Power键会被interceptKeyTq这个过滤器吃掉用来调用关机对话框或者使机器休眠。而Home键会被interceptKeyTi这个过滤器吃掉,用来把当前Activity切换到后台并把桌面程序切换到前台。所以,应用程序在View和Activity的onKeyDown/Up中是监听不到这两个按键的。除了这两个键以外的按键,都有机会继续前进。接下来,KeyEvent会先经过interceptKeyTi过滤器。 如果这个过滤器不吃掉的话,就会继续前进,进入View树。如果没有被哪个View吃掉的话,最后进入到Activity的onKeyDown/Up方法中。 当一个KeyEvent经过上面的过程还没有被吃掉的话,系统就会利用它做一些定制的功能。比如音量键被系统用来调整声音,多媒体按键用来控制媒体播放,搜索键用来快速打开搜索功能,返回键用来退出当前Activity等。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
如果你的键盘是全键盘(包括了ALT、SHIFT、CAPS_LOCK功能键),基本上用Android默认的键盘映射文件qwerty.kcm,qwerty.kl就可以了。 如果你需要添加新的按键,或者需要修改按键的映射,就需要修改这两个文件了。
添加新的键盘 比如支持usb键盘,需要导入keylayout.  file: frameworks/base/libs/ui/EventHub.cpp
int EventHub::open_device(const char *deviceName) { //.................          // find the .kl file we need for this device         const char* root = getenv("ANDROID_ROOT");         snprintf(keylayoutFilename, sizeof(keylayoutFilename),                  "%s/usr/keylayout/%s.kl", root, tmpfn);         bool defaultKeymap = false;         if (access(keylayoutFilename, R_OK)) {             snprintf(keylayoutFilename, sizeof(keylayoutFilename),                      "%s/usr/keylayout/%s", root, "qwerty.kl");             defaultKeymap = true;         }         device->layoutMap->load(keylayoutFilename); }
*********问题:这里在导入keylayout文件的时候,是指定路径,通过后缀获取的,所以kl文件名字不重要???
比如使用usb键盘,添加一个按键,物理按键是F1,对应android上的功能是SEARCH: 1 按下物理按键后,驱动通过接口input_report_key向上层input子系统report一个按键SCANCODE:#define KEY_F159 (定义在内核input.h中) 2 查找static const KeycodeLabel KEYCODES[](在文件frameworks/base/include/ui/KeycodeLabels.h中),得知我们需要的功能键的KEYCODE是“SEARCH” 3 在文件/system/usr/keylayout/qwerty.kl中添加下面一行, key 59    SEARCH  重新启动即可:

总结:android按键消息通过二次转换: 1 将驱动report上来的SCANCODE,通过文件qwerty.kl的映射,得到KEYCODE字串; 2 通过二维表static const KeycodeLabel KEYCODES[],将上面的字符串转换成android 需要的键值信息。 如果是输入键,还需要查询keymap,得到相应的字符。
相关文件: key scancode定义: 文件:include/linux/input.h ......   #define KEY_SPACE    57   #define KEY_CAPSLOCK     58   #define KEY_F1   59   #define KEY_F2   60   #define KEY_F3   61   #define KEY_F4   62   #define KEY_F5   63   #define KEY_F6   64   #define KEY_F7   65   #define KEY_F8   66   #define KEY_F9   67   #define KEY_F10  68   ........     KEYLAYOUT 按键布局 文件:/system/usr/keylayout/qwerty.kl 文件格式: key SCANCODE KEYCODE [FLAGS...] 第一列:key 第二列: SCANCODE是一个整数,是驱动里面定义的,在文件 第三列: KEYCODE 是一个字串,定义在你描述的布局文件frameworks/base/include/ui/KeycodeLabels.h
另外可以设置相关的FLAGS: SHIFT: 当按下,自动加上SHIFT键值 ALT:当按下,自动加上ALT CAPS:当按下,自动带上CAPS大写 WAKE:当按下,当设备进入睡眠的时候,按下这个键将唤醒,而且发送消息给应用层。 WAKE_DROPPED:当按下,且设备正处于睡眠,设备被唤醒,但是不发送消息给应用层。
关于SCANCODE,也无需查找驱动代码。在字符界面下可以使用命令getevent获取按键的scan code: # getevent   / $ getevent   add device 1: /dev/input/event4     name:     "Fake Touchscreen"   add device 2: /dev/input/event0     name:     "gpio-keys"   add device 3: /dev/input/event3     name:     "Dell Dell USB Keyboard"   add device 4: /dev/input/event2     name:     "PixArt USB Optical Mouse"   add device 5: /dev/input/event1     name:     "twl4030_pwrbutton"   支持5种输入设备:触摸屏  GPIOkey usb键盘  usb鼠标  powerkey
点击usb键盘的按键“A”的打印信息:  

/dev/input/event3: 0004 0004 00070004   /dev/input/event3: 0001 001e 00000001   /dev/input/event3: 0000 0000 00000000   /dev/input/event3: 0004 0004 00070004   /dev/input/event3: 0001 001e 00000000   /dev/input/event3: 0000 0000 00000000   按下一个GPIO按键的打印信息:   /dev/input/event0: 0001 0114 00000001   /dev/input/event0: 0000 0000 00000000   /dev/input/event0: 0001 0114 00000000   /dev/input/event0: 0000 0000 00000000     其中: 0001实际上是输入设备的类型。(USB键盘上的 0004 0004 00070004不太清楚是什么信息,大概是这个USB设备的各种ID信息吧) 0114是按键的SCANCODE, 00000001和00000000分别是按下和抬起的附加信息。
此文件部分内容如下: .....   key 30    A   key 31    S   key 32    D   key 33    F   key 34    G   key 35    H   key 36    J   key 79    1                                key 80    2                                key 81    3                                  key 96    ENTER   key 69    NUM    key 56    ALT_LEFT   key 100   ALT_RIGHT   key 1     POWER   key 58    NUM   key 111   MUTE    key 1     BACK   key 59    SEARCH    .....  
按键码:KEYCODE frameworks/base/include/ui/KeycodeLabels.h

struct KeycodeLabel {       const char *literal;  // KEYCODE     int value;  //用于在keymap索引字符的value };  

static const KeycodeLabel KEYCODES[] = {       { "SOFT_LEFT", 1 },       { "SOFT_RIGHT", 2 },       { "HOME", 3 },       { "BACK", 4 },       { "CALL", 5 },       { "ENDCALL", 6 },       { "0", 7 },       { "1", 8 },       { "2", 9 },       { "3", 10 },       { "4", 11 },       { "A", 29 },       { "B", 30 },       { "C", 31 },       { "SEARCH", 84 },       .............          }  
字符映射 键字符映射位于:/system/usr/keychars/qwerty.kcm.bin,源文件是android/device/ti/omap3evm/qwerty.kcm
首先,需要理解kcm文件的格式: # keycode       display number  base    caps    fn      caps_fn
keycode:由kernel层发出,经*.kl键盘映射文件得到keycode; base:META_KEY没有被激活时的状态,即MetaState==0时映射的字符; caps:毫无疑问,是SHIFT或CAPS_LOCK被激活时的状态,此时MetaState==1时,映射的字符; fn:ALT被激活,对应MetaState==2时映射的字符; caps_fn:ALT,SHIFT或CAPS_LOCK同时被激活时映射的字符;此时MetaState==3;通过这种方式,实现了一键对应多个字符的输出,
How To修改字符映射: 比如现在的字符映射,is_shitf时按下“,”,映射的字符是“;”,见下面这行: COMMA           ','     ','     ','     ';'     ';'     '|' 但在usb全键盘里面,这里应该是字符“<”,所以修改这里即可。
注:META Keys:就是ALT、SHIFT、CAPS_LOCK。
[type=QWERTY]                         # keycode       display number  base    caps    fn      caps_fn                                                          A               'A'     '2'     'a'     'A'     '#'     0x00 B               'B'     '2'     'b'     'B'     '<'     0x00 C               'C'     '2'     'c'     'C'     '9'     0x00E7 D               'D'     '3'     'd'     'D'     '5'     0x00 E               'E'     '3'     'e'     'E'     '2'     0x0301 F               'F'     '3'     'f'     'F'     '6'     0x00A5 G               'G'     '4'     'g'     'G'     '-'     '_' H               'H'     '4'     'h'     'H'     '['     '{' I               'I'     '4'     'i'     'I'     '$'     0x0302 J               'J'     '5'     'j'     'J'     ']'     '}' K               'K'     '5'     'k'     'K'     '"'     '~' L               'L'     '5'     'l'     'L'     '''     '`' M               'M'     '6'     'm'     'M'     '!'     0x00 N               'N'     '6'     'n'     'N'     '>'     0x0303 O               'O'     '6'     'o'     'O'     '('     0x00 P               'P'     '7'     'p'     'P'     ')'     0x00 Q               'Q'     '7'     'q'     'Q'     '*'     0x0300 R               'R'     '7'     'r'     'R'     '3'     0x20AC S               'S'     '7'     's'     'S'     '4'     0x00DF T               'T'     '8'     't'     'T'     '+'     0x00A3 U               'U'     '8'     'u'     'U'     '&'     0x0308 V               'V'     '8'     'v'     'V'     '='     '^' W               'W'     '9'     'w'     'W'     '1'     0x00 X               'X'     '9'     'x'     'X'     '8'     0xEF00 Y               'Y'     '9'     'y'     'Y'     '%'     0x00A1 Z               'Z'     '9'     'z'     'Z'     '7'     0x00                                                          # on pc keyboards COMMA           ','     ','     ','     ';'     ';'     '|' PERIOD          '.'     '.'     '.'     ':'     ':'     0x2026 AT              '@'     '0'     '@'     '0'     '0'     0x2022 SLASH           '/'     '/'     '/'     '?'     '?'     '\'                                                          SPACE           0x20    0x20    0x20    0x20    0xEF01  0xEF01 ENTER         0xa     0xa     0xa     0xa     0xa     0xa                                                          TAB             0x9     0x9     0x9     0x9     0x9     0x9 0               '0'     '0'     '0'     ')'     ')'     ')' 1               '1'     '1'     '1'     '!'     '!'     '!' 2               '2'     '2'     '2'     '@'     '@'     '@' 3               '3'     '3'     '3'     '#'     '#'     '#' 4               '4'     '4'     '4'     '$'     '$'     '$' 5               '5'     '5'     '5'     '%'     '%'     '%' 6               '6'     '6'     '6'     '^'     '^'     '^' 7               '7'     '7'     '7'     '&'     '&'     '&' 8               '8'     '8'     '8'     '*'     '*'     '*' 9               '9'     '9'     '9'     '('     '('     '('                                                          GRAVE           '`'     '`'     '`'     '~'     '`'     '~' MINUS           '-'     '-'     '-'     '_'     '-'     '_' EQUALS          '='     '='     '='     '+'     '='     '+' LEFT_BRACKET    '['     '['     '['     '{'     '['     '{' RIGHT_BRACKET   ']'     ']'     ']'     '}'     ']'     '}' BACKSLASH       '\'     '\'     '\'     '|'     '\'     '|' SEMICOLON       ';'     ';'     ';'     ':'     ';'     ':' APOSTROPHE      '''     '''     '''     '"'     '''     '"' STAR            '*'     '*'     '*'     '*'     '*'     '*' POUND           '#'     '#'     '#'     '#'     '#'     '#' PLUS            '+'     '+'     '+'     '+'     '+'     '+'

 

linker from : http://blog.csdn.net/doom66151/article/details/6575271

该篇文章的中文件需要重新查找,由于系统版本不一样,文件路径不一样,比如说EnevtHub.cpp,可以在eclipse之用ctrl+shift+R组合件查找该文件.

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值