Android按键分析

Android按键分析



按键的驱动可以在linux内核的平台文件中找到(arch/arm/mach-xxx)下的button-xxx.c 或 mach-xxx.c


这里主要讲android事件的处理过程,需要经过两个转换步骤: 


按键码KeyCode -- (整型数)[按键码转换] <<-- 按键标签KeycodeLabel(字符串) -- [按键布局转换(kl配置文件)] <<-- 按键扫描码ScanCode(整型) -- [Event设备/dev/input/X] 


1、键扫描码ScanCode是由linux的Input驱动框架定义的整数类型,可参考input.h头文件


在步骤一中将其值转换成表示按键的字符串


键盘布局文件(*.kl)将完成第一步的转换,放在/system/usr/keylayout/下面


举例如下:


input.h 中字母键定义:


#define KEY_Q 16 


#define KEY_W 17 #define KEY_E 18 


#define KEY_R 19 #define KEY_T 20 


#define KEY_Y 21 #define KEY_U 22 


#define KEY_I 23 #define KEY_O 24 


#define KEY_P 25 


而qwert.kl中定义如下:


ScanCode + 字符串值 


key 16 Q 


key 17 W 


key 18 E 


key 19 R 


key 20 T 


key 21 Y 


key 22 U 


key 23 I 


key 24 O 


key 25 P 


2、通过查找KEYCODES数组,将literal字符串转换成value的整型值,即转换到KeyCode值了


片段如下,右边的值是android系统中使用的KeyCode值:(文件路径:frameworks/base/include/ui/KeycodeLabels.h)


static const KeycodeLabel KEYCODES[] = {


...


{ "A", 29 },


{ "B", 30 },


{ "C", 31 }, 


{ "D", 32 }, 


{ "E", 33 }, 


{ "F", 34 },


{ "G", 35 }, 


{ "H", 36 }, 


{ "I", 37 }, 


{ "J", 38 }, 


{ "K", 39 }, 


{ "L", 40 },


{ "M", 41 }, 


{ "N", 42 }, 


{ "O", 43 }, 


{ "P", 44 }, 


{ "Q", 45 }, 


{ "R", 46 }, 


{ "S", 47 }, 


{ "T", 48 }, 


{ "U", 49 }, 


{ "V", 50 }, 


{ "W", 51 }, 


{ "X", 52 }, 


{ "Y", 53 }, 


{ "Z", 54 },


...


};


右边的值在android中定义如下:(文件路径:frameworks/base/include/android/keycodes.h)


/* * Key codes. */ enum {


AKEYCODE_A = 29, 


AKEYCODE_B = 30, 


AKEYCODE_C = 31, 


AKEYCODE_D = 32, 


AKEYCODE_E = 33, 


AKEYCODE_F = 34, 


AKEYCODE_G = 35, 


AKEYCODE_H = 36, 


AKEYCODE_I = 37, 


AKEYCODE_J = 38, 


AKEYCODE_K = 39, 


AKEYCODE_L = 40, 


AKEYCODE_M = 41, 


AKEYCODE_N = 42, 


AKEYCODE_O = 43, 


AKEYCODE_P = 44, 


AKEYCODE_Q = 45, 


AKEYCODE_R = 46, 


AKEYCODE_S = 47, 


AKEYCODE_T = 48, 


AKEYCODE_U = 49, 


AKEYCODE_V = 50, 


AKEYCODE_W = 51, 


AKEYCODE_X = 52, 


AKEYCODE_Y = 53, 


AKEYCODE_Z = 54,


..


};


这里的键值与KeyEvent.java中的值是对应的:(文件路径:frameworks/base/core/java/Android/view/KeyEvent.java)


/** Key code constant: 'A' key. */ 


public static final int KEYCODE_A = 29;


/** Key code constant: 'B' key. */ 


public static final int KEYCODE_B = 30; 


/** Key code constant: 'C' key. */ 


public static final int KEYCODE_C = 31;


/** Key code constant: 'D' key. */ 


public static final int KEYCODE_D = 32; 


/** Key code constant: 'E' key. */ 


public static final int KEYCODE_E = 33; 


/** Key code constant: 'F' key. */ 


public static final int KEYCODE_F = 34;


/** Key code constant: 'G' key. */ 


public static final int KEYCODE_G = 35; 


/** Key code constant: 'H' key. */ 


public static final int KEYCODE_H = 36;


/** Key code constant: 'I' key. */ 


public static final int KEYCODE_I = 37; 


/** Key code constant: 'J' key. */ 


public static final int KEYCODE_J = 38; 


/** Key code constant: 'K' key. */ 


public static final int KEYCODE_K = 39; 


/** Key code constant: 'L' key. */ 


public static final int KEYCODE_L = 40; 


/** Key code constant: 'M' key. */ 


public static final int KEYCODE_M = 41; 


/** Key code constant: 'N' key. */ 


public static final int KEYCODE_N = 42; 


/** Key code constant: 'O' key. */ 


public static final int KEYCODE_O = 43; 


/** Key code constant: 'P' key. */ 


public static final int KEYCODE_P = 44; 


/** Key code constant: 'Q' key. */ 


public static final int KEYCODE_Q = 45; 


/** Key code constant: 'R' key. */ 


public static final int KEYCODE_R = 46; 


/** Key code constant: 'S' key. */ 


public static final int KEYCODE_S = 47; 


/** Key code constant: 'T' key. */ 


public static final int KEYCODE_T = 48; 


/** Key code constant: 'U' key. */ 


public static final int KEYCODE_U = 49; 


/** Key code constant: 'V' key. */ 


public static final int KEYCODE_V = 50;


/** Key code constant: 'W' key. */ 


public static final int KEYCODE_W = 51; 


/** Key code constant: 'X' key. */ 


public static final int KEYCODE_X = 52; 


/** Key code constant: 'Y' key. */ 


public static final int KEYCODE_Y = 53; 


/** Key code constant: 'Z' key. */ 


public static final int KEYCODE_Z = 54;


...


ok,理清楚了以上的转换关系,下面就说一下如何增加按键,以增加gamekey为例:


1 、键盘布局文件中增加键,一般是qwery.kl (一定是以*.kl结尾的文件):


key 304 BUTTON_A


key 305 BUTTON_B


key 306 BUTTON_C


key 307 BUTTON_X


key 308 BUTTON_Y


key 309 BUTTON_Z


key 315 BUTTON_START


key 316 BUTTON_MODE


2、在frameworks/base/include/ui/KeycodeLabels.h中增加KeycodeLabel类型的Code数组


{ "BUTTON_A", 96 }, 


{ "BUTTON_B", 97 }, 


{ "BUTTON_C", 98 }, 


{ "BUTTON_X", 99 }, 


{ "BUTTON_Y", 100 }, 


{ "BUTTON_Z", 101 },


{ "BUTTON_START", 108 },


{ "BUTTON_MODE", 110 }, 


目前的2.3系统已经添加


3、在frameworks/base/include/android/keycodes.h中增加KeyCode的枚举值


AKEYCODE_BUTTON_A = 96, 


AKEYCODE_BUTTON_B = 97, 


AKEYCODE_BUTTON_C = 98, 


AKEYCODE_BUTTON_X = 99, 


AKEYCODE_BUTTON_Y = 100, 


AKEYCODE_BUTTON_Z = 101,


AKEYCODE_BUTTON_START = 108, 


AKEYCODE_BUTTON_MODE = 110, 


目前的2.3系统已经添加


4、JAVA层的keyEvent.java中增加用于java应用程序使用


略,目前的2.3系统已经添加


5、在frameworks\base\core\res\res\values\attrs.xml中增加表示属性的资源文件,添加相应用name="keycode"的attr


<enum name="KEYCODE_BUTTON_A" value="96" />


<enum name="KEYCODE_BUTTON_B" value="97" />


<enum name="KEYCODE_BUTTON_C" value="98" />


<enum name="KEYCODE_BUTTON_X" value="99" /> 


<enum name="KEYCODE_BUTTON_Y" value="100" />


<enum name="KEYCODE_BUTTON_Z" value="101" />


<enum name="KEYCODE_BUTTON_START" value="108" />


<enum name="KEYCODE_BUTTON_MODE" value="110" />


ok,完成以上步骤应该就可以使用了。


查找key是否有没有被过滤掉重点确认的地方:


1、EventHub.cpp 文件中的getEvent函数


if (iev.type == EV_KEY) { 


status_t err = device->layoutMap->map(iev.code, & outEvent->keyCode, & outEvent->flags); 


LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n", iev.code, outEvent->keyCode, outEvent->flags, err);


if (err != 0) { outEvent->keyCode = AKEYCODE_UNKNOWN; 


outEvent->flags = 0; }


}


确认这里转换是否ok了,如果没有则可能*.kl文件中没有添加进去这个键值


2、InputReader.cpp文件中的KeyboardInputMapper处理函数process


void KeyboardInputMapper::process(const RawEvent* rawEvent) { 


switch (rawEvent->type) {


case EV_KEY: { 


int32_t scanCode = rawEvent->scanCode; 


if (isKeyboardOrGamepadKey(scanCode)) { p


rocessKey(rawEvent->when, rawEvent->value != 0, rawEvent->keyCode, scanCode, rawEvent->flags); 


} break; } } }


bool KeyboardInputMapper::isKeyboardOrGamepadKey(int32_t scanCode) { 


return scanCode < BTN_MOUSE || scanCode >= KEY_OK || (scanCode >= BTN_GAMEPAD && scanCode < BTN_DIGI); }


可以在processKey中加打印,确认已通过notifyKey上报键值给android系统了。


现在的普通按键也集成到Linux Input子系统中了,


只需要把按键对应的IO端口配置好,按键就可以工作了。 


所以一般提供的BSP(或者叫作解决方案)中,已经完善了按键驱动.


Linux按键的扫描码   扫描码是Linux Input系统中规定的码值,


好比PC键盘上每个键的键值。都是数字。 


在设备上输入一下命令后,按键可以探测到得到每个按键的扫描码Code.


Android 与 Linux分隔线   Android也定义了一套码,叫作键盘码,


通过一个/system/usr/keylayout/来将两套码对应起来。  目前调试的是全志的A10的BSP包。这里用的是sun4i-keyboard.kl。(


如果没有其它*.kl,则是默认的qwerty.kl)      


Linux上传的Code是0x00d9对应10进制217,


打开sun4i-keyboard.kl后可以看到映射关系:key 217 BRIGHTNESS_DOWN   


可以看出对应的是BRIGHTNESS_DOWN,


Android中只认BRIGHTNESS_DOWN(这里成为字串),


Linux中的Code至此为止。 (在Android源码中也能找到这个映射文件可以依名字搜索找到其位置)


Android源码中添加该按键   如果Android中frameworks/base/core/java/android/view/KeyEvent.java有要添加的功能,


比如HOME,则只修改*.kl映射按键即可修改或者添加映射。   


如果KeyEvent.java中本没有要添加按键的功能,


就可以在KeyEvent.java的KeyEvent类最后依葫芦画瓢添加: 


如不知道功能的键盘码是多少可以到这里找到。   


添加后,Android应用程序就可以通过onKeyDown检测到了检测到这个按键了。


至于这个按键具体功能的实现比如这里的BRIGHTNESS_DOWN(亮度减)功能,


要修改frameworks/base/policies/base/phone/com/android/internal/policy/impl/PhoneWindowManager.java。


根据具体需求实现。


首先,简要的介绍一下按键的处理流程。


先简单的分为两大类:一类是虚拟按键。另一类是物理按键。 无论是虚拟按键还是物理按键都是要经过驱动层注册为输入设备,


然后上报到kernel/drivers/input/input.c中。


这里有相关函数的定义。


然后通过、sys上报到frameworks/services/input/EventHub.cpp中,


在这里会对设备进行扫描并且判断是哪种设备,


然后在InputReader.cpp中对原始数据进行读取。


在framewoks/services/input/InputDispatcher.cpp中实现数据的派发。


在framework/base/core/jni/Android_view_KeyEvent.cpp中实现通过JNI机制向上层的KeyEvent.java提供数据。


并且在frameworks/base/core/java/android/view/KeyEvent.java中向上层的APP开发人员提供接口。


  Android按键灯流程分析 调用代码为:


alps\frameworks\base\services\java\com\Android\server\LightsService.java


使用方法: private LightsService.Light mButtonLight;


mButtonLight = mLightsService.getLight(


LightsService.LIGHT_ID_BUTTONS); mButtonLight.setBrightness(screenBrightness); 


mButtonLight.turnOff();


本地代码在: alps\frameworks\base\services\jni\com_android_server_LightsService.cpp


接口关联使用:


static JNINativeMethod method_table[] = { 


{ "init_native", "()I", (void*)init_native }, 


{ "finalize_native", "(I)V", (void*)finalize_native },


{ "setLight_native", "(IIIIIII)V", (void*)setLight_native }, 


};


int register_android_server_LightsService(JNIEnv *env) {


return jniRegisterNativeMethods(env, "com/android/server/LightsService", method_table, NELEM(method_table)); }


register_android_server_LightsService函数在alps\frameworks\base\services\jni\onload.cpp里面注册


本地c代码在: alps\mediatek\hardware\liblights\lights.c里面open_lights里面


static int set_light_buttons(struct light_device_t* dev, struct light_state_t const* state) {


int err = 0; int on = is_lit(state); 


pthread_mutex_lock(&g_lock); 


g_buttons = on; 


err = write_int(BUTTON_FILE, on?255:0); 


pthread_mutex_unlock(&g_lock); 


return err; }


com_android_server_LightsService.cpp里面使用 


devices->lights[light]->set_light(devices->lights[light], &state);


来调用真正的代码 如果有root机子,


可以如下测试: 


echo 0 > /sys/class/leds/button-backlight/brightness 关按键灯 


echo 1 > /sys/class/leds/button-backlight/brightness 开按键灯 


echo 0 > /sys/class/leds/button-backlight/brightness 


执行的意思为:输出0,作为/sys/class/leds/button-backlight/brightness的输入传入。 如此便会打开brightness设备,


并执行write将0带入执行。    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值