首页 / 操作系统 / Linux / Android平台开发-Android keypad map-Android按键识别及映射过程
一、Android底层按键事件处理过程 在系统启动后,在文件。。。中,android 会通过 static const char *device_path = "/dev/input"; bool EventHub::penPlatformInput(void) res = scan_dir(device_path); 通过下面的函数打开设备。 int EventHub::pen_device(const char *deviceName) { ... fd = open(deviceName, O_RDWR); ... mFDs[mFDCount].fd = fd; mFDs[mFDCount].events = POLLIN; ... ioctl(mFDs[mFDCount].fd, EVIOCGNAME(sizeof(devname)-1), devname); ... const char* root = getenv("ANDROID_ROOT"); snprintf(keylayoutFilename, sizeof(keylayoutFilename), "%s/usr/keylayout/%s.kl", root, tmpfn); ... device->layoutMap->load(keylayoutFilename); ... } 打开设备的时候,如果 device->classes&CLASS_KEYBOARD 不等于 0 表明是键盘。 常用输入设备的定义有: enum { CLASS_KEYBOARD = 0x00000001, //键盘 CLASS_ALPHAKEY = 0x00000002, // CLASS_TOUCHSCREEN = 0x00000004, //触摸屏 CLASS_TRACKBALL = 0x00000008 //轨迹球 }; 打开键盘设备的时候通过上面的 ioctl 获得设备名称,命令字 EVIOCGNAME 的定义在文件: kernel/include/linux/input.h 中。 对于按键事件,调用mDevices->layoutMap->map进行映射,调用的是文件 KeyLayoutMap.cpp (frameworksaselibsui)中的函数: status_t KeyLayoutMap::load(const char* filename)通过解析 <Driver name>.kl 把按键的 映射关系保存在 :KeyedVector<int32_t,Key> m_keys; 中。 当获得按键事件以后调用: status_t KeyLayoutMap::map(int32_t scancode, int32_t *keycode, uint32_t *flags) 由映射关系 KeyedVector<int32_t,Key> m_keys 把扫描码转换成andorid上层可以识别的按键。二、按键映射 Key layout maps的路径是 /system/usr/keylayout,第一个查找的名字是按键驱动的名字,例如 mxckpd.kl。如果没有的话,默认为qwerty.kl。 Key character maps的路径是 /system/usr/keychars,第一个查找的名字是按键驱动的名字,例如 mxckpd.kcm。如果没有的话,默认为qwerty.kl。 qwerty.kl是 UTF-8类型的,格式为:key SCANCODE KEYCODE [FLAGS...]。 SCANCODE表示按键扫描码; KEYCODE表示键值,例如HOME,BACK,1,2,3... FLAGS有如下定义: SHIFT: While pressed, the shift key modifier is set ALT: While pressed, the alt key modifier is set CAPS: While pressed, the caps lock key modifier is set WAKE: When this key is pressed while the device is asleep, the device will wake up and the key event gets sent to the app. WAKE_DROPPED: When this key is pressed while the device is asleep, the device will wake up and the key event does not get sent to the app qwerty.kcm文件为了节省空间,在编译过程中会用工具makekcharmap转化为二进制文件qwerty.bin。三、按键分发 1、输入事件分发线程 在frameworks/base/services/java/com/android/server/WindowManagerService.java里创 建了一个输入事件分发线程,它负责把事件分发到相应的窗口上去。 在WindowManagerService类的构造函数WindowManagerService()中: mQueue = new KeyQ(); //读取按键 mInputThread = new InputDispatcherThread(); //创建分发线程 ... mInputThread.start(); 在启动的线程InputDispatcherThread中: run() process(); QueuedEvent ev = mQueue.getEvent(...) 在process() 方法中进行处理事件: switch (ev.classType) case RawInputEvent.CLASS_KEYBOARD: ... dispatchKey((KeyEvent)ev.event, 0, 0); mQueue.recycleEvent(ev); break; case RawInputEvent.CLASS_TOUCHSCREEN: //Log.i(TAG, "Read next event " + ev); dispatchPointer(ev, (MotionEvent)ev.event, 0, 0); break; case RawInputEvent.CLASS_TRACKBALL: dispatchTrackball(ev, (MotionEvent)ev.event, 0, 0); break; 2、上层读取按键的流程 WindowManagerService() //(frameworksaseservicesjavacomandroidserver WindowManagerService.java) | KeyQ() //KeyQ 是抽象类 KeyInputQueue 的实现 | InputDeviceReader //在 KeyInputQueue 类中创建的线程 | readEvent() // | android_server_KeyInputQueue_readEvent() //frameworksaseservicesjni com_android_server_KeyInputQueue.cpp | hub->getEvent() | EventHub::getEvent() //frameworksaselibsuiEventHub.cpp | res = read(mFDs.fd, &iev, sizeof(iev)); // Android的应用不仅仅是平板电脑,MID,phone,还可以放到STB机顶盒,智能家庭终端上面去,所以按键的映射是一定要自定义的,不管按键是固定在设备上,还是通过无线设备还是蓝牙遥控,都需要键的映射。 Android也是基于Linux的核心,大部分时候都是操作系统在调度任务,执行任务。相应的,Android输入系统也是遵循LINUX的input输入输出子系统,关于这部分的分析可以Google,有许多原理方面的分析。Android使用标准的Linux输入事件设备(/dev/event0),驱动描述可以查看内核树头文件include/linux/input.h。如果想深入学习Linux input subsystem,可以访问:http://git.kernel.org/?p=linux/kernel/git/stable/linux-2.6.24.y.git;a=blob;f=Documentation/input/input.txt注:event0是您的keypad/gpio-key注册到内核的节点号,如果有其他的输入设备注册进内核,也可以是event1。
收藏该网址