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

目录

[一 输入设备编程介绍](#一 输入设备编程介绍)

[1.1 什么是输入设备呢?](#1.1 什么是输入设备呢?)

[1.2 什么是输入设备的应用编程?](#1.2 什么是输入设备的应用编程?)

[1.3 input子系统](#1.3 input子系统)

[1.4 数据读取流程](#1.4 数据读取流程)

[1.5 应用程序如何解析数据](#1.5 应用程序如何解析数据)

[1.5.1 按键类事件:](#1.5.1 按键类事件:)

[1.5.2 相对位移事件](#1.5.2 相对位移事件)

[1.5.3 绝对位移事件](#1.5.3 绝对位移事件)

[二 读取 struct input_event数据](#二 读取 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 结构体类型数据,该结构体定 义在头文件中,它的定义如下:

cpp 复制代码
struct input_event { 
 struct timeval time; 
 __u16 type; 
 __u16 code; 
 __s32 value; 
}; 

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

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

cpp 复制代码
#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 
#define EV_SND 0x12 
#define EV_REP 0x14 
#define EV_FF 0x15 
#define EV_PWR 0x16 
#define EV_FF_STATUS 0x17 
#define EV_MAX 0x1f 
#define EV_CNT (EV_MAX+1) 

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

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

1.5.1 按键类事件:

cpp 复制代码
#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 键 

1.5.2 相对位移事件

cpp 复制代码
#define REL_X 0x00 //X 轴 
#define REL_Y 0x01 //Y 轴 
#define REL_Z 0x02 //Z 轴 
#define REL_RX 0x03 
#define REL_RY 0x04   
#define REL_RZ 0x05 
#define REL_HWHEEL 0x06 
#define REL_DIAL 0x07 
#define REL_WHEEL 0x08 
#define REL_MISC 0x09 
#define REL_MAX 0x0f 
#define REL_CNT (REL_MAX+1)

1.5.3 绝对位移事件

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

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

cpp 复制代码
#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 
#define ABS_BRAKE 0x0a 
#define ABS_HAT0X 0x10 
#define ABS_HAT0Y 0x11 
#define ABS_HAT1X 0x12 
#define ABS_HAT1Y 0x13 
#define ABS_HAT2X 0x14 
#define ABS_HAT2Y 0x15 
#define ABS_HAT3X 0x16 
#define ABS_HAT3Y 0x17 
#define ABS_PRESSURE 0x18 
#define ABS_DISTANCE 0x19 
#define ABS_TILT_X 0x1a 
#define ABS_TILT_Y 0x1b 
#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类型数据中的每一个元素打印出来、并对它们进行解析。

cpp 复制代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <linux/input.h>

void main(int argc,char *argv[])
{
    struct input_event in_ev = {0};
    int fd = -1;    //打开设备文件返回的句柄
    if(argc != 2)
    {
        fprintf(stderr,"格式:%s  <input-dev> \n <input-dev>为设备文件路径\n",argv[0]);
        exit(-1);
    }
    fd = open(argv[1],O_RDONLY);
    if(fd < 0)
    {
        perror("");
        exit(-1);
    }
    while(1)
    {
         if (sizeof(struct input_event) != read(fd, &in_ev, sizeof(struct input_event))) 
         {
             perror("");
             exit(-1);
         }
        printf("type(对事件的分类):%d code(具体事件):%d value(状态):%d\n", in_ev.type, in_ev.code, in_ev.value);
    }

}

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

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

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

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

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

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

相关推荐
永霖光电_UVLED10 小时前
KAIST 团队研发出高效、超高分辨率的红色微米发光二极管(Micro-LED)显示器
计算机外设
春日见2 天前
车辆动力学:前后轮车轴
java·开发语言·驱动开发·docker·计算机外设
PHOSKEY2 天前
光子精密QM系列闪测仪在鼠标电路板部件质量控制中的核心应用
计算机外设
墩墩冰2 天前
计算机图形学 分析选择缓冲区中的数字
计算机外设
UI设计兰亭妙微2 天前
中车株州所显示器界面设计
计算机外设·界面设计
墩墩冰2 天前
计算机图形学 多视区的显示
计算机外设
墩墩冰2 天前
计算机图形学 GLU库中的二次曲面函数
计算机外设
墩墩冰2 天前
计算机图形学 利用鼠标实现橡皮筋技术
计算机外设
企鹅侠客4 天前
鼠标键盘按键统计工具
计算机外设·键盘·鼠标
华一精品Adreamer5 天前
便携式显示器供应链与成本结构:挑战与机遇
计算机外设