爱踢门之锤子自由截屏快捷键配置(中)
16lz
2021-12-04
Android输入系统
Android输入事件分发
上一篇已经分析完linux事件到android事件的转化,事件已经在队列上,下面就是读取数据并分发了,整个过程如下:
InputDispatcherThread::~InputDispatcherThread() {}bool InputDispatcherThread::threadLoop() { mDispatcher->dispatchOnce(); return true;}void InputDispatcher::dispatchOnce() { { // acquire lock if (!haveCommandsLocked()) { //分发事件 dispatchOnceInnerLocked(&nextWakeupTime); } } // release lock //等待事件 mLooper->pollOnce(timeoutMillis);}void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {if (! mPendingEvent) { //从队列中读取下一个事件 mPendingEvent = mInboundQueue.dequeueAtHead(); } switch (mPendingEvent->type) { //只分析key事件 case EventEntry::TYPE_KEY: { KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent); done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); break; } }}bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) { // 这个逻辑很重要,是我们实现快捷键动态配置的关键逻辑 if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) { if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) { // doInterceptKeyBeforeDispatchingLockedInterruptible很重要 CommandEntry* commandEntry = postCommandLocked( & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible); if (mFocusedWindowHandle != NULL) { commandEntry->inputWindowHandle = mFocusedWindowHandle; } commandEntry->keyEntry = entry; entry->refCount += 1; return false; // wait for the command to run } else { entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE; } } Vector<InputTarget> inputTargets; //只有focused window对象才能接收key事件,这也是为什么android系统,按back,menu //只是当前最top的程序响应的原因 int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime, entry, inputTargets, nextWakeupTime); if (injectionResult == INPUT_EVENT_INJECTION_PENDING) { return false; } //monitor对象会接收所有key事件 addMonitoringTargetsLocked(inputTargets); // 真正将key分发给应用,这里的inputTargets就是应用程序的window在native input //对应的对象 dispatchEventLocked(currentTime, entry, inputTargets); return true;}void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible( CommandEntry* commandEntry) { // interceptKeyBeforeDispatching给了java层一个机会去提前处理事件 //由于有返回值,则同时可以达到丢弃该事件的效果,因此该函数也可以很好的 //用来实现快捷键的动态配置 delay = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle, &event, entry->policyFlags); mLock.lock(); if (delay < 0) { //丢弃该事件 entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_SKIP; } else if (!delay) { entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE; } else { entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER; entry->interceptKeyWakeupTime = now() + delay; } entry->release();}void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) { for (size_t i = 0; i < inputTargets.size(); i++) { const InputTarget& inputTarget = inputTargets.itemAt(i); ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel); if (connectionIndex >= 0) { //我们知道,这里的代码运行在系统进程(system_server),而应用程序运行在 //的进程中,要传递按键信息肯定需要有跨进程的消息传递机制,下面的 //connection就是为了传递输入事件而建立的一个跨进程传递信息的一个对象 //它的具体实现将在后面的章节详细讲解 sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex); prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget); } else { } }}void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) { enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);}void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime, const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) { bool wasEmpty = connection->outboundQueue.isEmpty(); // Enqueue dispatch entries for the requested modes. enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_OUTSIDE); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_IS); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER); // If the outbound queue was previously empty, start the dispatch cycle going. if (wasEmpty && !connection->outboundQueue.isEmpty()) { startDispatchCycleLocked(currentTime, connection); }}void InputDispatcher::enqueueDispatchEntryLocked( const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget, int32_t dispatchMode) { //将EventEntry封装成DispatchEntry DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, // increments ref inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset, inputTarget->scaleFactor); // 将事件添加到window的connection的事件队列里 connection->outboundQueue.enqueueAtTail(dispatchEntry);}
到此为止,system层对事件的处理都完成了。总的说来就是system 从linux设备读取事件,然后翻译成android的事件,然后找到事件的对象(获取到焦点的程序),并将此事件放到window对象的connection队列上。大家很容易想到,程序端获取事件的大致流程肯定是:Connection在程序端的代理读取connection server端队列中的事件,并将事件发送到事件处理逻辑。
Connection的建立和数据发送及程序端的事件处理会在后面的章节里详细讲解。
/********************************
* 本文来自博客 “爱踢门”
* 转载请标明出处:http://blog.csdn.net/itleaks
******************************************/
更多相关文章
- 类和 Json对象
- Service与Android系统实现(1)-- 应用程序里的Service
- Android事件处理的两种模型
- Android(安卓)中文 API (102)―― CursorAdapter
- Android消息机制分析
- Android(安卓)Keyboard/Touch Panel分析
- Android(安卓)监听软键盘弹起和收起事件
- android 按键
- Android事件处理第一节(View对Touch事件的处理)