首页 > 系统相关 >Linux系统中输入设备的应用编程实现

Linux系统中输入设备的应用编程实现

时间:2022-11-12 19:02:02浏览次数:43  
标签:编程 value 事件 KEY Linux input 应用程序 输入 define


    大家好,今天主要来聊一聊,如何使用Linux系统下的输入设备进行应用编程。

目录

​​第一:什么是输入设备​​

​​第二:读取数据的流程​​

​​第三:应用程序该如何解析​​

​​第四:数据同步方法​​

​​第五:读取struct input_event数据代码实现​​


Linux系统中输入设备的应用编程实现_输入设备

第一:什么是输入设备

     先来了解一下什么是输入设备(称为input设备),常见的输入设备有鼠标、键盘、触摸屏、遥控器、画图板等,用户通过输入设备与系统进行交互。

     由上面可知,输入设备种类非常多,那么Linux系统如何管理呢?Linux系统为了统一管理这些输入设备,实现了一套能够兼容所有输入设备的框架,那么这个框架就是input子系统。驱动开发人员基于input子系统开发输入设备的驱动程序,input子系统可以屏蔽硬件的差异,向应用层提供一套统一的接口。

     基于input子系统注册成功的输入设备,都会在/dev/input目录下生产对应的设备节点(设备文件),设备文件节点名称通常为eventX()(X表示一个数字编号0,1,2,3,等),譬如/dev/input/event0、/dev/input/event1、 /dev/input/event2 等,通过读取这些设备节点可以获取输入设备上报的数据。

第二:读取数据的流程

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

     1、应用程序打开/dev/input/event0设备文件。

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

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

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

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

第三:应用程序该如何解析

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

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

    结构体中的time成员变量是一个struct timeval类型的变量,该结构体在前面给大家介绍过,内核会记录每个上报的事件及发生的时间,并通过变量 time 返回给应用程序。时间参数通常不是那么重要,而其它 3 个成员变量 type、code、value 更为重要。

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

#define EV_SYN 0x00 //同步类事件,用于同步事件
#define EV_KEY 0x01 //按键类事件
#define EV_REL 0x02 //相对位移类事件(譬如鼠标)
#define EV_ABS 0x03 //绝对位移类事件(譬如触摸屏)
#define EV_MSC 0x04 //其它杂类事件

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

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

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

相对位移事件

#define REL_X 0x00 //X 轴
#define REL_Y 0x01 //Y 轴
#define REL_Z 0x02 //Z 轴
#define REL_RX 0x03
#define REL_RY 0x04

绝对位移事件

    触摸屏设备是一种绝对位移设备,它能产生绝对位移事件;譬如对于触摸屏来说,一个触摸点所包含的信息可能有多种,譬如触摸点的X轴坐标、Y轴坐标、Z轴坐标,按压大小以及接触面积等,所以code变量告知应用程序当前上报的是触摸点的哪一种信息。

#define ABS_X 0x00 //X 轴
#define ABS_Y 0x01 //Y 轴
#define ABS_Z 0x02 //Z 轴
#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

     以上除了列举出来的之外,还有很多,大家可以预览<linux/input.h>头文件。

     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 值而定!

第四:数据同步方法

      应用程序读取输入设备上报的数据时,一次 read 操作只能读取一个 struct input_event 类型数据,譬如对于触摸屏来说,一个触摸点的信息包含了 X 坐标、Y 坐标以及其它信息,对于这样情况,应用程序需要执行多次 read 操作才能把一个触摸点的信息全部读取出来,这样才能得到触摸点的完整信息。那么应用程序如何得知本轮已经读取到完整的数据了呢?其实这就是通过同步事件来实现的,内核将本轮需要上报、发送给接收者的数据全部上报完毕后,接着会上报一个同步事件,以告知应用程序本轮数据已经完整、可以进行同步了。

     所有的输入设备都需要上报同步事件通常是SYN_REPORT,而value值通常为0。

第五:读取struct input_event数据代码实现

     对输入设备调用read()会读取到一个struct input_event类型数据。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/input.h>
int main(int argc, char *argv[])
{
struct input_event in_ev = {0};
int fd = -1;
/* 校验传参 */
if (2 != argc) {
fprintf(stderr, "usage: %s <input-dev>\n", argv[0]);
exit(-1);
}
/* 打开文件 */
if (0 > (fd = open(argv[1], O_RDONLY))) {
perror("open error");
exit(-1);
}
for ( ; ; ) {
/* 循环读取数据 */
if (sizeof(struct input_event) !=
read(fd, &in_ev, sizeof(struct input_event))) {
perror("read error");
exit(-1);
}
printf("type:%d code:%d value:%d\n",
in_ev.type, in_ev.code, in_ev.value);
}
}

    分析:该案件是,在出厂系统中,该案件驱动基于input子系统而实现,所以在/dev/input目录下存在KEY0的设备节点,具体是哪个设备节点,可以查看/proc/bus/input/devices文件得知。

Linux系统中输入设备的应用编程实现_驱动开发_02

执行结果如下:

Linux系统中输入设备的应用编程实现_linux_03

程序运行后,执行按下 KEY0、松开 KEY0 等操作,终端将会打印出相应的信息,如上图所示。

      第一行中 type 等于 1,表示上报的是按键事件 EV_KEY,code=114,打开 input-event-codes.h 头文件进行查找,可以发现 cpde=114 对应的是键盘上的 KEY_VOLUMEDOWN 按键,这个开发板出厂系统已经配置好的。而 value=1 表示按键按下,所以整个第一行的意思就是按键 KEY_VOLUMEDOWN被按下。

    第二行,表示上报了 EV_SYN 同步类事件(type=0)中的 SYN_REPORT 事件(code=0),表示本轮数据已经完整、报告同步。

     第三行,type 等于 1,表示按键类事件,code 等于 114、value 等于 0,所以表示按键 KEY_VOLUMEDOWN被松开。

      第四行,又上报了同步事件。

      所以整个上面 4 行的打印信息就是开发板上的 KEY0 按键被按下以及松开这个过程,内核所上报的事件以及发送给应用层的数据 value。我们试试长按按键 KEY0,按住不放,如下所示:

Linux系统中输入设备的应用编程实现_输入设备_04

   可以看到上报按键事件时,对应的 value 等于 2,表示长按状态。

  总结:使用好标准的输入设备系统,对实现输入功能具有重要意义。

标签:编程,value,事件,KEY,Linux,input,应用程序,输入,define
From: https://blog.51cto.com/u_11947739/5846753

相关文章

  • Linux系统中线程同步方式中的条件变量操作方法
      大家好,今天主要和大家聊一聊,如何使用Linux中线程同步方式中的条件变量。    第一:条件变量基本简介   条件变量是线程可用的另一种同步机制,条件变量用于自动阻......
  • ubuntu安装搜狗输入法
    https://shurufa.sogou.com/linux?r=pinyin在如上链接下载,然后使用dpkg命令安装在电脑设置中找到“区域和语言”,然后点击“管理已安装的语言”,将系统输入法系统更改为“f......
  • 编写C程序,实现链队列的下列功能: 1、设计一个虚拟界面,让用户选择操作(根据提示输入数据
    编写C程序,实现链队列的下列功能: 1、设计一个虚拟界面,让用户选择操作(根据提示输入数据)2、采用模块化编程思想,编写main函数和若干子函数(实现功能)3、队列的基本功能有:......
  • 极客编程python入门-不可变对象
    不可变对象str是不变对象,而list是可变对象对于可变对象,比如list,对list进行操作,list内部的内容是会变化的,比如l=[1,2,34,56,34,78,23,12,12,34,45,657,45]l.sort()print(l)......
  • 实验二结对编程
    1实验内容及要求 1.1 教学内容及要求完成结对项目,实现代码复审。1.2 实验要求首先在同学中找一个同伴,范围不限,可以在1~3班中随意组合,不要找同组的成员,女同学尽量......
  • 增加虚拟机容量之linux硬盘格式在线从mbr转为gpt格式
    1、安装gdiskyuminstall-ygdisk 2、3、以上操作完毕后,检查一下数据(正常不会丢数据的)4、扩容yuminstallcloud-utils-growpartyuminstallxfsprogs扩展磁盘,扩容文件系......
  • linux 中shell 脚本将 gff文件转换为bed文件
     001、[b20223040323@admin1test]$ls##测试gff文件exons_only.gff[b20223040323@admin1test]$gff2bed<exons_only.gff>exons_only.bed##gff2bed模块......
  • linux_mint_21 vim配置:剪贴板支持和输入法自动切换
    一、vim的剪贴板支持有的vim版本不支持系统剪切板,也就是说在vim编辑器外面复制的内容,不能够粘贴到vim中;在vim中通过yy、d、c复制剪切的内容也不能粘贴在vim编辑器外......
  • 输入密码才可见指定工作表
     问题:Sheet3只有输入密码才能进入。查看Sheet3的代码:SubSh()DimMyPwAsStringMyPw=InputBox("请输入密码","密码")IfMyPw="aaa"ThenSheets(......
  • linux下安装MySQL8.0
    linux下安装MySQL8.0本次安装演示版本为8.0.281、准备安装目录及其安装包cd/usr/local/mkdirmysqlcdmysql#使用wget下载mysql安装包(如果下载慢,可自行提前准备安......