EventHub可以看成是输入消息的集散地,因为android支持多种输入设备,而各种设备的消息类型可能不一样,为了统一管理这些输入消息,Android提出了EventHub的概念,所有的输入事件都会通过EventHub收集,并通过EventHub传递给InputReader,这样对上层来说,就不需要关注底层设备的多样性,减少了上层使用的复杂性。EventHub同时还负责扫描和加载所有的输入设备,InputReader在第一次读取数据的时候会扫描所有的输入设备,并保存每个设备的配置信息。
在EventHub::getEvents中,当mNeedToScanDevices为true时(当创建EventHub对象时,它就为true),即当InputReader第一次调用getEvents的时候需要打开设备,它将从/dev/input目录下查找所有设备,并进行打开,获取其相关属性,最后加入mDevices列表中。
在openDeviceLocked()方法中,首先调用open()打开设备, ioctl()获取设备名字,识别打开设备是哪个classs的,即按键、单点触摸屏、多点触摸屏等等。如果设备是认为是合法的,创建了设备,然后向epoll注册该设备,并添加到mDevices列表中:
// Register withepoll. struct epoll_event eventItem; memset(&eventItem, 0,sizeof(eventItem)); eventItem.events = EPOLLIN; eventItem.data.u32 = deviceId; if (epoll_ctl(mEpollFd,EPOLL_CTL_ADD, fd, &eventItem)) { ALOGE("Could not add device fd to epoll instance. errno=%d", errno); delete device; return -1; } addDeviceLocked(device); |
要说EventHub::getEvents如何获取输入事件,不得不先说说它的几个相关的成员变量:
n mPendingEventCount:调用epoll_wait时的返回值,当然如果没有事件,则其值为0;
n mPendingEventIndex:当前需要处理的事件索引
n mEpollFd:epoll实例,在EventHub::EventHub中调用epoll_create(EPOLL_SIZE_HINT)初始化此例,所有输入事件通过epoll_wait来获取,每一个事件的数据结构为:struct epoll_event。注:epoll_event只表明某个设备上有事件,并不包含事件内容,具体事件内容需要通过read来读取。
看看epoll_event结构体:
typedef unionepoll_data { void*ptr; intfd; unsigned int u32; unsigned long long u64; } epoll_data_t; structepoll_event { unsigned int events; epoll_data_t data; };
|
每个设备被创建(在函数EventHub::openDeviceLocked中)时,都会向epoll注册,代码如下:
struct epoll_event eventItem; memset(&eventItem, 0,sizeof(eventItem)); eventItem.events = EPOLLIN; eventItem.data.u32 = deviceId; if (epoll_ctl(mEpollFd,EPOLL_CTL_ADD, fd, &eventItem)) { …… } |
查看设备上是否有输入事件:
int pollResult =epoll_wait(mEpollFd,mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis); if (pollResult < 0) { …… } else { // Some events occurred. mPendingEventCount = size_t(pollResult); } |
在调用epoll_wait()之后,读到的epoll_event输入事件保存在mPendingEventItems,总共的事件数保存在mPendingEventCount,当然,在调用epoll_wait()之前,mPendingEventIndex被清0。
size_tEventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_tbufferSize) { struct input_event readBuffer[bufferSize]; RawEvent* event = buffer; size_t capacity = bufferSize; boolawoken = false; for(;;) { …… while (mPendingEventIndex < mPendingEventCount){ const struct epoll_event& eventItem =mPendingEventItems[mPendingEventIndex++]; …… ssize_t deviceIndex =mDevices.indexOfKey(eventItem.data.u32); Device* device = mDevices.valueAt(deviceIndex); if (eventItem.events & EPOLLIN) { int32_t readSize =read(device->fd, readBuffer, sizeof(struct input_event) * capacity); ……. } …… mPendingEventIndex = 0; int pollResult =epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS,timeoutMillis);
if (pollResult < 0) { …… } else { // Some events occurred. mPendingEventCount= size_t(pollResult); } } return event - buffer; } |
在上面的代码中可以看到,如果没有输入事件,那么代码将在epoll_wait()阻塞,当有输入事件的时候读到数据,mPendingEventItems保存了输入事件,mPendingEventCount保存了事件的数量,而且mPendingEventIndex=0,所以此时满足了条件:mPendingEventIndex
首先,需要看看相关的数据结构:
经过1.2小节介绍,我们知道,epoll_event结构体是用来存储输入事件的,调用epoll_wait()读取输入事件,一般情况下mPendingEventCount=1,当有输入事件的时候,通过read()方法读取输入数据。
size_tEventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_tbufferSize) {
struct input_eventreadBuffer[bufferSize]; RawEvent* event =buffer; size_t capacity = bufferSize; while (mPendingEventIndex ALOGE(“mPendingEventCount=%d”, mPendingEventCount); int32_t readSize = read(device->fd,readBuffer, sizeof(struct input_event) * capacity); ize_t count = size_t(readSize) /sizeof(struct input_event); for (size_t i = 0; i < count; i++) { ALOGE("%s got: t0=%d, t1=%d, type=%d, code=%d,value=%d", device->path.string(), (int) iev.time.tv_sec, (int) iev.time.tv_usec, iev.type, iev.code, iev.value); const struct input_event& iev =readBuffer[i]; event->when = now; event->deviceId = deviceId; event->type= iev.type; event->code = iev.code; event->value = iev.value; event += 1; } } return event- buffer } |
我们来分下上面的代码,先看看几个重要的变量
n buffer
一个RawEvent结构体的一个数组,数组元素个数为bufferSize,buffer看成这个数组的指针。
n event
一个RawEvent结构体的一个数组,数组元素个数为bufferSize,刚开始被赋值为buffer,
n readBuffer
一个input_event结构体的一个数组,数组元素个数为bufferSize,在read()方法中用于读取一个输入事件的数据。
n count
表示读取了多少组数据。
我们模拟按下一个按键然后松开为例子,在上面代码中加了两个打印。
n 按键按下
按下按键被描述才一次输入的事件,log打印如下:
mPendingEventCount=1 /dev/input/event0 got:t0=658, t1=734424, type=1, code=1, value=1 /dev/input/event0 got:t0=658, t1=734434, type=0, code=0, value=0 |
第一行,mPendingEventCount=1表示一个输入事件,
第二行表示按键按下的消息value=1
第三行表示该消息结束标志
n 按键松开
按键松开被描述成一个输入事件,log打印如下:
mPendingEventCount=1 /dev/input/event0 got:t0=658, t1=765679, type=1, code=1, value=0 /dev/input/event0 got:t0=658, t1=765694, type=0, code=0, value=0 |
第一行,mPendingEventCount=1表示一个输入事件
第二行表示按键松开的消息value=0
第三行表示该消息结束标志
对上面变量的分析之后,思路应该清晰多了。在调用getEvents()的时候,将buffer作为参数传进来,并赋值给event,event用来存储输入事件的数据。将readBuffer指针传入kernel获取输入事件数据,经过for循环,将input_event数据映射到RawEvent上。在return那里返回了描述一个输入事件的RawEvent结构体数组的个数。在上面我们可以看到,描述一个按键的输入事件只需要两个RawEvent,相对简单,但是,触摸事件相对复杂些。
到此,EventHub完成了数据的读取,那么将在InputReader中对RawEvent数据进行处理。
参考博客:http://blog.csdn.net/myarrow/article/details/7091061
http://blog.csdn.net/luoshengyang/article/details/6882903