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

本文涉及的产品
语种识别,语种识别 100万字符
图片翻译,图片翻译 100张
文档翻译,文档翻译 1千页
简介: Linux系统struct input_event结构体分类型(鼠标、键盘、触屏)详解与例子

一、概述

Linux系统是通过输入子系统来管理输入设备(如鼠标、键盘、触摸屏、游戏摇杆)的。配置了内核支持且安装对应驱动后,当系统接入输入设备,会在/dev/input下生成对应设备文件,下图是鼠标、键盘在不同情况下/dev/input的设备文件。

2018122814580746.png

当输入设备有事件产生时,内核就会将事件上报到设备文件,事件的数据以struct input_event为单位存入设备文件,所以读取事件数据时使用struct input_event结构体,这个结构体定义在/usr/include/linux/input.h中,定义如下:

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


二、结构体字段解析

  • time:事件产生的时间。

  • type:事件类型,常见的有:EV_KEY(键盘)、EV_REL(相对坐标)、EV_ABS(绝对坐标)、,定义在input-event-codes.hinput.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)

code:事件的代码,对事件进一步的描述,如:

键盘事件的键值(KEY_NUMLOCK、KEY_ESC、KEY_1、KEY_A),定义在input-event-codes.h、

鼠标事件的位置信息(REL_X、REL_Y),滚轮信息(REL_WHEEL),定义在input-event-codes.h、

触摸屏事的地位置信息(ABS_MT_POSITION_X),slot信息(ABS_MT_SLOT)定义在input-event-codes.h


value:事件的值,对事件更具体地描述,如:

按键的按下/抬起

鼠标位置信息的具体 x值、y值

触摸屏事件slot信息表示第几个的值、ABS_MT_TRACKING_ID的值

三、不同类型地解释字段

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

3.1 鼠标事件

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

2018122814580746.png

EV_REL类型(相对坐标)

如果事件是相对坐标时,读取到的struct input_event的type字段的值为 2 ,

code字段的取值可能是REL_X(相对坐标X值)、REL_X(相对坐标Y值)、REL_WHEEL(滚轮),

value字段根据code的取值不同而不同,可以表示坐标(X值、Y值),滚轮上滑(-1)、下滑(1)

下图是相对坐标时,code的定义的值

2018122814580746.png

EV_KEY类型(按键:左键、右键、滚轮键)

鼠标事件也有按键类型,表示左键、右键、滚轮键按下/抬起,读取到的struct input_event的type字段的值为 1 ,

code字段取值可能是BTN_LEFT(左键)、BTN_RIGHT(右键)、BTN_MIDDLE(滚轮键),

value字段一般是 1 表示按下,0 表示抬起,

下图是鼠标按键,code的定义的值

2018122814580746.png

3.2 键盘事件

键盘事件比较简单,它的事件类型一般EV_KEY,下面读取一段键盘事件进行分析2018122814580746.png

键盘事件的type字段一般为 EV_KEY (1),每次按键按下、抬起都有一个杂项类型EV_MSC(4),目前没什么用处;

code字段取值可能是为1到255,表示各个按键值,定义在定义在input-event-codes.h

value字段一般是 1 表示按下,0 表示抬起

3.3 触摸屏事件

触摸屏事件比较复杂,触摸屏协议A类协议、B类协议之分,具体的见之前这篇介绍触摸屏协议的文件文章,下面抓取一段B类协议触摸屏事件进行分析:

2018122814580746.png

上面是在触摸屏右下角按下、抬起获取的事件数据,可以看出:

触摸屏事件主要事件类型是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 <faith@redhat.com> 
 * 
 */  
#include <stdio.h>  
#include <stdlib.h>  
#include <unistd.h>  
#include <string.h>  
#include <sys/types.h>  
#include <fcntl.h>  
#include <errno.h>  
#include <time.h>  
#include <linux/input.h>  
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;  
}


目录
相关文章
|
2月前
|
Ubuntu Linux Anolis
Linux系统禁用swap
本文介绍了在新版本Linux系统(如Ubuntu 20.04+、CentOS Stream、openEuler等)中禁用swap的两种方法。传统通过注释/etc/fstab中swap行的方式已失效,现需使用systemd管理swap.target服务或在/etc/fstab中添加noauto参数实现禁用。方法1通过屏蔽swap.target适用于新版系统,方法2通过修改fstab挂载选项更通用,兼容所有系统。
218 3
Linux系统禁用swap
|
2月前
|
Linux
Linux系统修改网卡名为eth0、eth1
在Linux系统中,可通过修改GRUB配置和创建Udev规则或使用systemd链接文件,将网卡名改为`eth0`、`eth1`等传统命名方式,适用于多种发行版并支持多网卡配置。
312 3
|
Ubuntu Linux 网络安全
Linux系统初始化脚本
一款支持Rocky、CentOS、Ubuntu、Debian、openEuler等主流Linux发行版的系统初始化Shell脚本,涵盖网络配置、主机名设置、镜像源更换、安全加固等多项功能,适配单/双网卡环境,支持UEFI引导,提供多版本下载与持续更新。
289 0
Linux系统初始化脚本
|
3月前
|
运维 Linux 开发者
Linux系统中使用Python的ping3库进行网络连通性测试
以上步骤展示了如何利用 Python 的 `ping3` 库来检测网络连通性,并且提供了基本错误处理方法以确保程序能够优雅地处理各种意外情形。通过简洁明快、易读易懂、实操性强等特点使得该方法非常适合开发者或系统管理员快速集成至自动化工具链之内进行日常运维任务之需求满足。
231 18
|
2月前
|
安全 Linux Shell
Linux系统提权方式全面总结:从基础到高级攻防技术
本文全面总结Linux系统提权技术,涵盖权限体系、配置错误、漏洞利用、密码攻击等方法,帮助安全研究人员掌握攻防技术,提升系统防护能力。
280 1
|
2月前
|
监控 安全 Linux
Linux系统提权之计划任务(Cron Jobs)提权
在Linux系统中,计划任务(Cron Jobs)常用于定时执行脚本或命令。若配置不当,攻击者可利用其提权至root权限。常见漏洞包括可写的Cron脚本、目录、通配符注入及PATH变量劫持。攻击者通过修改脚本、创建恶意任务或注入命令实现提权。系统管理员应遵循最小权限原则、使用绝对路径、避免通配符、设置安全PATH并定期审计,以防范此类攻击。
996 1
|
3月前
|
缓存 监控 Linux
Linux系统清理缓存(buff/cache)的有效方法。
总结而言,在大多数情形下你不必担心Linux中buffer与cache占用过多内存在影响到其他程序运行;因为当程序请求更多内存在没有足够可用资源时,Linux会自行调整其占有量。只有当你明确知道当前环境与需求并希望立即回收这部分资源给即将运行重负载任务之前才考虑上述方法去主动干预。
1562 10
|
3月前
|
安全 Linux 数据安全/隐私保护
为Linux系统的普通账户授予sudo访问权限的过程
完成上述步骤后,你提升的用户就能够使用 `sudo`命令来执行管理员级别的操作,而无需切换到root用户。这是一种更加安全和便捷的权限管理方式,因为它能够留下完整的权限使用记录,并以最小权限的方式工作。需要注意的是,随意授予sudo权限可能会使系统暴露在风险之中,尤其是在用户不了解其所执行命令可能带来的后果的情况下。所以在配置sudo权限时,必须谨慎行事。
564 0
|
3月前
|
Ubuntu Linux 开发者
国产 Linux 发行版再添新成员,CutefishOS 系统简单体验
当然,系统生态构建过程并不简单,不过为了帮助国产操作系统优化生态圈,部分企业也开始用国产操作系统替代 Windows,我们相信肯定会有越来越多的精品软件登录 Linux 平台。
291 0
|
3月前
|
Ubuntu 安全 Linux
Linux系统入门指南:从零开始学习Linux
Shell脚本是一种强大的自动化工具,可以帮助您简化重复的任务或创建复杂的脚本程序。了解Shell脚本的基本语法和常用命令,以及编写和运行Shell脚本的步骤,将使您更高效地处理日常任务。
461 0