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文档即可。
2。校准后保存了一个新的pointercal文档,但ts_lib怎么知道当前的pointercal文档是应该读取的新文档。刚开始的时候我们在 linear.c的linear_read()函数中采取计数轮询的方式查看/etc/poinercal文档的最后更新时间,假如当前的更新时间大于上次更新时间,就去读取下pointercal文档。我们暂且不说在一台刚下流水线的机器,他的rtc时间是不确定,再进行时间比较时会出现错误。另外始终的轮询的方式和ts_lib的采样间隔时间值很小。这样用户在进行触摸屏常按操作时,会很明显的消耗系统资源。
3。此时想到的办法就是进程通信,ts_lib是个动态库运行于系统中,他存在系统中不是以进程方式,但能够采取折衷方法,将调用ts_lib的进程号(实际上就是X的进程号)保存到一个配置文档中。这样在使用ts_calibrate校准触摸屏后,利用信号的方式给ts_lib发送用户自定义信号,ts_lib的 lineral.c中加一个简单的信号处理函数。在接受到信号后就去读取下新的pointercal文档。正常情况下不做任何的轮询和读取操作。
从上说的3个步骤中完全解决了校准后应用端触摸及时生效的问题。更有个次要问题就是怎样锁屏?这需要从内核入手了,查看linux2.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:%d/n",ioctl_ret);
if (ioctl_ret!=0)
{
printf("Error: %s/n", strerror(errno));
exit(1);
}
printf("lock the ts success /n")