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
******************************************/