Android开发之input子系统一

一、了解

Android系统主机默认携带input子系统,并且开机就会产生默认的mouse和keyboard事件,这样使得用户开机就可以触屏点击和使用按键。可通过adb shell getevent 命令看到用户input事件产生的信息。Android系统主机也支持链接遥控设备(蓝牙遥控器,dongle遥控器(2.4G),鼠标,键盘等)并根据遥控设备向系统注册的信息,系统生成对应的input事件event,所有event均由uinput 在 /dev/input/event*(数字) 生成。

二、input子系统相关命令

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 []  [...]");
        System.err.println();
        System.err.println("The sources are: ");
        for (String src : SOURCES.keySet()) {
            System.err.println("      " + src);
        }
        System.err.println();
        System.err.println("The commands and default sources are:");
        System.err.println("      text  (Default: touchscreen)");
        System.err.println("      keyevent [--longpress]  ..."
                + " (Default: keyboard)");
        System.err.println("      tap   (Default: touchscreen)");
        System.err.println("      swipe     [duration(ms)]"
                + " (Default: touchscreen)");
        System.err.println("      press (Default: trackball)");
        System.err.println("      roll   (Default: trackball)");
    }

根据源码可知模拟按键事件:

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
模拟确认键

三、input子系统映射流程

以下源码基于android N

3.1 用户按键,发送hid keycode,映射到内核驱动hid-input.c
3.2 hid-input.c将hid keycode 转换成scancode。
对于蓝牙遥控器来说,hid KeyCode
分为 usage+keycode
关于usage可以为如下值:
Android开发之input子系统一_第1张图片
Android开发之input子系统一_第2张图片

常用的为

  1. KEYBOARD/KEYPAD PAGE (0X07)
  2. CONSUMER PAGE (0X0C) .

hid-input.c通过函数其静态函数hidinput_configure_usage映射scanCode,
其中hidinput_configure_usage函数根据遥控器所发送的usage的值来对应具体映射scanCode的方法:

  • 假如usage为:KEYBOARD/KEYPAD PAGE (0X07),则根据hid-input.c中定义的静态数组 hid_keyboard[256] 来映射具体的scanCode
static 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,假如keycode0x17,
0x17对应十进制23,那么最终对应的scanCode为:hid_keyboard[23]

假如usage为:CONSUMER PAGE (0X0C),则直接根据遥控器所发送的keycode来建立映射关系,如下图:
Android开发之input子系统一_第3张图片

前面的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

你可能感兴趣的:(Android知识汇总)