Linux输入设备应用编程

news2024/12/27 7:45:28

本章学习输入设备的应用编程,首先要知道什么是输入设备?输入设备其实就是能够产生输入事件的设备就称为输入设备,常见的输入设备包括鼠标、键盘、触摸屏、按钮等等,它们都能够产生输入事件,产生输入数据给计算机系统。

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

本章将会讨论如下主题内容。

⚫ 什么是输入设备;

⚫ 如何读取输入设备的数据;

⚫ 如何解析从输入设备中获取到的数据;

⚫ 按键、触摸屏设备如何解析数据、应用编程。

输入类设备编程介绍

什么是输入设备

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

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,那么数据读取流程如下:

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

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

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

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

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

应用程序如何解析数据

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

示例代码 17.1.1 struct input_event 结构体

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

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

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

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

相对位移事件

绝对位移事件

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

除了以上列举出来的之外,还有很多,大家可以自己浏览<linux/input.h>头文件(这些宏其实是定义在input-event-codes.h 头文件中,该头文件被<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 值而定!

数据同步

上面我们提到了同步事件类型 EV_SYN,同步事件用于实现同步操作、告知接收者本轮上报的数据已经完整。应用程序读取输入设备上报的数据时,一次 read 操作只能读取一个 struct input_event 类型数据,譬如对于触摸屏来说,一个触摸点的信息包含了 X 坐标、Y 坐标以及其它信息,对于这样情况,应用程序需要执行多次 read 操作才能把一个触摸点的信息全部读取出来,这样才能得到触摸点的完整信息。

那么应用程序如何得知本轮已经读取到完整的数据了呢?其实这就是通过同步事件来实现的,内核将本轮需要上报、发送给接收者的数据全部上报完毕后,接着会上报一个同步事件,以告知应用程序本轮数据已经完整、可以进行同步了。

同步类事件中也包含了多种不同的事件,如下所示:

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

读取 struct input_event 数据

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

本例程源码对应的路径为:开发板光盘->11、Linux C 应用编程例程源码->17_input->read_input.c。

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

Tips:设备文件不同于普通文件,读写设备文件之前无需设置读写位置偏移量。

使用交叉编译工具编译上述代码得到可执行文件 testApp:

在开发板上验证

ALPHA 和 Mini 开发板上都有一个用户按键 KEY0,它就是一个典型的输入设备,如下图所示:

该按键是提供给用户使用的一个 GPIO 按键,在出厂系统中,该按键驱动基于 input 子系统而实现,所以在/dev/input 目录下存在 KEY0 的设备节点,具体是哪个设备节点,可以使用 13.1.1 小节介绍的方法进行判断,这里不再重述!也可以通过查看/proc/bus/input/devices 文件得知,查看该文件可以获取到系统中注册的所有输入设备相关的信息,如下所示:

接下来我们使用这个按键进行测试,执行下面的命令:

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

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

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

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

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

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

我们试试长按按键 KEY0,按住不放,如下所示:

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

按键应用编程

本小节编写一个应用程序,获取按键状态,判断按键当前是按下、松开或长按状态。从上面打印的信息可知,对于按键来说,它的事件上报流程如下所示:

如果是按下,则上报 KEY_A 事件时,value=1;如果是松开,则 value=0;如果是长按,则 value=2。

接下来编写按键应用程序,读取按键状态并将结果打印出来,代码如下所示:

本例程源码对应的路径为:开发板光盘->11、Linux C 应用编程例程源码->17_input->read_key.c。

在 for 循环中,调用 read()读取输入设备上报的数据,当按键按下或松开(以及长按)动作发生时,read()会读取到输入设备上报的数据,首先判断此次上报的事件是否是按键类事件(EV_KEY),如果是按键类事件、接着根据 value 值来判断按键当前的状态是松开、按下还是长按。

将上述代码进行编译:

将编译得到的可执行文件拷贝开发板 Linux 系统的/home/root 目录下。

首先我们来测试开发板的 KEY0 按键,执行应用程序:

./testApp /dev/input/event2 //测试开发板上的 KEY0

运行程序之后,按下 KEY0 或松开 KEY0 以及长按情况下,终端会打印出相应的信息,如上图所示。

code=114(KEY_VOLUMEDOWN 按键)。

除了测试开发板上的 KEY0 按键之外,我们还可以测试键盘上的按键,首先找到一个 USB 键盘连接到开发板的 USB HOST 接口上,当键盘插入之后,终端将会打印出相应的驱动加载信息:

驱动加载成功之后,可以查看下该键盘设备对应的设备节点,使用命令"cat/proc/bus/input/devices",在打印信息中找到键盘设备的信息:

譬如笔者使用的是一个罗技的USB 键盘"Logitech USB Keyboard",对应的设备节点为/dev/input/event3,

运行测试程序并按下、松开键盘上的按键:

大家可以根据 code 值查询到对应的按键(通过 input-event-codes.h 头文件),譬如 code=30 对应的是键盘上的字母 A 键,code=48 对应的是字母 B 键。

触摸屏应用编程

本小节编写触摸屏应用程序,获取触摸屏的坐标信息并将其打印出来。

解析触摸屏设备上报的数据

触摸屏设备是一个绝对位移设备,可以上报绝对位移事件,绝对位移事件如下:

单点触摸和多点触摸

触摸屏分为多点触摸设备和单点触摸设备。单点触摸设备只支持单点触摸,一轮(笔者把一个同步事件称为一轮)完整的数据只包含一个触摸点信息;单点触摸设备以 ABS_XXX 事件承载、上报触摸点的信息,譬如 ABS_Xvalue 值对应的是 X 轴坐标值)、ABS_Yvalue 值对应的是 Y 轴坐标值)等绝对位移事件,而有些设备可能还支持 Z 轴坐标(通过 ABS_Z 事件上报、value 值对应的便是 Z 轴坐标值)、按压力大小(通过 ABS_PRESSURE 事件上报、value 值对应的便是按压力大小)以及接触面积等属性。大部分的单点触摸设备都会上报 ABS_X ABS_Y 事件,而其它绝对位移事件则根据具体的设备以及驱动的实现而定!

多点触摸设备可支持多点触摸,譬如 ALPHA/Mini 开发板配套使用的 4.3 寸、7 寸等触摸屏均支持多点触摸,对于多点触摸设备,一轮完整的数据可能包含多个触摸点信息。多点触摸设备则是以 ABS_MT_XXX(MT Multi-touch,意思为:多点触摸)事件承载、上报触摸点的信息,如 ABS_MT_POSITION_XX 轴坐标)、ABS_MT_POSITION_YY 轴坐标)等绝对位移事件。

触摸屏设备除了上报绝对位移事件之外,还可以上报按键类事件和同步类事件。同步事件很好理解,因为几乎每一个输入设备都会上报同步事件、告知应用层本轮数据是否完整;当手指点击触摸屏或手指从触摸屏离开时,此时就会上报按键类事件,用于描述按下触摸屏和松开触摸屏;具体的按键事件为BTN_TOUCH(code=0x14a,也就是 330),当然,手指在触摸屏上滑动不会上报 BTN_TOUCH 事件。

Tips:BTN_TOUCH 事件不支持长按状态,故其 value 不会等于 2。对于多点触摸设备来说,只有第一个点按下时上报 BTN_TOUCH 事件 value=1、当最后一个点离开触摸屏时上报 BTN_TOUCH 事件 value=0。

单点触摸设备--事件上报的顺序

通过上面的介绍可知,单点触摸设备事件上报的流程大概如下所示:

以上列举出只是一个大致流程,实际上对于不同的触摸屏设备,能够获取到的信息量大小是不相同的,譬如某设备只能读取到触摸点的 X Y 坐标、而另一设备却能读取 XY 坐标以及按压力大小、触点面积等信息,总之这些数据都会在 SYN_REPORT 同步事件之前上报给应用层。

当手指点击触摸屏时,首先上报 BTN_TOUCH 事件,此时 value=1,表示按下;接着上报ABS_XABS_Y事件将 XY 轴坐标数据发送给应用层;数据上报完成接着上报一个同步事件 SYN_REPORT,表示此次触摸点信息已经完整。

当手指在触摸屏上滑动时,并不会上报 BTN_TOUCH 事件,因为滑动过程并未发生按下、松开这种动作。

当松开时,首先上报了 BTN_TOUCH 事件,此时 value=0,表示手指已经松开了触摸屏,接着上报一个同步事件 SYN_REPORT

以上就是单点触摸设备事件上报的一个大致流程,接下来看看多点触摸设备。

多点触摸设备--事件上报的顺序

多点触摸设备上报的一轮完整数据中可能包含多个触摸点的信息,譬如 5 点触摸设备,如果 5 个手指同时在触摸屏上滑动,那么硬件就会更新 5 个触摸点的信息,内核需要把这 5 个触摸点的信息上报给应用层。

Linux 内核中,多点触摸设备使用多点触摸(MT)协议上报各个触摸点的数据,MT 协议分为两种类型:Type A Type BType A 协议实际使用中用的比较少,几乎处于淘汰的边缘,这里就不再给大家介绍了,我们重点来看看 Type B 协议。

MT 协议之 Type B 协议

Type B 协议适用于能够追踪并区分触摸点的设备,开发板配套使用的触摸屏都属于这类设备。Type B协议的重点是通过 ABS_MT_SLOT 事件上报各个触摸点信息的更新!能够追踪并区分触摸点的设备通常在硬件上能够区分不同的触摸点,譬如对于一个 5 点触摸设备来说, 硬件能够为每一个识别到的触摸点与一个 slot 进行关联,这个 slot 就是一个编号,触摸点 0、触摸点 1、触摸点 2 等。底层驱动向应用层上报 ABS_MT_SLOT 事件,此事件会告诉接收者当前正在更新的是哪个触摸点的数据,ABS_MT_SLOT 事件中对应的 value 数据存放的便是一个 slot、以告知应用层当前正在更新 slot关联的触摸点对应的信息。

每个识别出来的触摸点分配一个 slot,与该 slot 关联起来,利用这个 slot 来传递对应触点的变化。除了ABS_MT_SLOT 事 件 之 外 , Type B 协 议 还 会 使 用 到 ABS_MT_TRACTKING_ID 事 件,ABS_MT_TRACTKING_ID 事件则用于触摸点的创建、替换和销毁工作,ABS_MT_TRACTKING_ID 事件携带的数据 value 表示一个 ID,一个非负数的 IDID>=0)表示一个有效的触摸点,如果 ID 等于-1 表示该触摸点已经不存在、被移除了;一个以前不存在的 ID 表示这是一个新的触摸点。

Type B 协议可以减少发送到用户空间的数据,只有发生了变更的数据才会上报,譬如某个触摸点发生了移动,但仅仅只改变了 X 轴坐标、而未改变 Y 轴坐标,那么内核只会将改变后的 X 坐标值通过ABS_MT_POSITION_X 事件发送给应用层。

以上关于 Type B 协议就给大家介绍这么多,为了帮助大家理解,笔者把 Type B 协议下多点触摸设备上报数据的流程列举如下:

单看这个可能大家看不懂,接下来我们打印触摸屏的数据一个一个进行分析。

Tips:大家可能会对 slot 和 ID 这两个概念有点混乱,这里笔者将自己的理解告知大家;slot 是硬件上的一个概念、而 ID 则可认为是软件上的一个概念;对于一个多点触摸设备来说,它最大支持的触摸点数是确定的,譬如 5 个触摸设备,最多支持 5 个触摸点;每一个触摸点在硬件上它有一个区分的编号,譬如触摸点0、触摸点 1、触摸点 2 等,这个编号就是一个 slot(通常从 0 开始);如何给识别到的触点分配一个 slot 呢(触点与 slot 关联)?通常是按照时间先后顺序来的,譬如第一根手指先触碰到触摸屏,那第一根手指就对应触摸点 0(slot=0),接着第二根手指触碰到触摸屏则对应触摸点 1(slot=1)以此类推!这个通常是硬件所支持的。而 ID 可认为是软件上的一个概念,它也用于区分不同的触摸点,但是它跟 slot 不同,不是同一层级的概念;举个例子,譬如一根手指触碰到触摸屏之后拿开,然后再次触碰触摸屏,这个过程中,假设只有这一根手指进行触碰操作,那么两次触碰对应都是触摸点 0(slot=0),这个无疑义!但从触摸点的生命周期来看,它们是同一个触摸点吗?答案肯定不是,为啥呢?手指从触摸屏上离开后,该触摸点就消失了、被删除了,该触摸点的生命周期也就到此结束了,所以它们自然是不同的触摸点,所以它们的 ID 是不同的。

触摸屏上报数据分析

首先在测试触摸屏之前,需要保证开发板上已经连接了 LCD 屏,ALPHA/Mini I.MX6U 开发板出厂系统配套支持多种不同分辨率的 LCD 屏,包括 4.3 480*2724.3 800*4807 800*4807 1024*600以及 10.1 1280*800,在启动开发板之前需要将 LCD 屏通过软排线连接到开发板的 LCD 接口,开发板连接好 LCD 屏之后上电启动开发板、运行出厂系统。

触摸屏与 LCD 液晶屏面板是粘合在一起的,也就是说触摸屏是直接贴在了 LCD 液晶屏上面,直接在LCD 屏上触摸、滑动操作即可。为了测试方便,可以将出厂系统的 GUI 应用程序退出,如何退出呢?点击屏幕进入设置页面,可以看到在该页面下有一个退出按钮选项,直接点击即可!

使用命令"cat /proc/bus/input/devices",确定触摸屏对应的设备节点,如下所示:

笔者使用的是开发板配套的 4.3 800*480 LCD 屏,如果各位读者使用的是其它屏,那么查看到的名称可能不是"goodix-ts"。执行示例代码 17.2.1 对应的可执行文件,一个手指点击触摸屏先不松开,终端将会打印如下信息:

首先第一行上报了绝对位移事件 EV_ABStype=3)中的 ABS_MT_TRACKING_IDcode=57)事件,并且 value 值等于 78,也就是 ID,这个 ID 是一个非负数,所以表示这是一个新的触摸点被创建,也就意味着触摸屏上产生了一个新的触摸点(手指按下)。

第二行上报了绝对位移事件 EV_ABStype=3)中的 ABS_MT_POSITION_Xcode=53)事件,其 value对应的便是触摸点的 X 坐标;第三行上报了 ABS_MT_POSITION_Ycode=54)事件,其 value 值对应的便是触摸点 Y 坐标,所以由此可知该触摸点的坐标为(372, 381)

第四行上报了按键类事件 EV_KEYtype=1)中的 BTN_TOUCHcode=330),value 值等于 1,表示这是触摸屏上最先产生的触摸点(slot=0、也就是触摸点 0)。

第五行和第六行分别上报了绝对位移事件 EV_ABStype=3)中的 ABS_Xcode=0)和 ABS_Ycode=1),其 value 分别对应的是触摸点的 X 坐标和 Y 坐标。多点触摸设备也会通过 ABS_XABS_Y 事件上报触摸点的 XY 坐标,但通常只有触摸点 0 支持,所以可以把多点触摸设备当成单点触摸设备来使用。

最后一行上报了同步类事件 EV_SYNtype=0)中的 SYN_REPORTcode=0)事件,表示此次触摸点的信息全部上报完毕。

在第一个触摸点的基础上,增加第二个触摸点,打印信息如下所示:

1~7 行不再解释,第八行上报了绝对位移事件 EV_ABStype=3)中的 ABS_MT_SLOT 事件(code=47),表示目前要更新 slot=1 所关联的触摸点(也就是触摸点 1)对应的信息。

第九行上报了绝对位移事件 EV_ABStype=3)中的 ABS_MT_TRACKING_ID 事件(code=57),ID=79,这是之前没有出现过的 ID,表示这是一个新的触摸点。

第十、十一行分别上报了 ABS_MT_POSITION_X ABS_MT_POSITION_Y 事件。

最后一行上报同步事件(type=0code=0),告知应用层数据完整。

当手指松开时,触摸点就会被销毁,上报 ABS_MT_TRACKING_ID 事件,并将 value 设置为-1ID),如下所示:

关于触摸屏数据的分析就给大家介绍这么多,不管是键盘也好、或者是鼠标、触摸屏,都可以像上面那样将输入设备的数据直接打印出来,然后自己再去分析,确定该输入设备上报事件的规则和流程,把这些弄懂之后再去编写程序验证结果。下面我们将自己动手编写单点触摸以及多点触摸应用程序,读取触摸点的坐标信息。

获取触摸屏的信息

本小节介绍如何获取触摸屏设备的信息,譬如触摸屏支持的最大触摸点数、触摸屏 XY 坐标的范围等。通过 ioctl()函数可以获取到这些信息,3.10.2 小节给大家介绍过该函数,ioctl()是一个文件 I/O 操作的杂物箱,可以处理的事情非常杂、不统一,一般用于操作特殊文件或设备文件,为了方便讲解,再次把 ioctl()函数的原型列出:

#include <sys/ioctl.h>

int ioctl(int fd, unsigned long request, ...);

第一个参数 fd 对应文件描述符;第二个参数 request 与具体要操作的对象有关,没有统一值,表示向文件描述符请求相应的操作,也就是请求指令;此函数是一个可变参函数,第三个参数需要根据 request 参数来决定,配合 request 来使用。

先来看下输入设备的 ioctl()该怎么用,在 input.h 头文件有这样一些宏定义,如下所示:

每一个宏定义后面都有相应的注释,对于 input 输入设备,对其执行 ioctl()操作需要使用这些宏,不同的宏表示不同请求指令;譬如使用 EVIOCGNAME 宏获取设备名称,使用方式如下:

EVIOCGNAME(len)就表示用于接收字符串数据的缓冲区大小,而此时 ioctl()函数的第三个参数需要传入一个缓冲区的地址,该缓冲区用于存放设备名称对应的字符串数据。

EVIOCGget)开头的表示获取信息,EVIOCSset)开头表示设置;这里暂且不管其它宏,重点来看看 EVIOCGABS(abs)宏,这个宏也是通常使用最多的,如下所示:

#define EVIOCGABS(abs)

_IOR('E', 0x40 + (abs), struct input_absinfo)

通过这个宏可以获取到触摸屏 slotslot<0>表示触摸点 0slot<1>表示触摸点 1slot<2>表示触摸点 2,以此类推!)的取值范围,可以看到使用该宏需要传入一个 abs 参数,该参数表示为一个 ABS_XXX 绝对位移事件,譬如 EVIOCGABS(ABS_MT_SLOT)表示获取触摸屏的 slot 信息,此时 ioctl()函数的第三个参数是一个 struct input_absinfo *的指针,指向一个 struct input_absinfo 对象,调用 ioctl()会将获取到的信息写入到struct input_absinfo 对象中。struct input_absinfo 结构体如下所示:

获取触摸屏支持的最大触摸点数:

其它宏定义不再介绍,读者可以自行测试。

获取触摸屏支持的最大触摸点数

本例程源码对应的路径为:开发板光盘->11Linux C 应用编程例程源码->17_input->read_slot.c

编译示例代码,将其拷贝到开发板 Linux 系统的用户家目录下,执行该应用程序:

所以从打印结果可知,我们这个屏是一个 5 点触摸屏。

单点触摸应用程序

通过上面的详细介绍,详细大家应该知道如何去编写一个触摸屏的应用程序了,本小节我们编写一个单点触摸应用程序,获取一个触摸点的坐标信息,并将其打印出来。

ALPHA/Mini 开发板配套使用的触摸屏均支持多点触摸,这里我们把它当成单点触摸设备来使用,编写一个程序读取一个触摸点,示例代码如下所示:

本例程源码对应的路径为:开发板光盘->11Linux C 应用编程例程源码->17_input->read_ts.c

程序中首先校验传参,通过传参的方式将触摸屏设备文件路径传入到程序中,main()函数中定义了 4 个变量:

⑴、变量 x 表示触摸点的 X 坐标;

⑵、变量 y 表示触摸点的 Y 坐标;

⑶、变量 down 表示手指状态时候按下、松开还是滑动,down=1 表示手指按下、down=0 表示手指松开、down=-1 表示手指滑动;

⑷、变量 valid 表示数据是否有效,valid=1 表示有效、valid=0 表示无效;有效指的是我们检测的信息发生了更改,譬如程序中只检测了手指的按下、松开动作以及坐标值的变化。

接着调用 open()打开触摸屏设备文件得到文件描述符 fd;在 for 循环之前,首先对 xydownvalid这 4 个变量进行初始化操作。在 for 循环读取触摸屏上报的数据,将读取到的数据存放在 struct input_event数据结构中。在 switch…case 语句中对读取到的数据进行解析,获取 BTN_TOUCH 事件的 value 数据,判断触摸屏是按下还是松开状态,获取 ABS_X ABS_Y 事件的 value 变量,得到触摸点的 X 轴坐标和 Y 轴坐标。

当上报同步事件时,表示数据已经完整,接着对我们得到的数据进行分析、打印坐标信息。

编译应用程序:

将编译得到的可执行文件拷贝到开发板 Linux 系统的用户家目录下,准备进行测试。

笔者使用的是 4.3 800*480 LCD 屏,执行单点触摸应用程序,程序执行之后,接着用一个手指按下触摸屏、松开以及滑动操作,串口终端将会打印出相应的信息:

当手指点击触摸屏时会打印"按下(X, Y)",松开时会打印"松开",手指在触摸屏上滑动时会打印"移动(X, Y)"等信息。大家可以自己动手测试,对代码不理解的,可以对照测试结果进行对比。

多点触摸应用程序

介绍完单点触摸应用程序之后,再来看看多点触摸应用程序该如何编写,前面已经详细给大家介绍了多点触摸设备的事件上报流程。

本例程源码对应的路径为:开发板光盘->11Linux C 应用编程例程源码->17_input->read_mt.c

示例代码中申明了 struct ts_mt 数据结构,用于描述多点触摸情况下每一个触摸点的信息。

首先来看下 main()函数,定义了 max_slots 变量,用于指定触摸屏设备的支持的最大触摸点数,通过:

ioctl(fd, EVIOCGABS(ABS_MT_SLOT), &slot)

获取到触摸屏该信息。

接着根据 max_slots 变量的值,为 mt 指针申请内存:

mt = calloc(max_slots, sizeof(struct ts_mt));

for( ; ; )循环中调用 ts_read()函数,该函数是自定义函数,用于获取触摸屏上报的数据,第一个参数表示文件描述符 fd、第二个参数表示触摸屏支持的最大触摸点数、第三个参数则是 struct ts_mt 数组,ts_read()函数会将获取到的数据存放在数组中,mt[0]表示 slot<0>数据、mt[1]表示 slot<1>的数据依次类推!

在内部的 for 循环中,则对获取到的数据进行分析,判断数据是否有效,并根据 id 判断手指的动作,在单点触摸应用程序中,我们是通过 BTN_TOUCH 事件来判断手指的动作;而在多点触摸应用中,我们需要通过 id 来判断多个手指的动作。

关于自定义函数 ts_read()就不再介绍了,代码的注释已经描述很清楚了!

接着编译应用程序,将编译得到的可执行文件拷贝到开发板 Linux 系统的用户家目录下,执行应用程序,接着可以用多个手指触摸触摸屏、松开、滑动等操作:

每一个不同的 slot 表示不同的触摸点,譬如 slot<0>表示触摸点 0slot<1>表示触摸点 1 以此类推!

鼠标应用编程

本小节是笔者留给各位读者的一个作业,交给大家去完成,通过本章内容的介绍相信大家可以独立完成,ALPHA/Mini 开发板出厂系统支持 USB 鼠标,直接将一个 USB 鼠标插入到开发板的 USB HOST 接口即可,在终端会打印驱动加载信息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2253773.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

STM32MX 配置CANFD收发通讯

一、环境 MCU&#xff1a;STM32G0B1CEU6 CAN收发器&#xff1a;JIA1042 二、MX配置 配置SYS 配置canfd并开启中断&#xff0c;我开了两个FDCAN&#xff0c;配置是一样的&#xff0c;这里贴一下波特率的计算公式&#xff1a; 也就是&#xff1a;CAN时钟频率/预分频器/&…

第100+32步 ChatGPT学习:时间序列EMD分解

基于Python 3.9版本演示 一、写在前面 之前我们介绍过时间序列的季节性分解。 最近又学到了好几种骚操作分解&#xff0c;且可以用这些分解优化时间序列预测性能。 首先&#xff0c;我们来学一学经验模态分解&#xff08;Empirical Mode Decomposition&#xff0c;EMD&#…

Spring Shell如何与SpringBoot集成并快速创建命令行界面 (CLI) 应用程序

Spring Shell 介绍 Spring Shell 是一个强大的工具&#xff0c;可用于构建命令行应用程序&#xff0c;提供了简单的方式来创建和管理交互式 CLI。它适合那些希望通过命令行与 Java 应用程序进行交互的开发者&#xff0c;尤其是在需要自动化、交互式输入或与 Spring 生态系统集…

后端返回前端的数据量过大解决方案

后端返回前端的数据量过大解决方案 性能面板(Performance) chrome调试指南 原因 遇到一个页面有好几个表格&#xff0c;部分表格采用虚拟滚动条 数据量有点大 接近快60s了&#xff0c;看一下是哪里导致的慢 后台请求方法执行并不慢 2024-12-04 15:21:52.889 INFO 69948 …

linux 系列服务器 高并发下ulimit优化文档

系统输入 ulimit -a 结果如下 解除 Linux 系统的最大进程数 要解除或提高 Linux 系统的最大进程数&#xff0c;可以修改 ulimit 设置和 /etc/security/limits.conf 文件中的限制。 临时修改 ulimit 设置 可以使用 ulimit 命令来查看和修改当前会话的最大进程数&#xff1a; 查…

c++数据结构算法复习基础--11--高级排序算法-快速排序-归并排序-堆排序

高阶排序 1、快速排序 冒泡排序的升级算法 每次选择一个基准数&#xff0c;把小于基准数的放到基准数的左边&#xff0c;把大于基准数的放到基准数的右边&#xff0c;采用 “ 分治算法 ”处理剩余元素&#xff0c;直到整个序列变为有序序列。 最好和平均的复杂度&#xff1a…

洛谷P1827 [USACO3.4] 美国血统 American Heritage(c嘎嘎)

题目链接&#xff1a;P1827 [USACO3.4] 美国血统 American Heritage - 洛谷 | 计算机科学教育新生态 题目难度&#xff1a;普及 首先介绍下二叉树的遍历&#xff1a; 学过数据结构都知道二叉树有三种遍历&#xff1a; 1.前序遍历&#xff1a;根左右 2.中序遍历&#xff1a;左根…

# 全过程 快速创建一个Vue项目

如何快速创建一个Vue项目 前置知识 ​ 下载 Node.js 并且进行安装和配置 Node.js&#xff0c;因为 npm&#xff08;Node Package Manager&#xff09;是随 Node.js 一起安装的。 Node.js 下载地址 : Node.js 官方网站 ​ (如果你还没有关于 Node.js&webpack 的相关知识…

小程序 模版与配置

WXML模版语法 一、数据绑定 1、数据绑定的基本原则 &#xff08;1&#xff09;在data中定义数据 &#xff08;2&#xff09;在WXML中使用数据 2、在data中定义页面的数据 3、Mustache语法的格式&#xff08;双大括号&#xff09; 4、Mustache语法的应用场景 &#xff08;…

智慧银行反欺诈大数据管控平台方案(四)

智慧银行反欺诈大数据管控平台的核心内容&#xff0c;是通过整合多维度、多层次的金融交易信息&#xff0c;利用先进的大数据分析、机器学习与人工智能算法&#xff0c;构建一个系统性、实时性和智能化的反欺诈管控网络&#xff0c;旨在提供全面、高效、精准的风险评估机制。该…

MSSQL2022的一个错误:未在本地计算机上注册“Microsoft.ACE.OLEDB.16.0”提供程序

MSSQL2022导入Excel的一个错误&#xff1a;未在本地计算机上注册“Microsoft.ACE.OLEDB.16.0”提供程序 一、导入情况二、问题发现三、问题解决 最近在安装新版SQLServer SSMS 2022后&#xff0c;每次导入Excel都会出现错误提示&#xff1a;未在本地计算机上注册“Microsoft.AC…

基于极角排序实现二维点的逆时针排列

在二维几何计算中,常常需要对一组点进行逆时针排序,以便用于构建多边形、实现凸包算法或绘制几何图形等。本文将详细介绍一种基于极角计算的方法,使用C++实现将点集按照逆时针顺序排列,并提供完整代码和输出示例,适合直接应用于工程项目或算法学习。 一、问题背景 在一个…

Hbase整合Mapreduce案例2 hbase数据下载至hdfs中——wordcount

目录 整合结构准备数据下载pom.xmlMain.javaReduce.javaMap.java操作 总结 整合结构 和案例1的结构差不多&#xff0c;Hbase移动到开头&#xff0c;后面跟随MR程序。 因此对于输入的K1 V1会进行一定的修改 准备 在HBASE中创建表&#xff0c;并写入数据 create "wunaii…

学习threejs,使用canvas更新纹理

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️Texture 贴图 二、&#x1…

K8s 十年回顾(Ten Year Review of K8s)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。Kubernetes 十年回顾 起源与…

AMR移动机器人赋能制造业仓储自动化升级

在当今制造业的激烈竞争中&#xff0c;智能化、数字化已成为企业转型升级的关键路径。一家制造业巨头&#xff0c;凭借其庞大的生产体系和多个仓库资源&#xff0c;正以前所未有的决心和行动力&#xff0c;在制造业智能化浪潮中勇立潮头&#xff0c;开启了降本增效的新篇章。这…

数据分析(一): 掌握STDF 掌握金钥匙-码农切入半导体的捷径

中国的半导体行业必然崛起&#xff01;看清这个大势&#xff0c;就会有很多机会。 今天&#xff0c;我们一起来了解一下半导体行业的一朵金花&#xff1a;STDF。 实际上这只是一种文件格式&#xff0c;但是当你熟练掌握解析这种文件的时候&#xff0c;你就已经打开在这个基础…

自动化测试之等待方式详解

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 在自动化测试中&#xff0c;等待是一个重要的技术&#xff0c;用于处理页面加载、元素定位、元素状态改变等延迟问题。 等待能够确保在条件满足后再进行后续操…

Solving the Makefile Missing Separator Stop Error in VSCode

1. 打开 Makefile 并转换缩进 步骤 1: 在 VSCode 中打开 Makefile 打开 VSCode。使用文件浏览器或 Ctrl O&#xff08;在 Mac 上是 Cmd O&#xff09;打开你的 Makefile。 步骤 2: 打开命令面板 按 Ctrl Shift P&#xff08;在 Mac 上是 Cmd Shift P&#xff09;&…

HTML CSS JS基础考试题与答案

一、选择题&#xff08;2分/题&#xff09; 1&#xff0e;下面标签中&#xff0c;用来显示段落的标签是&#xff08; d &#xff09;。 A、<h1> B、<br /> C、<img /> D、<p> 2. 网页中的图片文件位于html文件的下一级文件夹img中&#xff0c;…