




已阅读5页,还剩5页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Init-zygote-system-server-windosmanager - UEventObserver- InputDeviceRead-InputDispatcher-DisplayEventThr-ActivityManagerEventHub:而事件的传入是从EventHub开始的,EventHub是事件的抽象结构,维护着系统设备的运行情况,设备类型包括Keyboard、TouchScreen、TraceBall。它在系统启动的时候会通过open_device方法将系统提供的输入设备都增加到这个抽象结构中,并维护一个所有输入设备的文件描述符,如果输入设备是键盘的话还会读取/system/usr/keylayout/目录下对应键盘设备的映射文件,另外getEvent方法是对EventHub中的设备文件描述符使用poll操作等侍驱动层事件的发生,如果发生的事件是键盘事件,则调用Map函数按照映射文件转换成相应的键值并将扫描码和键码返回给KeyInputQueue。KeyLayoutMap主要是读取键盘映射文件并将键盘扫描码和键码进行转换frameworksbasecorejniserver com_android_server_KeyInputQueue.cppEventHub和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或将事件发送到具有权限的指定的窗口中去;Android 输入事件流程EventHubEventHub对输入设备进行了封装。输入设备驱动程序对用户空间应用程序提供一些设备文件,这些设备文件放在/dev/input里面。EventHub扫描/dev/input下所有设备文件,并打开它们。C代码1. boolEventHub:openPlatformInput(void)2. 3. .4. mFDCount=1;5. mFDs=(pollfd*)calloc(1,sizeof(mFDs0);6. mDevices=(device_t*)calloc(1,sizeof(mDevices0);7. mFDs0.events=POLLIN;8. mDevices0=NULL;9. 10. res=scan_dir(device_path);11. .12. returntrue;13. EventHub对外提供了一个函数用于从输入设备文件中读取数据。C代码1. boolEventHub:getEvent(int32_t*outDeviceId,int32_t*outType,2. int32_t*outScancode,int32_t*outKeycode,uint32_t*outFlags,3. int32_t*outValue,nsecs_t*outWhen)4. 5. .6. while(1)7. 8. /First,reportanydevicesthathadlastbeenadded/removed.9. if(mClosingDevices!=NULL)10. device_t*device=mClosingDevices;11. LOGV(Reportingdeviceclosed:id=0x%x,name=%sn,12. device-id,device-path.string();13. mClosingDevices=device-next;14. *outDeviceId=device-id;15. if(*outDeviceId=mFirstKeyboardId)*outDeviceId=0;16. *outType=DEVICE_REMOVED;17. deletedevice;18. returntrue;19. 20. if(mOpeningDevices!=NULL)21. device_t*device=mOpeningDevices;22. LOGV(Reportingdeviceopened:id=0x%x,name=%sn,23. device-id,device-path.string();24. mOpeningDevices=device-next;25. *outDeviceId=device-id;26. if(*outDeviceId=mFirstKeyboardId)*outDeviceId=0;27. *outType=DEVICE_ADDED;28. returntrue;29. 30. 31. release_wake_lock(WAKE_LOCK_ID);32. 33. pollres=poll(mFDs,mFDCount,-1);34. 35. acquire_wake_lock(PARTIAL_WAKE_LOCK,WAKE_LOCK_ID);36. 37. if(pollres=0)38. if(errno!=EINTR)39. LOGW(selectfailed(errno=%d)n,errno);40. usleep(100000);41. 42. continue;43. 44. 45. for(i=1;ipath.string(),53. (int)iev.time.tv_sec,(int)iev.time.tv_usec,54. iev.type,iev.code,iev.value);55. *outDeviceId=mDevicesi-id;56. if(*outDeviceId=mFirstKeyboardId)*outDeviceId=0;57. *outType=iev.type;58. *outScancode=iev.code;59. if(iev.type=EV_KEY)60. err=mDevicesi-layoutMap-map(iev.code,outKeycode,outFlags);61. LOGV(iev.code=%doutKeycode=%doutFlags=0x%08xerr=%dn,62. iev.code,*outKeycode,*outFlags,err);63. if(err!=0)64. *outKeycode=0;65. *outFlags=0;66. 67. else68. *outKeycode=iev.code;69. 70. *outValue=iev.value;71. *outWhen=s2ns(iev.time.tv_sec)+us2ns(iev.time.tv_usec);72. returntrue;73. else74. if(reslayoutMap-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,用于读 取输入设备事件。C代码1. staticjboolean2. android_server_KeyInputQueue_readEvent(JNIEnv*env,jobjectclazz,3. jobjectevent)4. 5. gLock.lock();6. sphub=gHub;7. if(hub=NULL)8. hub=newEventHub;9. gHub=hub;10. 11. gLock.unlock();12. 13. int32_tdeviceId;14. int32_ttype;15. int32_tscancode,keycode;16. uint32_tflags;17. int32_tvalue;18. nsecs_twhen;19. boolres=hub-getEvent(&deviceId,&type,&scancode,&keycode,20. &flags,&value,&when);21. 22. env-SetIntField(event,gInputOffsets.mDeviceId,(jint)deviceId);23. env-SetIntField(event,gInputOffsets.mType,(jint)type);24. env-SetIntField(event,gInputOffsets.mScancode,(jint)scancode);25. env-SetIntField(event,gInputOffsets.mKeycode,(jint)keycode);26. env-SetIntField(event,gInputOffsets.mFlags,(jint)flags);27. env-SetIntField(event,gInputOffsets.mValue,value);28. env-SetLongField(event,gInputOffsets.mWhen,29. (jlong)(nanoseconds_to_milliseconds(when);30. 31. returnres;32. readEvent调用hub-getEvent读了取事件,然后转换成JAVA的结构。事件中转线程在frameworks/base/services/java/com/android/server/KeyInputQueue.java 里创建了一个线程,它循环的读取事件,然后把事件放入事件队列里。Java代码1. ThreadmThread=newThread(InputDeviceReader)2. publicvoidrun()3. android.os.Process.setThreadPriority(4. android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);5. 6. try7. RawInputEventev=newRawInputEvent();8. while(true)9. InputDevicedi;10. 11. readEvent(ev);12. 13. send=preprocessEvent(di,ev);14. addLocked(di,curTime,ev.flags,.,me);15. 16. 17. ;输入事件分发线程在frameworks/base/services/java/com/android/server/WindowManagerService.java里创建了一个输入事件分发线程,它负责把事件分发到相应的窗口上去。Java代码1. mQueue.getEvent2. dispatchKey/dispatchPointer/dispatchTrackball按键,触摸屏流程分析按键触摸屏流程分析:WindowManagerService类的构造函数WindowManagerService() mQueue = new KeyQ();因为 WindowManagerService.java (frameworksbaseservicesjavacomandroidserver)中有:private class KeyQ extends KeyInputQueueKeyQ 是抽象类 KeyInputQueue 的实现,所以 new KeyQ类的时候实际上在 KeyInputQueue 类中创建了一个线程 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; igetEvent(&deviceId, &type, &scancode, &keycode,&flags, &value, &when);调用的是 EventHub.cpp (frameworksbaselibsui)中的: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(mFDsi.fd, &iev, sizeof(iev);在构造函数 WindowManagerService()调用 new KeyQ() 以后接着调用了: mInputThread = new InputDispatcherThread(); . mInputThread.start();来启动一个线程 InputDispatcherThreadrun() process(); QueuedEvent ev = mQueue.getEvent(.)因为WindowManagerService类中: final KeyQ mQueue;所以实际上 InputDispatcherThread 线程实际上从 KeyQ 的事件队列中读取按键事件。switch (ev.classType) case RawInputEvent.CLASS_KEYBOARD: . dispatchKey(KeyEvent)ev.event, 0, 0); mQueue.recycleEvent(ev); break; case RawInputEvent.CLASS_TOUCHSCREEN: /Log.i(TAG, Read next event + ev); dispatchPointer(ev, (MotionEvent)ev.event, 0, 0); break;=KeyInputQueue.java (frameworksbaseservicesjavacomandroidserver):的线程 Thread mThread = new Thread(InputDeviceReader) 本地调用:readEvent(ev);读取按键。readEvent 调用的是文件:com_android_server_KeyInputQueue.cpp (frameworksbaseservicesjni)中的函数:static jboolean android_server_KeyInputQueue_readEvent(JNIEnv* env, jobject clazz, jobject event)android_server_KeyInputQueue_readEvent中有:hub = new EventHub;bool res = hub-getEvent(&deviceId, &type, &scancode, &keycode, &flags, &value, &when);hub-getEvent 调用的是EventHub.cpp (frameworksbaselibsui) 文件中的函数:bool EventHub:getEvent(int32_t* outDeviceId, int32_t* outType, int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags, int32_t* outValue, nsecs_t* outWhen)读取按键。class RefBase:weakref_impl : public RefBase:weakref_type在系统启动后,android 会通过static const char *device_path = /dev/input;bool EventHub:openPlatformInput(void) res = scan_dir(device_path);通过下面的函数打开设备。int EventHub:open_device(const char *deviceName) . fd = open(deviceName, O_RDWR); . mFDsmFDCount.fd = fd; mFDsmFDCount.events = POLLIN; . ioctl(mFDsmFDCount.fd, EVIOCGNAME(sizeof(devname)-1), devname); . const char* root = getenv(ANDROID_ROOT); snprintf(keylayoutFilename, sizeof(keylayoutFilename), %s/usr/keylayout/%s.kl, root, tmpfn); . device-layoutMap-load(keylayoutFilename); .打开设备的时候,如果 device-classes&CLASS_KEYBOARD 不等于 0 表明是键盘。常用输入设备的定义有:enum CLASS_KEYBOARD = 0x00000001, /键盘 CLASS_ALPHAKEY = 0x00000002, / CLASS_TOUCHSCREEN = 0x00000004, /触摸屏 CLASS_TRACKBALL = 0x00000008 /轨迹球 ;打开键盘设备的时候通过上面的 ioctl 获得设备名称,命令字 EVIOCGNAME 的定义在文件:kernel/include/linux/input.h 中。#define EVIOCGNAME(len) _IOC(_IOC_READ, E, 0x06, len) /* get device name */在内核键盘驱动文件 drivers/input/keyboard/pxa27x_keypad.c 中定义了设备名称:pxa27x-keypadstatic struct platform_driver pxa27x_keypad_driver = .probe = pxa27x_keypad_probe, .remove = _devexit_p(pxa27x_keypad_remove), .suspend = pxa27x_keypad_suspend, .resume = pxa27x_keypad_resume, .driver = .name = pxa27
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 卫生事业单位年度考核个人总结
- 2025年城市环卫工人招聘考试知识点与模拟题解析
- 国际贸易质量安全保障措施
- (2025年标准)股东之间出资协议书
- (2025年标准)股东协议及退伙协议书
- (2025年标准)股东挂账协议书
- 合同违约起诉书范文
- 2025年建筑设计师招聘专业知识预测试题
- 2025年市场营销岗位招聘面试预测题及策略
- 2025年政策性金融招聘面试官揭秘常见面试题预测及备考建议
- 2025年统编版小升初语文阅读专项训练:点面结合(含答案)
- T-ZHHX 004-2024 粉苞酸脚杆盆花生产技术规范
- 无人机驾照考证知识题
- 心电监护的并发症及预防
- 生态经济学-杨建州-课件专题
- 香港借住合同范例
- 安全伴我行-大学生安全教育知到智慧树章节测试课后答案2024年秋哈尔滨工程大学
- 2025年蛇年年会汇报年终总结大会模板
- 存款代持协议书范文模板
- DB3301T 0374-2022 疗休养基地评价规范
- 胖东来企业文化指导手册
评论
0/150
提交评论