1 EventHub获取输入设备数据

EventHub可以看成是输入消息的集散地,因为android支持多种输入设备,而各种设备的消息类型可能不一样,为了统一管理这些输入消息,Android提出了EventHub的概念,所有的输入事件都会通过EventHub收集,并通过EventHub传递给InputReader,这样对上层来说,就不需要关注底层设备的多样性,减少了上层使用的复杂性。EventHub同时还负责扫描和加载所有的输入设备,InputReader在第一次读取数据的时候会扫描所有的输入设备,并保存每个设备的配置信息。

1.1 打开设备

EventHub::getEvents中,当mNeedToScanDevicestrue(当创建EventHub对象时,它就为true),即当InputReader第一次调用getEvents的时候需要打开设备,它将从/dev/input目录下查找所有设备,并进行打开,获取其相关属性,最后加入mDevices列表中。

InputFramework(二)---EventHub" title="AndroidInputFramework(二)---EventHub">

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);

1.2 读取输入事件

要说EventHub::getEvents如何获取输入事件,不得不先说说它的几个相关的成员变量:

nmPendingEventCount:调用epoll_wait时的返回值,当然如果没有事件,则其值为0

nmPendingEventIndex:当前需要处理的事件索引

nmEpollFdepoll实例,在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 <mPendingEventCount,将进入while循环mPendingEventCount次,每次通过read()方法读取相对应的输入数据。


1.3 读取输入数据

首先,需要看看相关的数据结构:

InputFramework(二)---EventHub" title="AndroidInputFramework(二)---EventHub">

经过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 <mPendingEventCount) {

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

}

我们来分下上面的代码,先看看几个重要的变量

nbuffer

一个RawEvent结构体的一个数组,数组元素个数为bufferSizebuffer看成这个数组的指针。

nevent

一个RawEvent结构体的一个数组,数组元素个数为bufferSize,刚开始被赋值为buffer

nreadBuffer

一个input_event结构体的一个数组,数组元素个数为bufferSize,在read()方法中用于读取一个输入事件的数据。

ncount

表示读取了多少组数据。

我们模拟按下一个按键然后松开为例子,在上面代码中加了两个打印。

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作为参数传进来,并赋值给eventevent用来存储输入事件的数据。将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

更多相关文章

  1. Android串口通讯整理
  2. Android(安卓)adb使用sqlite3对一个数据库进行sql查询
  3. 【重拾Android】(2)SQLite数据库与数据持久化
  4. Android的Parcelable用法
  5. Android(安卓)NFC开发-实践篇
  6. android 代码优化(2)
  7. Android(安卓)ScrollView嵌套WebView
  8. Android中init进程的工作
  9. Android(安卓)SharedPreferences用法及程序共享机制

随机推荐

  1. Android写入内部存储和sd卡
  2. Android(安卓)常见分辨率(mdpi、hdpi 、xh
  3. android5.1-在系统设置里添加设置选项 以
  4. Android应用程序访问远程数据库(mysql) i
  5. android studio 导入第三方类库
  6. Android(安卓)有输入框的页面,一打开就会
  7. Android(安卓)P 图形显示系统(十) BufferQu
  8. Button控件
  9. android 计入高德地图——实时天气和天气
  10. Android(安卓)8.0 App 安装卸载流程