Android系统主机默认携带input子系统,并且开机就会产生默认的mouse和keyboard事件,这样使得用户开机就可以触屏点击和使用按键。可通过adb shell getevent 命令看到用户input事件产生的信息。Android系统主机也支持链接遥控设备(蓝牙遥控器,dongle遥控器(2.4G),鼠标,键盘等)并根据遥控设备向系统注册的信息,系统生成对应的input事件event,所有event均由uinput 在 /dev/input/event*(数字) 生成。
2.1 getevent 得到input信息
基于Android N,getevent 源代码位于:/system/core/toolbox/getevent.c
查看源码可知使用如下:
static void usage(char *name)
{
fprintf(stderr, "Usage: %s [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-d] [-p] [-i] [-l] [-q] [-c count] [-r] [device]\n", name);
fprintf(stderr, " -t: show time stamps\n");
fprintf(stderr, " -n: don't print newlines\n");
fprintf(stderr, " -s: print switch states for given bits\n");
fprintf(stderr, " -S: print all switch states\n");
fprintf(stderr, " -v: verbosity mask (errs=1, dev=2, name=4, info=8, vers=16, pos. events=32, props=64)\n");
fprintf(stderr, " -d: show HID descriptor, if available\n");
fprintf(stderr, " -p: show possible events (errs, dev, name, pos. events)\n");
fprintf(stderr, " -i: show all device info and possible events\n");
fprintf(stderr, " -l: label event types and names in plain text\n");
fprintf(stderr, " -q: quiet (clear verbosity mask)\n");
fprintf(stderr, " -c: print given number of events then exit\n");
fprintf(stderr, " -r: print rate events are received\n");
}
getevent -i/p 可以查看该event支持的所有keyType和keyCode。
2.2 sendevent 模拟input事件
基于Android N,sendevent源代码位于:/system/core/toolbox/sendevent.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
int sendevent_main(int argc, char *argv[])
{
int fd;
ssize_t ret;
int version;
struct input_event event;
if(argc != 5) {
fprintf(stderr, "use: %s device type code value\n", argv[0]);
return 1;
}
fd = open(argv[1], O_RDWR);
if(fd < 0) {
fprintf(stderr, "could not open %s, %s\n", argv[optind], strerror(errno));
return 1;
}
if (ioctl(fd, EVIOCGVERSION, &version)) {
fprintf(stderr, "could not get driver version for %s, %s\n", argv[optind], strerror(errno));
return 1;
}
memset(&event, 0, sizeof(event));
event.type = atoi(argv[2]);
event.code = atoi(argv[3]);
event.value = atoi(argv[4]);
ret = write(fd, &event, sizeof(event));
if(ret < (ssize_t) sizeof(event)) {
fprintf(stderr, "write event failed, %s\n", strerror(errno));
return -1;
}
return 0;
}
通过阅读sendevent.c源码可以得出sendevent的命令格式为:
sendevent event事件 eventType eventKeyCode eventValue
event事件:/dev/input/event*(数字)
eventType:
EV_SYN 0x00 同步事件
EV_KEY 0x01 按键事件
EV_REL 0x02 相对坐标
EV_ABS 0x03 绝对坐标
EV_MSC 0x04 其它
EV_LED 0x11 LED
EV_SND 0x12 声音
EV_REP 0x14 Repeat
EV_FF 0x15 力反馈
EV_PWR 电源
EV_FF_STATUS 状态
eventKeyCode: 通过getevent -i/p查询到的信息
eventValue: 0001 表示down 0000表示up
130|p212:/ $ sendevent /dev/input/event4 1 28 1
p212:/ $ sendevent /dev/input/event4 0 0 0
p212:/ $ sendevent /dev/input/event4 1 28 0
p212:/ $ sendevent /dev/input/event4 0 0 0
这样就模拟了一个确认键。
2.3 input 模拟input 事件
基于Android N,input.java 源代码位于:
/frameworks/base/cmds/input/src/com/android/commands/input
private void showUsage() {
System.err.println("Usage: input [
根据源码可知模拟按键事件:
input keyevent keycode number/name
基于Android N,keycode number/name对应
/frameworks/base/core/java/android/view/KeyEvent.java
input keyevent KEYCODE_DPAD_CENTER
等同于
input keyevent 23
模拟确认键
以下源码基于android N
3.1 用户按键,发送hid keycode,映射到内核驱动hid-input.c
3.2 hid-input.c
将hid keycode 转换成scancode。
对于蓝牙遥控器来说,hid KeyCode
分为 usage+keycode
关于usage可以为如下值:
常用的为
hid-input.c
通过函数其静态函数hidinput_configure_usage
映射scanCode,
其中hidinput_configure_usage
函数根据遥控器所发送的usage
的值来对应具体映射scanCode的方法:
usage
为:KEYBOARD/KEYPAD PAGE (0X07),则根据hid-input.c
中定义的静态数组 hid_keyboard[256]
来映射具体的scanCodestatic const unsigned char hid_keyboard[256] = {
0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3,
4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26,
27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
115,114,unk,unk,unk,121,unk, 89, 93,124, 92, 94, 95,unk,unk,unk,
122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,111,unk,unk,unk,
unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
unk,unk,unk,unk,unk,unk,179,180,unk,unk,unk,unk,unk,unk,unk,unk,
unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
unk,unk,unk,unk,unk,unk,unk,unk,111,unk,unk,unk,unk,unk,unk,unk,
29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
150,158,159,128,136,177,178,176,142,152,173,140,unk,unk,unk,unk
};
那么怎么再具体到此数组中具体哪个值呢,这时候就用到了遥控器所发送的keycode
,假如keycode
为0x17
,
0x17对应十进制23,那么最终对应的scanCode为:hid_keyboard[23]
。
假如usage
为:CONSUMER PAGE (0X0C),则直接根据遥控器所发送的keycode
来建立映射关系,如下图:
前面的case **
部分表示遥控器所发送的keycode
,map_key_clear(***)
对应到具体的ScanCode,map_key_clear
中对应宏定义在input.h
3.3 scancode 映射到该event*对应的.kl文件,可通过
dumpsys input
命令查看event*对应的.kl文件,.kl定义内容粗略如下:
key 1 ESCAPE
key 2 1
key 3 2
key 4 3
key 5 4
key 6 5
中间的数组为scancode,最右边的String字符为对应的KeyCodeLabel,
假设现在scancode为1,则映射到对应String字符KeyCodeLabel为: ESCAPE
3.4 ESCAPE 映射到源码目录:
/frameworks/native/include/input/InputEventLabels.h
最终映射到InputEventLabels.h中KEYCODES数组,粗略定义如下:
#define DEFINE_KEYCODE(key) { #key, AKEYCODE_##key }
#define DEFINE_AXIS(axis) { #axis, AMOTION_EVENT_AXIS_##axis }
#define DEFINE_LED(led) { #led, ALED_##led }
#define DEFINE_FLAG(flag) { #flag, POLICY_FLAG_##flag }
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(ENDCALL),
...............
{ NULL, 0 }
};
经过此次映射,ESCAPE变成AKEYCODE_ESCAPE。
3.5 AKEYCODE_ESCAPE映射到keycodes.h中所对应的value,源码位于:
/frameworks/native/include/android/keycodes.h
3.6value 映射到 keyEvent.java,源码位于:
/frameworks/base/core/java/android/view/keyEvent.java