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

简介: 大家好,今天主要和大家聊一聊,如何使用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库的使用方法,对未来个人的发展具有重要作用。

目录
相关文章
|
6月前
|
Ubuntu Linux Anolis
Linux系统禁用swap
本文介绍了在新版本Linux系统(如Ubuntu 20.04+、CentOS Stream、openEuler等)中禁用swap的两种方法。传统通过注释/etc/fstab中swap行的方式已失效,现需使用systemd管理swap.target服务或在/etc/fstab中添加noauto参数实现禁用。方法1通过屏蔽swap.target适用于新版系统,方法2通过修改fstab挂载选项更通用,兼容所有系统。
594 3
Linux系统禁用swap
|
6月前
|
Linux
Linux系统修改网卡名为eth0、eth1
在Linux系统中,可通过修改GRUB配置和创建Udev规则或使用systemd链接文件,将网卡名改为`eth0`、`eth1`等传统命名方式,适用于多种发行版并支持多网卡配置。
1127 3
|
Ubuntu Linux 网络安全
Linux系统初始化脚本
一款支持Rocky、CentOS、Ubuntu、Debian、openEuler等主流Linux发行版的系统初始化Shell脚本,涵盖网络配置、主机名设置、镜像源更换、安全加固等多项功能,适配单/双网卡环境,支持UEFI引导,提供多版本下载与持续更新。
702 3
Linux系统初始化脚本
|
7月前
|
运维 Linux 开发者
Linux系统中使用Python的ping3库进行网络连通性测试
以上步骤展示了如何利用 Python 的 `ping3` 库来检测网络连通性,并且提供了基本错误处理方法以确保程序能够优雅地处理各种意外情形。通过简洁明快、易读易懂、实操性强等特点使得该方法非常适合开发者或系统管理员快速集成至自动化工具链之内进行日常运维任务之需求满足。
494 18
|
6月前
|
安全 Linux Shell
Linux系统提权方式全面总结:从基础到高级攻防技术
本文全面总结Linux系统提权技术,涵盖权限体系、配置错误、漏洞利用、密码攻击等方法,帮助安全研究人员掌握攻防技术,提升系统防护能力。
785 1
|
6月前
|
监控 安全 Linux
Linux系统提权之计划任务(Cron Jobs)提权
在Linux系统中,计划任务(Cron Jobs)常用于定时执行脚本或命令。若配置不当,攻击者可利用其提权至root权限。常见漏洞包括可写的Cron脚本、目录、通配符注入及PATH变量劫持。攻击者通过修改脚本、创建恶意任务或注入命令实现提权。系统管理员应遵循最小权限原则、使用绝对路径、避免通配符、设置安全PATH并定期审计,以防范此类攻击。
1227 1
|
7月前
|
缓存 监控 Linux
Linux系统清理缓存(buff/cache)的有效方法。
总结而言,在大多数情形下你不必担心Linux中buffer与cache占用过多内存在影响到其他程序运行;因为当程序请求更多内存在没有足够可用资源时,Linux会自行调整其占有量。只有当你明确知道当前环境与需求并希望立即回收这部分资源给即将运行重负载任务之前才考虑上述方法去主动干预。
2100 10
|
7月前
|
安全 Linux 数据安全/隐私保护
为Linux系统的普通账户授予sudo访问权限的过程
完成上述步骤后,你提升的用户就能够使用 `sudo`命令来执行管理员级别的操作,而无需切换到root用户。这是一种更加安全和便捷的权限管理方式,因为它能够留下完整的权限使用记录,并以最小权限的方式工作。需要注意的是,随意授予sudo权限可能会使系统暴露在风险之中,尤其是在用户不了解其所执行命令可能带来的后果的情况下。所以在配置sudo权限时,必须谨慎行事。
1350 0
|
7月前
|
Ubuntu Linux 开发者
国产 Linux 发行版再添新成员,CutefishOS 系统简单体验
当然,系统生态构建过程并不简单,不过为了帮助国产操作系统优化生态圈,部分企业也开始用国产操作系统替代 Windows,我们相信肯定会有越来越多的精品软件登录 Linux 平台。
597 0
|
7月前
|
Ubuntu 安全 Linux
Linux系统入门指南:从零开始学习Linux
Shell脚本是一种强大的自动化工具,可以帮助您简化重复的任务或创建复杂的脚本程序。了解Shell脚本的基本语法和常用命令,以及编写和运行Shell脚本的步骤,将使您更高效地处理日常任务。
685 0