触摸屏中鼠标事件的捕获和传递及触摸屏的移植

触摸屏中鼠标事件的捕获和传递及触摸屏的移植

在Linux系统中,如果硬件设备的驱动程序被正确安装,那么在/dev路径下会有相应的设备文件,它们是对应硬件设备的驱动程序接口,应用程序可以打开这些设备文件,从中读取的数据就对应着硬件设备传回的信息。当鼠标被点击时,会产生中断并进入中断处理程序,在中断处理程序中,鼠标的动作会被翻译成相应的数据存在一个数据缓冲区中。用户打开设备文件后,就是从这个这个缓冲区读取数据的。注意,这时的数据是最原始的数据。

当Qt应用程序作为GuiServer运行时,QApplication会创建一个QWSServer*类的指针qwsServer,它是一个全局的指针,在整个Qt应用程序的生命周期都存在,而且只有一个。qwsServer在创建过程中会调用QWSServer::startup(),这个函数会调用QWSServer::openMouse()和QWSServer::openKeyboard()来建立与鼠标和键盘硬件设备的连接。在Qt中,触摸屏作为一种特别的鼠标,具有和鼠标同等的处理方法。

1. openMouse()

它会从环境变量QWS_MOUSE_PROT得到鼠标的类型和设备,它的格式是protocol:device,protocol包括以下的几种:MouseMan,IntelliMouse,Microsoft等,device就是鼠标(或者触摸屏)的设备文件,一般是/dev/mouse,还可能是/dev/ps2(ps类型的鼠标),而对于触摸屏,则会是/dev/Tpanel。最后它会创建一个QWSMouseHandler。

2. QWSMouseHandler* h = newMouseHandler(ms);

newMouseHandler从环境变量字符串中分析出设备文件路径和协议名,然后调用QMouseDriverFactory::create()创建QWSMouseHandler对象。

注:有的qt版本是直接在newMouseHandler()中创建QWSMouseHandler对象

3. QMouseDriverFactory::create(mouseProto, mouseDev)

这个鼠标驱动工厂创建一个指定的QWSMouseHandler对象

4. QWSMouseHandler对象的创建

它会调用自己的数据子对象QWSMouseHandlerPrivate的openDevices()打开鼠标设备文件并进行测试,最后调用QWSMouseHandlerPrivate的notify()将文件描述符(使用open()打开后返回的标志符)和处理函数连接起来。

5. notify(fd)

为设备fd创建一个QSocketNotifier*指针mouseNotifier,并将其activated(int)信号和QWSMouseHandlerPrivate::readMouseData(int)绑定在一起。

这样当设备fd发生中断时,readMouseData(int)会去读取设备缓冲区的内容。这中间有一个桥梁。当应用程序进入主事件循环时,会在循环中不断调用select()来检查文件描述符的变化,检测到变化时会发出QEvent::SockAt事件(通过QApplication::sendEvent()发送)给对应的QSocketNotifier,QSocketNotifier的event()函数中会对数据进行处理并发出activated(int)信号。

6. QWSMouseHandlerPrivate::readMouseData(int)

它先读取数据,得到按下点的坐标,然后调用sendFiltered( pp, Qt::LeftButton )将数据通过信号mouseChanged()发送出去。

如果要判断是否长按,先初始化一个计数器counter用来表示鼠标按下的时间,然后在if ( pressure > 0 ){..}中启动一个定时器,counter++,它表示鼠标还在按下。在if ( pressure < 0 ){…}中停止这个定时器,counter=0。它表示鼠标已经离开触摸屏。

在定时器的slot函数中进行判断,如果counter>0 表示鼠标被按下了一段时间,这时就可以发送mouseChanged()信号了,普通状态下发送的信号形如 mouseChanged(mousePos, Qt::LeftButton, 0); 长按信号就形如emit mouseChanged(mousePos, Qt::MouseLongPress | Qt::LeftButton, 0);

可我们还没定义Qt::MouseLongPress呢?在哪里定义呢?在qnamespace.h中

Qt里原来定义了一个Qt::ButtonState的枚举类型,描述了鼠标和组合键的状态,现在我们对它进行了扩展,让它还可以描述键盘的状态:

enum ButtonState

{

NoButton = 0x0000,

LeftButton = 0x0001,

RightButton = 0x0002,

MidButton = 0x0004,

MouseButtonMask = 0x0007,

ShiftButton = 0x0008,

ControlButton = 0x0010,

AltButton = 0x0020,

KeyButtonMask = 0x0038,

MouseLongPress = 0x0100,

ButtonLongPress = 0x0200,

ReplaceKey = 0x0400,

IMSpecKey = 0x8000,

Keypad = 0x4000

};

mouseChanged()这个信号是绑定在QWSServer* qwsServer上的,slot为setMouse(const QPoint &, int, int它会调用QWSServer的方法QWSServer::sendMouseEvent(const QPoint & p, int state, int wheel)中进行处理的。

7. QWSServer::sendMouseEvent(const QPoint & p, int state, int wheel)

它会创建一个QWSMouseEvent event,并对其进行赋值

event.simpleData.state = state | qws_keyModifiers;

最后调用serverClient->sendEvent(&event);将事件发送给客户端。

8. QWSClient::sendEvent(QWSEvent* e)

当应用程序为多进程时,会将事件写入到socket中,并调用csocket->flush().如果为单进程,则将事件写入到全局队列中qt_client_enqueue(e).客户端收到事件后,会将QWSMouseEvent转化为QWSEvent,转化过程是在QApplication::qwsEventFilter (QWSEvent* e)中进行。

9. QApplication::qwsEventFilter (QWSEvent* e)

所有重QWSServer传回的QWSEvent事件都将在这里进行处理,它先将QWSEvent转化为QEvent,然后使用QApplication::nofity()派发相应的接收窗口。???

当窗口接收到QEvent之后,将其转化为QMouseEvent,其成员函数state()返回的状态就包括我们事先写入的MouseLongPress属性了,简单的使用方式如下:

if(e->state() & Qt::MouseLongPress) {…}

到这里,我们可以看出,移植触摸屏的操作主要分为两步,一是将硬件设备安装到Linux系统中,在/dev下能看到相应的设备。二是基于Qt层面的处理,我们需要重新设置QWS_MOUSE_PROT,让它对应步骤一中的设备,然后就是修改动缓冲区读取数据的函数。

从设备缓冲区读取数据的是QWSMouseHandlerPrivate::readMouseData(int),对不同的鼠标设备,readMouseData(int)的内容是不同的。为了方便用户移植不同类型的鼠标,Qt提供了一个基类QWSMouseHandler,不同类型的鼠标从它派生出不同的子类,最后重载它的一些方法(主要是readMouseData(int))即可。这些dd的定义都在qwsmouse_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

原文地址 http://fanzhichao.blog.hexun.com/24027892_d.html

生气是拿别人做错的事来惩罚自己

触摸屏中鼠标事件的捕获和传递及触摸屏的移植

相关文章:

你感兴趣的文章:

标签云: