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

本文详细介绍了在Linux环境下如何通过Qt框架移植触摸屏设备,包括配置环境变量、处理设备文件等内容。同时,文章还深入探讨了如何在Qt中实现触摸屏的长按功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值