Android输入事件流程 收藏

news/2024/11/7 18:36:16

Android输入事件流程


转载时请注明出处和作者联系方式

文章出处:http://www.limodev.cn/blog
作者联系方式:李先静 <xianjimli at hotmail dot com>

EventHub对输入设备进行了封装。输入设备驱动程序对用户空间应用程序提供一些设备文件,这些设备文件放在/dev/input里面。

EventHub扫描/dev/input下所有设备文件,并打开它们。

bool EventHub::openPlatformInput(void)
{
...
mFDCount = 1;
mFDs = (pollfd *)calloc(1, sizeof(mFDs[0]));
mDevices = (device_t **)calloc(1, sizeof(mDevices[0]));
mFDs[0].events = POLLIN;
mDevices[0] = NULL;

res = scan_dir(device_path);
...
return true;
}

EventHub对外提供了一个函数用于从输入设备文件中读取数据。

bool EventHub::getEvent(int32_t* outDeviceId, int32_t* outType,
int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags,
int32_t* outValue, nsecs_t* outWhen)
{
...
while(1) {

// First, report any devices that had last been added/removed.
if (mClosingDevices != NULL) {
device_t* device = mClosingDevices;
LOGV("Reporting device closed: id=0x%x, name=%s/n",
device->id, device->path.string());
mClosingDevices = device->next;
*outDeviceId = device->id;
if (*outDeviceId == mFirstKeyboardId) *outDeviceId = 0;
*outType = DEVICE_REMOVED;
delete device;
return true;
}
if (mOpeningDevices != NULL) {
device_t* device = mOpeningDevices;
LOGV("Reporting device opened: id=0x%x, name=%s/n",
device->id, device->path.string());
mOpeningDevices = device->next;
*outDeviceId = device->id;
if (*outDeviceId == mFirstKeyboardId) *outDeviceId = 0;
*outType = DEVICE_ADDED;
return true;
}

release_wake_lock(WAKE_LOCK_ID);

pollres = poll(mFDs, mFDCount, -1);

acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);

if (pollres <= 0) {
if (errno != EINTR) {
LOGW("select failed (errno=%d)/n", errno);
usleep(100000);
}
continue;
}

for(i = 1; i < mFDCount; i++) {
if(mFDs[i].revents) {
LOGV("revents for %d = 0x%08x", i, mFDs[i].revents);
if(mFDs[i].revents & POLLIN) {
res = read(mFDs[i].fd, &iev, sizeof(iev));
if (res == sizeof(iev)) {
LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, v=%d",
mDevices[i]->path.string(),
(int) iev.time.tv_sec, (int) iev.time.tv_usec,
iev.type, iev.code, iev.value);
*outDeviceId = mDevices[i]->id;
if (*outDeviceId == mFirstKeyboardId) *outDeviceId = 0;
*outType = iev.type;
*outScancode = iev.code;
if (iev.type == EV_KEY) {
err = mDevices[i]->layoutMap->map(iev.code, outKeycode, outFlags);
LOGV("iev.code=%d outKeycode=%d outFlags=0x%08x err=%d/n",
iev.code, *outKeycode, *outFlags, err);
if (err != 0) {
*outKeycode = 0;
*outFlags = 0;
}
} else {
*outKeycode = iev.code;
}
*outValue = iev.value;
*outWhen = s2ns(iev.time.tv_sec) + us2ns(iev.time.tv_usec);
return true;
} else {
if (res<0) {
LOGW("could not get event (errno=%d)", errno);
} else {
LOGE("could not get event (wrong size: %d)", res);
}
continue;
}
}
}
}
...
}

对于按键事件,调用mDevices[i]->layoutMap->map进行映射。映射实际是由 KeyLayoutMap::map完成的,KeyLayoutMap类里读取配置文件qwerty.kl,由配置文件qwerty.kl决定键值的映射关系。你可以通过修改./development/emulator/keymaps/qwerty.kl来改变键值的映射关系。

JNI函数

在frameworks/base/services/jni/com_android_server_KeyInputQueue.cpp文件中,向JAVA提供了函数android_server_KeyInputQueue_readEvent,用于读取输入设备事件。

static jboolean
android_server_KeyInputQueue_readEvent(JNIEnv* env, jobject clazz,
jobject event)
{
gLock.lock();
sp hub = gHub;
if (hub == NULL) {
hub = new EventHub;
gHub = hub;
}
gLock.unlock();

int32_t deviceId;
int32_t type;
int32_t scancode, keycode;
uint32_t flags;
int32_t value;
nsecs_t when;
bool res = hub->getEvent(&deviceId, &type, &scancode, &keycode,
&flags, &value, &when);

env->SetIntField(event, gInputOffsets.mDeviceId, (jint)deviceId);
env->SetIntField(event, gInputOffsets.mType, (jint)type);
env->SetIntField(event, gInputOffsets.mScancode, (jint)scancode);
env->SetIntField(event, gInputOffsets.mKeycode, (jint)keycode);
env->SetIntField(event, gInputOffsets.mFlags, (jint)flags);
env->SetIntField(event, gInputOffsets.mValue, value);
env->SetLongField(event, gInputOffsets.mWhen,
(jlong)(nanoseconds_to_milliseconds(when)));

return res;
}

readEvent调用hub->getEvent读了取事件,然后转换成JAVA的结构。




o 事件中转线程

在frameworks/base/services/java/com/android/server/KeyInputQueue.java里创建了一个线程,它循环的读取事件,然后把事件放入事件队列里。

    Thread mThread = new Thread("InputDeviceReader") {
public void run() {
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);

try {
RawInputEvent ev = new RawInputEvent();
while (true) {
InputDevice di;

readEvent(ev);

send = preprocessEvent(di, ev);
addLocked(di, curTime, ev.flags, ..., me);
}
}
};





o 输入事件分发线程

在frameworks/base/services/java/com/android/server/WindowManagerService.java里创建了一个输入事件分发线程,它负责把事件分发到相应的窗口上去。

mQueue.getEvent
dispatchKey/dispatchPointer/dispatchTrackball


http://www.niftyadmin.cn/n/3613040.html

相关文章

LinqToNhibernate中的DateTime陷阱

能用LinqToNhibernate还是很爽的~~能获得编译时类型检查就不说了&#xff0c;就连where子句的复用都比用HQL爽快很多~~~比如我有这种有时间限制的实体publicinterfaceITerminableEntity { DateTime StartDate { get; } DateTime?EndDate { get; } }然后我…

Linux设备模型之input子系统详解(一)

------------------------------------------ 本文系本站原创,欢迎转载! 转载请注明出处:http://ericxiao.cublog.cn/ ------------------------------------------ 一&#xff1a;前言 在键盘驱动代码分析的笔记中&#xff0c;接触到了input子系统.键盘驱动&#xff0c;键盘驱…

创建你的第一个游戏Pong——挑战:改进您的Pong游戏

挑战&#xff1a;改进您的Pong游戏 现在轮到您来对游戏进行一些改进了&#xff1b;也许您能换一换图片或声音&#xff0c;或者调整游戏的玩法。如果您有Gamepad控制器&#xff0c;您还可以试着给它添加Rumble支持。而且如果您阅读本书的话&#xff0c;的确应该有一个Gamepad&am…

定义silverlight报表样式-Styling a Silverlight Chart

定义silverlight报表样式-Styling a Silverlight Chart A article on how to style a standard Silverlight chart to look like the Google Analytics chart.Download source code - 11.1 KBIntroductionI love Google Analytics! I use it to monitor every site I own… Goo…

linux input subsystem 架构分析

主要数据结构 struct input_dev { void *private; const char *name; const char *phys; const char *uniq; struct input_id id; unsigned long evbit[NBITS(EV_MAX)]; unsigned long keybit[NBITS(KEY_MAX)]; unsigned long relbit[NBITS(REL_MAX)]; unsigned long absbit[N…

HDU 2020,2021,2024,2028,2029,2030

//Made by syx //Time 2010年7月29日 09:55:28 // //2020 绝对值排序 //2021 发工资咯&#xff1a;&#xff09; //2024 C语言合法标识符 //2028 Lowest Common Multiple Plus //2029 Palindromes_easy version 回文串 //2030 汉字统计 /*//2030 汉字统计 #include <iostrea…

linux内存寻址

本章节介绍linux寻址技术&#xff0c;详细描述80x86微处理器怎样进行芯片级的内存寻址&#xff0c;linux又是如何寻址硬件的。 1. linux内存地址 80x86微处理器下主要有三种不同的地址&#xff1a;逻辑地址&#xff0c;线性地址&#xff0c;物理地址。 逻辑地址&#xff1a; 主…

Linux Input Device 介紹: APIs

Linux Input Device 介紹: APIs jollen 發表於 April 8, 2009 12:18 PM Linux 的 Input Device 是重要的一個 subsystem&#xff0c;在進行實例介紹前&#xff0c;先大略了解一下相關的 API。 Linux Input Device &#xfeff;input.c是Linux的”input”驅動程式&#xff0c;主…