您的位置:首页 > 移动开发 > Android开发

Android开发之input子系统一

2018-02-07 18:08 405 查看

一、了解

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,sendevent 源代码位于:/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 <errno.h>
#include <fcntl.h>
#include <linux/input.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>

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 [<source>] <command> [<arg>...]");
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 <string> (Default: touchscreen)");
System.err.println("      keyevent [--longpress] <key code number or name> ..."
+ " (Default: keyboard)");
System.err.println("      tap <x> <y> (Default: touchscreen)");
System.err.println("      swipe <x1> <y1> <x2> <y2> [duration(ms)]"
+ " (Default: touchscreen)");
System.err.println("      press (Default: trackball)");
System.err.println("      roll <dx> <dy> (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,映射到内核驱动input.c

3.2 input.c将hid keycode 转换成scancode。

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: