Step 8. InputDispatcher.notifyKey

这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:

  1. voidInputDispatcher::notifyKey(nsecs_teventTime,int32_tdeviceId,int32_tsource,
  2. uint32_tpolicyFlags,int32_taction,int32_tflags,
  3. int32_tkeyCode,int32_tscanCode,int32_tmetaState,nsecs_tdownTime){
  4. ......
  5. if(!validateKeyEvent(action)){
  6. return;
  7. }
  8. /*Accordingtohttp://source.android.com/porting/keymaps_keyboard_input.html
  9. *Keydefinitions:KeydefinitionsfollowthesyntaxkeySCANCODEKEYCODE[FLAGS...],
  10. *whereSCANCODEisanumber,KEYCODEisdefinedinyourspecifickeylayoutfile
  11. *(android.keylayout.xxx),andpotentialFLAGSaredefinedasfollows:
  12. *SHIFT:Whilepressed,theshiftkeymodifierisset
  13. *ALT:Whilepressed,thealtkeymodifierisset
  14. *CAPS:Whilepressed,thecapslockkeymodifierisset
  15. *SinceKeyEvent.javadoesn'tcheckifCaplockisONandwedon'thavea
  16. *modiferstateforcaplock,wewillnotsupportit.
  17. */
  18. if(policyFlags&POLICY_FLAG_ALT){
  19. metaState|=AMETA_ALT_ON|AMETA_ALT_LEFT_ON;
  20. }
  21. if(policyFlags&POLICY_FLAG_ALT_GR){
  22. metaState|=AMETA_ALT_ON|AMETA_ALT_RIGHT_ON;
  23. }
  24. if(policyFlags&POLICY_FLAG_SHIFT){
  25. metaState|=AMETA_SHIFT_ON|AMETA_SHIFT_LEFT_ON;
  26. }
  27. policyFlags|=POLICY_FLAG_TRUSTED;
  28. mPolicy->interceptKeyBeforeQueueing(eventTime,deviceId,action,/*byref*/flags,
  29. keyCode,scanCode,/*byref*/policyFlags);
  30. boolneedWake;
  31. {//acquirelock
  32. AutoMutex_l(mLock);
  33. int32_trepeatCount=0;
  34. KeyEntry*newEntry=mAllocator.obtainKeyEntry(eventTime,
  35. deviceId,source,policyFlags,action,flags,keyCode,scanCode,
  36. metaState,repeatCount,downTime);
  37. needWake=enqueueInboundEventLocked(newEntry);
  38. }//releaselock
  39. if(needWake){
  40. mLooper->wake();
  41. }
  42. }

函数首先是调用validateKeyEvent函数来验证action参数是否正确:

  1. staticboolisValidKeyAction(int32_taction){
  2. switch(action){
  3. caseAKEY_EVENT_ACTION_DOWN:
  4. caseAKEY_EVENT_ACTION_UP:
  5. returntrue;
  6. default:
  7. returnfalse;
  8. }
  9. }
  10. staticboolvalidateKeyEvent(int32_taction){
  11. if(!isValidKeyAction(action)){
  12. LOGE("Keyeventhasinvalidactioncode0x%x",action);
  13. returnfalse;
  14. }
  15. returntrue;
  16. }

正确的action参数的值只能为AKEY_EVENT_ACTION_DOWN(按下)或者AKEY_EVENT_ACTION_UP(松开)。

参数action检查通过后,还通过policyFlags参数来检查一下同时是否有ALT和SHIFT键被按下:

  1. if(policyFlags&POLICY_FLAG_ALT){
  2. metaState|=AMETA_ALT_ON|AMETA_ALT_LEFT_ON;
  3. }
  4. if(policyFlags&POLICY_FLAG_ALT_GR){
  5. metaState|=AMETA_ALT_ON|AMETA_ALT_RIGHT_ON;
  6. }
  7. if(policyFlags&POLICY_FLAG_SHIFT){
  8. metaState|=AMETA_SHIFT_ON|AMETA_SHIFT_LEFT_ON;
  9. }

最后,调用enqueueInboundEventLocked函数把这个按键事件封装成一个KeyEntry结构加入到InputDispatcher类的mInboundQueue队列中去:

  1. boolInputDispatcher::enqueueInboundEventLocked(EventEntry*entry){
  2. boolneedWake=mInboundQueue.isEmpty();
  3. mInboundQueue.enqueueAtTail(entry);
  4. switch(entry->type){
  5. caseEventEntry::TYPE_KEY:{
  6. KeyEntry*keyEntry=static_cast<KeyEntry*>(entry);
  7. if(isAppSwitchKeyEventLocked(keyEntry)){
  8. if(keyEntry->action==AKEY_EVENT_ACTION_DOWN){
  9. mAppSwitchSawKeyDown=true;
  10. }elseif(keyEntry->action==AKEY_EVENT_ACTION_UP){
  11. if(mAppSwitchSawKeyDown){
  12. <spanstyle="white-space:pre"></span>......
  13. mAppSwitchDueTime=keyEntry->eventTime+APP_SWITCH_TIMEOUT;
  14. mAppSwitchSawKeyDown=false;
  15. needWake=true;
  16. }
  17. }
  18. }
  19. break;
  20. }
  21. }
  22. returnneedWake;
  23. }

从这个函数我们可以看出,在两种情况下,它的返回值为true,一是当加入该键盘事件到mInboundQueue之前,mInboundQueue为空,这表示InputDispatccherThread线程正在睡眠等待InputReaderThread线程的唤醒,因此,它返回true表示要唤醒InputDispatccherThread线程;二是加入该键盘事件到mInboundQueue之前,mInboundQueue不为空,但是此时用户按下的是Home键,按下Home键表示要切换App,我们知道,在切换App时,新的App会把它的键盘消息接收通道注册到InputDispatcher中去,并且会等待InputReader的唤醒,因此,在这种情况下,也需要返回true,表示要唤醒InputDispatccherThread线程。如果不是这两种情况,那么就说明InputDispatccherThread线程现在正在处理前面的键盘事件,不需要唤醒它。

回到前面的notifyKey函数中,根据enqueueInboundEventLocked函数的返回值来决定是否要唤醒InputDispatccherThread线程:

  1. if(needWake){
  2. mLooper->wake();
  3. }

这里,假设needWake为true,于是,就会调用mLooper对象的wake函数来唤醒InputDispatccherThread线程了。Step 9. Looper.wake

这个函数定义在frameworks/base/libs/utils/Looper.cpp文件中,在前面一篇文章Android应用程序消息处理机制(Looper、Handler)分析中,我们已经分析过这个函数了,这里不再详述,简单来说,它的作用就是用来唤醒睡眠在Looper对象内部的管道读端的线程,在我们的这个场景中,睡眠在Looper对象内部的管道读端的线程就是InputDispatccherThread线程了。

从上面InputManager启动过程的Step 15中,我们知道,此时InputDispatccherThread线程正在InputDispatcher类的dispatchOnceb函数中通过调用mLooper->loopOnce函数进入睡眠状态。当它被唤醒以后,它就会从InputDispatcher类的dispatchOnceb函数返回到InputDispatcherThread类的threadLoop函数,而InputDispatcherThread类的threadLoop函数是循环执行的,于是,它又会再次进入到InputDispatcher类的dispatchOnce函数来处理当前发生的键盘事件。

Step 10.InputDispatcher.dispatchOnce

这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:

  1. voidInputDispatcher::dispatchOnce(){
  2. nsecs_tkeyRepeatTimeout=mPolicy->getKeyRepeatTimeout();
  3. nsecs_tkeyRepeatDelay=mPolicy->getKeyRepeatDelay();
  4. nsecs_tnextWakeupTime=LONG_LONG_MAX;
  5. {//acquirelock
  6. AutoMutex_l(mLock);
  7. dispatchOnceInnerLocked(keyRepeatTimeout,keyRepeatDelay,&nextWakeupTime);
  8. ......
  9. }//releaselock
  10. ......
  11. }

它调用dispatchOnceInnerLocked函数来进一步处理这个键盘事件。

更多相关文章

  1. Android UI 线程更新UI也会崩溃???
  2. android 测试读取LEB数据的函数
  3. Android如何快速打开系统软键盘和关闭系统软键盘
  4. android 自定义软键盘
  5. Android Activity 阻止软键盘自动弹出
  6. android软键盘的搜索按钮
  7. Android创建子线程和回调主线程的几种方式
  8. Android AlertDialog包含EditText,软键盘不能弹出的解决方法
  9. Android PopUpWindow 软键盘

随机推荐

  1. Android作为HTTP服务器--NanoHTTPD源码分
  2. Android 播放提示音
  3. android中调用相册里面的图片并返回
  4. 录音及播放音频文件
  5. jamendo_android 一个开源的Android在线
  6. android中的一个属性动画,可以显示更多的
  7. Android利用Looper在子线程中改变UI
  8. 编程回忆之Android回忆(Android应用参数的
  9. android 判断 网络 类型
  10. 如何把android设备中的固件dump出来