Android的frameworks层键盘事件处理流程分析

本文详细解析了Android系统的事件处理流程,包括InputManager如何读取事件,并将其传递给WindowManagerService,以及事件如何被分发到最前端的窗口。同时介绍了事件拦截处理的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

事件处理流程
1)InputManager负责读取事件并把事件送到frameworks的java层
2)WindowManagerService里会有一个InputMonitor类来监听事件变化并做相应的分发处理。
3)在WindowManagerService会有一个WindowManagerPolicy来做消息拦截处理。
4)WindowManagerService会把消息发给最上面运行的窗口接收

源码分析
WindowManagerService.java主要向 Android 为窗口系统提供服务,把KeyEvent分发给最上层的窗口;
WindowManagerService通过InputManager提供的native接口开启了两个线程驱动做KeyEvent读取和分发给WindowManagerService管理的客户端。
mInputManager = new InputManager(context, this);
mInputManager.start();

InputManager是WindowManagerService的成员变量,主要实现了读取RawEvent,分发事件给WindowManagerService;
InputManager.java的native代码InputManager.cpp实现了读取和事件分发,他初始化两个线程
void InputManager::initialize() {
    mReaderThread = new InputReaderThread(mReader);//不断地从/dev/input/目录下面的设备文件读取事件
    mDispatcherThread = new InputDispatcherThread(mDispatcher);//事件分发
}
InputManager通过InputManager.Callbacks类响应回调,在回调里再调用WindowManagerService.InputMonitor来接收事件。并在WindowManagerService.InputMonitor.interceptKeyBeforeQueueing()和 interceptKeyBeforeDispatching()进行消息拦截处理。处理的代码如下:
WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager();
        /* Provides an opportunity for the window manager policy to intercept early key
         * processing as soon as the key has been read from the device. */
        public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down,
                int policyFlags, boolean isScreenOn) {
            return mPolicy.interceptKeyBeforeQueueing(whenNanos,
                    keyCode, down, policyFlags, isScreenOn);
        }
拦截处理的执行代码就在PhoneWindowManager.interceptKeyBeforeQueueing()方法中。详细的请参看源码

EventHub.cpp主要用来读取设备文件中的RawEvent,而InputReader.cpp和InputDispatcher.cpp算是它们之间的对接层。InputReader从设备文件中读取的是RawEvent,在交给InputDispatcher进行分发之前,它需要先把RawEvent进行转化分类,拆分成KeyEvent、MotionEvent、TrackEvent各种类型等。

相关源代码位置
/frameworks/base/services/java/com/android/server/WindowManagerService.java(事件分发给最前面的窗口)
/frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java(拦截消息的处理类)
/frameworks/base/core/java/android/view/KeyEvent.java(按键事件定义)
/frameworks/base/services/java/com/android/server/InputManager.Java(Java层输入管理)
/frameworks/base/libs/ui/InputManager.cpp(native层输入管理)
/frameworks/base/libs/ui/InputReader.cpp(事件读取线程)
/frameworks/base/libs/ui/InputDispatcher.cpp(事件分发线程)
/frameworks/base/libs/ui/EventHub.cpp(键码与键值转换)
### RK3568 平台下修改红外键值方法 对于RK3568平台下的红外遥控开发,当需要自定义或调整按键映射时,通常涉及多个次的工作。这不仅限于底驱动程序的配置,还包括Android框架面上的相关设置。 #### 底驱动面 在Linux内核环境中,通过`/dev/input/eventX`设备文件来处理输入事件。为了使特定的红外信号能够被识别并转换成相应的键盘扫描码,在驱动代码中需指定这些映射关系。具体来说,可以通过编辑DTS(Device Tree Source)文件中的节点属性实现对不同功能键的支持[^1]。 例如,假设要增加两个新的按键——音量加(`KEY_VOLUMEUP`)和音量减(`KEY_VOLUMEDOWN`): ```dts ir@ff { compatible = "rockchip,ir"; pinctrl-names = "default"; pinctrl-0 = <&ir_rx>; status = "okay"; linux,keymap = < /* ...其他已有映射... */ 0x1a KEY_VOLUMEUP // 音量+ 0x1b KEY_VOLUMEDOWN // 音量- >; }; ``` 上述代码片段展示了如何向现有的键表中加入新条目。其中`linux,keymap`属性用于存储从接收到的脉冲序列到标准键盘事件之间的对应规则。每一对数值分别代表接收端检测到的具体编码以及期望触发的操作码。 完成以上更改后重新编译固件,并确保更新后的版本已正确加载至目标板上运行。此时应该可以利用`getevent`工具验证新增按键是否按预期工作[^2]。 #### Android 框架面 为了让应用程序感知来自红外控制器的动作反馈,还需要进一步定制Android系统的输入管理部分。主要操作是在源码树内的路径`frameworks/base/data/keyboards/Generic.kl`里添加对应的声明语句,从而建立物理硬件按钮与虚拟逻辑指令间的联系[^3]。 针对前述例子而言,则应追加如下两行内容: ```text key 179 VOLUME_UP WAKE DUMMY key 178 VOLUME_DOWN WAKE DUMMY ``` 请注意这里的数字编号并非随意选取;而是依据官方文档给出的标准对照表选定最接近实际用途的那一项作为参照对象。此外,“WAKE”标记指示该类交互可唤醒休眠状态下的装置;而“DUMMY”则表示此行为不会产生任何额外效果除非有特别设定。 最后一步是要清理构建环境缓存并将改动同步反映在整个项目结构之中,接着执行完整的编译流程直至产出可供刷写的镜像包为止。安装完毕重启系统之后便能体验经由本次改造所带来的全新特性了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值