Android Framework 输入子系统 (11)sendevent与getevent命令解读

112 篇文章 81 订阅

该系列文章总纲链接:专题分纲目录 Android Framework 输入子系统


本章关键点总结 & 说明:

以上是迭代导图,主要关注➕ 基础部分->调试工具部分即可,同时上图是总图,局部显示的有点小,局部截图,如下所示:

本章节的思维导图放大后如上所示,这里主要研究getevent 和sendevent两个工具命令以及实现原理。

1 getevent

1.1 工具使用:

@1 getevent直接使用,显示当前有那些输入设备,数量与 /dev/input 目录下相同,如下:

$getevent

add device 1: /dev/input/event3
  name:     "ILITEK Multi-Touch-V3020"
add device 2: /dev/input/event2
  name:     "PC Camera"
add device 3: /dev/input/event1
  name:     "gsensor"
add device 4: /dev/input/event0
  name:     "rk29-keypad"

@2 getevent查看默认上报数据,如下:

$getevent /dev/input/event3
0003 0039 00000004
0003 0035 00002324
0003 0036 00001a9f
0001 014a 00000001
0003 0000 00002324
0003 0001 00001a9f
0000 0000 00000000
0003 0039 ffffffff
0001 014a 00000000
0000 0000 00000000

@3 getevent显示时间戳,如下:

$getevent -t /dev/input/event3
[    1141.248434] 0003 0039 0000000e
[    1141.248434] 0003 0035 00002cd4
[    1141.248434] 0003 0036 00001a09
[    1141.248434] 0001 014a 00000001
[    1141.248434] 0003 0000 00002cd4
[    1141.248434] 0003 0001 00001a09
[    1141.248434] 0000 0000 00000000
[    1141.322181] 0003 0039 ffffffff
[    1141.322181] 0001 014a 00000000
[    1141.322181] 0000 0000 00000000

@4  getevent 根据 mask 值显示相关信息,执行后会一直显示上报数据,如下:

【errs=1, dev=2, name=4, info=8, vers=16, pos. events=32, props=64,说明:这里默认显示 dev| name| info| vers = 30;】

$getevent -v /dev/input/event3
add device 1: /dev/input/event3
  bus:      0003
  vendor    222a
  product   004d
  version   0110
  name:     "ILITEK Multi-Touch-V3020"
  location: "usb-ff540000.usb-1.3/input0"
  id:       ""
  version:  1.0.1

$getevent -v2 /dev/input/event3
add device 1: /dev/input/event3

$getevent -v8 /dev/input/event3
  bus:      0003
  vendor    222a
  product   004d
  version   0110
  location: "usb-ff540000.usb-1.3/input0"
  id:       ""

$getevent -v16 /dev/input/event3
  version:  1.0.1

$getevent -v30 /dev/input/event3
add device 1: /dev/input/event3
  bus:      0003
  vendor    222a
  product   004d
  version   0110
  name:     "ILITEK Multi-Touch-V3020"
  location: "usb-ff540000.usb-1.3/input0"
  id:       ""
  version:  1.0.1

$getevent -v32 /dev/input/event3
  events:
    KEY (0001): 014a
    ABS (0003): 0000  : value 12008, min 0, max 16384, fuzz 0, flat 0, resolution 31
                0001  : value 5790, min 0, max 9600, fuzz 0, flat 0, resolution 32
                002f  : value 0, min 0, max 9, fuzz 0, flat 0, resolution 0
                0035  : value 0, min 0, max 16384, fuzz 0, flat 0, resolution 31
                0036  : value 0, min 0, max 9600, fuzz 0, flat 0, resolution 32
                0039  : value 0, min 0, max 65535, fuzz 0, flat 0, resolution 0

@5  getevent 显示设备支持的事件类型和编码方式,如下:

$getevent -p /dev/input/event3
add device 1: /dev/input/event3
  name:     "ILITEK Multi-Touch-V3020"
  events:
    KEY (0001): 014a
    ABS (0003): 0000  : value 13084, min 0, max 16384, fuzz 0, flat 0, resolution 31
                0001  : value 5284, min 0, max 9600, fuzz 0, flat 0, resolution 32
                002f  : value 0, min 0, max 9, fuzz 0, flat 0, resolution 0
                0035  : value 0, min 0, max 16384, fuzz 0, flat 0, resolution 31
                0036  : value 0, min 0, max 9600, fuzz 0, flat 0, resolution 32
                0039  : value 0, min 0, max 65535, fuzz 0, flat 0, resolution 0
  input props:
    INPUT_PROP_DIRECT

@6  getevent 以文本形式输出事件类型和名称,比 -t 更清楚直观,如下:

$getevent -l /dev/input/event3
// 事件类型      事件码              事件值
EV_ABS       ABS_MT_TRACKING_ID   0000000f
EV_ABS       ABS_MT_POSITION_X    00002bbc
EV_ABS       ABS_MT_POSITION_Y    00001b6d
EV_KEY       BTN_TOUCH            DOWN
EV_ABS       ABS_X                00002bbc
EV_ABS       ABS_Y                00001b6d
EV_SYN       SYN_REPORT           00000000
EV_ABS       ABS_MT_TRACKING_ID   ffffffff
EV_KEY       BTN_TOUCH            UP
EV_SYN       SYN_REPORT           00000000

@7 getevent 显示事件上报速率,如下:

$getevent -r /dev/input/event3
0003 0039 00000015
0003 0035 000030d8
0003 0036 00001954
0001 014a 00000001
0003 0000 000030d8
0003 0001 00001954
0000 0000 00000000 rate 0
0003 0039 ffffffff
0001 014a 00000000
0000 0000 00000000 rate 9

@8 getevent 一次性查看需要的触摸屏信息,如下:

$getevent -tlr /dev/input/event3
[    2514.550104] EV_ABS       ABS_MT_TRACKING_ID   0000001c
[    2514.550104] EV_ABS       ABS_MT_POSITION_X    00002dac
[    2514.550104] EV_ABS       ABS_MT_POSITION_Y    000018ca
[    2514.550104] EV_KEY       BTN_TOUCH            DOWN
[    2514.550104] EV_ABS       ABS_X                00002dac
[    2514.550104] EV_ABS       ABS_Y                000018ca
[    2514.550104] EV_SYN       SYN_REPORT           00000000             rate 0
[    2514.638845] EV_ABS       ABS_MT_TRACKING_ID   ffffffff
[    2514.638845] EV_KEY       BTN_TOUCH            UP
[    2514.638845] EV_SYN       SYN_REPORT           00000000             rate 11

1.2 源码该要解读:

int getevent_main(int argc, char *argv[])
{
    //...
    const char *device_path = "/dev/input";
    opterr = 0;
    do {
        c = getopt(argc, argv, "tns:Sv::dpilqc:rh");
        if (c == EOF)
            break;
        switch (c) {
        case 't':
            get_time = 1;
            break;
        //...
        case 'h':
            usage(argv[0]);
            exit(1);
        }
    } while (1);
    //...
    nfds = 1;
    ufds = calloc(1, sizeof(ufds[0]));
    ufds[0].fd = inotify_init();
    ufds[0].events = POLLIN;
    if(device) {
        if(!print_flags_set)
            print_flags |= PRINT_DEVICE_ERRORS;
        res = open_device(device, print_flags);
        if(res < 0) {
            return 1;
        }
    } else {
        if(!print_flags_set)
            print_flags |= PRINT_DEVICE_ERRORS | PRINT_DEVICE | PRINT_DEVICE_NAME;
        print_device = 1;
		res = inotify_add_watch(ufds[0].fd, device_path, IN_DELETE | IN_CREATE);
        //...
        res = scan_dir(device_path, print_flags);
        //...
    }
    //...
    while(1) {
        //int pollres =
        poll(ufds, nfds, -1);
        //printf("poll %d, returned %d\n", nfds, pollres);
        if(ufds[0].revents & POLLIN) {
            read_notify(device_path, ufds[0].fd, print_flags);
        }
        for(i = 1; i < nfds; i++) {
            if(ufds[i].revents) {
                if(ufds[i].revents & POLLIN) {
                    res = read(ufds[i].fd, &event, sizeof(event));
                    //...
                    if(get_time) {
                        printf("[%8ld.%06ld] ", event.time.tv_sec, event.time.tv_usec);
                    }
                    if(print_device)
                        printf("%s: ", device_names[i]);
                    print_event(event.type, event.code, event.value, print_flags);
                    if(sync_rate && event.type == 0 && event.code == 0) {
                        int64_t now = event.time.tv_sec * 1000000LL + event.time.tv_usec;
                        if(last_sync_time)
                            printf(" rate %lld", 1000000LL / (now - last_sync_time));
                        last_sync_time = now;
                    }
                    printf("%s", newline);
                    if(event_count && --event_count == 0)
                        return 0;
                }
            }
        }
    }
    return 0;
}

这里getevent看上去较为繁琐,但实际上无非就是几个机制的结合,inofity机制(/dev/input目录变化),poll机制(监听具体某个event文件变化),其他的无非就是根据具体情况做一些处理,输出不同的信息罢了。

2 sendevent

2.1 工具使用:

sendevent命令的格式是:

sendevent /dev/input/eventX type code value

其中 /dev/input/eventX 对应一个event设备,可以通过getevent获得可用的event设备,而type, code, value的定义可参看kernel/include/linux/input.h,其中type如下定义:

#define EV_SYN          0x00
#define EV_KEY          0x01
#define EV_REL          0x02
#define EV_ABS          0x03
#define EV_MSC          0x04
#define EV_SW           0x05
#define EV_LED          0x11
#define EV_SND          0x12
#define EV_REP          0x14
#define EV_FF           0x15
#define EV_PWR          0x16
#define EV_FF_STATUS        0x17
#define EV_MAX          0x1f
#define EV_CNT          (EV_MAX+1)

常用的是EV_KEY, EV_REL, EV_ABS, EV_SYN,分别对应keyboard, 相对坐标, 绝对坐标, 同步事件;EV_SYN则表示一组完整事件已经完成,需要处理,EV_SYN的code定义事件分发的类型,接下来对三种事件的code值分别进行说明。

EV_SYN对应的code如下:

#define SYN_REPORT      0
#define SYN_CONFIG      1
#define SYN_MT_REPORT       2

EV_REL对应的code如下:

#define REL_X           0x00
#define REL_Y           0x01
#define REL_Z           0x02
#define REL_RX          0x03
#define REL_RY          0x04
#define REL_RZ          0x05
#define REL_HWHEEL      0x06
#define REL_DIAL        0x07
#define REL_WHEEL       0x08
#define REL_MISC        0x09
#define REL_MAX         0x0f
#define REL_CNT         (REL_MAX+1)

EV_ABS对应的code如下:

#define ABS_X           0x00
#define ABS_Y           0x01
#define ABS_Z           0x02
#define ABS_RX          0x03
#define ABS_RY          0x04
#define ABS_RZ          0x05
#define ABS_THROTTLE        0x06
#define ABS_RUDDER      0x07
#define ABS_WHEEL       0x08
#define ABS_GAS         0x09
#define ABS_BRAKE       0x0a
#define ABS_HAT0X       0x10
#define ABS_HAT0Y       0x11
#define ABS_HAT1X       0x12
#define ABS_HAT1Y       0x13
#define ABS_HAT2X       0x14
#define ABS_HAT2Y       0x15
#define ABS_HAT3X       0x16
#define ABS_HAT3Y       0x17
#define ABS_PRESSURE        0x18
#define ABS_DISTANCE        0x19
#define ABS_TILT_X      0x1a
#define ABS_TILT_Y      0x1b
#define ABS_TOOL_WIDTH      0x1c
#define ABS_VOLUME      0x20
#define ABS_MISC        0x28

#define ABS_MT_TOUCH_MAJOR  0x30    /* Major axis of touching ellipse */
#define ABS_MT_TOUCH_MINOR  0x31    /* Minor axis (omit if circular) */
#define ABS_MT_WIDTH_MAJOR  0x32    /* Major axis of approaching ellipse */
#define ABS_MT_WIDTH_MINOR  0x33    /* Minor axis (omit if circular) */
#define ABS_MT_ORIENTATION  0x34    /* Ellipse orientation */
#define ABS_MT_POSITION_X   0x35    /* Center X ellipse position */
#define ABS_MT_POSITION_Y   0x36    /* Center Y ellipse position */
#define ABS_MT_TOOL_TYPE    0x37    /* Type of touching device */
#define ABS_MT_BLOB_ID      0x38    /* Group a set of packets as a blob */
#define ABS_MT_TRACKING_ID  0x39    /* Unique ID of initiated contact */
#define ABS_MT_PRESSURE     0x3a    /* Pressure on contact area */

#define ABS_MAX         0x3f
#define ABS_CNT         (ABS_MAX+1)

sendevent命令的使用方法如下:

按键类事件使用案例:

sendevent /dev/input/event1: 0001 014a 00000001   // BTN touch事件 值为1
sendevent /dev/input/event1: 0001 014a 00000000   // BTN touch事件 值为0
sendevent /dev/input/event1: 0000 0000 00000000   // sync事件

触摸屏事件使用案例:

sendevent /dev/input/event1 0003 0000 0000015e    // ABS x 坐标
sendevent /dev/input/event1: 0003 0001 000000df    // ABS y 坐标
sendevent /dev/input/event1: 0003 0018 00000000   // ABS pressure事件
sendevent /dev/input/event1: 0000 0000 00000000   // sync事件

2.2 源码该要解读:

因为sendevent的代码并不多,因此这里直接全部贴出来,如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/ioctl.h>
//#include <linux/input.h> // this does not compile
#include <errno.h>

struct input_event {
	struct timeval time;
	__u16 type;
	__u16 code;
	__s32 value;
};

#define EVIOCGVERSION		_IOR('E', 0x01, int)			/* get driver version */
#define EVIOCGID		_IOR('E', 0x02, struct input_id)	/* get device ID */
#define EVIOCGKEYCODE		_IOR('E', 0x04, int[2])			/* get keycode */
#define EVIOCSKEYCODE		_IOW('E', 0x04, int[2])			/* set keycode */
#define EVIOCGNAME(len)		_IOC(_IOC_READ, 'E', 0x06, len)		/* get device name */
#define EVIOCGPHYS(len)		_IOC(_IOC_READ, 'E', 0x07, len)		/* get physical location */
#define EVIOCGUNIQ(len)		_IOC(_IOC_READ, 'E', 0x08, len)		/* get unique identifier */
#define EVIOCGKEY(len)		_IOC(_IOC_READ, 'E', 0x18, len)		/* get global keystate */
#define EVIOCGLED(len)		_IOC(_IOC_READ, 'E', 0x19, len)		/* get all LEDs */
#define EVIOCGSND(len)		_IOC(_IOC_READ, 'E', 0x1a, len)		/* get all sounds status */
#define EVIOCGSW(len)		_IOC(_IOC_READ, 'E', 0x1b, len)		/* get all switch states */
#define EVIOCGBIT(ev,len)	_IOC(_IOC_READ, 'E', 0x20 + ev, len)	/* get event bits */
#define EVIOCGABS(abs)		_IOR('E', 0x40 + abs, struct input_absinfo)		/* get abs value/limits */
#define EVIOCSABS(abs)		_IOW('E', 0xc0 + abs, struct input_absinfo)		/* set abs value/limits */
#define EVIOCSFF		_IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect))	/* send a force effect to a force feedback device */
#define EVIOCRMFF		_IOW('E', 0x81, int)			/* Erase a force effect */
#define EVIOCGEFFECTS		_IOR('E', 0x84, int)			/* Report number of effects playable at the same time */
#define EVIOCGRAB		_IOW('E', 0x90, int)			/* Grab/Release device */

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;
}

这里实现上比较简单,就是打开设备节点argv[1], 之后对event事件 结构题首先初始化,type、code、value赋值后将event事件直接写入到节点argv[1]中。一般的设备节点都是“dev/input/eventX”这种。

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

图王大胜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值