Linux 应用层开发入门(二十四)| tslib框架分析与实战 📅 发布时间:2026/7/15 11:01:18 👁️ 浏览次数: 在嵌入式Linux开发中触摸屏是人机交互的核心外设之一但不同硬件的触摸屏原始数据往往存在噪声、偏移、校准等问题。tslib作为一款开源的触摸屏输入处理库完美解决了这些痛点成为嵌入式触摸屏开发的标准选择。本文将从基础概念、核心功能、编译使用到实战案例全面解析tslib库的使用方法。1 引言在介绍触摸屏相关tslib库之前首先我们来介绍下触摸屏的相关知识。在我们日常生活中每个人都离不开智能手机、IPad等可触摸操作的设备。目前触摸屏的类型分为电阻屏、电容屏。电阻屏结构简单在以前是特别流行的电容屏相对于电阻屏来说支持多点触摸也就是现在的智能设备的屏幕都采用电容屏。区别注意LCD、触摸屏不是一回事哦LCD是输出设备触摸屏是输入设备。重要的是制作触摸屏的时特意把它的尺寸做的和LCD屏幕一模一样的尺寸并且把触摸屏覆盖在LCD显示屏幕上。2 tslib库介绍与框架分析2.1 tslib库介绍tslibTouch Screen Library是一款面向嵌入式Linux系统的开源触摸屏处理库作为触摸屏驱动与上层应用之间的中间件专门负责对原始触摸坐标进行校准、滤波、去抖、坐标转换等标准化处理解决了不同触摸屏硬件差异大、原始数据不稳定的问题。它轻量高效、兼容性强支持基于Linux input子系统的各类电阻屏、电容屏向上提供统一稳定的触摸接口被广泛用于工控、车载、智能终端等嵌入式GUI开发场景是嵌入式Linux触摸方案中最主流的基础库之一。我们可以采用tslib库来访问触摸屏设备可以给输入设备添加各种“gilter”过滤器即各种处理如果需要详细了解的话可以访问tslib库。2.2 tslib框架分析tslib的核心架构以 “模块化插件” 为核心结合链表式数据处理流程实现灵活的触摸屏数据处理整体框架可拆解为设备初始化、配置加载、模块化数据处理三大核心环节以下从核心设计和执行流程两方面详细分析2.2.1 核心设计模块化插件机制tslib的主要代码如下所示 tslib/src/ 接口函数 ts_setup.c ts_read.c ts_open.c ts.config.c ... tslib/plugins/ 插件module dejitter.c linear.c evthres.c median.c pthres.c skip.c ... tslib/tests/ 测试程序 ts_print.c ts_print_mt.c ts_test.c ts_test_mt.c ...tslib的核心逻辑集中在plugins目录下的功能模块module这是整个框架的核心支撑模块统一接口每个模块仅需实现两个核心函数——read处理单点触摸屏数据和read_mt处理多点触摸屏数据接口标准化便于扩展和替换两类模块分类框架将模块分为module数据处理模块如滤波、校准和module_raw原始数据读取模块通常仅input模块各司其职且解耦链表挂载管理加载配置后module会被挂载到tsdev.list链表module_raw挂载到tsdev.list_raw链表且tsdev.list最后一个模块会指向tsdev.list_raw头部形成完整的数据处理链路。2.2.2 完整执行流程tslib的使用流程遵循 “打开设备→加载配置→读取处理数据” 的逻辑每一步均有明确的优先级和规则①设备打开ts_opents_open函数负责初始化触摸屏设备并生成核心的tsdev结构体设备查找优先级如下优先读取环境变量TSLIB_TSDEVICE指定的设备节点若未配置该环境变量依次尝试默认路径/dev/input/ts、/dev/input/touchscreen、/dev/touchscreen/ucb1x00若上述路径均失败扫描/dev/input目录自动匹配第一个属性为INPUT_PROP_DIRECT的触摸屏设备。②配置加载ts_configts_config函数负责解析配置文件并挂载处理模块配置文件加载规则如下优先读取环境变量TSLIB_CONFFILE指定的配置文件默认加载/etc/ts.conf配置文件每行对应一个模块例如典型配置module_raw input module pthres pmin1 module dejitter delta100 module linear按配置文件顺序module会从链表尾部开始挂载最后一行模块在链表头部module_raw单独挂载到list_raw链表。③数据读取与处理ts_read/ts_read_mt调用ts_read单点或ts_read_mt多点时触发模块链表的递归调用数据处理方向从tsdev.list头部模块开始递归调用下一级模块最终到module_raw读取原始数据以典型配置为例数据流转路径为linear校准→dejitter去抖→pthres压力阈值过滤→input读取原始数据原始数据经上述模块层层处理后最终返回标准化的触摸坐标数据。注意因为递归调用所有最先使用input模块读取设备节点得到原始数据再依次经过pthres模块、dejitter模块、linear模块处理后才返回最终数据。3 tslib交叉编译与测试3.1 交叉编译tslib库首先下载tslib库的数据包tslib-1.21.tar.xz存放在Linux系统中的root/book/study/创建的目录中。其次通过cd指令进入压缩包的位置如下所示tar xJf tslib-1.21.tar.xz其次环境配置命令步骤如以下所示红色框框为重点3.2 tslib测试完成库的编译安装之后我们需要将tslib-1.21/tmp文件夹中的相关文件传入到我们的开发板上以IMX6ULL为例:cd tslib-1.21/tmp adb push lib/ts /lib adb push lib/*so* /lib adb push bin/* /bin adb push etc/ts.conf /etc在IMX6ULL开发板上验证tslib功能时需先处理系统默认自启的GUI程序避免触摸设备被占用再配置环境变量并执行测试程序以下是完整的实操步骤①关闭默认 Qt/LVGL GUI 程序IMX6ULL开发板通常会默认自启 Qt 或 LVGL 相关的人机交互程序这类程序会占用触摸屏设备节点导致 tslib 测试程序无法正常读取触摸数据需先关闭自启项# 移动自启脚本到root目录临时禁用可恢复 mv /etc/init.d/*hmi* /root mv /etc/init.d/*lvgl* /root # 同步文件系统避免修改丢失 sync # 重启开发板使修改生效 reboot说明*hmi*和*lvgl*是开发板中Qt/LVGL自启脚本的通配符若实际脚本名称不同需替换为对应名称该操作仅临时禁用自启若需永久关闭可删除对应脚本或修改自启配置。②执行 tslib 多点触摸测试程序开发板重启后即可配置 tslib 环境变量并运行多点触摸测试程序ts_test_mt# 配置tslib插件目录IMX6ULL标准路径 export TSLIB_PLUGINDIR/lib/ts # 运行多点触摸测试程序 ts_test_mt③测试效果验证执行ts_test_mt后终端会实时打印触摸坐标、压力值、触点ID等信息单点触摸打印x/y坐标、压力值pressure、触点ID0多点触摸打印多个触点的ID及对应坐标验证多触点功能是否正常若无数据输出需检查触摸屏驱动加载状态、TSLIB_PLUGINDIR路径是否正确。4 tslib实战4.1 问题描述实现一个程序不断打印2个触点的距离。思路假设是5点触摸屏调用一次ts_read_mt可以得到5个新数据使 用新旧数据进行判断如果有2个触点就打印出距离。4.2 完整代码#include stdio.h // 标准输入输出用于打印调试信息 #include stdint.h // 固定宽度整数类型保证跨平台兼容性 #include stdlib.h // 内存分配函数(malloc/calloc/free)、退出函数等 #include string.h // 内存拷贝(memcpy)等字符串/内存操作函数 #include signal.h // 信号处理本代码未使用可保留 #include errno.h // 错误码定义用于错误处理 #include sys/types.h // 系统类型定义 #include sys/stat.h // 文件状态相关本代码未使用可保留 #include fcntl.h // 文件控制相关本代码未使用可保留 #include unistd.h // 系统调用接口如read/write #include getopt.h // 命令行参数解析本代码未使用可保留 #include linux/input.h // Linux输入子系统头文件定义触摸事件、ABS_MT_SLOT等 #include sys/ioctl.h // IO控制函数头文件用于获取触摸slot信息 #include tslib.h // tslib核心头文件提供触摸设备操作API #include math.h // 数学库用于sqrt计算两点距离 /** * brief 计算两个触摸点之间的欧几里得距离 * param point1 第一个触摸点的坐标结构体指针 * param point2 第二个触摸点的坐标结构体指针 * return 两点之间的距离整数形式sqrt返回浮点型自动转int */ int distance(struct ts_sample_mt *point1, struct ts_sample_mt *point2) { // 计算x轴方向差值 int x point1-x - point2-x; // 计算y轴方向差值 int y point1-y - point2-y; // 欧几里得距离公式√(x² y²) return sqrt(x*x y*y); } int main(int argc, char **argv) { struct tsdev *ts; // tslib核心结构体代表一个触摸设备 int i; // 循环变量 int ret; // 函数返回值存储 struct ts_sample_mt **samp_mt; // 存储当前读取的多点触摸数据 struct ts_sample_mt **pre_samp_mt;// 存储上一帧的多点触摸数据用于稳定取值 int max_slots; // 触摸屏支持的最大触点数slot数 int point_pressed[20]; // 存储当前按下的触点ID最多支持20个 struct input_absinfo slot; // 用于获取ABS_MT_SLOT的信息最大/最小slot值 int touch_cnt 0; // 当前按下的触点数量 // 初始化并打开触摸设备 // ts_setup参数1设备节点NULL表示使用tslib默认规则查找参数2非0表示阻塞读取0表示非阻塞 ts ts_setup(NULL, 0); if(!ts) // 触摸设备打开失败 { printf(ts_setup err\n); return -1; } // 通过IOCTL获取ABS_MT_SLOT的信息用于确定最大支持的触点数 // EVIOCGABS获取输入设备绝对坐标信息ABS_MT_SLOT多点触摸的slot索引 if (ioctl(ts_fd(ts), EVIOCGABS(ABS_MT_SLOT), slot) 0) { perror(ioctl EVIOGABS); // 打印具体错误原因 ts_close(ts); // 关闭触摸设备 return errno; // 返回错误码 } // 计算最大支持的slot数触点数 最大slot值 - 最小slot值 1 max_slots slot.maximum 1 - slot.minimum; // 第一步分配存储当前触摸数据的外层指针内存 samp_mt malloc(sizeof(struct ts_sample_mt *)); if (!samp_mt) { // 内存分配失败 ts_close(ts); return -ENOMEM; // 返回内存不足错误码 } // 第二步分配当前触摸数据的实际存储内存按最大slot数初始化calloc会清零 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; } // 第二步分配上一帧触摸数据的实际存储内存calloc清零 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; } // 初始化上一帧触摸数据的valid标志为0表示无有效触点 for(i0; imax_slots; i) { pre_samp_mt[0][i].valid 0; } // 无限循环读取触摸数据 while(1) { // 读取多点触摸数据 // ts_read_mt参数触摸设备结构体、存储数据的指针、最大slot数、要读取的样本数1表示读取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; } // 将当前帧的有效触摸数据拷贝到上一帧缓冲区保证数据稳定 for(i0; imax_slots; i) { // 仅拷贝valid为1的有效触点数据 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(i0; imax_slots; i) { // valid1 表示触点有效tracking_id!-1 表示触点处于跟踪状态未松开 if(pre_samp_mt[0][i].valid pre_samp_mt[0][i].tracking_id ! -1) { // 记录有效触点的slot ID 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]])); } } // 注本代码为死循环以下代码实际不会执行仅作为规范补充 free(samp_mt[0]); free(samp_mt); free(pre_samp_mt[0]); free(pre_samp_mt); ts_close(ts); return 0; }核心注释补充说明struct tsdevtslib 的核心设备句柄所有触摸操作都基于此结构体struct ts_sample_mt多点触摸数据结构体包含x/y坐标、valid数据是否有效、tracking_id触点跟踪 ID等核心字段ts_setup()初始化触摸设备自动查找系统中的触摸屏节点ts_read_mt()读取多点触摸数据阻塞 / 非阻塞由ts_setup的第二个参数决定ts_fd()获取触摸设备的文件描述符用于 IOCTL 操作EVIOCGABS(ABS_MT_SLOT)获取触摸屏支持的最大 slot 数即最大触点数。核心逻辑梳理先初始化触摸设备获取最大支持触点数分配两块内存分别存储 “当前帧” 和 “上一帧” 触摸数据避免数据抖动循环读取触摸数据仅保留有效触点当检测到两个触点按下时调用distance函数计算并打印两点距离。4.3 实战验证4.3.1 编译上传4.3.2 测试效果
Tauri 生态安全体系从代码提交到版本发布的全链路防护 为什么框架自身的安全体系很重要? 近年来,开源供应链攻击事件屡见不鲜。攻击者的手段多种多样:伪装成贡献者提交恶意代码、劫持维护者账号发布被篡改的版本、在 CI/CD 流水线中注入后门……这些攻击的共同特点是,一旦得手… 2026/7/15 6:49:33
Windows 环境升级 triton-windows 修复 ptxas.exe DLL 崩溃问题 Windows 环境升级 triton-windows 修复 ptxas.exe DLL 崩溃问题 Triton 官方源码仓库 https://github.com/triton-lang/triton Triton-Windwos 源码仓库 https://github.com/woct0rdho/triton-windows vllm 官方源码仓库(Triton依赖) https://github.com… 2026/7/11 10:41:16
代码随想录算法训练营 Day04 | 链表 part02 24. 两两交换链表中的节点 给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。 class Solution { public:// 方法:虚拟头… 2026/7/15 6:36:21
高性能LDO电源设计:从原理到实践,打造极致纯净的供电系统 1. 项目概述:为什么我们需要一颗“安静”且“精准”的电源?在高速通信、精密测量、医疗成像或者高端射频系统中,工程师们常常会遇到一个看似简单却极其棘手的问题:如何为那些“娇贵”的核心芯片提供一块“纯净”的电力土壤&#x… 2026/7/15 11:00:21
微信消息完整性保障解决方案:技术原理与应用实践 微信消息完整性保障解决方案:技术原理与应用实践 【免费下载链接】WeChatIntercept 微信防撤回插件,一键安装,MAC可用,支持最新v4.1.10微信 项目地址: https://gitcode.com/gh_mirrors/we/WeChatIntercept 在数字通信时代&… 2026/7/15 10:58:18
DLPC3434控制器驱动DLP230KP DMD:微型投影与近眼显示方案详解 1. 项目概述与核心价值如果你正在设计一款追求极致便携与高清画质的移动投影设备,或者为AR眼镜、工业HUD寻找可靠的微型显示引擎,那么DLP230KP DMD搭配DLPC3434控制器的方案,大概率已经进入了你的视野。这套由德州仪器(TI… 2026/7/15 10:58:18
SSH密钥交换算法实战:从兼容性问题到国密算法配置 1. SSH密钥交换算法基础与兼容性问题诊断当你用SSH连接服务器时突然看到"No compatible key exchange method"报错,就像带着最新款手机充电器去老式宾馆——插头根本不匹配。密钥交换算法(KEX)就是SSH握手过程中的"充电协议&q… 2026/7/15 10:56:17
WarcraftHelper魔兽辅助工具:3步解决经典魔兽在现代电脑上的兼容性问题 WarcraftHelper魔兽辅助工具:3步解决经典魔兽在现代电脑上的兼容性问题 【免费下载链接】WarcraftHelper Warcraft III Helper , support 1.20e, 1.24e, 1.26a, 1.27a, 1.27b 项目地址: https://gitcode.com/gh_mirrors/wa/WarcraftHelper 还在为魔兽争霸III… 2026/7/15 10:56:17
FPGA设计入门:从零开始的六个关键步骤 1. FPGA设计入门:从零开始的六个关键步骤第一次接触FPGA设计时,我被这个看似复杂的领域吓到了。但经过多年的实践,我发现只要掌握正确的学习路径,任何人都能成为FPGA设计高手。FPGA(现场可编程门阵列)是一种… 2026/7/15 10:52:15
行星减速机的工作原理是什么?从齿轮运动关系到减速比计算 一、行星齿轮机构的组成 标准行星齿轮机构主要包括: 太阳轮; 行星轮; 内齿圈; 行星架。 太阳轮位于机构中心。 多个行星轮围绕太阳轮均匀布置,行星轮内侧与太阳轮外啮合,外侧与内齿圈内啮合。 行星轮通过轴… 2026/7/15 0:03:00
阅读Java开源框架源码的心得分享! 前几日闲来无事有幸看到了一位博主分享自己阅读开源框架源码的心得,看了之后也引发了我的一些深度思考。我们为什么要看源码?我们该怎么样去看源码? 其中前者那位博主描述的我觉得很全了(如下图所示),就不做… 2026/7/15 0:03:00
【LINUX】驱动 【LINUX驱动】【字符设备】【中断】【Platform】【网课 设备树】【GPIO】【PINCTRL】【INPUT】【IIC】【SPI】【网络驱动】【屏幕驱动】【一 设备树】【二 内核模块编译】【三 基本驱动框架】【四 Platform总线设备驱动框架】【五 驱动子系统】【六 综合】 2026/7/15 0:07:01
Git reset 与 revert 深度对比:5个关键差异与 3 种典型应用场景 Git Reset 与 Revert 深度对比:5个关键差异与3种典型应用场景在团队协作开发中,代码版本管理如同行走钢丝——一步失误可能导致整个项目陷入混乱。作为Git进阶用户,你是否曾在深夜面对错误的提交束手无策?是否在强制推送后收到同事… 2026/7/13 8:31:55
GitHub 学生包申请避坑:5个常见失败原因与开发者工具调试方案 GitHub 学生包申请技术排障指南:5个高频失败场景与开发者工具实战方案第一次尝试申请GitHub学生包时,我盯着屏幕上那个不断转圈的加载动画整整15分钟,最终只等来了一行冰冷的错误提示。这可能是许多开发者共同的经历——明明按照教程操作&… 2026/7/14 18:25:04
冒烟测试用例设计规范:5%-10%覆盖率下的3类核心场景与执行标准 冒烟测试用例设计的黄金法则:5%-10%覆盖率下的精准筛选策略在快节奏的敏捷开发环境中,冒烟测试作为质量保障的第一道防线,其重要性不言而喻。当测试资源有限而时间紧迫时,如何从海量测试用例中精准筛选出那关键的5%-10%࿰… 2026/7/14 5:09:41