现在的位置: 首页 > 综合 > 正文

GWES输入路径分析

2017年12月24日 ⁄ 综合 ⁄ 共 2088字 ⁄ 字号 评论关闭

1 输入路径的一般原理
按键,鼠标消息从收集到最终发送到焦点窗口?可分为不同的情况进行判定:
(1)用户输入根据系统状况是否应该派送。
(2)是否有拦截Listener
(3)对按键事件来讲,是否存在输入法
(4)是否是焦点终点
(5)是否为焦点切换相关键
1.1 一般的输入路径设计

从活动主窗口到焦点窗口。

信息输入路径分为两步:
Step 1)窗口管理器将信息发送到活动窗口
Step 2)活动窗口通过缺省处理函数将该消息一层层的传递到焦点。
应用程序可以在活动View 的处理函数中来预先处理用户输入信息,从而增强用户信息的控制力。

传递路径是通过View 的缺省处理函数Onxxx 来完成。通过ActiveView ->focus->focus->focus的链条关系,一级一级的将按键消息MSG_KEYDOWN,MSG_KEYUP, MSG_CHAR 等传递到focus窗口。

此时用户按键输入先发送到输入法窗口,经过输入法管理器处理,过滤后将输入法产生的结果放置到焦点View。
1.3 输入系统整体流程
下面示意图是Android 输入系统的数据流途径,通过WM 的输入系统线程收集消息,分发到Focus Activity 消息队列,然后通过消息系统派发。

2 Android 输入路径详细描述
2.1 第一步:用户数据收集及其初步判定
KeyInputQ在WindowMangerService中建立一个独立的线程InputDeviceReader,使用Native函数readEvent 来读取Linux Driver的数据构建RawEvent,放入到KeyQ 消息队列中。

preProcessEvent()@KeyInptQ@KeyInputQueue.java 这个是在输入系统中的第一个拦截函数原型。KeyQ 重载了preProcessEvent()@WindowManagerService.java。在该成员函数中进行如
下动作:
(1) 根据PowerManager获取的Screen on,Screen off 状态来判定用户输入的是否
WakeUPScreen。
(2) 如果按键是应用程序切换按键,则切换应用程序。
(3) 根据WindowManagerPolicy 决定该用户输入是否投递。
2.2 第二步消息分发第一层面
InputDispatcherThread从KeyQ 中读取Events,找到Window Manager 中的Focus Window,通过Focus Window 记录的mClient 接口,将Events 传递到Client 端。

如何将KeyEvent对象传到Client 端:
在客户端建立Window Manager Proxy 后,添加窗口到Window Manager service 时,传递了一个跟客户ViewRoot 相关的IWindow 接口实例过去,记录在WindowState 中的mClient 成员变量中。
通过IWindow 这个AIDL 接口实例,Service 可以访问客户端的信息,IWindow 是Service 连接View 桥梁。

看看在Client ViewRootKeyEvent 的分发过程
IWindow:dispatchKey(event)
ViewRoot.dispatchKey(event)@ViewRoot.java
sendMessageAtTime(msg) @Handler.java
Looper,Handler,Key Message 已经放入到应用程序的消息队列。

2.3 第三步:应用消息队列分发
消息的分发,Looper.loop()在最后调用了
handleMesage.

ActivityThread.main()
Looper.loop()
ViewRoot$RootHandler().dispatch()
handleMessage
....

handlerMessage @ViewRoot.java
deliverkeyEvent
如果输入法存在,dispatchKey到输入法服务。否则deliverKeyEventToViewHierarchy @ViewRoot.java
输入法的KeyEvent 的拦截并没有放入到Window ManagerService 中,而是放入到了客户端的RootView 中来处理。
2.4 第四步:向焦点进发,完成焦点路径的遍历。

分发函数调用栈
deliverKeyEventToViewHierarchy @ViewRoot.java
mView.dispatchKeyEvent @ViewGroup  
mView是与ViewRoot 相对应的Top-Level View.如果mView 是一个ViewGroup则分发消息到他的mFocus。
Event.dispatch
mFocus.dispatchKeyEevent
如果此时的mFocu 还是一个ViewGroup,将事件专递到下一层的焦点,直到mFocus为一个View。通过这轮调用,就遍历了焦点Path,至此,用户事件传递完成一个段落。
2.5 第五步缺省处理
如果事件在上述Focus View 没有处理掉,并且为方向键之类的焦点转换相关按键,则转移焦点到下一个View。

抱歉!评论已关闭.