Android应用程序键盘(Keyboard)消息处理机制分析(16)
Step 8. InputDispatcher.notifyKey
这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:
- voidInputDispatcher::notifyKey(nsecs_teventTime,int32_tdeviceId,int32_tsource,
- uint32_tpolicyFlags,int32_taction,int32_tflags,
- int32_tkeyCode,int32_tscanCode,int32_tmetaState,nsecs_tdownTime){
- ......
- if(!validateKeyEvent(action)){
- return;
- }
- /*Accordingtohttp://source.android.com/porting/keymaps_keyboard_input.html
- *Keydefinitions:KeydefinitionsfollowthesyntaxkeySCANCODEKEYCODE[FLAGS...],
- *whereSCANCODEisanumber,KEYCODEisdefinedinyourspecifickeylayoutfile
- *(android.keylayout.xxx),andpotentialFLAGSaredefinedasfollows:
- *SHIFT:Whilepressed,theshiftkeymodifierisset
- *ALT:Whilepressed,thealtkeymodifierisset
- *CAPS:Whilepressed,thecapslockkeymodifierisset
- *SinceKeyEvent.javadoesn'tcheckifCaplockisONandwedon'thavea
- *modiferstateforcaplock,wewillnotsupportit.
- */
- if(policyFlags&POLICY_FLAG_ALT){
- metaState|=AMETA_ALT_ON|AMETA_ALT_LEFT_ON;
- }
- if(policyFlags&POLICY_FLAG_ALT_GR){
- metaState|=AMETA_ALT_ON|AMETA_ALT_RIGHT_ON;
- }
- if(policyFlags&POLICY_FLAG_SHIFT){
- metaState|=AMETA_SHIFT_ON|AMETA_SHIFT_LEFT_ON;
- }
- policyFlags|=POLICY_FLAG_TRUSTED;
- mPolicy->interceptKeyBeforeQueueing(eventTime,deviceId,action,/*byref*/flags,
- keyCode,scanCode,/*byref*/policyFlags);
- boolneedWake;
- {//acquirelock
- AutoMutex_l(mLock);
- int32_trepeatCount=0;
- KeyEntry*newEntry=mAllocator.obtainKeyEntry(eventTime,
- deviceId,source,policyFlags,action,flags,keyCode,scanCode,
- metaState,repeatCount,downTime);
- needWake=enqueueInboundEventLocked(newEntry);
- }//releaselock
- if(needWake){
- mLooper->wake();
- }
- }
函数首先是调用validateKeyEvent函数来验证action参数是否正确:
- staticboolisValidKeyAction(int32_taction){
- switch(action){
- caseAKEY_EVENT_ACTION_DOWN:
- caseAKEY_EVENT_ACTION_UP:
- returntrue;
- default:
- returnfalse;
- }
- }
- staticboolvalidateKeyEvent(int32_taction){
- if(!isValidKeyAction(action)){
- LOGE("Keyeventhasinvalidactioncode0x%x",action);
- returnfalse;
- }
- returntrue;
- }
正确的action参数的值只能为AKEY_EVENT_ACTION_DOWN(按下)或者AKEY_EVENT_ACTION_UP(松开)。
参数action检查通过后,还通过policyFlags参数来检查一下同时是否有ALT和SHIFT键被按下:
- if(policyFlags&POLICY_FLAG_ALT){
- metaState|=AMETA_ALT_ON|AMETA_ALT_LEFT_ON;
- }
- if(policyFlags&POLICY_FLAG_ALT_GR){
- metaState|=AMETA_ALT_ON|AMETA_ALT_RIGHT_ON;
- }
- if(policyFlags&POLICY_FLAG_SHIFT){
- metaState|=AMETA_SHIFT_ON|AMETA_SHIFT_LEFT_ON;
- }
最后,调用enqueueInboundEventLocked函数把这个按键事件封装成一个KeyEntry结构加入到InputDispatcher类的mInboundQueue队列中去:
- boolInputDispatcher::enqueueInboundEventLocked(EventEntry*entry){
- boolneedWake=mInboundQueue.isEmpty();
- mInboundQueue.enqueueAtTail(entry);
- switch(entry->type){
- caseEventEntry::TYPE_KEY:{
- KeyEntry*keyEntry=static_cast<KeyEntry*>(entry);
- if(isAppSwitchKeyEventLocked(keyEntry)){
- if(keyEntry->action==AKEY_EVENT_ACTION_DOWN){
- mAppSwitchSawKeyDown=true;
- }elseif(keyEntry->action==AKEY_EVENT_ACTION_UP){
- if(mAppSwitchSawKeyDown){
- <spanstyle="white-space:pre"></span>......
- mAppSwitchDueTime=keyEntry->eventTime+APP_SWITCH_TIMEOUT;
- mAppSwitchSawKeyDown=false;
- needWake=true;
- }
- }
- }
- break;
- }
- }
- returnneedWake;
- }
从这个函数我们可以看出,在两种情况下,它的返回值为true,一是当加入该键盘事件到mInboundQueue之前,mInboundQueue为空,这表示InputDispatccherThread线程正在睡眠等待InputReaderThread线程的唤醒,因此,它返回true表示要唤醒InputDispatccherThread线程;二是加入该键盘事件到mInboundQueue之前,mInboundQueue不为空,但是此时用户按下的是Home键,按下Home键表示要切换App,我们知道,在切换App时,新的App会把它的键盘消息接收通道注册到InputDispatcher中去,并且会等待InputReader的唤醒,因此,在这种情况下,也需要返回true,表示要唤醒InputDispatccherThread线程。如果不是这两种情况,那么就说明InputDispatccherThread线程现在正在处理前面的键盘事件,不需要唤醒它。
回到前面的notifyKey函数中,根据enqueueInboundEventLocked函数的返回值来决定是否要唤醒InputDispatccherThread线程:
- if(needWake){
- mLooper->wake();
- }
这里,假设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文件中:
- voidInputDispatcher::dispatchOnce(){
- nsecs_tkeyRepeatTimeout=mPolicy->getKeyRepeatTimeout();
- nsecs_tkeyRepeatDelay=mPolicy->getKeyRepeatDelay();
- nsecs_tnextWakeupTime=LONG_LONG_MAX;
- {//acquirelock
- AutoMutex_l(mLock);
- dispatchOnceInnerLocked(keyRepeatTimeout,keyRepeatDelay,&nextWakeupTime);
- ......
- }//releaselock
- ......
- }
它调用dispatchOnceInnerLocked函数来进一步处理这个键盘事件。
更多相关文章
- Android UI 线程更新UI也会崩溃???
- android 测试读取LEB数据的函数
- Android如何快速打开系统软键盘和关闭系统软键盘
- android 自定义软键盘
- Android Activity 阻止软键盘自动弹出
- android软键盘的搜索按钮
- Android创建子线程和回调主线程的几种方式
- Android AlertDialog包含EditText,软键盘不能弹出的解决方法
- Android PopUpWindow 软键盘