Linux驱动 2026年7月9日 43 分钟

tslib 使用手册1

tslib 使用手册 目录 简介 什么是 tslib? tslib 是一个 C 语言编写的触摸屏事件过滤库,主要功能包括…

tslib 使用手册

目录


简介

什么是 tslib?

tslib 是一个 C 语言编写的触摸屏事件过滤库,主要功能包括:

  • 触摸屏校准:将触摸屏坐标映射到屏幕坐标
  • 信号过滤:去除触摸输入中的噪声和抖动
  • 多点触摸支持:支持多点触摸事件处理
  • 跨平台:支持 Linux、FreeBSD、Android 等操作系统

核心组件

┌─────────────┐
│  应用程序    │  ← 你的程序通过 libts API 读取过滤后的数据
└─────────────┘
      ↑
┌─────────────┐
│   libts     │  ← 核心库,提供 API 和过滤器链管理
└─────────────┘
      ↑
┌─────────────┐
│ 过滤器模块   │  ← median, dejitter, linear 等
└─────────────┘
      ↑
┌─────────────┐
│  raw 模块   │  ← 从设备文件读取原始触摸数据
└─────────────┘
      ↑
┌─────────────┐
│ /dev/input/ │  ← 硬件设备驱动
└─────────────┘

快速开始

1. 安装 tslib

从源码编译

cd tslib-1.21
./configure
make
sudo make install

配置环境变量

export TSLIB_TSDEVICE=/dev/input/event0    # 触摸屏设备
export TSLIB_CALIBFILE=/etc/pointercal      # 校准文件
export TSLIB_CONFFILE=/etc/ts.conf          # 配置文件
export TSLIB_PLUGINDIR=/usr/local/lib/ts    # 插件目录

2. 配置触摸屏

创建配置文件 /etc/ts.conf

# 这是推荐的基础配置
module_raw input              # 从 /dev/input/eventX 读取数据
module median depth=3         # 中值滤波,去除尖峰噪声
module dejitter delta=100     # 去抖动,平滑快速移动
module linear                 # 线性校准,应用校准参数

3. 校准触摸屏

# 运行校准程序
ts_calibrate

# 按照屏幕提示,依次点击出现的十字标记
# 校准数据会保存到 /etc/pointercal

4. 测试触摸屏

# 打印触摸事件
ts_print

# 图形化测试(支持多点触摸)
ts_test_mt

5. 第一个程序

创建 test_touch.c

#include <stdio.h>
#include <stdlib.h>
#include <tslib.h>

int main(void)
{
    struct tsdev *ts;
    struct ts_sample samp;
    int ret;

    // 1. 打开并初始化触摸屏
    ts = ts_setup(NULL, 0);
    if (!ts) {
        perror("ts_setup");
        return 1;
    }

    printf("触摸屏已就绪,开始监听...\n");
    printf("触摸屏幕任意位置,按 Ctrl+C 退出\n\n");

    // 2. 循环读取触摸事件
    while (1) {
        ret = ts_read(ts, &samp, 1);
        if (ret < 0) {
            perror("ts_read");
            break;
        }

        if (ret != 1)
            continue;

        // 3. 处理触摸数据
        printf("时间: %ld.%06ld  X: %6d  Y: %6d  压力: %6d\n",
               samp.tv.tv_sec, 
               samp.tv.tv_usec,
               samp.x, 
               samp.y, 
               samp.pressure);

        // pressure > 0 表示按下,== 0 表示松开
        if (samp.pressure == 0) {
            printf("  → 触摸松开\n\n");
        }
    }

    // 4. 关闭设备
    ts_close(ts);
    return 0;
}

编译运行:

gcc -o test_touch test_touch.c -lts
./test_touch

配置文件详解

/etc/ts.conf 结构

配置文件定义了数据处理的过滤器链,触摸数据从上到下依次经过每个模块。

基本语法

module_raw <模块名> [参数]     # 第一行必须是 raw 模块
module <过滤器名> [参数]       # 后续是过滤器模块

常用 raw 模块

1. input(推荐,用于 Linux)

module_raw input
# 自动从 /dev/input/event* 查找触摸屏设备

module_raw input grab_events=1
# grab_events=1: 独占设备,防止其他程序干扰

常用过滤器模块

1. median – 中值滤波器

去除触摸信号中的尖峰噪声。

module median depth=3
  • depth: 取多少个样本的中值(默认 3)
  • 原理:对连续 N 个样本排序,取中间值
  • 适用:去除偶然的错误读数

2. dejitter – 去抖动

平滑触摸移动轨迹。

module dejitter delta=100
  • delta: 快速移动阈值(默认 100)
  • 原理:加权平滑,最新样本权重最大
  • 适用:减少手指移动时的抖动

3. linear – 线性校准(必需)

将触摸屏坐标转换为屏幕坐标。

module linear
module linear rot=0           # 不旋转
module linear rot=1           # 顺时针 90°
module linear rot=2           # 180°
module linear rot=3           # 逆时针 90°
  • 读取 /etc/pointercal 中的校准参数
  • 必须运行 ts_calibrate 生成校准文件

4. pthres – 压力阈值过滤

过滤压力值太小或太大的触摸。

module pthres pmin=1 pmax=1000
  • pmin: 最小压力值(默认 1)
  • pmax: 最大压力值(默认 INT_MAX)

5. iir – 无限冲激响应滤波

平滑低频噪声。

module iir N=6 D=10
  • N/D: 平滑系数(N=6, D=10 表示 0.6 的平滑度)
  • 值越大,响应越慢但越平滑

6. debounce – 防抖动

防止快速连续的误触。

module debounce drop_threshold=40
  • drop_threshold: 松开后丢弃事件的时间(毫秒)

7. invert – 坐标反转

反转 X 或 Y 坐标。

module invert x0=1024 y0=768
  • x0: X 轴反转中心
  • y0: Y 轴反转中心

配置示例

配置 1:基础配置(推荐)

module_raw input
module median depth=3
module dejitter delta=100
module linear

配置 2:高精度触摸屏

module_raw input
module pthres pmin=10          # 忽略轻微触摸
module median depth=5          # 更强的去噪
module iir N=8 D=10            # 平滑处理
module dejitter delta=50       # 更敏感的抖动过滤
module linear

配置 3:多点触摸,低噪声

module_raw input grab_events=1
module median depth=3
module dejitter delta=100
module linear

配置 4:旋转屏幕(顺时针 90°)

module_raw input
module median depth=3
module dejitter delta=100
module linear rot=1

API 使用说明

核心数据结构

单点触摸数据

struct ts_sample {
    int x;                    // X 坐标
    int y;                    // Y 坐标
    unsigned int pressure;    // 压力值(0 = 松开,>0 = 按下)
    struct timeval tv;        // 时间戳
};

多点触摸数据

struct ts_sample_mt {
    int x, y;                 // 坐标
    unsigned int pressure;    // 压力值
    int slot;                 // 触摸点编号(0, 1, 2...)
    int tracking_id;          // 跟踪 ID
    
    // 以下为扩展字段
    int tool_type;            // 工具类型(手指/笔)
    int tool_x, 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;              // blob ID
    
    struct timeval tv;        // 时间戳
    short pen_down;           // 按下状态
    short valid;              // 数据有效标志
};

核心 API 函数

1. ts_setup() – 初始化(推荐)

struct tsdev *ts_setup(const char *dev_name, int nonblock);
  • 功能:自动查找、打开设备并加载配置
  • 参数
    • dev_name: 设备路径(NULL = 自动检测)
    • nonblock: 0 = 阻塞模式,1 = 非阻塞模式
  • 返回:成功返回 tsdev 指针,失败返回 NULL

示例

struct tsdev *ts = ts_setup(NULL, 0);  // 自动检测,阻塞模式
if (!ts) {
    perror("ts_setup");
    exit(1);
}

2. ts_open() – 打开设备

struct tsdev *ts_open(const char *dev_name, int nonblock);
  • 功能:仅打开设备,不加载配置
  • 参数:同 ts_setup()
  • 返回:tsdev 指针或 NULL

3. ts_config() – 加载配置

int ts_config(struct tsdev *ts);
  • 功能:读取 /etc/ts.conf 并加载过滤器链
  • 返回:0 = 成功,-1 = 失败

4. ts_read() – 读取单点触摸

int ts_read(struct tsdev *ts, struct ts_sample *samp, int nr);
  • 功能:读取经过滤波和校准的触摸数据
  • 参数
    • ts: 设备句柄
    • samp: 接收数据的数组
    • nr: 期望读取的样本数
  • 返回:实际读取的样本数,-1 = 错误

示例

struct ts_sample samp;
int ret = ts_read(ts, &samp, 1);
if (ret == 1) {
    printf("坐标: (%d, %d) 压力: %d\n", 
           samp.x, samp.y, samp.pressure);
}

5. ts_read_mt() – 读取多点触摸

int ts_read_mt(struct tsdev *ts, 
               struct ts_sample_mt **samp, 
               int max_slots, 
               int nr);
  • 功能:读取多点触摸数据
  • 参数
    • samp: 二维数组指针
    • max_slots: 最大触摸点数
    • nr: 期望读取的样本数
  • 返回:实际读取的样本数

示例

#define SLOTS 5
#define SAMPLES 1

struct ts_sample_mt *samp_mt[SAMPLES];
for (int i = 0; i < SAMPLES; i++) {
    samp_mt[i] = calloc(SLOTS, sizeof(struct ts_sample_mt));
}

int ret = ts_read_mt(ts, samp_mt, SLOTS, SAMPLES);
for (int j = 0; j < ret; j++) {
    for (int i = 0; i < SLOTS; i++) {
        if (samp_mt[j][i].valid & TSLIB_MT_VALID) {
            printf("slot %d: (%d, %d) 压力: %d\n",
                   samp_mt[j][i].slot,
                   samp_mt[j][i].x,
                   samp_mt[j][i].y,
                   samp_mt[j][i].pressure);
        }
    }
}

6. ts_read_raw() – 读取原始数据

int ts_read_raw(struct tsdev *ts, struct ts_sample *samp, int nr);
  • 功能:读取未经过滤的原始数据
  • 用途:调试、查看过滤前的数据

7. ts_close() – 关闭设备

void ts_close(struct tsdev *ts);

8. ts_fd() – 获取文件描述符

int ts_fd(struct tsdev *ts);
  • 用途:用于 select/poll/epoll 等多路复用

完整示例程序

示例 1:单点触摸监听

#include <stdio.h>
#include <stdlib.h>
#include <tslib.h>
#include <signal.h>

static struct tsdev *ts = NULL;

void cleanup(int sig) {
    if (ts)
        ts_close(ts);
    printf("\n程序退出\n");
    exit(0);
}

int main(void)
{
    struct ts_sample samp;
    int ret;
    
    signal(SIGINT, cleanup);
    
    ts = ts_setup(NULL, 0);
    if (!ts) {
        perror("ts_setup");
        return 1;
    }
    
    printf("单点触摸监听程序\n");
    printf("触摸屏幕查看坐标,按 Ctrl+C 退出\n\n");
    
    while (1) {
        ret = ts_read(ts, &samp, 1);
        if (ret < 0) {
            perror("ts_read");
            break;
        }
        
        if (ret != 1)
            continue;
        
        if (samp.pressure > 0) {
            printf("按下: X=%d, Y=%d, 压力=%d\n", 
                   samp.x, samp.y, samp.pressure);
        } else {
            printf("松开\n");
        }
    }
    
    ts_close(ts);
    return 0;
}

示例 2:多点触摸监听

#include <stdio.h>
#include <stdlib.h>
#include <tslib.h>
#include <signal.h>

#define MAX_SLOTS 10

static struct tsdev *ts = NULL;

void cleanup(int sig) {
    if (ts)
        ts_close(ts);
    exit(0);
}

int main(void)
{
    struct ts_sample_mt *samp_mt[1];
    int ret, i;
    
    signal(SIGINT, cleanup);
    
    ts = ts_setup(NULL, 0);
    if (!ts) {
        perror("ts_setup");
        return 1;
    }
    
    samp_mt[0] = calloc(MAX_SLOTS, sizeof(struct ts_sample_mt));
    if (!samp_mt[0]) {
        ts_close(ts);
        return 1;
    }
    
    printf("多点触摸监听程序\n");
    printf("支持最多 %d 个触摸点\n\n", MAX_SLOTS);
    
    while (1) {
        ret = ts_read_mt(ts, samp_mt, MAX_SLOTS, 1);
        if (ret < 0) {
            perror("ts_read_mt");
            break;
        }
        
        for (i = 0; i < MAX_SLOTS; i++) {
            if (samp_mt[0][i].valid & TSLIB_MT_VALID) {
                printf("触摸点 %d: X=%d, Y=%d, 压力=%d, ID=%d\n",
                       samp_mt[0][i].slot,
                       samp_mt[0][i].x,
                       samp_mt[0][i].y,
                       samp_mt[0][i].pressure,
                       samp_mt[0][i].tracking_id);
            }
        }
        printf("\n");
    }
    
    free(samp_mt[0]);
    ts_close(ts);
    return 0;
}

示例 3:非阻塞模式 + select

#include <stdio.h>
#include <stdlib.h>
#include <tslib.h>
#include <sys/select.h>
#include <unistd.h>

int main(void)
{
    struct tsdev *ts;
    struct ts_sample samp;
    fd_set rfds;
    int fd, ret;
    
    // 非阻塞模式打开
    ts = ts_setup(NULL, 1);
    if (!ts) {
        perror("ts_setup");
        return 1;
    }
    
    fd = ts_fd(ts);
    printf("使用 select 监听触摸事件(非阻塞)\n\n");
    
    while (1) {
        FD_ZERO(&rfds);
        FD_SET(fd, &rfds);
        
        // 等待数据可读
        ret = select(fd + 1, &rfds, NULL, NULL, NULL);
        if (ret < 0) {
            perror("select");
            break;
        }
        
        if (FD_ISSET(fd, &rfds)) {
            ret = ts_read(ts, &samp, 1);
            if (ret == 1) {
                printf("X=%d, Y=%d, 压力=%d\n",
                       samp.x, samp.y, samp.pressure);
            }
        }
    }
    
    ts_close(ts);
    return 0;
}

工具程序

1. ts_calibrate – 触摸屏校准

ts_calibrate

功能

  • 显示 5 个校准点(四角 + 中心)
  • 依次点击十字标记
  • 计算校准参数并保存到 /etc/pointercal

使用建议

  • 首次使用触摸屏时必须校准
  • 屏幕旋转后需要重新校准
  • 触摸不准时重新运行

2. ts_test_mt – 图形化测试

ts_test_mt

功能

  • 显示触摸轨迹
  • 支持多点触摸
  • 显示触摸点数量和坐标

3. ts_print – 打印触摸事件

ts_print              # 打印过滤后的数据
ts_print --raw        # 打印原始数据

4. ts_finddev – 查找触摸设备

ts_finddev

输出触摸屏设备路径,如 /dev/input/event0

5. ts_uinput – 虚拟输入设备

ts_uinput -d -v

功能

  • 创建虚拟输入设备 /dev/input/ts_uinput
  • 将 tslib 过滤后的数据转发到虚拟设备
  • GUI 程序可以读取虚拟设备

常见问题

Q1: ts_setup() 返回 NULL

可能原因

  1. 触摸设备不存在或权限不足
  2. 配置文件 /etc/ts.conf 找不到
  3. 环境变量设置错误

解决方法

# 检查设备是否存在
ls -l /dev/input/event*

# 添加读写权限
sudo chmod 666 /dev/input/event0

# 设置环境变量
export TSLIB_TSDEVICE=/dev/input/event0
export TSLIB_CONFFILE=/etc/ts.conf

# 检查配置文件
cat /etc/ts.conf

Q2: 触摸坐标不准确

解决方法

# 重新校准
ts_calibrate

Q3: 触摸无响应

检查步骤

  1. 查看原始数据是否有输出:


    ts_print --raw

  2. 检查 /etc/ts.conf 配置


  3. 确认触摸屏驱动已加载


Q4: 多点触摸只能识别一个点

可能原因

  • 配置文件中使用了 variance 模块(不支持多点)

解决方法

  • 移除 variance 模块
  • 使用 median 代替

Q5: 编译时找不到 tslib.h

解决方法

# 指定头文件路径
gcc -I/usr/local/include test.c -L/usr/local/lib -lts

# 或添加到环境变量
export C_INCLUDE_PATH=/usr/local/include
export LIBRARY_PATH=/usr/local/lib
export LD_LIBRARY_PATH=/usr/local/lib

Q6: 运行时找不到 libts.so

# 添加库路径
export LD_LIBRARY_PATH=/usr/local/lib

# 或者更新系统库缓存
sudo ldconfig

进阶话题

1. 交叉编译

# 为 ARM 平台编译
./configure --host=arm-linux-gnueabihf \
            --prefix=/opt/tslib
make
make install

2. 自定义过滤器

参考 plugins/median.c 实现自己的过滤器模块。

3. 与 Qt 集成

# Qt5 使用 tslib
export QT_QPA_GENERIC_PLUGINS=tslib
export QT_QPA_TSLIB_DEVICE=/dev/input/event0

4. 与 X11 集成

使用 xf86-input-tslib 驱动。


总结

核心概念

  • tslib 是触摸屏的中间层,位于驱动和应用之间
  • 通过过滤器链处理触摸数据
  • 支持单点和多点触摸

使用流程

  1. 配置 /etc/ts.conf
  2. 运行 ts_calibrate 校准
  3. 使用 ts_setup() + ts_read() 读取数据

关键文件

  • /etc/ts.conf – 配置文件
  • /etc/pointercal – 校准数据
  • /dev/input/eventX – 设备文件

文档版本:v1.0
适用 tslib 版本:1.21
最后更新:2026-07-06

上一篇 tslib 快速参考卡

tslib 快速参考卡 一、核心概念(5分钟速记) tslib 是什么? 触摸屏事件过滤和校准库 三大功能 数据流 二、...

下一篇 tslib 学习手册2

tslib 学习手册 目录 学习路线图 推荐学习顺序 新手(只想使用): 开发者(深入理解): 系统集成(移植适配): ...