• Linux输入设备应用编程(键盘,按键,触摸屏,鼠标)


    目录

    一 输入设备编程介绍

    1.1 什么是输入设备呢?

     1.2 什么是输入设备的应用编程? 

     1.3 input子系统

    1.4  数据读取流程

    1.5 应用程序如何解析数据

    1.5.1 按键类事件:

     1.5.2 相对位移事件 

    1.5.3 绝对位移事件 

    二 读取 struct input_event数据  


    一 输入设备编程介绍

    本章学习Linux输入设备的应用编程。

    1.1 什么是输入设备呢?

    输入设备其实就是能够产生输入事件的 设备就称为输入设备,常见的输入设备包括鼠标、键盘、触摸屏、按钮等等,它们都能够产生输入事件,产 生输入数据给计算机系统。

     1.2 什么是输入设备的应用编程? 

    输入设备的应用编程其主要是获取输入设备上报的数据、输入设备当前状态等,譬如获取触摸屏当 前触摸点的 X、Y 轴位置信息以及触摸屏当前处于按下还是松开状态,然后根据获取到的数据做出对应的操作。

     1.3 input子系统

    输入设备种类非常多,每种设备上报的数据类型又不一样,那么 Linux 系统如何管 理呢?

    Linux 系统为了统一管理这些输入设备,实现了一套能够兼容所有输入设备的框架,那么这个框架就 是 input 子系统。驱动开发人员基于 input 子系统开发输入设备的驱动程序,input 子系统可以屏蔽硬件的差 异,向应用层提供一套统一的接口。 基于 input 子系统注册成功的输入设备,都会在/dev/input 目录下生成对应的设备节点(设备文件),设 备节点名称通常为 eventX(X 表示一个数字编号 0、1、2、3 等),如/dev/input/event0、/dev/input/event1、 /dev/input/event2 等,通过读取这些设备节点可以获取输入设备上报的数据。

     

    1.4  数据读取流程

    我们要读取触摸屏的数据,假设触摸屏设备对应的设备节点为/dev/input/event0,那么数据读取流程 如下:

    ①、应用程序打开/dev/input/event0 设备文件;

    ②、应用程序发起读操作(譬如调用 read),如果没有数据可读则会进入休眠(阻塞 I/O 情况下);

    ③、当有数据可读时,应用程序会被唤醒,读操作获取到数据返回;

    ④、应用程序对读取到的数据进行解析。

    当无数据可读时,程序会进入休眠状态(也就是阻塞),譬如应用程序读触摸屏数据,如果当前并没有 去触碰触摸屏,自然是无数据可读;当我们用手指触摸触摸屏或者在屏上滑动时,此时就会产生触摸数据、 应用程序就有数据可读了,应用程序会被唤醒,成功读取到数据。那么对于其它输入设备亦是如此,无数据 可读时应用程序会进入休眠状态(阻塞式 I/O 方式下),当有数据可读时才会被唤醒。

    1.5 应用程序如何解析数据

    应用程序打开输入设备对应的设备文件,向其发起读操作,那么这个读操作获取到的是什么样的数据呢?其实每一次 read 操作获取的都是一个 struct input_event 结构体类型数据,该结构体定 义在头文件中,它的定义如下:

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

    time :内核会记 录每个上报的事件其发生的时间

    typetype 用于描述发生了哪一种类型的事件(对事件的分类),Linux 系统所支持的输入事件类 型如下所示:

    1. #define EV_SYN 0x00 //同步类事件,用于同步事件
    2. #define EV_KEY 0x01 //按键类事件
    3. #define EV_REL 0x02 //相对位移类事件(譬如鼠标)
    4. #define EV_ABS 0x03 //绝对位移类事件(譬如触摸屏)
    5. #define EV_MSC 0x04 //其它杂类事件
    6. #define EV_SW 0x05
    7. #define EV_LED 0x11
    8. #define EV_SND 0x12
    9. #define EV_REP 0x14
    10. #define EV_FF 0x15
    11. #define EV_PWR 0x16
    12. #define EV_FF_STATUS 0x17
    13. #define EV_MAX 0x1f
    14. #define EV_CNT (EV_MAX+1)

     以上这些宏定义也是在头文件中,所以在应用程序中需要包含该头文件;一种输入设备 通常可以产生多种不同类型的事件,譬如点击鼠标按键(左键、右键,或鼠标上的其它按键)时会上报按键 类事件,移动鼠标时则会上报相对位移类事件。

    codecode 表示该类事件中的哪一个具体事件,以上列举的每一种事件类型中都包含了一系列具 体事件,譬如一个键盘上通常有很多按键,譬如字母 A、B、C、D 或者数字 1、2、3、4 等,而 code 变量则告知应用程序是哪一个按键发生了输入事件。每一种事件类型都包含多种不同的事件,譬如

    1.5.1 按键类事件:

    1. #define KEY_RESERVED 0
    2. #define KEY_ESC 1 //ESC 键
    3. #define KEY_1 2 //数字 1 键
    4. #define KEY_2 3 //数字 2 键
    5. #define KEY_TAB 15 //TAB 键
    6. #define KEY_Q 16 //字母 Q 键
    7. #define KEY_W 17 //字母 W 键
    8. #define KEY_E 18 //字母 E 键
    9. #define KEY_R 19 //字母 R 键

     1.5.2 相对位移事件 

    1. #define REL_X 0x00 //X 轴
    2. #define REL_Y 0x01 //Y 轴
    3. #define REL_Z 0x02 //Z 轴
    4. #define REL_RX 0x03
    5. #define REL_RY 0x04
    6. #define REL_RZ 0x05
    7. #define REL_HWHEEL 0x06
    8. #define REL_DIAL 0x07
    9. #define REL_WHEEL 0x08
    10. #define REL_MISC 0x09
    11. #define REL_MAX 0x0f
    12. #define REL_CNT (REL_MAX+1)

    1.5.3 绝对位移事件 

    触摸屏设备是一种绝对位移设备,它能够产生绝对位移事件;

    对于触摸屏来说,一个触摸点所包含的信息可能有多种,譬如触摸点的 X 轴坐标、Y 轴坐标、Z 轴坐标、按压力大小以及接触面积等,所以 code变量告知应用程序当前上报的是触摸点的哪一种信息(X 坐标还是 Y 坐标、亦或者其它); 

    1. #define ABS_X 0x00 //X 轴
    2. #define ABS_Y 0x01 //Y 轴
    3. #define ABS_Z 0x02 //Z 轴
    4. #define ABS_RX 0x03
    5. #define ABS_RY 0x04
    6. #define ABS_RZ 0x05
    7. #define ABS_THROTTLE 0x06
    8. #define ABS_RUDDER 0x07
    9. #define ABS_WHEEL 0x08
    10. #define ABS_GAS 0x09
    11. #define ABS_BRAKE 0x0a
    12. #define ABS_HAT0X 0x10
    13. #define ABS_HAT0Y 0x11
    14. #define ABS_HAT1X 0x12
    15. #define ABS_HAT1Y 0x13
    16. #define ABS_HAT2X 0x14
    17. #define ABS_HAT2Y 0x15
    18. #define ABS_HAT3X 0x16
    19. #define ABS_HAT3Y 0x17
    20. #define ABS_PRESSURE 0x18
    21. #define ABS_DISTANCE 0x19
    22. #define ABS_TILT_X 0x1a
    23. #define ABS_TILT_Y 0x1b
    24. #define ABS_TOOL_WIDTH 0x1c

     value:内核每次上报事件都会向应用层发送一个数据 value,对 value 值的解释随着 code 的变化而 变化。

    • 如对于按键事件(type=1)来说,如果 code=2(键盘上的数字键 1,也就是 KEY_1),那 么如果 value 等于 1,则表示 KEY_1 键按下;value 等于 0 表示 KEY_1 键松开,如果 value 等于 2  则表示 KEY_1 键长按。
    • 再比如,在绝对位移事件中(type=3),如果 code=0(触摸点 X 坐标 ABS_X), 那么 value 值就等于触摸点的 X 轴坐标值;同理,如果 code=1(触摸点 Y 坐标 ABS_Y),此时 value 值便等于触摸点的 Y 轴坐标值;所以对 value 值的解释需要根据不同的 code 值而定!

    二 读取 struct input_event数据  

    根据前面的介绍可知,对输入设备调用read()会读取到一个struct input_event类型数据,现写一个简单地应用程序,将读取到的struct input_event类型数据中的每一个元素打印出来、并对它们进行解析。

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. void main(int argc,char *argv[])
    10. {
    11. struct input_event in_ev = {0};
    12. int fd = -1; //打开设备文件返回的句柄
    13. if(argc != 2)
    14. {
    15. fprintf(stderr,"格式:%s \n 为设备文件路径\n",argv[0]);
    16. exit(-1);
    17. }
    18. fd = open(argv[1],O_RDONLY);
    19. if(fd < 0)
    20. {
    21. perror("");
    22. exit(-1);
    23. }
    24. while(1)
    25. {
    26. if (sizeof(struct input_event) != read(fd, &in_ev, sizeof(struct input_event)))
    27. {
    28. perror("");
    29. exit(-1);
    30. }
    31. printf("type(对事件的分类):%d code(具体事件):%d value(状态):%d\n", in_ev.type, in_ev.code, in_ev.value);
    32. }
    33. }

    执行程序时需要传入参数,这个参数就是对应的输入设备的设备节点(设备文件),程序中会对传参进行校验。程序中首先调用open()函数打开设备文件,之后在while循环中调用read()函数读取文件,将读取到的数据存放在struct input_event结构体对象中,之后将结构体对象中的各个成员变量打印出来。注意,程序中使用了阻塞式I/O方式读取设备文件,所以当无数据可读时read调用会被阻塞,知道有数据可读时才会被唤醒!

     

    交叉编译并拷贝到开饭板上 ,用cat指令获得设备节点路径 cat /proc/bus/input/devices

    测试程序,获取输入设备信息 

     

    code = 1时(按键事件时),对应的value等于2,表示长按状态。

    value等于1,表示按下状态。

    value等于0,表示松开状态。

  • 相关阅读:
    轻量级简约仪表板Dasherr
    Android 10 如何在SurfaceFlinger中解决开机动画显示不全问题
    redis我记不住的那些命令(一)
    Docker 上 gitlab私有化部署及邮箱配置
    JavaScript小技能:原型链的运作机制、Promise链
    电容笔有什么用?Ipad2018电容笔推荐
    Bonree ONE 2.0重磅发布,中国IT运维迈入数智融合3.0时代
    采购供应链可见性的详细介绍(数智化采购供应链系统)
    C语言循环队列
    MySQL json相关函数详解
  • 原文地址:https://blog.csdn.net/weixin_73901182/article/details/134450746