Android物理按键功能更改
这两天有个需求,需要将Android手机上的音量 +/- 按键更改为以前功能机的上/下按键。一头雾水的我开始百度如何更改Android手机的物理按键功能。经过一番查询和实际演练终于完成了需求,下面将该过程进行总结。
(PS: 由于我只是做android应用相关的,对驱动层的知识懂的不多,这里仅仅是记录一下我解决问题的方法,如果要深究Android的按键流程,还是要参考其他资料。)
首先,我们需要搞清楚的是,用户点击了一个按钮后究竟发生了什么。这就不得不说一下Android的INPUT子系统了。其精简流程图如下:
根据流程图,从下往上看,首先是Linux内核层上报按键码,我在这里引用简书作者天空汁橙在《Android物理按键输入事件(一)》中所写来描述Linux内核层的操作:
① linux内核通过扫码,将硬件上按键按下电压变换为数字电压并映射到数组下标;
② 通过数组关系转化将按键映射到内核中预定义的键值;
③ 最终linux内核上报给上层的就是这个整型值。
其中,这些上报的值反映在kernel/uapi/linux/input.h中。
//input.h部分代码
... ...
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define KEY_RIGHTALT 100
#define KEY_LINEFEED 101
#define KEY_HOME 102
#define KEY_UP 103
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define KEY_PAGEUP 104
#define KEY_LEFT 105
#define KEY_RIGHT 106
#define KEY_END 107
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define KEY_DOWN 108
#define KEY_PAGEDOWN 109
#define KEY_INSERT 110
#define KEY_DELETE 111
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define KEY_MACRO 112
#define KEY_MUTE 113
#define KEY_VOLUMEDOWN 114
#define KEY_VOLUMEUP 115
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define KEY_POWER 116
#define KEY_KPEQUAL 117
#define KEY_KPPLUSMINUS 118
#define KEY_PAUSE 119
... ...
//input.h部分代码
... ...
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define KEY_RIGHTALT 100
#define KEY_LINEFEED 101
#define KEY_HOME 102
#define KEY_UP 103
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define KEY_PAGEUP 104
#define KEY_LEFT 105
#define KEY_RIGHT 106
#define KEY_END 107
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define KEY_DOWN 108
#define KEY_PAGEDOWN 109
#define KEY_INSERT 110
#define KEY_DELETE 111
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define KEY_MACRO 112
#define KEY_MUTE 113
#define KEY_VOLUMEDOWN 114
#define KEY_VOLUMEUP 115
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define KEY_POWER 116
#define KEY_KPEQUAL 117
#define KEY_KPPLUSMINUS 118
#define KEY_PAUSE 119
... ...
那么,这些linux内核上报按键值后又会发生什么?这里就需要提到kl文件了。Android kl文件是标准linux与android的键值映射文件,kl文件可以有很多个,有关kl文件的介绍
我们可以通过以下命令查看手机所使用的kl文件有哪些:
> cat /proc/bus/input/devices
> cat /proc/bus/input/devices
输入命令后,会出现下图这样的输出:
从图中我们可以确定终端目前所使用的kl文件(有些kl文件找不到)。我找到了“Name=”comip_gpio_keys””的kl文件,将其打开,我们可以查看到类似以下内容:
key 113 MUTE
key 115 VOLUME_UP
key 114 VOLUME_DOWN
key 163 MEDIA_NEXT
key 164 MEDIA_PLAY_PAUSE
key 165 MEDIA_PREVIOUS
key 226 HEADSETHOOK
key 158 BACK
key 28 DPAD_CENTER
key 231 CALL
key 107 ENDCALL
key 103 DPAD_UP
key 108 DPAD_DOWN
key 105 DPAD_LEFT
key 106 DPAD_RIGHT
key 59 F1
key 60 F2
key 113 MUTE
key 115 VOLUME_UP
key 114 VOLUME_DOWN
key 163 MEDIA_NEXT
key 164 MEDIA_PLAY_PAUSE
key 165 MEDIA_PREVIOUS
key 226 HEADSETHOOK
key 158 BACK
key 28 DPAD_CENTER
key 231 CALL
key 107 ENDCALL
key 103 DPAD_UP
key 108 DPAD_DOWN
key 105 DPAD_LEFT
key 106 DPAD_RIGHT
key 59 F1
key 60 F2
kl文件中,key后面的数字就是kernel上报的按键码,后面的字符标签就是该按键码对应的android中的按键标签,我们可以看到上面“103”对应的是物理按键中的“上”,“108”对应物理按键中的“下”。当用户按下按键后,kernel会上报对应按键的按键码,例如我们按下音量+键,kernel就会上报按键码115,然后上层根据正确的kl文件中的对应关系,将按键对应到上层的VOLUME_UP标签上来。
那这些按键标签是哪里来的呢?
其实,这些标签也都对应一个按键码,与kernel上报的按键码不同,按键标签所对应的按键码就是我们在上层代码逻辑中使用的按键码。我们可以在frameworks/native/include/input/InputEventLabels.h中看到:这里通过宏定义将标签字符与上层按键码对应起来,其中上层按键码又是通过frameworks/native/include/android/Keycodes.h中枚举的。我们在上层所使用的按键码就是这个枚举类型中所列出的整型值。
//InputEventLabels.h部分代码
#include <input/Input.h>
#include <android/keycodes.h>
#define DEFINE_KEYCODE(key) { #key, AKEYCODE_##key }
… …
struct InputEventLabel {
const char *literal;
int value;
};
static const InputEventLabel KEYCODES[] = {
// NOTE: If you add a new keycode here you must also add it to several other files.
// Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
DEFINE_KEYCODE(UNKNOWN),
DEFINE_KEYCODE(SOFT_LEFT),
DEFINE_KEYCODE(SOFT_RIGHT),
DEFINE_KEYCODE(HOME),
DEFINE_KEYCODE(BACK),
DEFINE_KEYCODE(CALL),
… …
DEFINE_KEYCODE(POUND),
DEFINE_KEYCODE(DPAD_UP),
DEFINE_KEYCODE(DPAD_DOWN),
DEFINE_KEYCODE(DPAD_LEFT),
DEFINE_KEYCODE(DPAD_RIGHT),
DEFINE_KEYCODE(DPAD_CENTER),
DEFINE_KEYCODE(VOLUME_UP),
DEFINE_KEYCODE(VOLUME_DOWN),
DEFINE_KEYCODE(POWER),
DEFINE_KEYCODE(CAMERA),
DEFINE_KEYCODE(CLEAR),
… …
{ NULL, 0 }
};
//InputEventLabels.h部分代码
#include <input/Input.h>
#include <android/keycodes.h>
#define DEFINE_KEYCODE(key) { #key, AKEYCODE_##key }
… …
struct InputEventLabel {
const char *literal;
int value;
};
static const InputEventLabel KEYCODES[] = {
// NOTE: If you add a new keycode here you must also add it to several other files.
// Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
DEFINE_KEYCODE(UNKNOWN),
DEFINE_KEYCODE(SOFT_LEFT),
DEFINE_KEYCODE(SOFT_RIGHT),
DEFINE_KEYCODE(HOME),
DEFINE_KEYCODE(BACK),
DEFINE_KEYCODE(CALL),
… …
DEFINE_KEYCODE(POUND),
DEFINE_KEYCODE(DPAD_UP),
DEFINE_KEYCODE(DPAD_DOWN),
DEFINE_KEYCODE(DPAD_LEFT),
DEFINE_KEYCODE(DPAD_RIGHT),
DEFINE_KEYCODE(DPAD_CENTER),
DEFINE_KEYCODE(VOLUME_UP),
DEFINE_KEYCODE(VOLUME_DOWN),
DEFINE_KEYCODE(POWER),
DEFINE_KEYCODE(CAMERA),
DEFINE_KEYCODE(CLEAR),
… …
{ NULL, 0 }
};
//Keycodes.h部分代码
enum {
AKEYCODE_UNKNOWN = 0,
AKEYCODE_SOFT_LEFT = 1,
AKEYCODE_SOFT_RIGHT = 2,
AKEYCODE_HOME = 3,
AKEYCODE_BACK = 4,
AKEYCODE_CALL = 5,
… …
AKEYCODE_POUND = 18,
AKEYCODE_DPAD_UP = 19,
AKEYCODE_DPAD_DOWN = 20,
AKEYCODE_DPAD_LEFT = 21,
AKEYCODE_DPAD_RIGHT = 22,
AKEYCODE_DPAD_CENTER = 23,
AKEYCODE_VOLUME_UP = 24,
AKEYCODE_VOLUME_DOWN = 25,
AKEYCODE_POWER = 26,
AKEYCODE_CAMERA = 27,
AKEYCODE_CLEAR = 28,
… …
// NOTE: If you add a new keycode here you must also add it to several other files.
// Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
};
//Keycodes.h部分代码
enum {
AKEYCODE_UNKNOWN = 0,
AKEYCODE_SOFT_LEFT = 1,
AKEYCODE_SOFT_RIGHT = 2,
AKEYCODE_HOME = 3,
AKEYCODE_BACK = 4,
AKEYCODE_CALL = 5,
… …
AKEYCODE_POUND = 18,
AKEYCODE_DPAD_UP = 19,
AKEYCODE_DPAD_DOWN = 20,
AKEYCODE_DPAD_LEFT = 21,
AKEYCODE_DPAD_RIGHT = 22,
AKEYCODE_DPAD_CENTER = 23,
AKEYCODE_VOLUME_UP = 24,
AKEYCODE_VOLUME_DOWN = 25,
AKEYCODE_POWER = 26,
AKEYCODE_CAMERA = 27,
AKEYCODE_CLEAR = 28,
… …
// NOTE: If you add a new keycode here you must also add it to several other files.
// Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
};
这样就将物理按键、kernel、上层之间的映射关系确定了,点击某个物理按键,上层就知道哪个按键被点击了。
如果我要将音量+/-按键变为上/下按键,只需要把对应kl文件中,104和105对应的VOLUME_UP和VOLUME_DOWN更改为DPAD_UP和DPAD_DOWN即可。整编后将系统烧到手机,重新开机就可以了。