Linux系统中如何使用tslib库实现触摸功能

本文涉及的产品
文本翻译,文本翻译 100万字符
文档翻译,文档翻译 1千页
图片翻译,图片翻译 100张
简介: 大家好,今天主要和大家聊一聊,如何使用tslib库来完成对应的功能。

第一:tslib库基本简介

   上篇文章为了获取触摸点,主要是对读取到的struct input_event类型数据进行分析,得到各个触摸点坐标。接下来,主要使用tslib库进行学习,这是Linux系统下,专门为触摸屏开发的应用层函数库。

tslib库是开源的,也就是可以直接获取到tslib的源代码。tslib为触摸屏驱动和应用层之间的适配层,它把应用程序中读取触摸屏struct input_event类型数据(这是输入设备上报给应用层的原始数据)并进行解析的操作过程进行了封装,向使用者提供了封装好的API接口。tslib从触摸屏中获得原始的坐标数据,并通过一系列的去抖、坐标变换等操作,来去除噪声并将原始的触摸屏坐标转换为相应的屏幕坐标。


   tslib可以作为Qt的触摸屏输入插件,为Qt提供触摸输入支持,如果在嵌入式Linux硬件平台上开发过Qt应用程序应该知道,并不是只有 tslib 才能作为 Qt 的插件、为其提供触摸输入支持,还有很多插件都可以。

第二:tslib安装目录下的文件夹介绍

    进入到tslib安装目录下:

78bdd92b4aa79151287293e511e036ad.png

bin目录

    bin目录下有一些tslib提供的小工具,可以用于测试触摸屏,如下所示:

3951865e7b8b55b6eb316b0aa27308c9.png

etc目录

    etc目录下有一个配置文件ts.conf,前面给大家提到过:

4d386fc36076ca968214c44970209199 (1).png

    打开ts.conf文件看看它有哪些配置选项:

55c19b034c2274d2483232a49da41f63 (1).png

     module_raw input:取消注释,使能支持input输入事件;


module pthres pmin=1:如果我们的设备支持按压力大小测试,那么可以把它的注释取消,pmin 用于调节按压力灵敏度,默认就是等于 1。


module dejitter delta=100:tslib 提供了触摸屏去噪算法插件,如果需要过滤噪声样本,取消注释,默认参数 delta=100。


module linear:tslib 提供了触摸屏坐标变换的功能,譬如将 X、Y 坐标互换、坐标旋转等之类,如果我们需要实现坐标变换,可以把注释去掉。


这里就不去改动了,直接使用默认的配置就行了。


    include 目录


    include目录下只有一个头文件tslib.h,该头文件中包含了一些结构体数据结构以及API接口的申明,使用tslib提供的API就需要包含该头文件。


    lib目录


    lib目录下包含了编译tslib源码所得到的库文件,默认这些都是动态库文件,也可以通过配置tslib工程使其生成静态库文件;ts目录下存放的是一些插件库。

94a04cccbe5ed1433edd699088867fc0.png

第三:在开发板上测试tslib库

     使用tslib提供的API接口来编写触摸屏的应用程序,使用tslib库函数需要在我们的应用程序中包含tslib的头文件tslib.h,使用tslib编程其实非常简单,基本步骤如下所示:

 第一步打开触摸屏设备;

      第二步配置触摸屏设备;

      第三步读取触摸屏数据;

1、打开触摸屏设备

     使用tslib提供的库函数ts_open打开触摸屏设备,其函数原型如下所示:

#include "tslib.h"
struct tsdev *ts_open(const char *dev_name,int nonblock);

 参数dev_name 指定了触摸屏的设备节点;参数nonblock表示是否以非阻塞方式打开触摸屏设备,如果nonblock等于0表示阻塞方式,如果为非0值则表示以非阻塞方式打开。


     调用成功返回一个struct sdev *指针,指向触摸屏设备句柄;如果打开设备失败,将返回NULL。除了使用ts_open()打开设备外,还可以使用ts_setup()函数,其函数原型如下所示:

#inlcude "tslib.h"
struct tsdev *ts_setup(const char *dev_name,int nonblock)

参数 dev_name 指定触摸屏的设备节点,与 ts_open()函数中的 dev_name 参数意义相同;但对于 ts_setup()来说,参数 dev_name 可以设置为 NULL,当 dev_name 设置为 NULL 时,ts_setup()函数内部会读取TSLIB_TSDEVICE 环境变量,获取该环境变量的内容以得知触摸屏的设备节点。


    ts_setup()相比ts_open(),除了打开触摸屏设备外,还可以对触摸屏设备进行配置。


2、配置触摸屏设备


    调用ts_config()函数进行配置,其函数原型如下所示:

#include "tslib.h"
int ts_config(struct tsdev *ts)

参数ts指向触摸屏句柄。

    成功返回0,失败返回-1。

    所谓配置其实指的就是解析ts.conf文件中的配置信息,加载相应的插件。

第四:读取触摸屏数据

读取触摸屏数据使用 ts_read()或 ts_read_mt()函数,区别在于 ts_read 用于读取单点触摸数据,而ts_read_mt 则用于读取多点触摸数据,其函数原型如下所示:

#include "tslib.h"
int ts_read(struct tsdev *ts,struct ts_sample *samp,int nr)
int ts_read_mt(struct tsdev *ts, struct ts_sample_mt **samp, int max_slots, int nr)

参数ts指向一个触摸屏设备句柄,参数nr表示对一个触摸点的采样数,设置为1即可。


     ts_read_mt()函数有一个 max_slots 参数,表示触摸屏支持的最大触摸点数,应用程序可以通过调用 ioctl()函数来获取触摸屏支持的最大触摸点数以及触摸屏坐标的最大分辨率等信息,稍后向大家介绍。


     ts_read()函数的 samp 参数是一个 struct ts_sample *类型的指针,指向一个 struct ts_sample 对象,struct ts_sample 数据结构描述了触摸点的信息;调用 ts_read()函数获取到的数据会存放在 samp 指针所指向的内存中。struct ts_sample 结构体内容如下所示:

struct ts_sample{
     int x;  //X坐标
     int y;  //Y坐标
     unsigned int pressure;  //按压力大小
     struct timeval  tv;   //时间
};

  ts_read_mt()函数的 samp 参数是一个 struct ts_sample_mt **类型的指针,多点触摸应用程序,每一个触摸点的信息使用 struct ts_sample_mt 数据结构来描述;一个触摸点的数据使用一个 struct ts_sample_mt 对象来装载,将它们组织成一个 struct ts_sample_mt 数组,调用 ts_read_mt()时,将数组地址赋值给 samp 参数。


    struct ts_sample结构体内容如下所示:

struct ts_sample_mt {
 /* ABS_MT_* event codes. linux/include/uapi/linux/input-event-codes.h
 * has the definitions.
 */
 int x; //X 坐标
 int y; //Y 坐标
 unsigned int pressure; //按压力大小
 int slot; //触摸点 slot
 int tracking_id; //ID
 int tool_type;
 int tool_x;
 int tool_y;
 unsigned int touch_major;
 unsigned int width_major;
 unsigned int touch_minor;
 unsigned int width_minor;
 int orientation;
 int distance;
 int blob_id;
 struct timeval tv; //时间
 /* BTN_TOUCH state */
 short pen_down; //BTN_TOUCH 的状态
 short valid;  //此次样本是否有效标志
 };

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

#include <stdio.h>
#include <stdlib.h>
#include <tslib.h>    //包含tslib.h的头文件
int main(int argc, char *argv[])
{
 struct tsdev *ts = NULL;
 struct ts_sample samp;
 int pressure = 0;//用于保存上一次的按压力,初始为 0,表示松开
 /* 打开并配置触摸屏设备 */
 ts = ts_setup(NULL, 0);
 if (NULL == ts) {
 fprintf(stderr, "ts_setup error");
 exit(EXIT_FAILURE);
 }
 /* 读数据 */
 for ( ; ; ) {
 if (0 > ts_read(ts, &samp, 1)) {
 fprintf(stderr, "ts_read error");
 ts_close(ts);
 exit(EXIT_FAILURE);
 }
 if (samp.pressure) {//按压力>0
     if (pressure) //若上一次的按压力>0
     printf("移动(%d,%d)\n",samp.x,samp.y);
     else
     printf("按下(%d,%d)\n",samp.x,samp.y);
     }
     else
     printf("松开\n");//打印坐标
     pressure = samp.pressure;
 }
     ts_close(ts);
     exit(EXIT_SUCCESS);
}

分析:利用代码直接打开、配置设备、接着读取数据,通过判断按压大小确定触摸的状态。

${CC} -I /home/dt/tools/tslib/include -L /home/dt/tools/tslib/lib -lts -o testApp testApp.c

061e0ca4c9f24f71f3b3245b274cc7b4 (1).png

  -I选项指定头文件的路径,也就是指定tslib安装目录下的include目录,如果不指定头文件路径,编译时将会找不到tslib.h头文件;-L 选项用于指定库文件的路径,也就是指定 tslib 安装目录下的 lib 目录;我们将 tslib 编译成了动态库文件,以库文件的形式提供,编译时需要链接到这些库文件;而-l 选项则用于指定链接库(也可写成-l ts,也就是 libts.so 库文件,Linux 中,动态库文件的命名方式为 lib+名字+.so)。


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

eaf5d77dd8c84282038f9ecd19f130dc (2).png

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

       接下来基于tslib的多点触摸应用程序,使用ts_read_mt()函数读取多点触摸数据。

#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <linux/input.h>
#include <tslib.h>
int main(int argc, char *argv[])
{
 struct tsdev *ts = NULL;
 struct ts_sample_mt *mt_ptr = NULL;
 struct input_absinfo slot;
 int max_slots;
 unsigned int pressure[12] = {0}; //用于保存每一个触摸点上一次的按压力,初始为 0,表示松开
 int i;
 /* 打开并配置触摸屏设备 */
 ts = ts_setup(NULL, 0);
 if (NULL == ts) {
 fprintf(stderr, "ts_setup error");
 exit(EXIT_FAILURE);
}
 /* 获取触摸屏支持的最大触摸点数 */
 if (0 > ioctl(ts_fd(ts), EVIOCGABS(ABS_MT_SLOT), &slot)) {
 perror("ioctl error");
 ts_close(ts);
 exit(EXIT_FAILURE);
 }
 max_slots = slot.maximum + 1 - slot.minimum;
 printf("max_slots: %d\n", max_slots);
 /* 内存分配 */
 mt_ptr = calloc(max_slots, sizeof(struct ts_sample_mt));
 /* 读数据 */
 for ( ; ; ) {
 if (0 > ts_read_mt(ts, &mt_ptr, max_slots, 1)) {
 perror("ts_read_mt error");
 ts_close(ts);
 free(mt_ptr);
 exit(EXIT_FAILURE);
 }
 for (i = 0; i < max_slots; i++) {
 if (mt_ptr[i].valid) {//有效表示有更新!
 if (mt_ptr[i].pressure) { //如果按压力>0
 if (pressure[mt_ptr[i].slot])//如果上一次的按压力>0
 printf("slot<%d>, 移动(%d, %d)\n", mt_ptr[i].slot, mt_ptr[i].x, mt_ptr[i].y);
 else
 printf("slot<%d>, 按下(%d, %d)\n", mt_ptr[i].slot, mt_ptr[i].x, mt_ptr[i].y);
 }
 else
 printf("slot<%d>, 松开\n", mt_ptr[i].slot);
 pressure[mt_ptr[i].slot] = mt_ptr[i].pressure;
 }
 }
 }
 /* 关闭设备、释放内存、退出 */ 
  ts_close(ts);
  free(mt_ptr);
  exit(EXIT_SUCCESS);
}

整个思路与单点触摸应用程序相同,通过ts_read_mt()函数读取触摸点数据,将这些数据存放在 mt_ptr 数组中,接着在 for()循环中判断每一个触摸点数据是否有效,有效则表示该触摸点信息发生更新。

${CC} -I /home/dt/tools/tslib/include -L /home/dt/tools/tslib/lib -lts -o testApp testApp.c

f0067d15dbcbc319052c2669d12ff98d (1).png

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

05e2e7293aee828a792be49d695dbe57.png

总结:触摸屏在很多场合下都会使用到,掌握tslib库的使用方法,对未来个人的发展具有重要作用。

目录
相关文章
|
3天前
|
Linux
在 Linux 系统中,“cd”命令用于切换当前工作目录
在 Linux 系统中,“cd”命令用于切换当前工作目录。本文详细介绍了“cd”命令的基本用法和常见技巧,包括使用“.”、“..”、“~”、绝对路径和相对路径,以及快速切换到上一次工作目录等。此外,还探讨了高级技巧,如使用通配符、结合其他命令、在脚本中使用,以及实际应用案例,帮助读者提高工作效率。
19 3
|
3天前
|
监控 安全 Linux
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景,包括 ping(测试连通性)、traceroute(跟踪路由路径)、netstat(显示网络连接信息)、nmap(网络扫描)、ifconfig 和 ip(网络接口配置)。掌握这些命令有助于高效诊断和解决网络问题,保障网络稳定运行。
16 2
|
13天前
|
Linux 应用服务中间件 Shell
linux系统服务二!
本文详细介绍了Linux系统的启动流程,包括CentOS 7的具体启动步骤,从BIOS自检到加载内核、启动systemd程序等。同时,文章还对比了CentOS 6和CentOS 7的启动流程,分析了启动过程中的耗时情况。接着,文章讲解了Linux的运行级别及其管理命令,systemd的基本概念、优势及常用命令,并提供了自定义systemd启动文件的示例。最后,文章介绍了单用户模式和救援模式的使用方法,包括如何找回忘记的密码和修复启动故障。
35 5
linux系统服务二!
|
13天前
|
Linux 应用服务中间件 Shell
linux系统服务!!!
本文详细介绍了Linux系统(以CentOS7为例)的启动流程,包括BIOS自检、读取MBR信息、加载Grub菜单、加载内核及驱动程序、启动systemd程序加载必要文件等五个主要步骤。同时,文章还对比了CentOS6和CentOS7的启动流程图,并分析了启动流程的耗时。此外,文中还讲解了Linux的运行级别、systemd的基本概念及其优势,以及如何使用systemd管理服务。最后,文章提供了单用户模式和救援模式的实战案例,帮助读者理解如何在系统启动出现问题时进行修复。
35 3
linux系统服务!!!
|
3天前
|
安全 网络协议 Linux
本文详细介绍了 Linux 系统中 ping 命令的使用方法和技巧,涵盖基本用法、高级用法、实际应用案例及注意事项。
本文详细介绍了 Linux 系统中 ping 命令的使用方法和技巧,涵盖基本用法、高级用法、实际应用案例及注意事项。通过掌握 ping 命令,读者可以轻松测试网络连通性、诊断网络问题并提升网络管理能力。
18 3
|
6天前
|
安全 Linux 数据安全/隐私保护
在 Linux 系统中,查找文件所有者是系统管理和安全审计的重要技能。
在 Linux 系统中,查找文件所有者是系统管理和安全审计的重要技能。本文介绍了使用 `ls -l` 和 `stat` 命令查找文件所有者的基本方法,以及通过文件路径、通配符和结合其他命令的高级技巧。还提供了实际案例分析和注意事项,帮助读者更好地掌握这一操作。
23 6
|
6天前
|
Linux
在 Linux 系统中,`find` 命令是一个强大的文件查找工具
在 Linux 系统中,`find` 命令是一个强大的文件查找工具。本文详细介绍了 `find` 命令的基本语法、常用选项和具体应用示例,帮助用户快速掌握如何根据文件名、类型、大小、修改时间等条件查找文件,并展示了如何结合逻辑运算符、正则表达式和排除特定目录等高级用法。
31 6
|
7天前
|
机器学习/深度学习 自然语言处理 Linux
Linux 中的机器学习:Whisper——自动语音识别系统
本文介绍了先进的自动语音识别系统 Whisper 在 Linux 环境中的应用。Whisper 基于深度学习和神经网络技术,支持多语言识别,具有高准确性和实时处理能力。文章详细讲解了在 Linux 中安装、配置和使用 Whisper 的步骤,以及其在语音助手、语音识别软件等领域的应用场景。
35 5
|
7天前
|
缓存 运维 监控
【运维必备知识】Linux系统平均负载与top、uptime命令详解
系统平均负载是衡量Linux服务器性能的关键指标之一。通过使用 `top`和 `uptime`命令,可以实时监控系统的负载情况,帮助运维人员及时发现并解决潜在问题。理解这些工具的输出和意义是确保系统稳定运行的基础。希望本文对Linux系统平均负载及相关命令的详细解析能帮助您更好地进行系统运维和性能优化。
25 3
|
7天前
|
监控 网络协议 算法
Linux内核优化:提升系统性能与稳定性的策略####
本文深入探讨了Linux操作系统内核的优化策略,旨在通过一系列技术手段和最佳实践,显著提升系统的性能、响应速度及稳定性。文章首先概述了Linux内核的核心组件及其在系统中的作用,随后详细阐述了内存管理、进程调度、文件系统优化、网络栈调整及并发控制等关键领域的优化方法。通过实际案例分析,展示了这些优化措施如何有效减少延迟、提高吞吐量,并增强系统的整体健壮性。最终,文章强调了持续监控、定期更新及合理配置对于维持Linux系统长期高效运行的重要性。 ####