android raw event,Android Eventhub处理流程

Eventhub是在Native 的inputmanager创建的时候被创建的,inputreadthread就通过eventhub的getevent方法来源源不断的获取driver上报的input事件。

bool EventHub::getEvent(RawEvent* outEvent)

{

if (!mOpened) {

mError = openPlatformInput() ? NO_ERROR :UNKNOWN_ERROR;

mOpened = true;

mNeedToSendFinishedDeviceScan = true;

}

//省略

如果是第一次进入getevent,则会去调用openplatforminput来获取input设备,加载对应的kl,将device加入eventhub的特定的结构体中。

bool EventHub::openPlatformInput(void)

{

//省略

res = scanDir(device_path);

if(res < 0) {

LOGE("scan dir failed for %s\n", device_path);

}

return true;

}

直接调用scandir来处理/dev/input/文件夹

int EventHub::scanDir(const char *dirname)

{   char devname[PATH_MAX];

char *filename;

DIR *dir;

struct dirent *de;

dir = opendir(dirname);

if(dir == NULL)

return -1;

strcpy(devname, dirname);

filename = devname + strlen(devname);

*filename++ = '/';

while((de = readdir(dir))) {

if(de->d_name[0] == '.' &&

(de->d_name[1] == '\0' ||

(de->d_name[1] == '.' && de->d_name[2] == '\0')))

continue;

strcpy(filename, de->d_name);

openDevice(devname);

}

closedir(dir);

return 0;

}

通过readdir来得到子文件的名字,拼成完整的设备路径后调用opendevice来打开他,如/dev/input/event0 (可以在adb shell进入手机后cd到/dev/input下ls下,就可以看到了)

int EventHub::openDevice(const char*deviceName) {

//省略,主要是将新发现的设备增加到mDevicesById和mFDs数组中。

//接下来是对设备类型的判断,我们以键盘为例:

LOGV("Getting keys...");

if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) >=0) {

//LOGI("MAP\n");

//for (int i = 0; i < sizeof(key_bitmask); i++) {

//    LOGI("%d:0x%02x\n", i, key_bitmask[i]);

//}

// See if this is a keyboard.  Ignoreeverything in the button range except for

// gamepads which are also considered keyboards.

if (containsNonZeroByte(key_bitmask, 0, sizeof_bit_array(BTN_MISC))

||containsNonZeroByte(key_bitmask, sizeof_bit_array(BTN_GAMEPAD),

sizeof_bit_array(BTN_DIGI))

||containsNonZeroByte(key_bitmask, sizeof_bit_array(KEY_OK),

sizeof_bit_array(KEY_MAX + 1))) {

device->classes |=INPUT_DEVICE_CLASS_KEYBOARD;

device->keyBitmask = newuint8_t[sizeof(key_bitmask)];

if (device->keyBitmask != NULL) {

memcpy(device->keyBitmask,key_bitmask, sizeof(key_bitmask));

} else {

delete device;

LOGE("out of memory allocating keybitmask");

return -1;

}

}

}

//具体的ioctl还没搞明白,从字面意思上看,就是判断当前设备是否是键盘,如果是则将其类型或上INPUT_DEVICE_CLASS_KEYBOARD

//其他的设备的处理也很类似,接下来是加载kl:

if((device->classes & INPUT_DEVICE_CLASS_KEYBOARD) != 0) {

//如果是键盘

char tmpfn[sizeof(name)];

char keylayoutFilename[300];

// a more descriptive name

device->name = name;

// replace all the spaces with underscores

strcpy(tmpfn, name);

for (char *p = strchr(tmpfn, ' '); p && *p; p = strchr(tmpfn, ''))

*p = '_';

// find the .kl file we need for this device

const char* root = getenv("ANDROID_ROOT");

//此处的root即是/system/

snprintf(keylayoutFilename, sizeof(keylayoutFilename),

"%s/usr/keylayout/%s.kl", root, tmpfn);

bool defaultKeymap = false;

if (access(keylayoutFilename, R_OK)) {

snprintf(keylayoutFilename, sizeof(keylayoutFilename),

"%s/usr/keylayout/%s",root, "qwerty.kl");

defaultKeymap = true;

}

status_t status = device->layoutMap->load(keylayoutFilename);

if (status) {

LOGE("Error %d loading key layout.", status);

}

device->next = mOpeningDevices;

mOpeningDevices = device;

mDevices[mFDCount] = device

mFDCount++;

//首先尝试去查找是否存在特定的keylayoutfile,如我们的键盘对应的kl应该是:

/system/usr/keylayout/sprd-keypad.kl

如果kl不存在,则尝试去打开默认的kl,即qwerty.kl,然后加载对应的kl。

//如果加载成功,则通知大家设备名(将hw.keyboards.0.devname赋值为对应的设备名,如sprd-keypad),并将其声明为mOpeningDevices到这里,一个input设备就打开成功可以为eventhub所用了。

接下来我们看下keylayoutMap的Load函数来了解下kl文件的解析。

Kl文件也比较简单,截取一部分:

Key  116     POWER             WAKE

Key是起始标志,116是硬件扫描码,POWER是对应的KEYCODE,WAKE是按键对应的FLAG。

KeyLayoutMap::load(const char* filename){

//省略无关。

enum { BEGIN,SCANCODE, KEYCODE, FLAG } state = BEGIN;

//state初始为BEGIN

while (true) {

String8 token = next_token(&p, &line);

if (*p == '\0') {

break;

}

switch (state)

{

case BEGIN:

if (token == "key") {

state = SCANCODE;

//如果读取到key,状态置为SCANCODE

} else {

LOGE("%s:%d: expectedkey, got '%s'\n", filename, line,

token.string());

err = BAD_VALUE;

goto done;

}

break;

case SCANCODE:

scancode = strtol(token.string(),&end, 0);

if (*end != '\0') {

LOGE("%s:%d: expectedscancode (a number), got '%s'\n",

filename, line,token.string());

goto done;

}

//LOGI("%s:%d: gotscancode %d\n", filename, line, scancode );

//

state = KEYCODE;

//读取扫描码成功后继续读取keycode

break;

case KEYCODE:

keycode =token_to_value(token.string(), KEYCODES);

//通过在KEYCODES中查找得到对应的按键码,如POWER:

staticconst KeycodeLabel KEYCODES[] = {

{"SOFT_LEFT", 1 },

{"SOFT_RIGHT", 2 },

{"HOME", 3 },

{"BACK", 4 },

{ "POWER", 26 },

}对应的是KEYCODE_POWER

此处的keycode就是上层的使用的keycode。通过kl,就将硬件扫描码转换成了keycode。

//LOGI("%s:%d: got keycode%d for %s\n", filename, line, keycode, token.string() );

if (keycode == 0) {

LOGE("%s:%d: expectedkeycode, got '%s'\n",

filename, line,token.string());

goto done;

}

state = FLAG;

break;

case FLAG:

if (token == "key") {

if (scancode != -1) {

//LOGI("got keydecl scancode=%d keycode=%d"

//       " flags=0x%08x\n", scancode,keycode, flags);

Key k = { keycode,flags };

m_keys.add(scancode,k);

state = SCANCODE;

scancode = -1;

keycode = -1;

flags = 0;

break;

}

}

tmp = token_to_value(token.string(),FLAGS);

//类似的,查FLAGS数组,找到对应的FLAGS:

static const KeycodeLabel FLAGS[] = {

{"WAKE", 0x00000001 },

WAKE,就是0x00000001,对应的是POLICY_FLAG_WAKE =0x00000001,在input.h

//LOGI("%s:%d: got flags%x for %s\n", filename, line, tmp, token.string() );

if (tmp == 0) {

LOGE("%s:%d: expectedflag, got '%s'\n",

filename, line,token.string());

goto done;

}

flags |= tmp;

break;

}

}

if (state == FLAG && scancode != -1 ) {

//LOGI("got key decl scancode=%d keycode=%d"

//       "flags=0x%08x\n", scancode, keycode, flags);

Key k = { keycode, flags };

m_keys.add(scancode, k);

}

done:

free(buf);

close(fd);

m_status = err;

return err;

}

这样,对应的keycode scancode,flag,都保存在了m_keys中。

接下来继续看getevent:这个神一样的函数

boolEventHub::getEvent(RawEvent* outEvent)

{

if (!mOpened) {

mError = openPlatformInput() ? NO_ERROR: UNKNOWN_ERROR;

mOpened = true;

mNeedToSendFinishedDeviceScan = true;

//如果发现了新设备,mNeedToSendFinishedDeviceScan被置为true,在下面会用到

}

for (;;) {

// Report any devices that had lastbeen added/removed.

if (mClosingDevices != NULL) {

//在closeDevice函数中被赋值,如果有设备需要关闭,则会走进来,返回一个DEVICE_REMOVED事件。

device_t* device = mClosingDevices;

LOGV("Reporting device closed:id=0x%x, name=%s\n",

device->id, device->path.string());

mClosingDevices = device->next;

if (device->id ==mFirstKeyboardId) {

outEvent->deviceId = 0;

} else {

outEvent->deviceId =device->id;

}

outEvent->type = DEVICE_REMOVED;

outEvent->when =systemTime(SYSTEM_TIME_MONOTONIC);

delete device;

mNeedToSendFinishedDeviceScan =true;

return true;

}

if (mOpeningDevices != NULL) {

//在上文中的opendevice中的末尾,会将其置为对应的device,也就是说如果发现了新设备,会返回一个DEVICE_ADDED的事件。在inputreader中会处理

device_t* device = mOpeningDevices;

LOGV("Reporting device opened:id=0x%x, name=%s\n",

device->id,device->path.string());

mOpeningDevices = device->next;

if (device->id ==mFirstKeyboardId) {

outEvent->deviceId = 0;

} else {

outEvent->deviceId =device->id;

}

outEvent->type = DEVICE_ADDED;

outEvent->when =systemTime(SYSTEM_TIME_MONOTONIC);

mNeedToSendFinishedDeviceScan =true;

return true;

}

if (mNeedToSendFinishedDeviceScan) {

//在ADD完成设备后,会发出一个FINISHD_DEVICE_SCAN,标志着所有的input设备都已经SCAN完成。

mNeedToSendFinishedDeviceScan =false;

outEvent->type =FINISHED_DEVICE_SCAN;

outEvent->when =systemTime(SYSTEM_TIME_MONOTONIC);

return true;

}

//接下来就是对按键的捕获处理

// Grab the next input event.

for (;;) {

// Consume buffered input events,if any.

if (mInputBufferIndex //如果当前存在需要处理的按键事件,则通过map返回对应的outevent

const struct input_event&iev = mInputBufferData[mInputBufferIndex++];

const device_t* device =mDevices[mInputDeviceIndex];

LOGV("%s got: t0=%d,t1=%d, type=%d, code=%d, v=%d", device->path.string(),

(int) iev.time.tv_sec,(int) iev.time.tv_usec, iev.type, iev.code, iev.value);

if (device->id ==mFirstKeyboardId) {

outEvent->deviceId = 0;

//keypad的设备id为0

} else {

outEvent->deviceId =device->id;

}

outEvent->type = iev.type;

outEvent->scanCode =iev.code;

if (iev.type == EV_KEY) {

status_t err =device->layoutMap->map(iev.code,

&outEvent->keyCode, & outEvent->flags);

//将扫描码转换成按键码,并给出按键的flag位

通过对应device的layoutMap中的m_keys中存储的信息(上文中的load中可以看到),返回对应的按键码,FLAG。

LOGV("iev.code=%dkeyCode=%d flags=0x%08x err=%d\n",

iev.code, outEvent->keyCode,outEvent->flags, err);

if (err != 0) {

outEvent->keyCode =AKEYCODE_UNKNOWN;

outEvent->flags = 0;

}

} else {

outEvent->keyCode =iev.code;

}

outEvent->value = iev.value;

// Use an event timestamp inthe same timebase as

// java.lang.System.nanoTime()and android.os.SystemClock.uptimeMillis()

// as expected by the rest of the system.

outEvent->when =systemTime(SYSTEM_TIME_MONOTONIC);

return true;

}

//如果读取完了所有存在buffer里的按键事件,或者因为设备刚初始化,不存在等待读取的按键事件,则去读。

mInputDeviceIndex += 1;

if (mInputDeviceIndex >= mFDCount) {

break;

}

const struct pollfd& pfd =mFDs[mInputDeviceIndex];

if (pfd.revents & POLLIN) {

int32_t readSize = read(pfd.fd, mInputBufferData,

sizeof(structinput_event) * INPUT_BUFFER_SIZE);

if (readSize < 0) {

if (errno != EAGAIN&& errno != EINTR) {

LOGW("could notget event (errno=%d)", errno);

}

} else if ((readSize %sizeof(struct input_event)) != 0) {

LOGE("could not getevent (wrong size: %d)", readSize);

} else {

mInputBufferCount= readSize / sizeof(struct input_event);

//将input事件存到buffer中,并计算出count,且将index赋值为0

mInputBufferIndex = 0;

}

}

这样,inputreadthread不停的调用getevent,不停的可以获取到当前的input事件,并上报处理。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值