前言
前面其实也有提到EventHub的构造函数,里面就是创建epoll实例,然后把一些事件触发的文件描述符加入到epoll里面统一管理。
EventHub
是服务于InputReader
线程的,前面在InputRead的构造函数里面有创建EventHub的实例。
InputReader线程
InputReader
线程主要就是查看threadLoop
接口中代码的实现,threadLoop
返回值是true代表的是会不断的循环,返回false的话就不会继续在调用threadLoop
函数。
1 | bool InputReaderThread::threadLoop() { |
不停的调用InputReader
的loopOnce
函数
loopOnce函数
InputReader.cpp
1 | void InputReader::loopOnce() { |
两个关键的地方,从注释可以很明确的看出来,首先是获取到底层的input事件,处理事件,然后发送到InputDispatcher
线程
mEventHub->getEvents
processEventsLocked(mEventBuffer, count)
mQueuedListener->flush
EventHub->getEvents
EventHub.cpp
1 | size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) { |
虽然精简了代码还是比较长,主要是以下几点:
- EventHub是采用了INotify和epoll机制监听目录
/dev/input
下设备节点,当有IO事件,会通过epoll_wait返回事件的详细信息 - 当epoll_wait被返回有IO数据的时候,通过read函数读取input事件的数据
- 把input_event结构体转化为RawEvent事件
InputEventReader.h
1 | struct input_event { |
事件类型:
- DEVICE_ADD
- DEVICE_REMOVED
- FINISHED_DEVICE_SCAN
- type
InputReader->processEventsLocked
InputReader.cpp
1 | void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) { |
主要是根据不同的事件类型做不同的处理,我们比较关注对数据的处理,主要是看这个函数processEventsForDeviceLocked
事件处理 processEventsForDeviceLocked
1 | void InputReader::processEventsForDeviceLocked(int32_t deviceId, |
通过deviceId
来获取合适的InputDevice
,InputDevice
是当检测到/dev/input/
下有设备节点添加的时候创建的
调用对应的device
的process函数
1 | void InputDevice::process(const RawEvent* rawEvents, size_t count) { |
这里处理输入事件主要是把Linux下发送过来的RawEvent转化为Android 的Key Event和Key Code,在Android中不同的输入设备对应不同的Key Layout文件,这里就是选择对应的kl文件来处理。
下面专门针对按键的事件处理跟一下流程。
按键事件处理流程
InputReader.cpp
KeyBoardInputMapper->process
1 | void KeyboardInputMapper::process(const RawEvent* rawEvent) { |
通过mapKey函数获取对应scanCode的Android Key Code
EventHub.cpp
1 | status_t EventHub::mapKey(int32_t deviceId, |
真正干活做转换的是KeyCharacterMap::mapKey
函数。
InputReader.cpp
InputMapper->processKey
1 | void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode, |
mKeyDowns
记录着所有按下的键mDownTime
记录按下时间点KeyboardInputMapper
的mContext
指向InputReader
,getListener()
获取mQueuedListener
,然后调用notifyKey
接口
InputListener.cpp
1 | void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) { |
把事件放入向量mArgsQueue
,然后就是把事件发送给InputDispatcher线程了
发送事件 QueuedInputListener->flush
InputListener.cpp
1 | void QueuedInputListener::flush() { |
遍历刚才的向量,调用对应的notify接口,NotifyArgs
的实现子类包含:
- NotifyConfigurationChangedArgs
- NotifyKeyArgs
- NotifyMotionArgs
- NotifySwitchArgs
- NotifyDeviceResetArgs
1 | void NotifyKeyArgs::notify(const sp<InputListenerInterface>& listener) const { |
InputDispatcher.cpp
1 | void InputDispatcher::notifyKey(const NotifyKeyArgs* args) { |
主要完成以下几个事情:
- 调用
NativeInputManager.interceptKeyBeforeQueueing
,加入队列前执行拦截动作,但并不改变流程-
IMS.interceptKeyBeforeQueueing
-
InputMonitor.interceptKeyBeforeQueueing
(继承IMS.WindowManagerCallbacks
) -
PhoneWindowManager.interceptKeyBeforeQueueing
(继承WindowManagerPolicy
)
-
- 当
mInputFilterEnabled=true
(该值默认为false
,可通过setInputFilterEnabled
设置),则调用NativeInputManager.filterInputEvent
过滤输入事件- 当返回值为
false
则过滤事件,不往下发
- 当返回值为
- 生成
KeyEvent
,并调用enqueueInboundEventLocked
,把事件加入到InputDispatchered
的成员变量mInboundQueue
。 - 唤醒
InputDispatcher
线程
1 | void Looper::wake() { |
InputDispatcher
线程主要是用来跟JAVA层的IMS和WMS通信的,给JAVA层IMS上报输入事件,找到对应的Window。