• Linux系统struct input_event结构体分类型(鼠标、键盘、触屏)详解与例子


    目录
    一、概述
    二、结构体字段解析
    三、不同类型地解释字段
    3.1 鼠标事件
    3.2 键盘事件
    3.3 触摸屏事件
    四、使用struct input_event读取设备文件的例子


    一、概述

    Linux系统是通过输入子系统来管理输入设备(如鼠标、键盘、触摸屏、游戏摇杆)的。配置了内核支持且安装对应驱动后,当系统接入输入设备,会在/dev/input下生成对应设备文件,下图是鼠标、键盘在不同情况下/dev/input的设备文件。
    在这里插入图片描述
    当输入设备有事件产生时,内核就会将事件上报到设备文件,事件的数据以struct input_event为单位存入设备文件,所以读取事件数据时使用struct input_event结构体,这个结构体定义在/usr/include/linux/input.h中,定义如下:

    struct input_event {
            struct timeval time;
            __u16 type;
            __u16 code;
            __s32 value;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    二、结构体字段解析

    • time:事件产生的时间。

    • type:事件类型,常见的有:EV_KEY(键盘)、EV_REL(相对坐标)、EV_ABS(绝对坐标)、,定义在[input-event-codes.h] (https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h#LC35) 或 input.h 中。
    /*
     * Event types
     */
    #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 //LED
    #define EV_SND            0x12 //声音
    #define EV_REP            0x14 //repeat、会自动发出重复按键
    #define EV_FF             0x15
    #define EV_PWR            0x16 //电源开关、按键
    #define EV_FF_STATUS      0x17
    #define EV_MAX            0x1f
    #define EV_CNT			(EV_MAX+1)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    • code:事件的代码,对事件进一步的描述,如:
      键盘事件的键值(KEY_NUMLOCK、KEY_ESC、KEY_1、KEY_A),定义在[input-event-codes.h] (https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h#LC75)、
      鼠标事件的位置信息(REL_X、REL_Y),滚轮信息(REL_WHEEL),定义在[input-event-codes.h] (https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h#LC812)、
      触摸屏事的地位置信息(ABS_MT_POSITION_X),slot信息(ABS_MT_SLOT)定义在[input-event-codes.h] (https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h#LC839)

    • value:事件的值,对事件更具体地描述,如:
      按键的按下/抬起
      鼠标位置信息的具体 x值、y值
      触摸屏事件slot信息表示第几个的值、ABS_MT_TRACKING_ID的值

    三、不同类型地解释字段

    前面对 struct input_event 的四个字段有了简单的了解,这里通过读取一下实际事件来进一步了解这个结构体

    3.1 鼠标事件

    鼠标的事件一般有 EV_REL(相对坐标)、EV_KEY(按键) 两种类型,EV_REL用来表示鼠标在屏幕的位置,EV_KEY用来表示鼠标的按钮。下面读取一段鼠标事件的数据,分析鼠标的事件。
    在这里插入图片描述

    • EV_REL类型(相对坐标)
      如果事件是相对坐标时,读取到的struct input_eventtype字段的值为 2
      code字段的取值可能是REL_X(相对坐标X值)、REL_X(相对坐标Y值)、REL_WHEEL(滚轮),
      value字段根据code的取值不同而不同,可以表示坐标(X值、Y值),滚轮上滑(-1)、下滑(1)
      下图是相对坐标时,code的定义的值
      在这里插入图片描述
    • EV_KEY类型(按键:左键、右键、滚轮键)
      鼠标事件也有按键类型,表示左键、右键、滚轮键按下/抬起,读取到的struct input_eventtype字段的值为 1
      code字段取值可能是BTN_LEFT(左键)、BTN_RIGHT(右键)、BTN_MIDDLE(滚轮键),
      value字段一般是 1 表示按下,0 表示抬起,
      下图是鼠标按键,code的定义的值
      在这里插入图片描述

    3.2 键盘事件

    键盘事件比较简单,它的事件类型一般EV_KEY,下面读取一段键盘事件进行分析
    在这里插入图片描述
    键盘事件的type字段一般为 EV_KEY (1),每次按键按下、抬起都有一个杂项类型EV_MSC(4),目前没什么用处;
    code字段取值可能是为1到255,表示各个按键值,定义在定义在[input-event-codes.h] (https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h#LC75)
    value字段一般是 1 表示按下,0 表示抬起

    3.3 触摸屏事件

    触摸屏事件比较复杂,触摸屏协议A类协议、B类协议之分,具体的见之前这篇介绍触摸屏协议的文件文章,下面抓取一段B类协议触摸屏事件进行分析:
    在这里插入图片描述
    上面是在触摸屏右下角按下、抬起获取的事件数据,可以看出:触摸屏事件主要事件类型是EV_ABS(3);

    code值在B类协议(多点触控)中主要有ABS_MT_SLOT(0x2f)、ABS_MT_TRACKING_ID(0x39)、ABS_MT_POSITION_X(0x35)、ABS_MT_POSITION_Y(0x36),这几个值的解析如下,
    ABS_MT_SLOT:在多点触控中,与每个触点相关联,用来传播触点状态信息,value字段为0表示第一个触点
    ABS_MT_TRACKING_ID:可跟踪ID,一个触点按下就会产生一个新的可跟踪ID,value值为-1表示该触点销毁
    ABS_MT_POSITION_X:接触椭圆中心的表面 X 坐标,value值表示坐标数组
    ABS_MT_POSITION_Y:接触椭圆中心的表面 Y 坐标,value值表示坐标数组

    另外,触摸屏被按下/抬起会有一个按键类型,其code值为BTN_TOUCH(0x14a);

    四、使用struct input_event读取设备文件的例子

    下面是一个读取输入设备的例子,很详细,可以根据上面讲到的再结合例子进行理解,最重要的是多看input-event-codes.h文件,几乎所有与输入子系统相关的宏定义都在该文件里。

    /* 
     * Copyright 2002 Red Hat Inc., Durham, North Carolina. 
     * 
     * All Rights Reserved. 
     * 
     * Permission is hereby granted, free of charge, to any person obtaining 
     * a copy of this software and associated documentation files (the 
     * "Software"), to deal in the Software without restriction, including 
     * without limitation on the rights to use, copy, modify, merge, 
     * publish, distribute, sublicense, and/or sell copies of the Software, 
     * and to permit persons to whom the Software is furnished to do so, 
     * subject to the following conditions: 
     * 
     * The above copyright notice and this permission notice (including the 
     * next paragraph) shall be included in all copies or substantial 
     * portions of the Software. 
     * 
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
     * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
     * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
     * NON-INFRINGEMENT.  IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS 
     * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 
     * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 
     * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
     * SOFTWARE. 
     * 
     * This is a simple test program that reads from /dev/input/event*, 
     * decoding events into a human readable form. 
     */  
    
    /* 
     * Authors: 
     *   Rickard E. (Rik) Faith  
     * 
     */  
    
    #include   
    #include   
    #include   
    #include   
    #include   
    #include   
    #include   
    #include   
    #include   
    
    struct input_event event;  
    
    int main(int argc, char **argv)  
    {  
        char          name[64];           /* RATS: Use ok, but could be better */  
        char          buf[256] = { 0, };  /* RATS: Use ok */  
        unsigned char mask[EV_MAX/8 + 1]; /* RATS: Use ok */  
        int           version;  
        int           fd = 0;  
        int           rc;  
        int           i, j;  
        char          *tmp;  
    
    #define test_bit(bit) (mask[(bit)/8] & (1 << ((bit)%8)))  
    
        for (i = 0; i < 32; i++) {  
            sprintf(name, "/dev/input/event%d", i);  
            if ((fd = open(name, O_RDONLY, 0)) >= 0) {  
                ioctl(fd, EVIOCGVERSION, &version);  
                ioctl(fd, EVIOCGNAME(sizeof(buf)), buf);  
                ioctl(fd, EVIOCGBIT(0, sizeof(mask)), mask);  
                printf("%s\n", name);  
                printf("    evdev version: %d.%d.%d\n",  
                       version >> 16, (version >> 8) & 0xff, version & 0xff);  
                printf("    name: %s\n", buf);  
                printf("    features:");  
                for (j = 0; j < EV_MAX; j++) {  
                    if (test_bit(j)) {  
                        const char *type = "unknown";  
                        switch(j) {  
                        case EV_KEY: type = "keys/buttons"; break;  
                        case EV_REL: type = "relative";     break;  
                        case EV_ABS: type = "absolute";     break;  
                        case EV_MSC: type = "reserved";     break;  
                        case EV_LED: type = "leds";         break;  
                        case EV_SND: type = "sound";        break;  
                        case EV_REP: type = "repeat";       break;  
                        case EV_FF:  type = "feedback";     break;  
                        }  
                        printf(" %s", type);  
                    }  
                }  
                printf("\n");  
                close(fd);  
            }  
        }  
    
        if (argc > 1) {  
            sprintf(name, "/dev/input/event%d", atoi(argv[1]));  
            if ((fd = open(name, O_RDWR, 0)) >= 0) {  
                printf("%s: open, fd = %d\n", name, fd);  
                for (i = 0; i < LED_MAX; i++) {  
                    event.time.tv_sec  = time(0);  
                    event.time.tv_usec = 0;  
                    event.type         = EV_LED;  
                    event.code         = i;  
                    event.value        = 0;  
                    write(fd, &event, sizeof(event));  
                }  
    
                while ((rc = read(fd, &event, sizeof(event))) > 0) {  
                    printf("%-24.24s.%06lu type 0x%04x; code 0x%04x;"  
                           " value 0x%08x; ",  
                           ctime(&event.time.tv_sec),  
                           event.time.tv_usec,  
                           event.type, event.code, event.value);  
                    switch (event.type) {  
                    case EV_KEY:  
                        if (event.code > BTN_MISC) {  
                            printf("Button %d %s",  
                                   event.code & 0xff,  
                                   event.value ? "press" : "release");  
                        } else {  
                            printf("Key %d (0x%x) %s",  
                                   event.code & 0xff,  
                                   event.code & 0xff,  
                                   event.value ? "press" : "release");  
                        }  
                        break;  
                    case EV_REL:  
                        switch (event.code) {  
                        case REL_X:      tmp = "X";       break;  
                        case REL_Y:      tmp = "Y";       break;  
                        case REL_HWHEEL: tmp = "HWHEEL";  break;  
                        case REL_DIAL:   tmp = "DIAL";    break;  
                        case REL_WHEEL:  tmp = "WHEEL";   break;  
                        case REL_MISC:   tmp = "MISC";    break;  
                        default:         tmp = "UNKNOWN"; break;  
                        }  
                        printf("Relative %s %d", tmp, event.value);  
                        break;  
                    case EV_ABS:  
                        switch (event.code) {  
                        case ABS_X:        tmp = "X";        break;  
                        case ABS_Y:        tmp = "Y";        break;  
                        case ABS_Z:        tmp = "Z";        break;  
                        case ABS_RX:       tmp = "RX";       break;  
                        case ABS_RY:       tmp = "RY";       break;  
                        case ABS_RZ:       tmp = "RZ";       break;  
                        case ABS_THROTTLE: tmp = "THROTTLE"; break;  
                        case ABS_RUDDER:   tmp = "RUDDER";   break;  
                        case ABS_WHEEL:    tmp = "WHEEL";    break;  
                        case ABS_GAS:      tmp = "GAS";      break;  
                        case ABS_BRAKE:    tmp = "BRAKE";    break;  
                        case ABS_HAT0X:    tmp = "HAT0X";    break;  
                        case ABS_HAT0Y:    tmp = "HAT0Y";    break;  
                        case ABS_HAT1X:    tmp = "HAT1X";    break;  
                        case ABS_HAT1Y:    tmp = "HAT1Y";    break;  
                        case ABS_HAT2X:    tmp = "HAT2X";    break;  
                        case ABS_HAT2Y:    tmp = "HAT2Y";    break;  
                        case ABS_HAT3X:    tmp = "HAT3X";    break;  
                        case ABS_HAT3Y:    tmp = "HAT3Y";    break;  
                        case ABS_PRESSURE: tmp = "PRESSURE"; break;  
                        case ABS_DISTANCE: tmp = "DISTANCE"; break;  
                        case ABS_TILT_X:   tmp = "TILT_X";   break;  
                        case ABS_TILT_Y:   tmp = "TILT_Y";   break;  
                        case ABS_MISC:     tmp = "MISC";     break;  
    					case ABS_MT_SLOT:  tmp = "MT_SLOT";     break;  
    					case ABS_MT_TRACKING_ID: tmp = "MT_TRACKING_ID";     break;  
    					case ABS_MT_POSITION_X:  tmp = "MT_X";     break;  
    					case ABS_MT_POSITION_Y:  tmp = "MT_Y";     break;  
                        default:           tmp = "UNKNOWN";  break;  
                        }  
                        printf("Absolute %s %d", tmp, event.value);  
                        break;  
                    case EV_MSC: printf("Misc"); break;  
                    case EV_LED: printf("Led");  break;  
                    case EV_SND: printf("Snd");  break;  
                    case EV_REP: printf("Rep");  break;  
                    case EV_FF:  printf("FF");   break;  
                        break;  
                    }  
                    printf("\n");  
                }  
                printf("rc = %d, (%s)\n", rc, strerror(errno));  
                close(fd);  
            }  
        }  
        return 0;  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186

    如果文章对你有帮助,请点赞、收藏支持一下 !!! *_^

  • 相关阅读:
    Python反射机制
    Linux系统中,如果您遇到“系统资源不足,无法创建新的管道“的错误
    ✔ ★【备战实习(面经+项目+算法)】 10.13学习时间表
    杨辉三角(Java实现)
    提取歌曲伴奏?用对软件一键帮你搞定~
    Prometheus(二)基础概念
    使用python自动化操作如何使用subprocess,mac如何查看软件安装路径
    华仔推荐书单
    node笔记记录26aynsc和await
    华为机试真题 C++ 实现【转骰子】
  • 原文地址:https://blog.csdn.net/wkd_007/article/details/126729030