参考转载:http://blog.csdn.net/dyfleoo/article/details/41210919

 1、Android 按键流程处理:
ScanCode -> KeyCodeLabel -> KeyCode -> Keyevent
1) 键扫描码ScanCode是由linux的Input驱动框架定义的整数类型,可参考input.h头文件(./external/kernel-headers/uapi/linux/input.h)。
2) 按键码(KeyCode),这个按键码是一个整数,在上层的JAVA程序中主要通过这个值来判断系统的实现。
----
实现过程:
1, ScanCode -> KeyCodeLabel。
键盘布局文件(*.kl) 把ScanCode转换为KeyCodeLabel。 *.kl文件在源码的devices文件夹中如(/device/rockchip/rk30sdk_bnd/rk29-keypad.kl;frameworks/base/data/keyboards)或设备中的/system/usr/keylayout/*.kl。
key 138 HELP //这里的HELP就是我们定义的android键值的字符形式,138则是linux键值,该值可以参考input.h, HELP 不能无缘无故就使用,必然有定义位置,这个位置就是InputEventLabels.h

底层传到的键值在EVENTHUB.CPP文件的getevent事件里面可以接收到,然后在传到KeyLayoutMap.cpp的mapKey函数中进行上层的映射,在5.1的系统中上层的映射按键定义在InputEventLabels.h的头文件中定义,按键传送走的流程跟4.4的差不多。

谈谈KL文件的作用:

android上层已经有按键事件的定义了,底层驱动也有按键事件上报。但是缺少了中间的对接层,也就是说哪个按键对应哪种事件还不清楚。所以,需要为它们加入一个布局文件。按键的布局文件存放在frameworks/base/data/keyboards目录下,以.kl为后缀的文件都是键盘的布局文件。那么编绎后我们可以在out/target/product/system/usr/keylayout文件夹中找到很多如果可缀为kl(布局)的文件,具体读取哪个布局文件是根据驱动的名字来确定的,如果找不到与驱动名字相同的文件,就会读取默认文件Generic.kl。现在我们假设键盘在驱动层的名字为“my_keypad”,所以需要创建一个名为“my_keypad,kl”的布局文件。

在keyboard.cpp中的文件中,有下函数解析到底使用那个名字的KL文件

 status_t KeyMap::load@frameworks/base/libs/androidfw/keyboard.cpp 
    {
        if (deviceConfiguration) {
            String8 keyLayoutName;
            if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"),
                ....
        }
        // Try searching by device identifier.
        if (probeKeyMap(deviceIdenfifier, String8::empty())) {
        return OK;
        }
       // Fall back on the Generic key map.
        // TODO Apply some additional heuristics here to figure out what kind of
        //      generic key map to use (US English, etc.) for typical external keyboards.
        if (probeKeyMap(deviceIdenfifier, String8("Generic"))) {
        return OK;
        }

        // Try the Virtual key map as a last resort.
        if (probeKeyMap(deviceIdenfifier, String8("Virtual"))) {
        return OK;
        }
    }

  查看input devices相关信息可以用如下命令:cat /proc/bus/input/devices 或者 getevent -i

  getevent命令同时也可以用于查看用户层是否接收到相关的键值信息。

     #getevent -i
    add device 2: /dev/input/event7
      bus:      0000
      vendor    0000
      product   0000
      version   0000
      name:     "msm8226-tapan-snd-card Button Jack"
      location: "ALSA"
      id:       ""
      version:  1.0.1
      events:
        KEY (0001): 00e2  0101  0102  0103  0104  0105  0106  0107 
      input props:
       

    读取*.kl的名字组合顺序为 
    a. 首先查看 props中是否有keyboard.layout的参数,如果有则读取该名字的kl文件
    b. 如果 该设备的vendor,product和version都不全为0,则通过它们的组合成 kl的文件名
        Vendor_%04x_Product_%04x_Version_%04x.kl
        Vendor_%04x_Product_%04x.kl
        最终形成文件路径system/usr/keylayout/Vendor_xxxx_Product_xxxx.kl或system/usr/keylayout/Vendor_xxxx_Product_xxxx_Version_xxxx.kl
    c. 如果vendor,product,version都为0,则通过该设备的name: "msm8226-tapan-snd-card Button Jack"来组合kl文件名
        appendInputDeviceConfigurationFileRelativePath中会把其中的空格转换成'_'
        最终形成文件路径system/usr/keylayout/msm8226-tapan-snd-card_Button_Jack.kl

3,KeyCode -> Keyevent。
KeyEvent.java中的对应KeyCode:(文件路径:/frameworks/base/core/java/android/view/KeyEvent.java)。
KeyEvent.java中有一个非常重要的提示,那就是我们自己填特殊按键的流程,但是我这是瑞芯微3168,Android4.2.2的源代码,源码中的注释路径是有误的!:



如果改动了KeyEvent,影响到API则需要调用make update-api,或者可以添加@hide
LAST_KEYCODE修改:
/** Key code constant: add by hcm, help key. */
public static final int KEYCODE_HELP = 220; 
private static final int LAST_KEYCODE = KEYCODE_HELP;
....
(KEYCODE_SYMBOLIC_NAMES修改,android 6.0上无此处修改
names.append(KEYCODE_ASSIST, "KEYCODE_ASSIST");
names.append(KEYCODE_HELP, "KEYCODE_HELP");
....
4、根据上面提示修改isSystem(),代码跟踪:
isSystem() 在/frameworks/base/core/java/android/view/KeyEvent.java
public final boolean isSystem() {
return native_isSystemKey(mKeyCode);
}

/frameworks/base/core/jni/android_view_KeyEvent.cpp
static jboolean native_isSystemKey(JNIEnv* env, jobject clazz, jint keyCode) {
return KeyEvent::isSystemKey(keyCode);
}

/frameworks/base/libs/androidfw/Input.cpp
bool KeyEvent::isSystemKey(int32_t keyCode) {
switch (keyCode) {
……
case AKEYCODE_SEARCH:
//add by hcm
case AKEYCODE_HELP:
}
}
5、/external/webkit/Source/WebKit/android/plugins/ANPKeyCodes.h
enum ANPKeyCodes {
……

kAppSwitch_ANPKeyCode = 187,
//add by hcm
kHelp_ANPKeyCode = 220,
};
6、frameworks/base/core/res/res/values/attrs.xml

.....................






总结:
这些操作完成了之后,就完成了linux键到android的键值映射。也就是android中多了一个KEYCODE_HELP它的值是220

keycode是Android定义好的,但是有时候无法满足需要,进行定制化难免会涉及到新增加keycode。分成两部分,驱动和framework,这里主要讲解framework部分:

一、驱动部分:

1.    在下列文件中定义

如KEY_SMS

#defineKEY_SMS 252

可能涉及的文件(可能还需要在别的文件):

kernel\include\linux\input.h

bionic\libc\kernel\common\linux\input.h

external\kernel-headers\original\linux\input.h

external\qemu\linux_keycodes.h

2.增加keypad layout文件键盘映射,linuxandroidkey映射

如:key   252   SMS 

注意所用版本和项目使用的KL文件,在adb shell中进入system/usr/keylyout/可以看到所用的KL,可以修改确认使用的KL 

一般定义在kpd.c 的新按键会使用***-kpd.kl,也就是注册input设备为***-kpd的会使用***-kpd.kl

新增加设备名称的时候一般会使用generic.kl和qwerty.kl

generic.kl 和qwerty.kl 在alps/frameworks/base/data/keyboards/

***-kpd.kl在config//

其中252 是linux键码,SMS是android识别key值 如果是需要唤醒系统,还需要增加WAKE

二、framework部分

1.修改Java识别keycode

framework/native/include/input/KeyCodelabels.h

KEYCODES数据结构后面增加

{"SMS",220}

 

 framework/native/include/android/KeyCodes.h

在按键定义项增加AKEYCODE_SMS  = 220;

 2.修改Java 键盘事件

framework/base/core/java/android/view/keyevent.java

/**

*@hide

*/

public static final int KEYCODE_SMS =220;

 最后的按键为新增的

private static final int LAST_KEYCODE==KEYCODE_SMS;

 以上/**/注释的code是android 非开放API或变量定义的时候,需要添加Java Doc的识别,否则要运行make update-api才能build通过

在KEYCODE_SYMBOLIC_NAMES 中增加name.append(KEYCODE_SMS, "KEYCODE_SMS");

 如果是系统按键,修改framework/base/libs/ui/input.cpp

isSystemKey()增加case AKEYCODE_SMS:

 3.修改XML文件描述符framework/base/core/res/res/values/attr.xml

 4.增加测试验证log在android

framework\base\policy\src\com\android\internal\polidy\impl\phoneWindowManager.java

在interceptKeyBeforeDispatching()增加

if(keycode== KeyEvent.KEYCODE_SMS){

       log.d(TAG, "interceptKeyTi KEYCODE_SMS keyCode="+ keyCode + " down=" + down + "repeatCount=" + repeatCount + “ keyguardOn=” + keyguardOn + “mHomePressed=” + mHomePressed + “ cancled=” + canceled)

p.s.并不是所有的linux keycode framework都会支持处理,如果您需要增加很多按键,就可能超出256(如Touch Panel的手势识别会用到很到键)

inputreader.cpp的KeyboardInputMapper这个class的process函数会先判断是否是isKeyboardOrGamepadKey. 这里面会对按键的大小进行判断,条件是: 1.小于272 2.大于352 3.大于等于256且小于272 4.大于等于288且小于320 满足其一即可。 否则会拦截掉,不会往inputDispatcher和phonewindowmanager.java走

按照以上步骤修改代码,即可在android系统中增加一个新的keycode。

转载参考链接:http://www.2cto.com/kf/201405/298944.html

更多相关文章

  1. Android(安卓)jni调用第三方so库和.h文件
  2. Android2.2添加Ethernet 框架支持(二)
  3. Android文件访问权限问题
  4. ant 一键打包
  5. android Immutable bitmap passed to Canvas constructor异常
  6. Android(安卓)studio 下的svn配置使用
  7. 基于Android(安卓)Studio 的NDK之 “Hello,World!”
  8. [Android] 文件夹下文件的个数限制
  9. NPM 和webpack 的基础使用

随机推荐

  1. android 实现类似Iphone底部消息数量提示
  2. android JNI cocos2dx调用对话框
  3. Android 修改项目名称
  4. android AnimationDrawable类实现动画效
  5. 通话距离感应实现源码
  6. Andriod自动化测试
  7. Android ScrollView 中 TextView 多行显
  8. 深入理解LayoutInflater
  9. Android(安卓)权限列表permission说明
  10. 怎么查看android 版本