Linux输入系统应用编程

什么是输入系统

Linux 输入系统是处理用户输入设备(如键盘、鼠标、触摸屏、游戏手柄等)的软件架构。在应用编程层面,它提供了与这些输入设备交互的接口。

主要组成部分

  1. 输入设备驱动层:直接与硬件交互的驱动程序

  2. 输入核心层:内核中的输入子系统核心

  3. 事件接口层:向用户空间提供的接口(主要是/dev/input/下的设备文件)

关键概念

        输入设备:任何能产生输入事件的硬件设备

        输入事件:描述用户输入动作的数据结构(如按键按下、鼠标移动等)

        输入子系统:Linux内核中管理所有输入设备的框架

编程接口

开发者主要通过以下方式与输入系统交互:

  1. 设备文件:通常位于/dev/input/目录下,如:

    • /dev/input/eventX - 输入事件接口

    • /dev/input/mice - 鼠标设备(传统接口)

  2. 系统调用:如open()read()ioctl()

  3. 库支持

    • libevdev - 直接与输入设备交互的库

    • Xlib/XCB - X Window系统的输入处理

    • Wayland协议 - 现代显示服务器的输入处理

典型编程流程

  1. 打开输入设备文件

  2. 读取输入事件(struct input_event)

  3. 解析并处理事件

  4. 关闭设备文件

输入事件结构

struct input_event {struct timeval time;  // 时间戳__u16 type;          // 事件类型(如EV_KEY, EV_REL等)__u16 code;          // 事件代码(如KEY_A, REL_X等)__s32 value;         // 事件值(如1表示按下,0表示释放)
};

电阻屏和电容屏


电阻屏

 电阻屏原理

Linux 驱动程序中,会上报触点的 X、Y 数据,注意:这不是 LCD 的坐标值,需要 APP 再次处理才能转换为 LCD 坐标值。

电阻屏数据

对应的 input_event 结构体中,“type、code、value” 如下:
按下时:
EV_KEY BTN_TOUCH 1 /* 按下 /
EV_ABS ABS_PRESSURE 1 /
 压力值,可以上报,也可以不报,可以是其他压力值 /
EV_ABS ABS_X x_value /
 X 坐标 /
EV_ABS ABS_Y x_value /
 Y 坐标 /
EV_SYNC 0 0 /
 同步事件 */

松开时:
EV_ABS BTN_TOUCH 0 /* 松开 /
EV_ABS ABS_PRESSURE 0 /
 压力值,可以上报,也可以不报 /
EV_SYNC 0 0 /
 同步事件 */

电容屏
 

电容屏原理

电容屏数据

Type A

该类型不能分辨哪一个触电,已被淘汰

Type B

该类型的触摸屏能分辨是哪一个触点,上报数据时会先上报触点 ID,再上报它的数据。
具体例子如下,这是最简单的示例,使用场景分析来看看它上报的数据。
当有 2 个触点时(type, code, value):

EV_ABS ABS_MT_SLOT 0 // 这表示 “我要上报一个触点信息了”,用来分隔触点信息
EV_ABS ABS_MT_TRACKING_ID 45 // 这个触点的 ID 是 45
EV_ABS ABS_MT_POSITION_X x [0] // 触点 X 坐标
EV_ABS ABS_MT_POSITION_Y y [0] // 触点 Y 坐标
EV_ABS ABS_MT_SLOT 1 // 这表示 “我要上报一个触点信息了”,用来分隔触点信息
EV_ABS ABS_MT_TRACKING_ID 46 // 这个触点的 ID 是 46
EV_ABS ABS_MT_POSITION_X x [1] // 触点 X 坐标
EV_ABS ABS_MT_POSITION_Y y [1] // 触点 Y 坐标
EV_SYNC SYN_REPORT 0 // 全部数据上报完毕

当 ID 为 45 的触点正在移动时:

EV_ABS ABS_MT_SLOT 0 // 这表示 “我要上报一个触点信息了”,之前上报过 ID,就不用再上报 ID 了
EV_ABS ABS_MT_POSITION_X x [0] // 触点 X 坐标
EV_SYNC SYN_REPORT 0 // 全部数据上报完毕

松开 ID 为 45 的触点时 (在前面 slot 已经被设置为 0,这里这需要再重新设置 slot,slot 就像一个全局变量一样:如果它没变化的话,就无需再次设置):

// 刚刚设置了 ABS_MT_SLOT 为 0,它对应 ID 为 45,这里设置 ID 为 - 1 就表示 ID 为 45 的触点被松开了
EV_ABS ABS_MT_TRACKING_ID -1
EV_SYNC SYN_REPORT 0 // 全部数据上报完毕

最后,松开 ID 为 46 的触点:

EV_ABS ABS_MT_SLOT 1 // 这表示 “我要上报一个触点信息了”,在前面设置过 slot 1 的 ID 为 46
EV_ABS ABS_MT_TRACKING_ID -1 // ID 为 - 1,表示 slot 1 被松开,即 ID 为 46 的触点被松开
EV_SYNC SYN_REPORT 0 // 全部数据上报完毕

电容屏的实验数据

假设你的开发板上电容屏对应的设备节点是/dev/input/event0,执行以下命令

hexdump /dev/input/event0

然后用一个手指点击触摸屏,得到类似如下的数据:

0000000 878d 5e3d 6026 0001 0003 0039 0000 0000 ABS_MT_TRACKING_ID 0
0000010 878d 5e3d 6026 0001 0003 0035 0236 0000 ABS_MT_POSITION_X
0000020 878d 5e3d 6026 0001 0003 0036 0146 0000 ABS_MT_POSITION_Y
0000030 878d 5e3d 6026 0001 0003 0030 0015 0000 ABS_MT_TOUCH_MAJOR
0000040 878d 5e3d 6026 0001 0003 0032 0015 0000 ABS_MT_WIDTH_MAJOR
0000050 878d 5e3d 6026 0001 0001 014a 0001 0000 EV_KEY BTN_TOUCH 1
0000060 878d 5e3d 6026 0001 0003 0236 0000 ABS_X
0000070 878d 5e3d 6026 0001 0003 0146 0000 ABS_Y
0000080 878d 5e3d 6026 0001 0000 0000 0000 0000 EV_SYNC
0000090 878d 5e3d 5cd4 0002 0003 0039 ffff ffff ABS_MT_TRACKING_ID -1
00000a0 878d 5e3d 5cd4 0002 0001 014a 0000 0000 EV_KEY BTN_TOUCH 0
00000b0 878d 5e3d 5cd4 0002 0000 0000 0000 0000 EV_SYNC

在上面的数据中,为了兼容老程序,它也上报了 ABS_X、ABS_Y 数据,电阻触摸屏就是使用这类型的数据。所以基于电阻屏的程序,也可以用在电容屏上。

当用两个手指点击触摸屏,得到类似如下的数据:

0000000 8fb8 5e3d b2a9 0003 0003 002f 0000 0000 ABS_MT_SLOT 0
0000010 8fb8 5e3d b2a9 0003 0003 0039 0007 0000 ABS_MT_TRACKING_ID 7
0000020 8fb8 5e3d b2a9 0003 0003 0035 01d6 0000 ABS_MT_POSITION_X
0000030 8fb8 5e3d b2a9 0003 0003 0036 0e05 0000 ABS_MT_POSITION_Y
0000040 8fb8 5e3d b2a9 0003 0003 002f 0001 0000 ABS_MT_SLOT 1
0000050 8fb8 5e3d b2a9 0003 0003 0039 0008 0000 ABS_MT_TRACKING_ID 8
0000060 8fb8 5e3d b2a9 0003 0003 0035 0285 0000 ABS_MT_POSITION_X
0000070 8fb8 5e3d b2a9 0003 0003 0036 00fd 0000 ABS_MT_POSITION_Y
0000080 8fb8 5e3d b2a9 0003 0003 0030 0016 0000 ABS_MT_TOUCH_MAJOR
0000090 8fb8 5e3d b2a9 0003 0003 0032 0016 0000 ABS_MT_WIDTH_MAJOR
00000a0 8fb8 5e3d b2a9 0003 0001 014a 0001 0000 EV_KEY BTN_TOUCH 1
00000b0 8fb8 5e3d b2a9 0003 0003 0001 01d6 0000 ABS_X
00000c0 8fb8 5e3d b2a9 0003 0003 0001 0e05 0000 ABS_Y
00000d0 8fb8 5e3d b2a9 0003 0000 0000 0000 0000 EV_SYNC
00000e0 8fb8 5e3d 54c7 0004 0003 002f 0000 0000 ABS_MT_SLOT 0
00000f0 8fb8 5e3d 54c7 0004 0003 0039 ffff ffff ABS_MT_TRACKING_ID -1
0000100 8fb8 5e3d 54c7 0004 0003 002f 0001 0000 ABS_MT_SLOT 1
0000110 8fb8 5e3d 54c7 0004 0003 0039 ffff ffff ABS_MT_TRACKING_ID -1
0000120 8fb8 5e3d 54c7 0004 0001 014a 0000 0000 EV_KEY BTN_TOUCH 0
0000130 8fb8 5e3d 54c7 0004 0000 0000 0000 0000 EV_SYNC

为了兼容老程序,它也上报了 ABS_X、ABS_Y 数据,但是只上报第 1 个触点的数据。

tslib

tslib是一个触摸屏的开源库,可以使用它来访问触摸屏设备

tslib的主要代码如下:

src/ 接口函数ts_setup.cts_open.cts_config.c
plugins/ 插件 /modulelinear.cdejitter.cpthres.cinput-raw.c
tests/ 测试程序ts_test.cts_test_mt.cts_print.cts_print_mt.c

核心在于 “plugins” 目录里的 “插件”,或称为 “module”。这个目录下的每个文件都是一个 module,每个 module 都提供 2 个函数:read、read_mt,前者用于读取单点触摸屏的数据,后者用于读取多点触摸屏的数据。

编写基于tslib的测试程序

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <getopt.h>#include <linux/input.h>#include <sys/ioctl.h>#include <tslib.h>int distance(struct ts_sample_mt *point1, struct ts_sample_mt *point2)
{int x = point1->x - point2->x;int y = point1->y - point2->y;return x*x + y*y;
}int main(int argc, char **argv)
{struct tsdev *ts;int i;int ret;struct ts_sample_mt **samp_mt;struct ts_sample_mt **pre_samp_mt;	int max_slots;int point_pressed[20];struct input_absinfo slot;int touch_cnt = 0;ts = ts_setup(NULL, 0);//打开配置设备if (!ts){printf("ts_setup err\n");return -1;}if (ioctl(ts_fd(ts), EVIOCGABS(ABS_MT_SLOT), &slot) < 0) {// 获取触摸屏支持的最大点数perror("ioctl EVIOGABS");ts_close(ts);return errno;}max_slots = slot.maximum + 1 - slot.minimum;// 计算最大槽位数(支持的最大触点数)// 分配当前采样和上一采样点的内存空间samp_mt = malloc(sizeof(struct ts_sample_mt *));if (!samp_mt) {ts_close(ts);return -ENOMEM;}samp_mt[0] = calloc(max_slots, sizeof(struct ts_sample_mt));if (!samp_mt[0]) {free(samp_mt);ts_close(ts);return -ENOMEM;}pre_samp_mt = malloc(sizeof(struct ts_sample_mt *));if (!pre_samp_mt) {ts_close(ts);return -ENOMEM;}pre_samp_mt[0] = calloc(max_slots, sizeof(struct ts_sample_mt));if (!pre_samp_mt[0]) {free(pre_samp_mt);ts_close(ts);return -ENOMEM;}for ( i = 0; i < max_slots; i++)pre_samp_mt[0][i].valid = 0;while (1){// 读取当前所有触点的状态ret = ts_read_mt(ts, samp_mt, max_slots, 1);if (ret < 0) {printf("ts_read_mt err\n");ts_close(ts);return -1;}// 更新有效触点数据到pre_samp_mt(保存上一帧数据)for (i = 0; i < max_slots; i++){if (samp_mt[0][i].valid){memcpy(&pre_samp_mt[0][i], &samp_mt[0][i], sizeof(struct ts_sample_mt));}}// 统计当前被按下的触点数量touch_cnt = 0;for (i = 0; i < max_slots; i++){if (pre_samp_mt[0][i].valid && pre_samp_mt[0][i].tracking_id != -1)point_pressed[touch_cnt++] = i;}// 如果有两个触点被按下,计算并输出它们之间的距离平方if (touch_cnt == 2){printf("distance: %08d\n", distance(&pre_samp_mt[0][point_pressed[0]], &pre_samp_mt[0][point_pressed[1]]));}}return 0;
}

ts_sample_mt结构体

struct ts_sample_mt {  // 触摸点数据结构int x;            // X坐标int y;            // Y坐标int valid;        // 数据是否有效int tracking_id;  // 触点ID// ...其他字段
};

程序逻辑:

  1. 设备初始化

    • ts_setup()打开触摸屏设备

    • 通过ioctl获取设备支持的最大触点数max_slots

  2. 内存分配

    • 为当前帧(samp_mt)和上一帧(pre_samp_mt)数据分配内存

    • 使用calloc确保初始化为零

  3. 历史数据清零

for(i=0; i<max_slots; i++) pre_samp_mt[0][i].valid = 0;

主循环逻辑

  1. 数据采集

    • ts_read_mt()读取当前所有触点状态到samp_mt

  2. 数据更新

    • 将当前有效触点数据复制到pre_samp_mt(作为下一轮的"上一帧"数据)

  3. 触点统计

    • 遍历所有槽位,统计有效触点(valid=1tracking_id!=-1

    • 记录被按下触点的索引到point_pressed数组

  4. 距离计算与输出

    • 恰好两个触点被按下时:

      • 计算两点间欧氏距离的平方

      • 格式化输出:distance: xxxxxxxx

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

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

相关文章

StarRocks BE宕机排查

StarRocks BE宕机排查 排查是否OOM dmesg -T|grep -i oom #排查是否oom原因&#xff1a; 2.X版本OOM原因 BE 的配置文件 (be.conf) 中 mem_limit 配置不合理&#xff0c;需要配置mem_limit(机器总内存-其他服务占用内存-1~2g(系统预留)) 比如机器内存40G&#xff0c;上面有…

逻辑回归(Logistic Regression)模型的概率预测函数

以二分类问题为例&#xff0c;常见的损失函数有 负对数似然损失(neg log-likelihood loss)&#xff0c;交叉熵损失(cross entropy loss)&#xff0c;deviance loss指数损失(exponential loss)。 前三者虽然名字不同&#xff0c;但却具有相同的表达形式。此外&#xff0c;neg …

函数式组件中的渲染函数 JSX

在 Vue.js 和 React 等现代前端框架中&#xff0c;函数式组件已成为一种非常流行的设计模式。函数式组件是一种没有内部状态和生命周期方法的组件&#xff0c;其主要功能是接受 props 并渲染 UI。随着这些框架的演进&#xff0c;渲染函数和 JSX&#xff08;JavaScript XML&…

Android 动态设置默认Launcher(默认应用 电话-短信-浏览器-主屏幕应用))

Android 动态设置默认Launcher(默认应用 电话-短信-浏览器-主屏幕应用&#xff09;) 文章目录 场景需求参考资料思路期待效果 实现方案源码流程分析和思路实现DefaultAppActivityHandheldDefaultAppFragmentHandheldDefaultAppPreferenceFragmentDefaultAppChildFragmentDefaul…

Qt下载模板到本地文件内容丢失问题

上源码 关键点已标注在源码中 A, B… // 保存的文件路径后缀QString dateTime Myapp::getCurrentTimeDescYMDHms().replace(" ", "").replace("-", "").replace(":", "");// 临时文件名称QString newFileName Q…

【数学建模】动态规划算法(Dynamic Programming,简称DP)详解与应用

动态规划算法详解与应用 文章目录 动态规划算法详解与应用引言动态规划的基本概念动态规划的设计步骤经典动态规划问题1. 斐波那契数列2. 背包问题3. 最长公共子序列(LCS) 动态规划的优化技巧动态规划的应用领域总结 引言 动态规划(Dynamic Programming&#xff0c;简称DP)是一…

蓝桥杯备考------>双指针(滑动窗口)

来看哈我们这道例题 我们第一种想法应该就是暴力求解&#xff0c;枚举每个子数组 当我们枚举第一个数的时候&#xff0c;我们要从第一个数开始挨个枚举每个结尾 如图&#xff0c;以第一个数开头的最长不重复数我们就枚举完了 然后我们让两个指针全部到第二个数 再枚举第二个…

python实现股票数据可视化

最近在做一个涉及到股票数据清洗及预测的项目&#xff0c;项目中需要用到可视化股票数据这一功能&#xff0c;这里我与大家分享一下股票数据可视化的一些基本方法。 股票数据获取 目前&#xff0c;我已知的使用python来获取股票数据方式有以下三种: 爬虫获取&#xff0c;实现…

【15】Selenium 爬取实战

一、selenium适用场景 二、爬取目标 三、爬取列表页 &#xff08;1&#xff09;初始化 &#xff08;2&#xff09;加载列表页 &#xff08;3&#xff09;解析列表页 &#xff08;4&#xff09;main 四、爬取详情页 &#xff08;1&#xff09;加载详情页 &#xff08;2…

如何封装一个上传文件组件

#今天用el-upload感到很多不方便&#xff0c;遂决定自己封装一个。注&#xff1a;本文不提供表面的按钮样式和文件上传成功后的样式&#xff0c;需要自己创建。本文仅介绍逻辑函数# 1&#xff0c;准备几个表面用来指引上传的元素 2&#xff0c;创造统一的隐藏文件上传输入框&…

【计网】数据包

期末复习自用的&#xff0c;处理得比较草率&#xff0c;复习的同学或者想看基础的同学可以看看&#xff0c;大佬的话可以不用浪费时间在我的水文上了 1.数据包的定义&#xff1a; 数据包是网络通信中的基本单元&#xff0c;它包含了通过网络传输的所有必要信息。数据包的结构…

HTTP抓包Websocket抓包(Fiddler)

近期时常要和各个厂商的java云平台打交道&#xff1a;登录、上传、下载等&#xff0c;程序的日志虽必不可少&#xff0c;但前期调试阶段&#xff0c;免不了遇到问题&#xff0c;这时有一个称手的抓包工具就显得尤为重要了。 Fiddler Everywhere是一款跨平台的网络调试工具&…

Git和GitCode使用(从Git安装到上传项目一条龙)

第一步 菜鸟教程-Git教程 点击上方链接&#xff0c;完成Git的安装&#xff0c;并了解Git 工作流程&#xff0c;知道Git 工作区、暂存区和版本库的区别 第二步 GitCode官方帮助文档-SSH 公钥管理 点击上方链接&#xff0c;完成SSH公钥设置 第三步&#xff08;GitCode的官方引…

基于 WebAssembly 的 Game of Life 交互实现

一、前言 在前期的实现中&#xff0c;我们使用 Rust 编写核心逻辑&#xff0c;并通过 WebAssembly 将其引入到 Web 环境中&#xff0c;再利用 JavaScript 进行渲染。接下来&#xff0c;我们将在这一基础上增加用户交互功能&#xff0c;使模拟过程不仅能够自动演化&#xff0c;…

【keil】单步调试

一、步骤 1、打开stc-isp软件 2.打开keil仿真设置&#xff0c;选择对应的单片机型号 3.点击将所选目标单片机设置为仿真芯片&#xff0c;点击下载&#xff0c;按一下单片机打下载按钮 4.此时已经将仿真程序下载到单片机 5.此时点击options,找到debug选择STC Montor 51 Driv…

c++弱指针实现原理

在 C 中&#xff0c;弱指针&#xff08;std::weak_ptr&#xff09;是一种特殊的智能指针&#xff0c;其核心目标是‌解决 std::shared_ptr 的循环引用问题‌&#xff0c;同时不增加对象的引用计数。它的实现原理基于与 std::shared_ptr 共享的 ‌控制块&#xff08;Control Blo…

【ManiSkill】环境success条件和reward函数学习笔记

1. “PickCube-v1” info["success"]&#xff1a;用于指示任务是否成功完成 布尔型张量&#xff0c;在环境的evaluate()方法中计算并返回&#xff1a; "success": is_obj_placed & is_robot_static这确保了机器人不仅能将物体准确放置在目标位置&am…

用空闲时间做了一个小程序-二维码生成器

一直在摸鱼中赚钱的大家好呀~ 先向各位鱼友们汇报一下情况&#xff0c;目前小程序已经有900的鱼友注册使用过。虽然每天都有新的鱼友注册&#xff0c;但是鱼友增长的还很缓慢。自从国庆前的文字转语音的工具上线到现在已经将近有1个月没有更新小程序了。但是今天终终终终终于又…

31天Python入门——第14天:异常处理

你好&#xff0c;我是安然无虞。 文章目录 异常处理1. Python异常2. 异常捕获try-except语句捕获所有的异常信息获取异常对象finally块 3. raise语句4. 自定义异常5. 函数调用里面产生的异常补充练习 异常处理 1. Python异常 Python异常指的是在程序执行过程中发生的错误或异…

PyQt6实例_批量下载pdf工具_使用pyinstaller与installForge打包成exe文件

目录 前置&#xff1a; 步骤&#xff1a; step one 准备好已开发完毕的项目代码 step two 安装pyinstaller step three 执行pyinstaller pdfdownload.py&#xff0c;获取初始.spec文件 step four 修改.spec文件&#xff0c;将data文件夹加入到打包程序中 step five 增加…