??Step 11.?InputDispatcher.dispatchOnceInnerLocked
?? ? ? ?這個函數定義在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;?????????????????????????????????}????????......??????}????????......??}?? ?? ? ? ?我們忽略了這個函數的次要邏輯,主要關注鍵盤事件的主要處理流程。首先,如果前面發生的鍵盤事件都已經處理完畢,那么這里的mPendingEvent就為NULL,又因為前面我們把剛剛發生的鍵盤事件加入了mInboundQueue隊列,因此,這里mInboundQueue不為NULL,于是,這里就把mInboundQueue隊列中的鍵盤事件取出來,放在mPendingEvent變量中:
mInboundQueue.dequeue(entry);??mPendingEvent?=?entry;?? ?? ? ? ?由于這里發生的是鍵盤事件,即mPendingEvent->type的值為EventEntry::TYPE_KEY,于是,在接下來的switch語句中就會執行dispatchKeyLocked函數來分發鍵盤消息。
?
?? ? ? ?Step 12.?InputDispatcher.dispatchKeyLocked
?? ? ? ?這個函數定義在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是否已經標志出誰是當前激活的Activity窗口,如果沒有,就需要通過findFocusedWindowTargetsLocked函數來把它找出來。當把當前激活的Activity窗口找出來以后,接下來就調用dispatchEventToCurrentInputTargetsLocked函數把鍵盤事件分發給它了。
?
?? ? ? ?我們先來看一InputDispatcher是如何找到當前激活的Activity窗口的,然后再分析它把鍵盤事件分發給當前激活Activity窗口的過程。
?? ? ? ?Step 13.?InputDispatcher.findFocusedWindowTargetsLocked
?? ? ? ?這個函數定義在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;??}?? ?? ? ? ?回憶前面我們分析應用程序注冊鍵盤消息接收通道的過程時,在Step 9中,當前處于激活狀態的應用程序會通過調用InputDispatcher類setInputWindows函數把把當前獲得焦點的Activity窗口設置到mFocusedWindow中去,因此,這里的mFocusedWindow不為NULL,于是,就通過了第一個if語句的檢查。
?
?? ? ? ?第二個if語句檢查權限問題,原來,這個鍵盤事件除了是由硬件觸發的外,也可以由其它進程注入進來的,如果這個鍵盤事件是由其它進程注入進來的,那么entry->injectState就不為NULL,它里面包含了事件注冊者的進程ID和用戶ID,于是,這里就會調用checkInjectionPermission來檢查這個事件注入者的進程ID和用戶ID,看看它是否具有這個權限。這里我們不考慮這種情況,因此,這里的entry->injectState為NULL,于是,這個if語句的檢查也通過了。
?? ? ? ?第三個if語句檢查當前激活的Activity窗口是否是處于paused狀態,如果是的話,也不用進一步處理了。一般情況下,當前激活的Activity窗口都是處于resumed狀態的,于是,這個if語句的檢查也通過了。
?? ? ? ?第四個if語句檢查當前激活的Activity窗口是否還正在處理前一個鍵盤事件,如果是的話,那就要等待它處理完前一個鍵盤事件后再來處理新的鍵盤事件了。這里我們也假設當前激活的Activity窗口不是正在處理前面的鍵盤事件,因此,這個if語句的檢查也通過了。
?? ? ? ?最后,就調用addWindowTargetLocked函數把當前激活的Activity窗口添加到InputDispatcher類的mCurrentInputTargets成員變量中去。
?? ? ? ?Step 14.?InputDispatcher.addWindowTargetLocked
?? ? ? ?這個函數定義在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;??}?? ?? ? ? ?這個函數簡單,就是把傳進來的參數window添加到mCurrentInputTargets中去就完事了,后面InputDispatcher就會從mCurrentInputTargets中取出恰當的Activity窗口,然后把鍵盤事件分發給它。
?? ? ? ?回到Step 12中的dispatchKeyLocked函數,它接下來就調用dispatchEventToCurrentInputTargetsLocked來進一步處理了。
?? ? ? ?Step 15.?InputDispatcher.dispatchEventToCurrentInputTargetsLocked
?? ? ? ?這個函數定義在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?{?????????????......?????}??}?? ?? ? ? ?這個函數的實現也比較簡單,前面我們已經把當前需要接受鍵盤事件的Activity窗口添加到mCurrentInputTargets中去了,因此,這里就分別把它們取出來,然后調用prepareDispatchCycleLocked函數把鍵盤事件分發給它們處理。
?
?? ? ? ?前面我們在分析應用程序注冊鍵盤消息接收通道的過程時,在Step 18中(InputDispatcher.registerInputChannel),把Server端的InputChannel封裝成了一個Connection,然后以這個InputChannel中的Receive Pipe Fd作為鍵值把這個Connection對象保存在mConnectionsByReceiveFd中。這里,既然我們已經通過mCurrentInputTargets得到了表示當前需要接收鍵盤事件的Activity窗口的InputTarget對象,而且這個InputTarget對象的inputChannel就表示當初在InputDispatcher中注冊的Server端InputChannel,因此,這里就可以把這個Connection對象取出來,最后調用prepareDispatchCycleLocked函數來進一步處理。
轉載于:https://blog.51cto.com/shyluo/966635
總結
以上是生活随笔為你收集整理的Android应用程序键盘(Keyboard)消息处理机制分析(17)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。