Linux系统中标准输入设备的控制实现

news2024/11/25 4:26:04

        大家好,今天主要和大家聊一聊,如何使用标准输入设备,进行控制信息的识别。

                                  

 

目录

第一:按键应用编程方法

第二:单点触摸应用程序实现

​第三:多点触摸应用程序实现


第一:按键应用编程方法

     编写一个应用程序,获取按键状态,判断按键当前是按下,松开或长按状态。

#以字母A键为例KEY_A    //上报KEY_A事件SYN_REPORT   //同步

      如果是按下,则上报KEY_A事件时,value=1;如果是松开,则value=0;如果长按,则value=2。接下来编写按钮应用程序,读取按键状态并将结果打印出来,代码如下所示。

#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; int value = -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); } if (EV_KEY == in_ev.type) { //按键事件 switch (in_ev.value) { case 0: printf("code<%d>: 松开\n", in_ev.code); break; case 1: printf("code<%d>: 按下\n", in_ev.code); break; case 2: printf("code<%d>: 长按\n", in_ev.code); break;       }     }   }}

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

    将编译得到的可执行文件复制到开发板Linux系统的家目录下:

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

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

      操作的时候,可以对应相应的设备节点/dev/input/event3,运行测试程序并按下、松开键盘上的按键;

     大家可以根据code值查询对应的按键,譬如code=30对应的键盘上的字母A键,code=48对应的字母B键。

第二:单点触摸应用程序实现

     通过上面的详细介绍,大家应该知道如何编写一个触摸屏的应用程序了,接下来我们编写一个单点触摸屏应用程序,获取一个触摸点的坐标信息,并将其打印出来。具体代码实现如下:

#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; int x, y; //触摸点 x 和 y 坐标 int down; //用于记录 BTN_TOUCH 事件的 value,1 表示按下,0 表示松开,-1 表示移动 int valid; //用于记录数据是否有效(我们关注的信息发生更新表示有效,1 表示有效,0 表示无效) int fd = -1; /* 校验传参 */ if (2 != argc) { fprintf(stderr, "usage: %s <input-dev>\n", argv[0]); exit(EXIT_FAILURE); } /* 打开文件 */ if (0 > (fd = open(argv[1], O_RDONLY))) { perror("open error"); exit(EXIT_FAILURE); } x = y = 0; //初始化 x 和 y 坐标值 down = -1; //初始化<移动> valid = 0;//初始化<无效> for ( ; ; ) { /* 循环读取数据 */ if (sizeof(struct input_event) != read(fd, &in_ev, sizeof(struct input_event))) { perror("read error"); exit(EXIT_FAILURE); } switch(in_ev.type) { case EV_KEY: //按键事件 if (BTN_TOUCH == in_ev.code) { down = in_ev.value; valid = 1; } break;  case EV_ABS: //绝对位移事件 switch (in_ev.code) { case ABS_X: //X 坐标 x = in_ev.value; valid = 1; break; case ABS_Y: //Y 坐标 y = in_ev.value; valid = 1; break; } break; case EV_SYN: //同步事件 if (SYN_REPORT == in_ev.code) { if (valid) {//判断是否有效 switch (down) {//判断状态 case 1: printf("按下(%d, %d)\n", x, y); break; case 0: printf("松开\n"); break; case -1: printf("移动(%d, %d)\n", x, y); break; } valid = 0; //重置 valid down = -1; //重置 down } } break;       }    }} 

     ​分析:程序中先传入参数,main()函数中定义了4个变量​;

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

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

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

⑷、变量 valid 表示数据是否有效,valid=1 表示有效、valid=0 表示无效;有效指的是我们检测的信息发生了更改,譬如程序中只检测了手指的按下、松开动作以及坐标值的变化。​接着调用 open()打开触摸屏设备文件得到文件描述符 fd;在 for 循环之前,首先对 x、y、down、valid这 4 个变量进行初始化操作。在 for 循环读取触摸屏上报的数据,将读取到的数据存放在 struct input_event数据结构中。在 switch…case 语句中对读取到的数据进行解析,获取 BTN_TOUCH 事件的 value 数据,判断触摸屏是按下还是松开状态,获取 ABS_X 和 ABS_Y 事件的 value 变量,得到触摸点的 X 轴坐标和 Y 轴坐标。

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

​第三:多点触摸应用程序实现

    实现了单点触摸应用程序之后,可以再来实现多点触摸屏应用程序该如何实现。

#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <sys/ioctl.h>#include <unistd.h>#include <string.h>#include <linux/input.h>/* 用于描述 MT 多点触摸每一个触摸点的信息 */struct ts_mt { int x; //X 坐标 int y; //Y 坐标 int id; //对应 ABS_MT_TRACKING_ID int valid; //数据有效标志位(=1 表示触摸点信息发生更新)};/* 一个触摸点的 x 坐标和 y 坐标 */struct tp_xy { int x; int y;};static int ts_read(const int fd, const int max_slots, struct ts_mt *mt){ struct input_event in_ev; static int slot = 0;//用于保存上一个 slot static struct tp_xy xy[12] = {0};//用于保存上一次的 x 和 y 坐标值,假设触摸屏支持的最大触摸点数不会超过 12 int i; /* 对缓冲区初始化操作 */ memset(mt, 0x0, max_slots * sizeof(struct ts_mt)); //清零 for (i = 0; i < max_slots; i++) mt[i].id = -2;//将 id 初始化为-2, id=-1 表示触摸点删除, id>=0 表示创建 for ( ; ; ) { if (sizeof(struct input_event) != read(fd, &in_ev, sizeof(struct input_event))) { perror("read error"); return -1; } switch (in_ev.type) { case EV_ABS: switch (in_ev.code) { case ABS_MT_SLOT: slot = in_ev.value; break; case ABS_MT_POSITION_X: xy[slot].x = in_ev.value; mt[slot].valid = 1; break; case ABS_MT_POSITION_Y: xy[slot].y = in_ev.value; mt[slot].valid = 1; break; case ABS_MT_TRACKING_ID: mt[slot].id = in_ev.value; mt[slot].valid = 1; break; } break; //case EV_KEY://按键事件对单点触摸应用比较有用// break; case EV_SYN: if (SYN_REPORT == in_ev.code) { for (i = 0; i < max_slots; i++) { mt[i].x = xy[i].x; mt[i].y = xy[i].y; } } return 0; } }}int main(int argc, char *argv[]){ struct input_absinfo slot; struct ts_mt *mt = NULL; int max_slots; int fd; int i; /* 参数校验 */ if (2 != argc) { fprintf(stderr,"usage: %s <input_dev>\n", argv[0]); exit(EXIT_FAILURE); } /* 打开文件 */ fd = open(argv[1], O_RDONLY); if (0 > fd) { perror("open error"); exit(EXIT_FAILURE); } /* 获取触摸屏支持的最大触摸点数 */ if (0 > ioctl(fd, EVIOCGABS(ABS_MT_SLOT), &slot)) { perror("ioctl error"); close(fd); exit(EXIT_FAILURE); } max_slots = slot.maximum + 1 - slot.minimum; printf("max_slots: %d\n", max_slots);  /* 申请内存空间并清零 */ mt = calloc(max_slots, sizeof(struct ts_mt)); /* 读数据 */ for ( ; ; ) { if (0 > ts_read(fd, max_slots, mt)) break; for (i = 0; i < max_slots; i++) { if (mt[i].valid) {//判断每一个触摸点信息是否发生更新(关注的信息发生更新) if (0 <= mt[i].id) printf("slot<%d>, 按下(%d, %d)\n", i, mt[i].x, mt[i].y); else if (-1 == mt[i].id) printf("slot<%d>, 松开\n", i); else printf("slot<%d>, 移动(%d, %d)\n", i, mt[i].x, mt[i].y); } } } /* 关闭设备、退出 */ close(fd); free(mt); exit(EXIT_FAILURE);}

      示例代码中申明了 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>表示触摸点 0、slot<1>表示触摸点 1 以此类推!

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

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

相关文章

java 实现删除单链表中所有指定的结点以及如何清空单链表

文章目录1. 删除单链表中的所有的指定结点1.1 删除思路1.2 删除步骤1.2.1 删除结点不是头结点1.2.2 删除的结点是头结点的情况1.3 部分代码思路分析1.4 整体代码演示2. 清空单链表1. 删除单链表中的所有的指定结点 1.1 删除思路 定义一个 cur 来代替 head 遍历单链表。遇到指…

Python检测和防御DOS攻击

目录 ​编辑 一、在CentOS上安装Python3 1.下载Python3.10源代码文件 2.运行以下命令行完成安装 3.确认是否安装成功 二、理解各个命令的含义 1.uptime 2.netstat 3.ss 4.firewall-cmd 5.sysctl 三、利用Python实现DDOS入侵检测 1.采集TCP连接数据 一、在CentOS上安…

生态系统服务——水源涵养水源涵养分布

水源涵养&#xff0c;是指养护水资源的举措。一般可以通过恢复植被、建设水源涵养区达到控制土壤沙化、降低水土流失的目的。 水源涵养数据是地理遥感生态网平台通过水量平衡方程&#xff08;The Water Balance Equation&#xff09;计算&#xff08;式29&#xff09;。水量平衡…

http://localhost:8080打不开/shutup.bat命令行闪退

前言&#xff1a;学过一阵java web后从头学起&#xff0c;发现http://localhost:8080打不开&#xff0c;双击shutup.bat闪退 http://localhost:8080打不开 一、tomcat 未启动&#xff0c;所以http://localhost:8080打不开&#xff1b; 二、tomcat图标显示已启动&#xff0c;但…

计算机毕业设计SSM草海帮帮帮【附源码数据库】

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

5G无线技术基础自学系列 | 无线帧结构

素材来源&#xff1a;《5G无线网络优化实践》 一边学习一边整理内容&#xff0c;并与大家分享&#xff0c;侵权即删&#xff0c;谢谢支持&#xff01; 附上汇总贴&#xff1a;5G无线技术基础自学系列 | 汇总_COCOgsta的博客-CSDN博客 1.3.1 基本时间单位 NR物理层的基本时间…

R语言绘制瑞利分布和指数分布,并为瑞利分布着不同色

从概率论和统计学角度看&#xff0c;Weibull Distribution是连续性的概率分布&#xff0c;其概率密度为&#xff1a; 其中&#xff0c;x是随机变量&#xff0c;λ>0是比例参数&#xff08;scale parameter&#xff09;&#xff0c;k>0是形状参数&#xff08;shape para…

python sympy求多元函数的梯度、Hessian矩阵

1 求梯度 sympy实际上提供了求梯度的方法&#xff0c;但个人认为不是很直观&#xff0c;求出的是∂f∂xi⃗∂f∂yj⃗∂f∂zk⃗\frac{\partial f}{\partial x} \vec {i}\frac{\partial f}{\partial y} \vec {j}\frac{\partial f}{\partial z}\vec {k}∂x∂f​i∂y∂f​j​∂z∂…

java计算机毕业设计springboot+vue股票交易模拟系统

项目介绍 股票交易模拟系统是针对目前股票交易模拟管理的实际需求&#xff0c;从实际工作出发&#xff0c;对过去的股票交易模拟管理系统存在的问题进行分析&#xff0c;完善客户的使用体会。采用计算机系统来管理信息&#xff0c;取代人工管理模式&#xff0c;查询便利&#…

eCal 基础安装和使用

参考文章&#xff1a; 自动驾驶通信中间件ecal源码分析—1. 什么是ecal 1、安装 使用官网提供的指令安装 主要参考官网进行安装&#xff0c; https://eclipse-ecal.github.io/ecal/index.html 主要这里兼容的主要系统&#xff1a; Ubuntu 18.04 Ubuntu 20.04 Ubuntu 22.04 这…

[附源码]java毕业设计8号体育用品销售及转卖系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

搜索服从幂律分布的网络 论文阅读

一、定义 1、幂律分布网络定义&#xff1a; 大部分通信网络和社会网络都具有幂律分布的特点&#xff0c;也即度数高的节点的数量少&#xff0c;度数低节点的数量多。 2、数学推导&#xff1a; 对于指数为τ、最小度数为k 1、在mkmaxm k_{max}mkmax​处有突变截止点的幂律分…

LeetCode链表练习(上)

文章目录前言1.反转链表1.题目分析2.代码示例2.力扣203. 移除链表元素1.题目分析2.代码示例3.力扣876. 链表的中间结点1.题目分析2.代码示例4.链表倒数第k个节点1.题目分析2.代码示例5.总结前言 之前介绍了链表的实现&#xff0c;为了更好巩固所学的知识&#xff0c;刷题是很有…

【路径规划】局部路径规划算法——DWA算法(动态窗口法)|(含python实现)

文章目录参考资料1. DWA算法原理1.1 简介1.2 算法原理1. 速度采样2. 轨迹预测&#xff08;轨迹推算&#xff09;3. 轨迹评价2. Python实现2.1 参数配置2.2 机器人运动学模型2.3 DWA算法类实现2.4 画图2.5 主函数3. 总结参考资料 The Dynamic Window Approach to Collision Avo…

二分查找的模板

这篇博客的二分用的都是左闭右闭的区间&#xff0c;对于二分来说还是我还是习惯这样写 最传统的二分查找&#xff0c;用左闭右闭写 int search(vector<int>& nums, int target) {int left 0;int right nums.size() - 1; // 定义target在左闭右闭的区间里&#xff0…

Mybatis学习之动态Sql

目录 1. 什么是动态Sql 2. 动态Sql需要学习什么 3. 动态Sql之《if》 4. 动态Sql之《where》 5. 动态Sql之《foreach》 6. 动态Sql之《sql》 7. PageHelper分页插件的使用 1. 什么是动态Sql 答案&#xff1a;动态Sql指的是&#xff0c;Sql语句是变化的&#xff0c;不是固…

Allegro原理图反标教程

Allegro原理图反标教程 Logic→Auto Rename Refdes→Rename 点击More进行详细设置 按照下图设置 点击Rename 打开刚刚rename时生成的rename.log文件,需要提取一些数据,如下图 将上图所有带有OLD和NEW的行提取出来,再将OLD,NEW删除 打开Capture,点击Tools→Back Annota…

C++中运行一个程序的内存分配情况及qt中的内存管理机制

一个由c/C编译的程序占用的内存分为以下几个部分 1、栈区&#xff08;stack&#xff09;— 由编译器自动分配释放 &#xff0c;存放函数的参数值&#xff0c;局部变量的值等。其操作方式类似于数据结构中的栈。 2、堆区&#xff08;heap&#xff09; — 一般由程序员分配释放&a…

【springboot】你了解@Autowired 和 @Resource吗?@Autowired 和 @Resource深入分析

Autowired 和 Resource深入分析“认祖归宗”--Autowired 和 Resource来源“通过现象看本质”--Autowired 和 Resource作用和区别1.现象一&#xff1a;一个业务接口只对应一个业务实现类2.现象二&#xff1a;一个业务接口 对应 两个或多个业务实现类我们在开发中&#xff0c;一直…

【数据结构】链表其实并不难 —— 手把手带你实现双向链表

文章目录0. 前言1. 双向链表的概念2. 双向链表的实现2.1 结构设计2.2 接口总览2.3 初始化2.4 创建新节点2.5 尾插2.6 头插2.7 尾删2.8 头删2.9 查找2.10 在pos位置之前插入2.11 在pos位置删除2.12 打印2.13 销毁3. 完整代码List.hList.ctest.c4. 结语0. 前言 之前&#xff0c;…