android Input专题-getevent深入分析

Posted Android高级知识分享官

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android Input专题-getevent深入分析相关的知识,希望对你有一定的参考价值。

android手机大厂Framework系统-Input系统专题实战课
https://ke.qq.com/course/4963459

[入门课,实战课,跨进程专题
ps需要学习深入framework课程和课程优惠
新课程优惠获取请加入qq群:422901085

hi,本节课我们来讲解一下经常做触摸相关开发同学都必须要掌握的一个命令:
getevent
下面将通过2个部分来分别讲解

1、具体使用方法

gemini:/ $ getevent -h
Usage: getevent [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-d] [-p] [-i] [-l] [-q] [-c count] [-r] [device]
    -t: show time stamps
    -n: don't print newlines
    -s: print switch states for given bits
    -S: print all switch states
    -v: verbosity mask (errs=1, dev=2, name=4, info=8, vers=16, pos. events=32, props=64)
    -d: show HID descriptor, if available
    -p: show possible events (errs, dev, name, pos. events)
    -i: show all device info and possible events
    -l: label event types and names in plain text
    -q: quiet (clear verbosity mask)
    -c: print given number of events then exit
    -r: print rate events are received

这里我们来简单看一下这个命令使用方式,上面列出了很多参数对应的解释,这里就不一一讲解了,我们就几个主要的
-t: show time stamps --显示事件的发生时间
-l: label event types and names in plain text —这里表示要把event事件类型名字打印出来
-r: print rate events are received --显示一下接受事件速率
一般调试使用命令: getevent -lrt

1|gemini:/ $ getevent -lrt                                                                                                                                                                                
add device 1: /dev/input/event6
  name:     "uinput-fpc"
add device 2: /dev/input/event5
  name:     "msm8996-tasha-mtp-snd-card Button Jack"
add device 3: /dev/input/event4
  name:     "msm8996-tasha-mtp-snd-card Headset Jack"
add device 4: /dev/input/event2
  name:     "gpio-keys"
add device 5: /dev/input/event0
  name:     "qpnp_pon"
could not get driver version for /dev/input/mice, Not a typewriter
add device 6: /dev/input/event3
  name:     "pwm-ir"
could not get driver version for /dev/input/mouse0, Not a typewriter
add device 7: /dev/input/event1
  name:     "synaptics_dsx"
[  160896.797487] /dev/input/event0: EV_KEY       KEY_POWER            DOWN                
[  160896.797487] /dev/input/event0: EV_SYN       SYN_REPORT           00000000            
[  160896.915581] /dev/input/event0: EV_KEY       KEY_POWER            UP                  
[  160896.915581] /dev/input/event0: EV_SYN       SYN_REPORT           00000000             rate 8
[  160898.678739] /dev/input/event1: EV_SYN       0004                 00027482            
[  160898.678739] /dev/input/event1: EV_SYN       0005                 284ca8a3            
[  160898.678739] /dev/input/event1: EV_ABS       ABS_MT_TRACKING_ID   00000052            
[  160898.678739] /dev/input/event1: EV_KEY       BTN_TOUCH            DOWN                
[  160898.678739] /dev/input/event1: EV_KEY       BTN_TOOL_FINGER      DOWN                
[  160898.678739] /dev/input/event1: EV_ABS       ABS_MT_POSITION_X    00000228            
[  160898.678739] /dev/input/event1: EV_ABS       ABS_MT_POSITION_Y    000006f5            
[  160898.678739] /dev/input/event1: EV_ABS       ABS_MT_TOUCH_MAJOR   00000003            

这里就会打印出对应的格式进行介绍
[ 160898.678739] /dev/input/event1: EV_ABS ABS_MT_TOUCH_MAJOR 00000003
时间 具体节点文件名 事件类型 事件code 事件value
从以上打印就可以看出我们此时手机产生了哪些事件

2、getevent源码分析

system/core/toolbox/getevent.c

//省略部分

static void print_event(int type, int code, int value, int print_flags)

    const char *type_label, *code_label, *value_label;

    if (print_flags & PRINT_LABELS) 
        type_label = get_label(ev_labels, type);
        code_label = NULL;
        value_label = NULL;

        switch(type) 
            case EV_SYN:
                code_label = get_label(syn_labels, code);
                break;
            case EV_KEY:
                code_label = get_label(key_labels, code);
                value_label = get_label(key_value_labels, value);
                break;
            case EV_REL:
                code_label = get_label(rel_labels, code);
                break;
            case EV_ABS:
                code_label = get_label(abs_labels, code);
                switch(code) 
                    case ABS_MT_TOOL_TYPE:
                        value_label = get_label(mt_tool_labels, value);
                
                break;
            case EV_MSC:
                code_label = get_label(msc_labels, code);
                break;
            case EV_LED:
                code_label = get_label(led_labels, code);
                break;
            case EV_SND:
                code_label = get_label(snd_labels, code);
                break;
            case EV_SW:
                code_label = get_label(sw_labels, code);
                break;
            case EV_REP:
                code_label = get_label(rep_labels, code);
                break;
            case EV_FF:
                code_label = get_label(ff_labels, code);
                break;
            case EV_FF_STATUS:
                code_label = get_label(ff_status_labels, code);
                break;
        

        if (type_label)
            printf("%-12.12s", type_label);
        else
            printf("%04x        ", type);
        if (code_label)
            printf(" %-20.20s", code_label);
        else
            printf(" %04x                ", code);
        if (value_label)
            printf(" %-20.20s", value_label);
        else
            printf(" %08x            ", value);
     else 
        printf("%04x %04x %08x", type, code, value);
    


//省略部分

static int open_device(const char *device, int print_flags)

    int version;
    int fd;
    int clkid = CLOCK_MONOTONIC;
    struct pollfd *new_ufds;
    char **new_device_names;
    char name[80];
    char location[80];
    char idstr[80];
    struct input_id id;

    fd = open(device, O_RDONLY | O_CLOEXEC);//打开这个节点
    if(fd < 0) 
        if(print_flags & PRINT_DEVICE_ERRORS)
            fprintf(stderr, "could not open %s, %s\\n", device, strerror(errno));
        return -1;
    
    
    if(ioctl(fd, EVIOCGVERSION, &version)) 
        if(print_flags & PRINT_DEVICE_ERRORS)
            fprintf(stderr, "could not get driver version for %s, %s\\n", device, strerror(errno));
        return -1;
    
    if(ioctl(fd, EVIOCGID, &id)) 
        if(print_flags & PRINT_DEVICE_ERRORS)
            fprintf(stderr, "could not get driver id for %s, %s\\n", device, strerror(errno));
        return -1;
    
    name[sizeof(name) - 1] = '\\0';
    location[sizeof(location) - 1] = '\\0';
    idstr[sizeof(idstr) - 1] = '\\0';
    if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) 
        //fprintf(stderr, "could not get device name for %s, %s\\n", device, strerror(errno));
        name[0] = '\\0';
    
    if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) 
        //fprintf(stderr, "could not get location for %s, %s\\n", device, strerror(errno));
        location[0] = '\\0';
    
    if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) 
        //fprintf(stderr, "could not get idstring for %s, %s\\n", device, strerror(errno));
        idstr[0] = '\\0';
    

    if (ioctl(fd, EVIOCSCLOCKID, &clkid) != 0) 
        fprintf(stderr, "Can't enable monotonic clock reporting: %s\\n", strerror(errno));
        // a non-fatal error
    

    new_ufds = realloc(ufds, sizeof(ufds[0]) * (nfds + 1));
    if(new_ufds == NULL) 
        fprintf(stderr, "out of memory\\n");
        return -1;
    
    ufds = new_ufds;
    new_device_names = realloc(device_names, sizeof(device_names[0]) * (nfds + 1));
    if(new_device_names == NULL) 
        fprintf(stderr, "out of memory\\n");
        return -1;
    
    device_names = new_device_names;

    if(print_flags & PRINT_DEVICE)
        printf("add device %d: %s\\n", nfds, device);
    if(print_flags & PRINT_DEVICE_INFO)
        printf("  bus:      %04x\\n"
               "  vendor    %04x\\n"
               "  product   %04x\\n"
               "  version   %04x\\n",
               id.bustype, id.vendor, id.product, id.version);
    if(print_flags & PRINT_DEVICE_NAME)
        printf("  name:     \\"%s\\"\\n", name);
    if(print_flags & PRINT_DEVICE_INFO)
        printf("  location: \\"%s\\"\\n"
               "  id:       \\"%s\\"\\n", location, idstr);
    if(print_flags & PRINT_VERSION)
        printf("  version:  %d.%d.%d\\n",
               version >> 16, (version >> 8) & 0xff, version & 0xff);

    if(print_flags & PRINT_POSSIBLE_EVENTS) 
        print_possible_events(fd, print_flags);
    

    if(print_flags & PRINT_INPUT_PROPS) 
        print_input_props(fd);
    
    if(print_flags & PRINT_HID_DESCRIPTOR) 
        print_hid_descriptor(id.bustype, id.vendor, id.product);
    

    ufds[nfds].fd = fd;//非常关键点,这里赋值给了ufds,后面会把ufds统一加入poll
    ufds[nfds].events = POLLIN;//感兴趣的事件只有POLLIN,即有数据可以读取了
    device_names[nfds] = strdup(device);
    nfds++;

    return 0;


int close_device(const char *device, int print_flags)

    int i;
    for(i = 1; i < nfds; i++) 
        if(strcmp(device_names[i], device) == 0) 
            int count = nfds - i - 1;
            if(print_flags & PRINT_DEVICE)
                printf("remove device %d: %s\\n", i, device);
            free(device_names[i]);
            memmove(device_names + i, device_names + i + 1, sizeof(device_names[0]) * count);
            memmove(ufds + i, ufds + i + 1, sizeof(ufds[0]) * count);
            nfds--;
            return 0;
        
    
    if(print_flags & PRINT_DEVICE_ERRORS)
        fprintf(stderr, "remote device: %s not found\\n", device);
    return -1;

//读取/dev/input路径下面的节点内容变化
static int read_notify(const char *dirname, int nfd, int print_flags)

    int res;
    char devname[PATH_MAX];
    char *filename;
    char event_buf[512];
    int event_size;
    int event_pos = 0;
    struct inotify_event *event;

    res = read(nfd, event_buf, sizeof(event_buf));
    if(res < (int)sizeof(*event)) 
        if(errno == EINTR)
            return 0;
        fprintf(stderr, "could not get event, %s\\n", strerror(errno));
        return 1;
    
    //printf("got %d bytes of event information\\n", res);

    strcpy(devname, dirname);
    filename = devname + strlen(devname);
    *filename++ = '/';

    while(res >= (int)sizeof(*event)) 
        event = (struct inotify_event *)(event_buf + event_pos);
        //printf("%d: %08x \\"%s\\"\\n", event->wd, event->mask, event->len ? event->name : "");
        if(event->len) 
            strcpy(filename, event->name);
            if(event->mask & IN_CREATE) 
                open_device(devname, print_flags);
            
            else 
                close_device(devname, print_flags);
            
        
        event_size = sizeof(*event) + event->len;
        res -= event_size;
        event_pos += event_size;
    
    return 0;

//读取扫描路径下的节点
static int scan_dir(const char *dirname, int print_flags)

    char devname[PATH_MAX];
    char *filename;
    DIR *dir;
    struct dirent *de;
    dir = opendir(dirname);
    if(dir == NULL)
        return -1;
    strcpy(devname, dirname);
    filename = devname + strlen(devname);
    *filename++ = '/';
    while((de = readdir(dir))) 
        if(de->d_name[0] == '.' &&
           (de->d_name[1] == '\\0' ||
            (de->d_name[1] == '.' && de->d_name[2] == '\\0')))
            continue;
        strcpy(filename, de->d_name);
        open_device(devname, print_flags);
    
    closedir(dir);
    return 0;

int getevent_main(int argc, char *argv[])

    int c;
    int i;
    int res;
    int get_time = 0;
    int print_device = 0;
    char *newline = "\\n";
    uint16_t get_switch = 0;
    struct input_event event;
    int print_flags = 0;
    int print_flags_set = 0;
    int dont_block = -1;
    int event_count = 0;
    int sync_rate = 0;
    int64_t last_sync_time = 0;
    const char *device = NULL;
    const char *device_path = "/dev/input";

    /* disable buffering on stdout */
    setbuf(stdout, NULL);

    opterr = 0;
    do 
        c = getopt(argc, argv, "tns:Sv::dpilqc:rh");//过滤参数
        if (c == EOF)
            break;
        switch (c) 
        case 't':
            get_time = 1;
            以上是关于android Input专题-getevent深入分析的主要内容,如果未能解决你的问题,请参考以下文章

android Input专题-getevent深入分析

android getevent sendevent input 接收发送事件

android getevent sendevent input 接收发送事件

Android input命令

Android 键盘 两个按键keyCode一样时,如何解决?

千里马Android Framework-input系统专题blog目录集合