1 EventHub获取输入设备数据

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

1.1 打开设备

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

Input Framework(二)---EventHub" title="Android Input Framework(二)---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如何获取输入事件,不得不先说说它的几个相关的成员变量:

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

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

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


 

1.3 读取输入数据

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

Input Framework(二)---EventHub" title="Android Input Framework(二)---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

   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结构体的一个数组,数组元素个数为bufferSizebuffer看成这个数组的指针。

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作为参数传进来,并赋值给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. 第17天android:《android从零开始》视频(1-5)
  2. Android(安卓)EditView
  3. [android]在上下文菜单的选中事件中获取列表选中的元素
  4. Android获取设备唯一标识完美解决方案
  5. android 多点触控
  6. Android解决父控件拦截子控件手势滑动事件的问题
  7. Android(安卓)Studio 3.0开始android Device Monitor弃用
  8. Android下模拟按键输入
  9. android touch事件解析

随机推荐

  1. 细读《深入理解 Android(安卓)内核设计思
  2. Android之系统架构
  3. android如何使webview不跳到自带的浏览器
  4. 基于android ndk-r15 生成ffmpeg4.0 .so
  5. Android环境的搭建
  6. Android之异步任务AsyncTask解析XML数据
  7. 二维码扫描(横屏、竖屏、解决竖屏后拉伸问
  8. Android-抽象类抽象方法
  9. 搭建NDK环境,运行samples
  10. android--------自定义控件 之 方法篇