一、tslib介绍
tslib 是专门为触摸屏设备所开发的 Linux 应用层函数库,并且是开源。
tslib 为触摸屏驱动和应用层之间的适配层,它把应用程序中读取触摸屏 struct input_event 类型数据(这是输入设备上报给应用层的原始数据)并进行解析的操作过程进行了封装,向使用者提供了封装好的 API 接口。
二、tslib 移植
首先进入到 tslib 的 git 仓库下载源码tslib下载地址
下载 1.16 版本的 tslib,往下翻找到 1.16 版本的下载链接:
点击红框字样进入下载页面:
下载 tar.gz 格式的压缩包文件,点击文字即可下载。
三、编译 tslib 源码
解压tslib-1.16.tar.gz 源码包
解压之后会生成 tslib-1.16 目录,tslib包目录下创建一个 tools 目录,然后在 tools 目录下创建 tslib 目录,等会编译 tslib 库的时候将安装目录指定到这里,如下所示:
进入到 tslib-1.16 目录,准备进行编译 tslib 源码:
首先在配置工程之前,先对交叉编译工具的环境进行设置
source /opt/fsl-imx-x11/4.1.15-2.1.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi
执行下面这条命令对 tslib 源码工程进行配置:
./configure --host=arm-poky-linux-gnueabi --prefix=/home/jack/linux/tslib/tools/tslib/
–host 选项用于指定交叉编译得到的库文件是运行在哪个平台,通常将–host 设置为交叉编译器名称的前缀,譬如 arm-pokylinux-gnueabi-gcc 前缀就是 arm-poky-linux-gnueabi;–prefix 选项则用于指定库文件的安装路径,后面写自己设置的路径
接着执行
make
make install
至此交叉编译完成,可以在安装目录下看到生成的文件夹。
移植的最后一步就是把 tslib 安装目录下的库文件、etc 下的配置文件以及编译得到的测试工具拷贝到开发板 Linux 系统目录下,由于开发板出厂系统中已经移植了 tslib 库,所以我们这里就不用拷贝了。如果是自己做的根文件系统并没有移植 tslib,那么就需要把这些库、可执行文件以及配置文件拷贝到根文件系统中,大致步骤如下:
- 将安装目录 bin/目录下的所有可执行文件拷贝到开发板/usr/bin 目录下;
- 将安装目录 etc/目录下的配置文件 ts.conf 拷贝到开发板/etc 目录下;
- 将安装目录 lib/目录下的所有库文件拷贝到开发板/usr/lib 目录下。
四、基于tslib写单点触摸屏应用程序
使用 tslib 提供的 API 接口来编写触摸屏应用程序,使用 tslib 库函数需要在我们的应用程序中包含 tslib 的头文件 tslib.h。
#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);
}
可以看出上述步骤:
- 打开触摸屏设备:struct tsdev *ts_setup(const char *dev_name, int nonblock),参数 dev_name 指定触摸屏的设备节点,参数 nonblock 表示是否以非阻塞方式打开触摸屏设备。
- 配置触摸屏设备:int ts_config(struct tsdev *ts),解析 ts.conf 文件中的配置信息,加载相应的插件。
- 读取触摸屏数据:int ts_read(struct tsdev *ts, struct ts_sample *samp, int nr),ts_read 用于读取单点触摸数据
代码中ts_setup函数的dev_name参数为null,函数内部会读取TSLIB_TSDEVICE 环境变量,获取该环境变量的内容以得知触摸屏的设备节点。
ts_read()函数的 samp 参数是一个 struct ts_sample *类型的指针,指向一个 struct ts_sample 对象,struct ts_sample 数据结构描述了触摸点的信息。
编译应用程序:
${CC} -I /home/jack/linux/tslib/tools/tslib/include -L /home/jack/linux/tslib/tools/tslib/lib -lts -o ts_single_touch tslib_touch.c
-I 指定tslib库的头文件路径
-L 指定tslib库路径
-l 指定链接库,也就是 libts.so 库文件
结果如下:
五、基于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);
}
结果如下: