linux屏幕触碰事件,触摸屏中⿏标事件的捕获和传递及触摸屏
的移植
触摸屏中⿏标事件的捕获和传递及触摸屏的移植
在Linux系统中,如果硬件设备的驱动程序被正确安装,那么在/dev路
径下会有相应的设备⽂件,它们是对应硬件设备的驱动程序接⼝,应⽤程序可以打开这些设备⽂件,从中读取的数据就对应着硬件设备传回的信息。当⿏标被点击
时,会产⽣中断并进⼊中断处理程序,在中断处理程序中,⿏标的动作会被翻译成相应的数据存在⼀个数据缓冲区中。⽤户打开设备⽂件后,就是从这个这个缓冲区
读取数据的。注意,这时的数据是最原始的数据。
当Qt应⽤程序作为GuiServer运⾏时,QApplication会创建⼀个QWSServer*类的指针qwsServer,它是⼀个全局的指针,在整个Qt应⽤程序的⽣命周期都存在,⽽且只有⼀个。qwsServer在创建过程中会调⽤QWSServer::startup(),这个函数会调⽤梦到发洪水
QWSServer::openMou()和QWSServer::openKeyboard()来建⽴与⿏标和键盘硬件设备的连接。在Qt中,触摸屏作为⼀种特别的⿏标,具有和⿏标同等的处理⽅法。
1.openMou()
它会从环境变量QWS_MOUSE_PROT得到⿏标的类型和设备,它的格式是protocol:device,protocol包括以下的⼏
种:MouMan,IntelliMou,Microsoft等,device就是⿏标(或者触摸屏)的设备⽂件,⼀般是/dev/mou,还可能是/dev/ps2(ps类型的⿏标),⽽对于触摸屏,则会是/dev/Tpanel。最后它会创建⼀个QWSMouHandler。
2.QWSMouHandler* h = newMouHandler(ms);
newMouHandler从环境变量字符串中分析出设备⽂件路径和协议名,然后调⽤QMouDriverFactory::create()创建QWSMouHandler对象。
注:有的qt版本是直接在newMouHandler()中创建QWSMouHandler对象
3.QMouDriverFactory::create(mouProto, mouDev)林徽因徐志摩
这个⿏标驱动⼯⼚创建⼀个指定的QWSMouHandler对象
4.QWSMouHandler对象的创建
早会故事它会调⽤⾃⼰的数据⼦对象QWSMouHandlerPrivate的openDevices()打开⿏标设备⽂件并进⾏测试,最后调⽤QWSMouHandlerPrivate的notify()将⽂件描述符(使⽤open()打开后返回的标志符)和处理函数连接起来。
为设备fd创建⼀个QSocketNotifier*指针mouNotifier,并将其activated(int)信号和
QWSMouHandlerPrivate::readMouData(int)绑定在⼀起。
这样当设备fd发⽣中断时,readMouData(int)会去读取设备缓冲区的内容。这中间有⼀个桥梁。当应⽤程序进⼊主事件循环时,会在循环中不断调⽤lect()来检查⽂件描述符的变化,检测到变化时会发出QEvent::SockAt事件(通过QApplication::ndEvent()发送)给对应的QSocketNotifier,QSocketNotifier的event()函数中会对数据进⾏处理并发出activated(int)信号。
6.QWSMouHandlerPrivate::readMouData(int)
它先读取数据,得到按下点的坐标,然后调⽤ndFiltered( pp, Qt::LeftButton )将数据通过信号mouChanged()发送出去。
如果要判断是否长按,先初始化⼀个计数器counter⽤来表⽰⿏标按下的时间,然后在if ( pressure > 0 ){..}中启动⼀个定时
器,counter++,它表⽰⿏标还在按下。在if ( pressure < 0 ){…}中停⽌这个定时器,counter=0。它表⽰⿏标已经离开触摸屏。
在定时器的slot函数中进⾏判断,如果counter>0表⽰⿏标被按下了⼀段时间,这时就可以发送mouChanged()信号了,普通状态下发送的信号形如mouChanged(mouPos, Qt::LeftButton, 0);长按信号就形如emit mouChanged(mouPos, Qt::MouLongPress | Qt::LeftButton, 0);
可我们还没定义Qt::MouLongPress呢?在哪⾥定义呢?在qnamespace.h中
Qt⾥原来定义了⼀个Qt::ButtonState的枚举类型,描述了⿏标和组合键的状态,现在我们对它进⾏了扩展,让它还可以描述键盘的状态:
enum ButtonState
{
NoButton= 0x0000,
LeftButton= 0x0001,
不放弃不抛弃RightButton= 0x0002,
MidButton= 0x0004,
MouButtonMask = 0x0007,
ShiftButton= 0x0008,
ControlButton= 0x0010,
AltButton= 0x0020,
KeyButtonMask= 0x0038,
MouLongPress= 0x0100,
ButtonLongPress = 0x0200,
莫言简介
ReplaceKey= 0x0400,
IMSpecKey= 0x8000,
Keypad= 0x4000
};
mouChanged()这个信号是绑定在QWSServer* qwsServer上的,slot为tMou(const QPoint &, int, int它会调⽤QWSServer的⽅法QWSServer::ndMouEvent(const QPoint & p, int state, int wheel)中进⾏处理的。
7.QWSServer::ndMouEvent(const QPoint & p, int state, int wheel)
它会创建⼀个QWSMouEventevent,并对其进⾏赋值
event.simpleData.state = state | qws_keyModifiers;
最后调⽤rverClient->ndEvent(&event);将事件发送给客户端。
8.QWSClient::ndEvent(QWSEvent* e)
当应⽤程序为多进程时,会将事件写⼊到socket中,并调⽤csocket->flush().如果为单进程,则将事件写⼊到全局队列中
qt_client_enqueue(e).客户端收到事件后,会将QWSMouEvent转化为QWSEvent,转化过程是在
QApplication::qwsEventFilter(QWSEvent* e)中进⾏。
9.QApplication::qwsEventFilter (QWSEvent* e)舌尖上的中国美食
所有重QWSServer传回的QWSEvent事件都将在这⾥进⾏处理,它先将QWSEvent转化为QEvent,然后使⽤QApplication::nofity()派发相应的接收窗⼝。
当窗⼝接收到QEvent之后,将其转化为QMouEvent,其成员函数state()返回的状态就包括我们事先写⼊的MouLongPress属性了,简单的使⽤⽅式如下:
昼夜的近义词if(e->state() & Qt::MouLongPress){…}
到这⾥,我们可以看出,移植触摸屏的操作主要分为两步,⼀是将硬件设备安装到Linux系统中,在/dev下能看到相应的设备。⼆是基于Qt 层⾯的处理,我们需要重新设置QWS_MOUSE_PROT,让它对应步骤⼀中的设备,然后就是修改动缓冲区读取数据的函数。
从设备缓冲区读取数据的是QWSMouHandlerPrivate::readMouData(int),对不同的⿏标设备,readMouData(int)的内容是不同的。为了⽅便⽤户移植不同类型的⿏标,Qt提供了⼀个基类QWSMouHandler,不同类型的⿏标从它派⽣出不同的⼦类,最后重载它的⼀些⽅法(主要是readMouData(int))即可。这些dd的定义都在qwsmou_qws.cpp当中。
此外,触摸屏和⿏标有⼀点的不同的地⽅,它需要进⾏调整。因为从设备得到的数据是物理屏的数据,⽐如s3c2410的触摸屏的ad转换是10位精度,也就是说物理数据从0~1023,在实际的情况中⼀般是100~1000之间的数据,⽽我们的液晶屏是640*480(或者是其他的,这和触摸屏的数据没有任何的关系),所以必须将物理数据转换为屏幕上点的数据.他们之间的转换公式,就必须通过定标的⽅式来确定。
所谓的定标,就是在屏幕上依次出现topleft,bottomleft,bottomright,topright和center⼀共5个点,⽤户必须依次在这5个点上点击(在触摸屏上点击,触摸屏就放在液晶屏的上⽅),这样我们得到了物理的点,也得到了对应的实际的点,因此就可以计算出相应的参数。
如果屏的质量稳定,我们可以将测得的数据放在这个⽂件当中,并取消掉定标的过程,这样就可以每次使⽤默认的设置,⽽不需要重新计算了,通常这些设置会保存在⽂件/etc/pointercal中。S3c2410的触摸屏驱动是iPAQ兼容的驱动,编译的时候需要定义2个宏:
学校章程QWS_MOUSE_IPAQ,QWS_MOUSE_IPAQ_RAW.
同时设定:QWS_MOUSE_PROTO=Tpanel:/dev/h3600_tsraw