在最底下的 Linux driver 要设置 input 的事件,后 input_report_abs(dev, 你设置的事件(如ABS_Y), 要上传的值); 最后再同步input_sync(dev);
Linux driver 以上:
WindowManagerService 类的构造函数 WindowManagerService() 中有一句:
mQueue = new KeyQ();
然而
private class KeyQ extends KeyInputQueue
在 KeyInputQueue 中创建了一个叫 InputDeviceReader 线程 Thread mThread = new Thread("InputDeviceReader")
InputDeviceReader 专门用来从设备中读取事件。
代码:
Thread mThread = new Thread("InputDeviceReader") {
public void run()
{
在循环中调用:
readEvent(ev);
...
send = preprocessEvent(di, ev);
实际调用的是
KeyQ
类的
preprocessEvent
函数
...
int keycode = rotateKeyCodeLocked(ev.keycode);
int[] map = mKeyRotationMap;
for (int i=0; i<N; i+=2)
{
if (map[i] == keyCode)
return map[i+1];
} //
addLocked(di, curTime,
ev.flags,RawInputEvent.CLASS_KEYBOARD,newKeyEvent(di, di.mDownTime,
curTime, down,keycode, 0, scancode,...));
QueuedEvent ev = obtainLocked(device, when, flags, classType, event);
}
}
readEvent()
实际上调用的是
com_android_server_KeyInputQueue.cpp (frameworks/base/services/jni)
中的:
static jboolean android_server_KeyInputQueue_readEvent(JNIEnv* env, jobject clazz,jobject event)
bool res = hub->getEvent(&deviceId, &type, &scancode, &keycode,&flags, &value, &when);
调用的是
EventHub.cpp (frameworks/base/libs/ui)
中的:
bool EventHub::getEvent(int32_t* outDeviceId, int32_t* outType,
int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags,
int32_t* outValue, nsecs_t* outWhen)
在函数中调用了读设备操作:
res = read(mFDs[i].fd, &iev, sizeof(iev));
EventHub
:
而事件的传入是从
EventHub
开始的,
EventHub
是事件的抽象结构,维护着系统设备的运行情况,设备类型包括
Keyboard
、
TouchScreen
、
TraceBall
。它在系统启动的时候会通过
open_device
方法将系统提供的输入设备都增加到这个抽象结构中,并维护一个所有输入设备的文件描述符,如果输入设备是键盘的话还会读取
/system/usr/keylayout/
目录下对应键盘设备的映射文件,另外
getEvent
方法是对
EventHub
中的设备文件描述符使用
poll
操作等侍驱动层事件的发生,如果发生的事件是键盘事件,则调用
Map
函数按照映射文件转换成相应的键值并将扫描码和键码返回给
KeyInputQueue
。
KeyLayoutMap
主要是读取键盘映射文件并将键盘扫描码和键码进行转换
frameworks/base/core/jni/server/ com_android_server_KeyInputQueue.cpp
EventHub
和
KeyinputQueue
的
JNI
接口层
KeyinputQueue
:
在线程
InputDeviceReader
中会根据事件的类型以及事件值进行判断处理,从而确定这个事件对应的设备状态是否发生了改变并相应的改变对这个设备的描述结构
InputDevice
。
getEvent
:在给定时间段时看是否有事件发生,如果有的话返回
true
否则
false
。
Windowmanager
:
(frameworks/base/services/java/com/android/server/windowmanagerservice.java)
进程
Windowmanager
会创建一个线程(
InputDispatcherThread
),在这个线程里从事件队列中读取发生的事件(
QueuedEvent ev = mQueue.getEvent
()),并根据读取到事件类型的不同分成三类(
KEYBOARD
、
TOUCHSCREEN
、
TRACKBALL
),分别进行处理,例如键盘事件会调用
dispatchKey((KeyEvent)ev.event, 0, 0)
以将事件通过
Binder
发送给具有焦点的窗口应用程序,然后调用
mQueue.recycleEvent(ev)
继续等侍键盘事件的发生
;
如果是触摸屏事件则调用
dispatchPointer(ev, (MotionEvent)ev.event, 0, 0)
,这里会根据事件的种类(
UP
、
DOWN
、
MOVE
、
OUT_SIDE
等)进行判断并处理,比如
Cancel
或将事件发送到具有权限的指定的窗口中去
;
在 Eventhub.cpp 的成员 getEvent 中的 pollres = poll(mFDs, mFDCount, -1); 一直在 poll 事件的状况,当没有新的事件输入时,停在这个函数中,当有新事件是返回一个值给 pollres ,然后再执行读函数 res = read(mFDs[i].fd, &iev, sizeof(iev)); ,读取事件。
本文介绍了Linux系统中输入事件的处理流程,从驱动层到WindowManagerService的传递过程,包括KeyInputQueue、EventHub等关键组件的工作原理。
1244

被折叠的 条评论
为什么被折叠?



