您的位置:首页 > 移动开发 > Android开发

Android平台开发-Android keypad map-Android按键事件

2013-10-24 17:10 309 查看
一、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

(frameworks\base\libs\ui)中的函数:

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() //(frameworks\base\services\java\com\android\server

\WindowManagerService.java)

|

KeyQ() //KeyQ 是抽象类 KeyInputQueue 的实现

|

InputDeviceReader //在 KeyInputQueue 类中创建的线程

|

readEvent() //

|

android_server_KeyInputQueue_readEvent() //frameworks\base\services\jni\

com_android_server_KeyInputQueue.cpp

|

hub->getEvent()

|

EventHub::getEvent() //frameworks\base\libs\ui\EventHub.cpp

|

res = read(mFDs.fd, &iev, sizeof(iev)); //
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: