RK3566-Android11-红外遥控器按键适配
文章目录
- 前言-需求场景
- 一、参考资料
- 二、需求分析
- 三、修改文件
- 四、实现方案
-
- 配置设备树-红外客户编码和按键编码
- [PhoneWindowManager- Framework层适配验证](#PhoneWindowManager- Framework层适配验证)
- 五、知识点扩展
-
- [getevent 验证是否配置了设备树映射按键](#getevent 验证是否配置了设备树映射按键)
- Framework层看是否接收并处理红外按键
- 总结
前言-需求场景
产品使用的是RK3566 主控,用到了红外遥控器功能。客户拿了一个遥控器过来,让对接红外遥控器,后面就用这个遥控器码值,系统对接成功先。
遥控器资料如下:

一、参考资料
LubanCat-RK3562/RK3566/RK3568系列板卡快红-外
遥控器按键事件-PhoneWindowManager-配合实现文件管理器菜单功能
Linux驱动-PWM-pwm输入捕获实验(二)- 字符设备-中断捕获基础知识点
二、需求分析
这里要有几个关键点:
- 内核相关:rk 红外irq 基本用的都是pwm3 口,所以 如何保证硬件环境、系统驱动配置 这个基本功,方便排查问题
- 设备树配置:irq 和 蓝牙遥控器配置不一样的,irq 遥控器按键映射直接配置在设备树里面的,区别于蓝牙遥控器物理映射
- framework 层配置:不管蓝牙遥控器还是irq 遥控器,最终按键值通过底层Linux 映射传递到framework层,在framework层处理: 这一点特别关键,如何配置按键、按键如何映射、最终如何传递到framework层 都是相关知识点内容。
三、修改文件
java
配置红外按键码和客户编码:kernel/arch/arm64/boot/dts/rockchip/rk3568-evb.dtsi
中间层直接匹配处理案件功能:frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
四、实现方案
配置设备树-红外客户编码和按键编码
路径:kernel/arch/arm64/boot/dts/rockchip/rk3568-evb.dtsi
配置了irkey1 如下:
java
ir_key1 {
rockchip,usercode = <0x01FE>;
rockchip,key_table =
//<0x45 KEY_POWER>,
<0x19 KEY_BACK>,
<0x51 KEY_LEFT>,
<0x16 KEY_UP>,
<0x50 KEY_RIGHT>,
<0x1A KEY_DOWN>,
<0x10 KEY_VOLUMEDOWN>,
<0x18 KEY_VOLUMEUP>,
<0x42 KEY_BRIGHTNESSDOWN>,
<0x4A KEY_BRIGHTNESSUP>,
<0x40 KEY_POWER>,
<0x11 KEY_HOMEPAGE>,
<0x13 KEY_SELECT>,
<0x43 KEY_MENU>,
<0x21 KEY_1>,
<0x22 KEY_2>,
<0x23 KEY_3>,
<0x24 KEY_4>,
<0x25 KEY_5>,
<0x26 KEY_6>,
<0x27 KEY_7>,
<0x28 KEY_8>,
<0x29 KEY_9>,
<0x20 KEY_0>,
<0x13 KEY_REPLY>,
<0x0D KEY_BACKSPACE>,
<0x00 BTN_MOUSE>;
};
核心配置-配置客户编码
rockchip,usercode = <0x01FE>;
这样配置了 开机后红外遥控器自动和机器连上的,就是找这个客户编码。
假如有不同的遥控器,支持不同的遥控器,那么就多配置几个irkeyn ,然后不同的客户编码即可。

配置红外按键
| scancode | KEY 宏 | 值 | 对应的物理按键 / 功能 |
|---|---|---|---|
| 0x19 | KEY_BACK | 158 | 返回键(逆时针箭头) |
| 0x51 | KEY_LEFT | 105 | 左方向键 |
| 0x16 | KEY_UP | 103 | 上方向键 |
| 0x50 | KEY_RIGHT | 106 | 右方向键 |
| 0x1A | KEY_DOWN | 108 | 下方向键 |
| 0x10 | KEY_VOLUMEDOWN | 114 | 音量减 |
| 0x18 | KEY_VOLUMEUP | 115 | 音量加 |
| 0x42 | KEY_BRIGHTNESSDOWN | 224 | 亮度减 |
| 0x4A | KEY_BRIGHTNESSUP | 225 | 亮度加 |
| 0x40 | KEY_POWER | 116 | 电源键 |
| 0x11 | KEY_HOMEPAGE | 172 | 主页(房子图标) |
| 0x13 | KEY_SELECT | 353 | ⚠️ 见下方冲突说明 |
| 0x43 | KEY_MENU | 139 | 设置 / 菜单键(原 KEY_SETUP 改来的) |
| 0x21~0x29 | KEY_1~KEY_9 | 2~10 | 数字键 1~9 |
| 0x20 | KEY_0 | 11 | 数字键 0 |
| 0x13 | KEY_REPLY | 232 | ⚠️ 与上面 0x13 重复 |
| 0x0D | KEY_BACKSPACE | 14 | 退格 / 删除 |
| 0x00 | BTN_MOUSE | 272 | 鼠标左键 |
细节说明
设备树中配置的按键宏KEY 并 不一定一定会在Linux 层映射为Framework层的按键值,所以先保证宏定义没问题 哪怕Linux 映射没有回传到Framework层,那么要么补充映射、要么直接定义其它宏定义KEY 按键再在Framework层完成适配。
PhoneWindowManager- Framework层适配验证
在 interceptKeyBeforeDispatching 方法中,找一个按键和设备树中配置的对应上,做跳转系统设置的功能。
参考:遥控器按键事件-PhoneWindowManager-配合实现文件管理器菜单功能
系统设置的按键我们配置的就是KEYCODE_MENU 对应系统设置功能,在Framework层适配了一次而已。
java
if (keyCode == KeyEvent.KEYCODE_MENU) {
// modify by fangchen start
// Hijack modified menu keys for debugging features
/*final int chordBug = KeyEvent.META_SHIFT_ON;
if (down && repeatCount == 0) {
if (mEnableShiftMenuBugReports && (metaState & chordBug) == chordBug) {
Intent intent = new Intent(Intent.ACTION_BUG_REPORT);
mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT,
null, null, null, 0, null, null);
return -1;
}
}*/
Log.d(TAG,"=== KEYCODE_SETTINGS");
if (down && repeatCount == 0) {
Log.d(TAG,"===>to KEYCODE_SETTINGS");
Intent intent = new Intent(Settings.ACTION_SETTINGS);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivityAsUser(intent, UserHandle.CURRENT);
}
return -1;
// modify by fangchen end
}
五、知识点扩展
getevent 验证是否配置了设备树映射按键
如上:验证是否配置好了设备树
- 实际验证发现即使你配置了 设置按键标准的宏
KEY_SETUP但是 Framework层并没有收到。 那解决方案两个:要么解决Linux 层内核映射传递到上层,要么写一个其它按键 在Framework层适配中转。
按了红外遥控器 物理设置按键,getevent 如下:
java
按了红外遥控器 物理设置按键,getevent 反馈如下:
/dev/input/event0: 0001 008d 00000001
/dev/input/event0: 0000 0000 00000000
/dev/input/event0: 0001 008d 00000000
/dev/input/event0: 0000 0000 00000000
getevent 显示 0x008d = 十进制 141 = KEY_SETUP,说明 Linux 层设备树映射完全正常,问题出在 Android 层的 .kl 按键映射和系统处理上。
java
红外码 → 设备树 KEY_SETUP(141) → .kl 文件映射 → Android KeyEvent → 系统处理打开设置
✓ ✓ ✗ 可能缺失 ✗ 无标准处理
Framework层看是否接收并处理红外按键
先看日志:
java
PhoneWindowManager.java 打印日志如下:
2017-08-04 18:34:15.583 444-534 WindowManager system_server D interceptKeyTq keycode=0 interactive=true keyguardActive=false policyFlags=22000000
2017-08-04 18:34:15.584 444-533 WindowManager system_server D interceptKeyTi keyCode=0 down=true repeatCount=0 keyguardOn=false canceled=false
2017-08-04 18:34:15.586 444-533 WindowManager system_server D Unhandled key: inputToken=android.os.BinderProxy@3d008f1, title=com.android.launcher3/com.android.launcher3.uioverrides.QuickstepLauncher, action=0, flags=8, keyCode=0, scanCode=141, metaState=0, repeatCount=0, policyFlags=1644167168
2017-08-04 18:34:15.586 444-533 WindowManager system_server D No fallback.
2017-08-04 18:34:15.766 444-534 WindowManager system_server D interceptKeyTq keycode=0 interactive=true keyguardActive=false policyFlags=22000000
2017-08-04 18:34:15.767 444-533 WindowManager system_server D interceptKeyTi keyCode=0 down=false repeatCount=0 keyguardOn=false canceled=false
2017-08-04 18:34:15.769 444-533 WindowManager system_server D Unhandled key: inputToken=android.os.BinderProxy@3d008f1, title=com.android.launcher3/com.android.launcher3.uioverrides.QuickstepLauncher, action=1, flags=8, keyCode=0, scanCode=141, metaState=0, repeatCount=0, policyFlags=1644167168
2017-08-04 18:34:15.769 444-533 WindowManager system_server D No fallback.
日志解读
java
keyCode=0, scanCode=141
Unhandled key
No fallback.
| 字段 | 值 | 含义 |
|---|---|---|
| scanCode=141 | 141 | Linux 层正确上报了 KEY_SETUP,设备树没问题 |
| keyCode=0 | 0 | Android 层映射为 KEYCODE_UNKNOWN(未知键) |
| Unhandled key | --- | PhoneWindowManager 不认识这个键,没人处理 |
| No fallback. | --- | 没有备用动作,事件直接丢弃 |
问题不在 PhoneWindowManager,而在它的上游 ------.kl 文件缺少 key 141 的映射。 Linux 键码 141 没有被翻译成任何 Android KEYCODE,所以传到 PhoneWindowManager 时已经是 0(UNKNOWN)了,它当然没法处理。
解决方案分析
所以这里就出现两种解决方案:
- 解决映射问题,系统层linux kernel 层补全映射
- 不去解决映射问题,拿一个物理按键映射其它功能在framework层映射为系统设置功能即可
PhoneWindowManager - framework层 坑点
即使你完成了映射功能,那么PhoneWindowManager 有没有实际功能也要确认的。 实际发现framework层 PhoneWindowManager 的 interceptKeyBeforeDispatching 方法中根本没有 KEYCODE_SETTINGS 的执行功能,那么先补充这个功能先如果采用方案一底层解决Linux 映射问题。
java
if (keyCode == KeyEvent.KEYCODE_SETTINGS) {
Log.d(TAG,"=== KEYCODE_SETTINGS");
if (down && repeatCount == 0) {
Log.d(TAG,"===>to KEYCODE_SETTINGS");
Intent intent = new Intent(Settings.ACTION_SETTINGS);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivityAsUser(intent, UserHandle.CURRENT);
}
return -1;
总结
- 红外遥控器完整适配解决方案,涉及到哪些知识点等分析,实际工作有一定参考意义。
- 内核层适配按键、设备树适配按键 、pwm 知识点也需要了解
- framework层的PhoneWindowManager 适配按键功能也需要掌握
- 对比蓝牙遥控器,按键映射逻辑可能稍微区别,实际验证问题还是有一定的共同之处的。