??Step 11.?InputDispatcher.dispatchOnceInnerLocked
?? ? ? ?這個(gè)函數(shù)定義在frameworks/base/libs/ui/InputDispatcher.cpp文件中:
void?InputDispatcher::dispatchOnceInnerLocked(nsecs_t?keyRepeatTimeout,??????nsecs_t?keyRepeatDelay,?nsecs_t*?nextWakeupTime)?{??????......????????????????????if?(!?mPendingEvent)?{??????????if?(mInboundQueue.isEmpty())?{??????????????......??????????}?else?{????????????????????????????EventEntry*?entry?=?mInboundQueue.headSentinel.next;????????????????......????????????????mInboundQueue.dequeue(entry);??????????????mPendingEvent?=?entry;??????????}????????????......??????}????????......????????switch?(mPendingEvent->type)?{??????......????????case?EventEntry::TYPE_KEY:?{??????????KeyEntry*?typedEntry?=?static_cast<KeyEntry*>(mPendingEvent);??????????......??????????done?=?dispatchKeyLocked(currentTime,?typedEntry,?keyRepeatTimeout,??????????????&dropReason,?nextWakeupTime);??????????break;?????????????????????????????????}????????......??????}????????......??}?? ?? ? ? ?我們忽略了這個(gè)函數(shù)的次要邏輯,主要關(guān)注鍵盤事件的主要處理流程。首先,如果前面發(fā)生的鍵盤事件都已經(jīng)處理完畢,那么這里的mPendingEvent就為NULL,又因?yàn)榍懊嫖覀儼褎倓偘l(fā)生的鍵盤事件加入了mInboundQueue隊(duì)列,因此,這里mInboundQueue不為NULL,于是,這里就把mInboundQueue隊(duì)列中的鍵盤事件取出來,放在mPendingEvent變量中:
mInboundQueue.dequeue(entry);??mPendingEvent?=?entry;?? ?? ? ? ?由于這里發(fā)生的是鍵盤事件,即mPendingEvent->type的值為EventEntry::TYPE_KEY,于是,在接下來的switch語句中就會(huì)執(zhí)行dispatchKeyLocked函數(shù)來分發(fā)鍵盤消息。
?
?? ? ? ?Step 12.?InputDispatcher.dispatchKeyLocked
?? ? ? ?這個(gè)函數(shù)定義在frameworks/base/libs/ui/InputDispatcher.cpp文件中:
bool?InputDispatcher::dispatchKeyLocked(??????????nsecs_t?currentTime,?KeyEntry*?entry,?nsecs_t?keyRepeatTimeout,??????????DropReason*?dropReason,?nsecs_t*?nextWakeupTime)?{??????......??????????????if?(!?mCurrentInputTargetsValid)?{??????????int32_t?injectionResult?=?findFocusedWindowTargetsLocked(currentTime,??????????????entry,?nextWakeupTime);????????????......??????}??????????????dispatchEventToCurrentInputTargetsLocked(currentTime,?entry,?false);??????return?true;??}?? ?? ? ? ? InputDispatcher類中的mCurrentInputTargetsValid成員變量表示InputDispatcher是否已經(jīng)標(biāo)志出誰是當(dāng)前激活的Activity窗口,如果沒有,就需要通過findFocusedWindowTargetsLocked函數(shù)來把它找出來。當(dāng)把當(dāng)前激活的Activity窗口找出來以后,接下來就調(diào)用dispatchEventToCurrentInputTargetsLocked函數(shù)把鍵盤事件分發(fā)給它了。
?
?? ? ? ?我們先來看一InputDispatcher是如何找到當(dāng)前激活的Activity窗口的,然后再分析它把鍵盤事件分發(fā)給當(dāng)前激活A(yù)ctivity窗口的過程。
?? ? ? ?Step 13.?InputDispatcher.findFocusedWindowTargetsLocked
?? ? ? ?這個(gè)函數(shù)定義在frameworks/base/libs/ui/InputDispatcher.cpp文件中:
int32_t?InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t?currentTime,??????????const?EventEntry*?entry,?nsecs_t*?nextWakeupTime)?{??????mCurrentInputTargets.clear();????????int32_t?injectionResult;????????????????????if?(!?mFocusedWindow)?{??????????if?(mFocusedApplication)?{??????????????......??????????????injectionResult?=?handleTargetsNotReadyLocked(currentTime,?entry,??????????????????mFocusedApplication,?NULL,?nextWakeupTime);??????????????goto?Unresponsive;??????????}????????????......??????????injectionResult?=?INPUT_EVENT_INJECTION_FAILED;??????????goto?Failed;??????}??????????????if?(!?checkInjectionPermission(mFocusedWindow,?entry->injectionState))?{??????????injectionResult?=?INPUT_EVENT_INJECTION_PERMISSION_DENIED;??????????goto?Failed;??????}??????????????if?(mFocusedWindow->paused)?{??????????......??????????injectionResult?=?handleTargetsNotReadyLocked(currentTime,?entry,??????????????mFocusedApplication,?mFocusedWindow,?nextWakeupTime);??????????goto?Unresponsive;??????}??????????????if?(!?isWindowFinishedWithPreviousInputLocked(mFocusedWindow))?{??????????......??????????injectionResult?=?handleTargetsNotReadyLocked(currentTime,?entry,??????????????mFocusedApplication,?mFocusedWindow,?nextWakeupTime);??????????goto?Unresponsive;??????}??????????????injectionResult?=?INPUT_EVENT_INJECTION_SUCCEEDED;??????addWindowTargetLocked(mFocusedWindow,?InputTarget::FLAG_FOREGROUND,?BitSet32(0));????????......????????return?injectionResult;??}?? ?? ? ? ?回憶前面我們分析應(yīng)用程序注冊(cè)鍵盤消息接收通道的過程時(shí),在Step 9中,當(dāng)前處于激活狀態(tài)的應(yīng)用程序會(huì)通過調(diào)用InputDispatcher類setInputWindows函數(shù)把把當(dāng)前獲得焦點(diǎn)的Activity窗口設(shè)置到mFocusedWindow中去,因此,這里的mFocusedWindow不為NULL,于是,就通過了第一個(gè)if語句的檢查。
?
?? ? ? ?第二個(gè)if語句檢查權(quán)限問題,原來,這個(gè)鍵盤事件除了是由硬件觸發(fā)的外,也可以由其它進(jìn)程注入進(jìn)來的,如果這個(gè)鍵盤事件是由其它進(jìn)程注入進(jìn)來的,那么entry->injectState就不為NULL,它里面包含了事件注冊(cè)者的進(jìn)程ID和用戶ID,于是,這里就會(huì)調(diào)用checkInjectionPermission來檢查這個(gè)事件注入者的進(jìn)程ID和用戶ID,看看它是否具有這個(gè)權(quán)限。這里我們不考慮這種情況,因此,這里的entry->injectState為NULL,于是,這個(gè)if語句的檢查也通過了。
?? ? ? ?第三個(gè)if語句檢查當(dāng)前激活的Activity窗口是否是處于paused狀態(tài),如果是的話,也不用進(jìn)一步處理了。一般情況下,當(dāng)前激活的Activity窗口都是處于resumed狀態(tài)的,于是,這個(gè)if語句的檢查也通過了。
?? ? ? ?第四個(gè)if語句檢查當(dāng)前激活的Activity窗口是否還正在處理前一個(gè)鍵盤事件,如果是的話,那就要等待它處理完前一個(gè)鍵盤事件后再來處理新的鍵盤事件了。這里我們也假設(shè)當(dāng)前激活的Activity窗口不是正在處理前面的鍵盤事件,因此,這個(gè)if語句的檢查也通過了。
?? ? ? ?最后,就調(diào)用addWindowTargetLocked函數(shù)把當(dāng)前激活的Activity窗口添加到InputDispatcher類的mCurrentInputTargets成員變量中去。
?? ? ? ?Step 14.?InputDispatcher.addWindowTargetLocked
?? ? ? ?這個(gè)函數(shù)定義在frameworks/base/libs/ui/InputDispatcher.cpp文件中:
void?InputDispatcher::addWindowTargetLocked(const?InputWindow*?window,?int32_t?targetFlags,??????????BitSet32?pointerIds)?{??????mCurrentInputTargets.push();????????InputTarget&?target?=?mCurrentInputTargets.editTop();??????target.inputChannel?=?window->inputChannel;??????target.flags?=?targetFlags;??????target.xOffset?=?-?window->frameLeft;??????target.yOffset?=?-?window->frameTop;??????target.pointerIds?=?pointerIds;??}?? ?? ? ? ?這個(gè)函數(shù)簡(jiǎn)單,就是把傳進(jìn)來的參數(shù)window添加到mCurrentInputTargets中去就完事了,后面InputDispatcher就會(huì)從mCurrentInputTargets中取出恰當(dāng)?shù)腁ctivity窗口,然后把鍵盤事件分發(fā)給它。
?? ? ? ?回到Step 12中的dispatchKeyLocked函數(shù),它接下來就調(diào)用dispatchEventToCurrentInputTargetsLocked來進(jìn)一步處理了。
?? ? ? ?Step 15.?InputDispatcher.dispatchEventToCurrentInputTargetsLocked
?? ? ? ?這個(gè)函數(shù)定義在frameworks/base/libs/ui/InputDispatcher.cpp文件中:
void?InputDispatcher::dispatchEventToCurrentInputTargetsLocked(nsecs_t?currentTime,??????????EventEntry*?eventEntry,?bool?resumeWithAppendedMotionSample)?{?????......???????for?(size_t?i?=?0;?i?<?mCurrentInputTargets.size();?i++)?{?????????const?InputTarget&?inputTarget?=?mCurrentInputTargets.itemAt(i);???????????ssize_t?connectionIndex?=?getConnectionIndexLocked(inputTarget.inputChannel);?????????if?(connectionIndex?>=?0)?{?????????????sp<Connection>?connection?=?mConnectionsByReceiveFd.valueAt(connectionIndex);?????????????prepareDispatchCycleLocked(currentTime,?connection,?eventEntry,?&?inputTarget,?????????????????resumeWithAppendedMotionSample);?????????}?else?{?????????????......?????}??}?? ?? ? ? ?這個(gè)函數(shù)的實(shí)現(xiàn)也比較簡(jiǎn)單,前面我們已經(jīng)把當(dāng)前需要接受鍵盤事件的Activity窗口添加到mCurrentInputTargets中去了,因此,這里就分別把它們?nèi)〕鰜?#xff0c;然后調(diào)用prepareDispatchCycleLocked函數(shù)把鍵盤事件分發(fā)給它們處理。
?
?? ? ? ?前面我們?cè)诜治鰬?yīng)用程序注冊(cè)鍵盤消息接收通道的過程時(shí),在Step 18中(InputDispatcher.registerInputChannel),把Server端的InputChannel封裝成了一個(gè)Connection,然后以這個(gè)InputChannel中的Receive Pipe Fd作為鍵值把這個(gè)Connection對(duì)象保存在mConnectionsByReceiveFd中。這里,既然我們已經(jīng)通過mCurrentInputTargets得到了表示當(dāng)前需要接收鍵盤事件的Activity窗口的InputTarget對(duì)象,而且這個(gè)InputTarget對(duì)象的inputChannel就表示當(dāng)初在InputDispatcher中注冊(cè)的Server端InputChannel,因此,這里就可以把這個(gè)Connection對(duì)象取出來,最后調(diào)用prepareDispatchCycleLocked函數(shù)來進(jìn)一步處理。
轉(zhuǎn)載于:https://blog.51cto.com/shyluo/966635
總結(jié)
以上是生活随笔為你收集整理的Android应用程序键盘(Keyboard)消息处理机制分析(17)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。