使用ts_lib包自带的ts_calibrate校准触摸屏非常简单实用,但在基于Xsever的GUI应用环境下,有两个问题存在:
1.校准后必须重新启动X,应用端才能生效。这样处理用户肯定不能接受,因为启动一次机器毕竟耗时。
2.在使用ts_calibrate校准触摸屏时,要触摸5个点,这时如果GUI应用端在运行其他响应触摸事件(鼠标事件)的程序就会出现错乱。所以安全的做法应该是在校准触摸屏时进行锁屏操作。
解决这两个问题之前来看看tslib校准方面的原理,如果将原理搞清楚,剩下就是方法实现的问题了。
Tslib
是触摸屏驱动和应用层之间的适配层,它从触摸屏驱动处获得原始的设备坐标数据,通过一系列的去噪、去抖、坐标变换等操作,来去除噪声并将原始的设备坐标转
换为相应的屏幕坐标。通过tslib/src/tslib.h文件可以看出,在tslib中为应用层提供了2个主要的接口
ts_open(),ts_close();ts_read()和ts_read_raw(),其中ts_read()为正常情况下的接
口,ts_read_raw()为校准情况下使用的接口。从tslib默认的ts.conf文件中可以看出包括如下基本插件:
pthres 为Tslib 提供的触摸屏灵敏度门槛插件;
variance 为Tslib提供的触摸屏滤波算法插件;
dejitter 为Tslib 提供的触摸屏去噪算法插件;
linear为Tslib 提供的触摸屏坐标变换插件。
tslib 从触摸屏驱动采样到的设备坐标进行处理再提供给应用端的过程大体如下:
raw device --> variance --> dejitter --> linear --> application
module module module module
再来看看ts_calibrate主要做了哪些事情,校准情况下,tslib对驱动采样到的数据进行处理的一般过程如下:
1。读取屏上5个点的坐标(Top Left,Top Right,Bottom Left,Bottom
Right,Center),在进行一系列的变换,取样的5个点,实际上是包含3个不同的X值,3个不同的Y值。和scaling
值一共7个值,一起保存到/etc/pointercal中.
2.这个/etc/pointercal文件主要是供linear插件使用。而我们每次的触摸的操作都进行多次触摸坐标变换。
至此已经找到解决问题的大体的方法了。在校准触摸屏后只需及时的让linear插件再次读取新的/etc/pointeracal文件,这样新校准的坐标信息就及时的更新到上层应用。下面就要考虑具体实现的问题了。
1。从linear.c文件可以看出在该模块初始化时读取了/etc/pointercal文件。只要在linear_read()中读取新的/etc/pointercal文件即可。
如何锁屏?这需要从内核入手了,查看
linux 2.6
内核
/drivers/input/evdev.c从该驱动提供的ioctl中看到对基于evdev的输入设备都提供EVIOCGRAB实现。顾名思
义,grab就是将当前的输入操作抓取到当前的操作中,让当前操作之外的所有应用端读不到触摸屏的触摸操作。由驱动 就很容易知道该如何实现锁屏解锁操作了。 如下:
truct tsdev *ts;
char *tsdevice = "/dev/input/event0";
ts = ts_open(tsdevice, 0);
int ts_tmpfd = ts_fd(ts);
if (ts_tmpfd== -1)
{
perror("ts_open");
exit(1);
}
unsigned long val =1;
int ioctl_ret=ioctl(ts_tmpfd,EVIOCGRAB,&val);
printf("now lock the ts ioctl ret is:%dn",ioctl_ret);
if (ioctl_ret!=0)
{
printf("Error: %sn", strerror(errno));
exit(1);
}
printf("lock the ts success n");
-
#include <stdlib.h>
-
#include <string.h>
-
#include <stdio.h>
-
#include <errno.h>
-
#include <sys/ioctl.h>
-
#include <linux/input.h>
-
-
#include <sys/types.h>
-
#include <sys/stat.h>
-
#include <fcntl.h>
-
#include <unistd.h>
-
#include <pthread.h>
-
-
#include <tslib.h>
-
-
#define TS_DEV_FAKE "/dev/fake_event1"
-
#define TSDEV_MAJOR 13
-
#define TS_DEV_MINOR 65
-
-
typedef struct {
-
int x[5], xfb[5];
-
int y[5], yfb[5];
-
int a[7];
-
} calibration;
-
-
static calibration cal;
-
-
static struct tsdev *fake_ts = NULL;
-
-
void fake_tsdev_grab(int bEnabled)
-
{
-
int ts_tmpfd = ts_fd(fake_ts);
-
-
ioctl(ts_tmpfd, EVIOCGRAB, &bEnabled);
-
}
-
-
void fake_tsdev_close(void)
-
{
-
if (fake_ts != NULL) {
-
fake_tsdev_grab(0);
-
ts_close(fake_ts);
-
}
-
-
fake_ts = NULL;
-
/*
-
if (0 == access( TS_DEV_FAKE, F_OK | R_OK))
-
remove(TS_DEV_FAKE);
-
*/
-
}
-
/*
-
* 复制一个 tsdev 的设备节点并打开。
-
* < 0: 失败。
-
* > 0:返回的设备句柄。
-
*/
-
-
int fake_tsdev_dup(void)
-
{
-
/*
-
int iret;
-
dev_t dev_id;
-
const char* tsdevice ;
-
struct stat stat_buf;
-
*/
-
if (fake_ts != NULL) {
-
fake_tsdev_close();
-
}
-
/* //all the fake device is create on system init process in script.
-
-
tsdevice = getenv ("TSLIB_TSDEVICE");
-
if (tsdevice == NULL)
-
{
-
perror("ENV TSLIB_TSDEVICE Not Found.");
-
return -1;
-
}
-
-
if ( 0 != (stat(tsdevice, &stat_buf)))
-
{
-
perror("stat TSLIB_TSDEVICE error.");
-
return -1;
-
}
-
-
//dev_id = makedev(TSDEV_MAJOR, TS_DEV_MINOR);
-
dev_id = stat_buf.st_rdev;
-
fprintf(stderr, "fake touchscreen. char dev %d-%d\n", major(dev_id), minor(dev_id));
-
-
if (access(TS_DEV_FAKE, F_OK) != 0) {
-
iret = mknod(TS_DEV_FAKE, stat_buf.st_mode, dev_id);
-
if (-1 == iret) {
-
perror("mknod fake tsdev");
-
fake_tsdev_close();
-
return -1;
-
}
-
}
-
*/
-
fake_ts = ts_open (TS_DEV_FAKE, 0);
-
if (!fake_ts) {
-
perror("fake ts_open");
-
fake_tsdev_close();
-
return -1;
-
}
-
-
fake_tsdev_grab(1);
-
-
if (ts_config(fake_ts)) {
-
perror("fake ts_config");
-
fake_tsdev_close();
-
return -1;
-
}
-
-
return ts_fd (fake_ts);
-
}
-
-
static int sort_by_x(const void* a, const void *b)
-
{
-
return (((struct ts_sample *)a)->x - ((struct ts_sample *)b)->x);
-
}
-
-
static int sort_by_y(const void* a, const void *b)
-
{
-
return (((struct ts_sample *)a)->y - ((struct ts_sample *)b)->y);
-
}
-
-
/*
-
* 开始获取某个点的坐标原始信息。0-4
-
* 0: get OK
-
* <0: failed.
-
*/
-
int fake_tsdev_get_sample (int index, int origin_x, int origin_y)
-
{
-
#define MAX_SAMPLES 128
-
struct ts_sample samp[MAX_SAMPLES];
-
int idx, middle;
-
int fs_fd, iret;
-
fd_set rfds;
-
struct timeval timeout;
-
-
if (index == 0) {
-
memset(&cal, 0, sizeof(cal));
-
}
-
-
printf("Took %d samples...\n",index);
-
-
if ((index<0) | (index>4)) return -1;
-
-
do {
-
fs_fd = ts_fd (fake_ts);
-
FD_ZERO (&rfds);
-
FD_SET(fs_fd, &rfds);
-
timeout.tv_sec = 0;
-
timeout.tv_usec = 10000;
-
iret = select (fs_fd + 1, &rfds, NULL, NULL, &timeout);
-
-
if (0 > iret) goto err; //some error
-
if (0 == iret) continue;
-
-
if (ts_read_raw(fake_ts, &samp[0], 1) < 0) {
-
perror("fake ts_read 0");
-
goto err;
-
}
-
} while (samp[0].pressure == 0);
-
-
/* Now collect up to MAX_SAMPLES touches into the samp array. */
-
idx = 0;
-
do {
-
if (idx < MAX_SAMPLES-1)
-
idx++;
-
-
if (NULL == fake_ts) return -2;
-
if (ts_read_raw(fake_ts, &samp[idx], 1) < 0) {
-
perror("fake ts_read 1");
-
return -2;
-
}
-
} while (samp[idx].pressure > 0);
-
-
middle = idx/2;
-
{
-
qsort(samp, idx, sizeof(struct ts_sample), sort_by_x);
-
if (idx & 1)
-
cal.x[index] = samp[middle].x;
-
else
-
cal.x[index] = (samp[middle-1].x + samp[middle].x) / 2;
-
}
-
{
-
qsort(samp, idx, sizeof(struct ts_sample), sort_by_y);
-
if (idx & 1)
-
cal.y [index] = samp[middle].y;
-
else
-
cal.y [index] = (samp[middle-1].y + samp[middle].y) / 2;
-
}
-
-
cal.xfb[index] = origin_x;
-
cal.yfb[index] = origin_y;
-
-
fprintf(stderr, "should[%d-%d] -> real[%d-%d]\n", cal.xfb[index], cal.yfb[index], cal.x[index], cal.y[index]);
-
-
return 0;
-
err:
-
return -2;
-
}
-
-
/*
-
* 计算
-
*/
-
int perform_calibration(calibration *cal) {
-
int j;
-
float n, x, y, x2, y2, xy, z, zx, zy;
-
float det, a, b, c, e, f, i;
-
float scaling = 65536.0;
-
-
// Get sums for matrix
-
n = x = y = x2 = y2 = xy = 0;
-
for(j=0;j<5;j++) {
-
n += 1.0;
-
x += (float)cal->x[j];
-
y += (float)cal->y[j];
-
x2 += (float)(cal->x[j]*cal->x[j]);
-
y2 += (float)(cal->y[j]*cal->y[j]);
-
xy += (float)(cal->x[j]*cal->y[j]);
-
}
-
-
// Get determinant of matrix -- check if determinant is too small
-
det = n*(x2*y2 - xy*xy) + x*(xy*y - x*y2) + y*(x*xy - y*x2);
-
if(det < 0.1 && det > -0.1) {
-
printf("ts_calibrate: determinant is too small -- %f\n",det);
-
return 0;
-
}
-
-
// Get elements of inverse matrix
-
a = (x2*y2 - xy*xy)/det;
-
b = (xy*y - x*y2)/det;
-
c = (x*xy - y*x2)/det;
-
e = (n*y2 - y*y)/det;
-
f = (x*y - n*xy)/det;
-
i = (n*x2 - x*x)/det;
-
-
// Get sums for x calibration
-
z = zx = zy = 0;
-
for(j=0;j<5;j++) {
-
z += (float)cal->xfb[j];
-
zx += (float)(cal->xfb[j]*cal->x[j]);
-
zy += (float)(cal->xfb[j]*cal->y[j]);
-
}
-
-
// Now multiply out to get the calibration for framebuffer x coord
-
cal->a[0] = (int)((a*z + b*zx + c*zy)*(scaling));
-
cal->a[1] = (int)((b*z + e*zx + f*zy)*(scaling));
-
cal->a[2] = (int)((c*z + f*zx + i*zy)*(scaling));
-
-
printf("%f %f %f\n",(a*z + b*zx + c*zy),
-
(b*z + e*zx + f*zy),
-
(c*z + f*zx + i*zy));
-
-
// Get sums for y calibration
-
z = zx = zy = 0;
-
for(j=0;j<5;j++) {
-
z += (float)cal->yfb[j];
-
zx += (float)(cal->yfb[j]*cal->x[j]);
-
zy += (float)(cal->yfb[j]*cal->y[j]);
-
}
-
-
// Now multiply out to get the calibration for framebuffer y coord
-
cal->a[3] = (int)((a*z + b*zx + c*zy)*(scaling));
-
cal->a[4] = (int)((b*z + e*zx + f*zy)*(scaling));
-
cal->a[5] = (int)((c*z + f*zx + i*zy)*(scaling));
-
-
printf("%f %f %f\n",(a*z + b*zx + c*zy),
-
(b*z + e*zx + f*zy),
-
(c*z + f*zx + i*zy));
-
-
// If we got here, we're OK, so assign scaling to a[6] and return
-
cal->a[6] = (int)scaling;
-
-
return 0;
-
}
-
-
/*
-
* fake_tsdev_get_sample获得5个点之后调用,用户计算最终结果并保存。
-
* 0:成功. <0 failed。
-
*/
-
int fake_tsdev_update_tscalibrate(void)
-
{
-
char *calfile = NULL;
-
int cal_fd, iret=0;
-
char cal_buffer[256];
-
-
iret = perform_calibration(&cal);
-
if (iret != 0) return iret;
-
-
if ((calfile = getenv("TSLIB_CALIBFILE")) != NULL) {
-
cal_fd = open (calfile, O_CREAT | O_RDWR);
-
} else {
-
cal_fd = open ("/etc/pointercal", O_CREAT | O_RDWR);
-
}
-
-
memset(cal_buffer, 0, sizeof(cal_buffer));
-
sprintf (cal_buffer,"%d %d %d %d %d %d %d",
-
cal.a[1], cal.a[2], cal.a[0],
-
cal.a[4], cal.a[5], cal.a[3], cal.a[6]);
-
-
printf("fake touch offset [%s]\n", cal_buffer);
-
write (cal_fd, cal_buffer, strlen (cal_buffer) + 1);
-
close (cal_fd);
-
return 0;
-
}
阅读(3106) | 评论(0) | 转发(0) |