输入事件的分发

2016-2-25 chenhui 输入系统

流程:

  1. InputReader 线程通过 EventHub 监听 /dev/input 内的文件
  2. InputReader 得到输入事件,封装后存入 InputDispatcher 的队列
  3. 唤醒 InputDispatcher 
  4. InputDispatcher 取出输入事件,并传递给 Window



在 输入事件的读取 这篇文章中,我们看到了 InputReader 是怎么从 EventHub 中读出输入事件的,我们重新回顾一下 loopOnce() 这个方法:


void InputReader::loopOnce() {
    ...
    mEventHub->getEvents(timeoutMillis,& rawEvent,EVENT_BUFFER_SIZE);
 
    if(count) {
       // 得到事件,进行处理
       processEventsLocked(rawEvent, count);
    }
 
    // 把事件交给 InputDispatcher 
    mQueuedListener->flush();
}


在我们从 getEvents() 中读出输入事件后,接下来就会调用 processEventsLocked() 进行处理,processEventsLocked() 把事件进行封装并存放到 mQueuedListener 的 mArgQueue 这个数组里,然后我们直接来看 mQueuedListener->flush() 这个方法,在这个方法中输入事件会提交给 InputDispatcher。


这里的 mQueuedListener 是 InputReader 在实例化的时候产生的:


InputReader::InputReader(const sp<EventHubInterface>& eventHub,
        const sp<InputReaderPolicyInterface>& policy,
        const sp<InputListenerInterface>& listener) :
        mContext(this), mEventHub(eventHub), mPolicy(policy),
        mGlobalMetaState(0),mDisableVirtualKeysTimeout(LLONG_MIN),mNextTimeout(LLONG_MAX),
        mConfigurationChangesToRefresh(0) {
    mQueuedListener = new QueuedInputListener(listener);

    ...
}


然后我们再来看看 flush() 里都做了些什么:


void QueuedInputListener::flush() {
    size_t count = mArgsQueue.size();
    for (size_t i = 0; i < count; i++) {
        NotifyArgs* args = mArgsQueue[i];
        args->notify(mInnerListener);
        delete args;
    }
    mArgsQueue.clear();
}


他遍历 mArgsQueue 数组里的对象并调用他们的 notify() 方法,这些对象就是我们在 processEventsLocked() 里放进去的那些事件,继续往下看:


void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const {
     listener->notifyMotion(this);
}


这里的 listener 就是 InputReader 在实例化 QueuedInputListener 时传入的 listener,而 InputReader 的 listener 又是 InputManager 实例化 InputReader 时传入的,他传入的那个对象的对象名叫 mDispatcher。没错,就是实例化 InputReader 时同时创建的另一个对象——InputDispatcher 对象。


是不是很神奇!!没错!InputReader 对象就是调用 InputDispatcher 的 notifyMotion 方法实现传递输入事件的功能的!

接下来再来看看 notifyMotion 的实现:


void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {

	...

	MotionEntry* newEntry = new MotionEntry(args->eventTime,
			args->deviceId, args->source, policyFlags,
			args->action, args->flags, args->metaState, args->buttonState,
			args->edgeFlags,args->xPrecision,args->yPrecision,args->downTime,
			args->pointerCount, args->pointerProperties, args->pointerCoords);

	needWake = enqueueInboundEventLocked(newEntry);

	if (needWake) {
		mLooper->wake();
	}
}


notifyMotion 把事件封装成 MotionEntry 对象并放入队列,这个 needWake 变量,只要成功插入,或者队列里不为空,就一定为 true,既然队列里有事件,那肯定就要唤醒 InputDispatcher 对象的线程了。


bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
    
    ...
	
    //插入
    mInboundQueue.enqueueAtTail(entry);

    ...

    return needWake;
}


事件被插入了名为 mInboundQueue 的队列,

InputDispatcher 线程被唤醒后,都干了些什么事呢?


bool InputDispatcherThread::threadLoop() {
    mDispatcher->dispatchOnce();
    return true;
}


和 InputReader 相似,InputDispatcher 调用的是他的 dispatchOnce() 方法:


void InputDispatcher::dispatchOnce() {

    dispatchOnceInnerLocked(&nextWakeupTime);
    mLooper->pollOnce(timeoutMillis);
}


事件就在 dispatchOnceInnerLocked() 这个方法里,被传递给 Window :


void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
    nsecs_t currentTime = now();
	
    // 有未处理的事件
    if (! mPendingEvent) {
        if (mInboundQueue.isEmpty()) {
            ...
      
        } else {
            
	    // 取出一个事件
            EventEntry* entry = mInboundQueue.head;

            ...
			
	    // 把事件从队列中摘除
            mInboundQueue.dequeue(entry);
			
	    // 让 mPendingEvent 指向该事件
            mPendingEvent = entry;
        }

        ...
    }
	
    // 根据事件的类型做不同处理,但最后结果都一样,都是调用 dispatchKeyLocked
    // dispatchKeyLocked 会把事件发送给 Window
    switch (mPendingEvent->type) {
		
    ...
	
    case EventEntry::TYPE_KEY: {
        KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
        ...
        done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
        break;
    }

    case EventEntry::TYPE_MOTION: {
        MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
        ...
        done = dispatchMotionLocked(currentTime, typedEntry,
                &dropReason, nextWakeupTime);
        break;
    }

    ....
}


至于 dispatchMotionLocked() 是怎么处理的,就不继续往下分析了,总之最后会把消息送给最前Activity的ViewRoot对象,再由应用程序进行处理。






发表评论:

Copyright ©2015-2016 freehui All rights reserved