Android Input Framework(二)---EventHub

Android Input Framework(二)---EventHub

  (2012-09-17 10:20:39)
标签: 

杂谈

分类: android


1 EventHub 获取输入设备数据

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

1.1 打开设备

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

Android <wbr>Input <wbr>Framework(二)---EventHub

     openDeviceLocked()方法中,首先调用open()打开设备, ioctl()获取设备名字,识别打开设备是哪个classs的,即按键、单点触摸屏、多点触摸屏等等。如果设备是认为是合法的,创建了设备,然后向epoll注册该设备,并添加到mDevices列表中:

// Register with 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)) {

        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 union epoll_data

{

    void *ptr;

    int fd;

    unsigned int u32;

    unsigned long long u64;

} epoll_data_t;

struct epoll_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_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {

    struct input_event readBuffer[bufferSize];

    RawEvent* event = buffer;

    size_t capacity = bufferSize;

    bool awoken = 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 读取输入数据

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

Android <wbr>Input <wbr>Framework(二)---EventHub

经过1.2小节介绍,我们知道,epoll_event结构体是用来存储输入事件的,调用epoll_wait()读取输入事件,一般情况下mPendingEventCount=1,当有输入事件的时候,通过read()方法读取输入数据。

size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {

 

    struct input_event readBuffer[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

}

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值