QT5.5.1 嵌入式平台 鼠标键盘不能热插拔问题解决(二)

上一篇文章已经介绍了qt键鼠热插拔经历的曲折之路,这篇就具体解决热插拔问题。


=======================================================

如上一篇文章所述,在源码中搜索了键鼠热插拔时的调试信息,

qt.qpa.input: Found mouse at "/dev/input/event0"
qt.qpa.input: Found matching devices ("/dev/input/event0")
qt.qpa.input: Adding mouse at "/dev/input/event0"
qt.qpa.input: create mouse handler for "/dev/input/event0" ""
qt.qpa.input: evdevtouch: Using device discovery

在QT_ROOT/qtbase/src源码目录下搜索上述信息,在中断键入【grep -rn "Adding mouse at"】,结果如下


发现在QT_ROOT/qtbase/src/platformsupport/input/evdevmouse/qevdevmousemanager.cpp文件中存在相应语句。从命名上就可以猜到该文件是用来管理mouse的,后续验证确实是。将相应的函数贴出来:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. void QEvdevMouseManager::addMouse(const QString &deviceNode)  
  2. {  
  3.     qCDebug(qLcEvdevMouse) << "Adding mouse at" << deviceNode;  
  4.     QEvdevMouseHandler *handler;  
  5.     handler = QEvdevMouseHandler::create(deviceNode, m_spec);  
  6.     if (handler) {  
  7.         connect(handler, SIGNAL(handleMouseEvent(int,int,bool,Qt::MouseButtons)), this, SLOT(handleMouseEvent(int,int,bool,Qt::MouseButtons)));  
  8.         connect(handler, SIGNAL(handleWheelEvent(int,Qt::Orientation)), this, SLOT(handleWheelEvent(int,Qt::Orientation)));  
  9.         m_mice.insert(deviceNode, handler);  
  10.         QInputDeviceManagerPrivate::get(QGuiApplicationPrivate::inputDeviceManager())->setDeviceCount(  
  11.             QInputDeviceManager::DeviceTypePointer, m_mice.count());  
  12.     } else {  
  13.         qWarning("evdevmouse: Failed to open mouse device %s", qPrintable(deviceNode));  
  14.     }  
  15. }  

在同一个文件中的类函数中(贴出部分,如下)可以看出该函数是用于接收信号的槽,且信号为deviceDetected

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. 。。。。   
  2.   
  3.        qCDebug(qLcEvdevMouse) << "evdevmouse: Using device discovery";  
  4.         m_deviceDiscovery = QDeviceDiscovery::create(QDeviceDiscovery::Device_Mouse | QDeviceDiscovery::Device_Touchpad, this);  
  5.         if (m_deviceDiscovery) {  
  6.             // scan and add already connected keyboards  
  7.             QStringList devices = m_deviceDiscovery->scanConnectedDevices();  
  8.             foreach (const QString &device, devices) {  
  9.                 addMouse(device);  
  10.             }  
  11.   
  12.             connect(m_deviceDiscovery, SIGNAL(deviceDetected(QString)), this, SLOT(addMouse(QString)));  
  13.             connect(m_deviceDiscovery, SIGNAL(deviceRemoved(QString)), this, SLOT(removeMouse(QString)));  
  14.         }  
  15.  。。。。  

同理还存在另外一对信号与槽,全部列举出来:

SIGNAL(deviceDetected(QString)) —— SLOT(addMouse(QString))
SIGNAL(deviceRemoved(QString))—— SLOT(removeMouse(QString))

这两对函数正如猜测的那样,是udev管理热插拔时发出的,具体的发出位置可以搜索【grep -rn "deviceDetected"】 ,结果如下:


发现在名为qdevicediscovery_udev.cpp的文件中进行的信号发送工作:emit deviceDetected(devNode);


打开qdevicediscovery_udev.cpp所在路径的devicediscovery.pri文件,内容如下:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. HEADERS += $$PWD/qdevicediscovery_p.h  
  2.   
  3. linux {  
  4.     contains(QT_CONFIG, libudev) {  
  5.         SOURCES += $$PWD/qdevicediscovery_udev.cpp  
  6.         HEADERS += $$PWD/qdevicediscovery_udev_p.h  
  7.         INCLUDEPATH += $$QMAKE_INCDIR_LIBUDEV  
  8.         LIBS_PRIVATE += $$QMAKE_LIBS_LIBUDEV  
  9.     } else: contains(QT_CONFIG, evdev) {  
  10.         SOURCES += $$PWD/qdevicediscovery_static.cpp  
  11.         HEADERS += $$PWD/qdevicediscovery_static_p.h  
  12.     } else {  
  13.         SOURCES += $$PWD/qdevicediscovery_dummy.cpp  
  14.         HEADERS += $$PWD/qdevicediscovery_dummy_p.h  
  15.     }  
  16. else {  
  17.     SOURCES += $$PWD/qdevicediscovery_dummy.cpp  
  18. }  
移植过Linux的应该很眼熟,很明显是根据配置单进行选择编译的文件,由于没有配置libudev而默认配置了evdev,因此自动编译的文件名称为 qdevicediscovery_static.cpp/.h。


思路与目标已经明确:

1.在qdevicediscovery_static.cpp文件中实现检测键鼠插入与移除,并发送相应的信号deviceDetected/deviceRemoved即可。
2.检测键鼠的插入与移除可以检测文件系统中/dev/input/目录下设备节点的变化,具体的监听采用QFileSystemWatcher类的路径监听(directoryChanged)。


一、添加监听代码

1.为了方便恢复,复制qdevicediscovery_static.cpp和头文件为qdevicediscovery_hotplug.cpp和qdevicediscovery_hotplug_p.h,修改文件中的static关键字为hotplug(强迫症,可不修改)。


2.由于需要保持监听长时存在,因此监听的实例声明要放在头文件中,并添加相应头文件,由于需要记住上一次添加的设备,因此仿造.cpp文件实现添加一个QStringList变量。

添加头文件:#include <QFileSystemWatcher>

                     #include <QStringList>

声明监听实例:QFileSystemWatcher *m_fileWatcher;

声明上一次添加设备的列表:QStringList m_devices;
声明信号函数:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. private slots:  
  2.     void handleHotPlugWatch(const QString &path);  


3.初始化监听变量与信号监听函数实现

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. // 初始化文件监听器  
  2. m_fileWatcher = new QFileSystemWatcher(this);  
  3. m_fileWatcher->addPath(QString::fromLatin1(QT_EVDEV_DEVICE_PATH));// "dev/input/"  
  4. connect(m_fileWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(handleHotPlugWatch(QString)));  

信号监听函数实现

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. void QDeviceDiscoveryHotPlug::handleHotPlugWatch(const QString &path)  
  2. {  
  3.     if(path.compare(QString::fromLatin1(QT_EVDEV_DEVICE_PATH)))  
  4.     {  
  5.         return;  
  6.     }  
  7.   
  8.     QStringList devices;  
  9.   
  10.     // 先移除原来的设备  
  11.     foreach (const QString &device, m_devices)  
  12.         deviceRemoved(device);  
  13.   
  14.     // 获取现在的设备  
  15.     // 注,这里获取的设备已经经过过滤,原因是在对该类进行实例化的时候  
  16.     // 已经传进了筛选参数,如:QDeviceDiscovery::Device_Keyboard  
  17.     devices = this->scanConnectedDevices();  
  18.   
  19.     // 重新添加设备  
  20.     foreach (const QString &device, devices)  
  21.         deviceDetected(device);  
  22. }  

4.修改QStringList QDeviceDiscoveryHotPlug::scanConnectedDevices()函数,保存添加设备的列表

将QStringList devices;改成m_devices.clear();,用以清除上一次的值

将该函数中的devices全部改成m_devices,用以保存新的值。



二、修改devicediscovery.pri文件中的编译选项

如下:


[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. 。。。  
  2.     } else: contains(QT_CONFIG, evdev) {  
  3.         SOURCES += $$PWD/qdevicediscovery_hotplug.cpp  
  4.         HEADERS += $$PWD/qdevicediscovery_hotplug_p.h  
  5.     }  
  6. 。。。  


修改文件完成后,重新make/make install,将安装后的qt文件移植到开发板上即可。现在QT5.5.1已经支持热插拔了~~~~






附录:修改后的qdevicediscovery_hotplug.cpp和qdevicediscovery_hotplug_p.h文件如下

1.qdevicediscovery_hotplug.cpp文件具体代码如下:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /**************************************************************************** 
  2. ** 
  3. ** usb input device hot plug function 
  4. ** by sn02241  
  5. ** 
  6. ****************************************************************************/  
  7.   
  8. #include "qdevicediscovery_hotplug_p.h"  
  9.   
  10. #include <QCoreApplication>  
  11. #include <QObject>  
  12. #include <QHash>  
  13. #include <QDir>  
  14. #include <QLoggingCategory>  
  15. #include <QtCore/private/qcore_unix_p.h>  
  16.   
  17. #include <linux/input.h>  
  18. #include <fcntl.h>  
  19.   
  20. /* android (and perhaps some other linux-derived stuff) don't define everything 
  21.  * in linux/input.h, so we'll need to do that ourselves. 
  22.  */  
  23. #ifndef KEY_CNT  
  24. #define KEY_CNT                 (KEY_MAX+1)  
  25. #endif  
  26. #ifndef REL_CNT  
  27. #define REL_CNT                 (REL_MAX+1)  
  28. #endif  
  29. #ifndef ABS_CNT  
  30. #define ABS_CNT                 (ABS_MAX+1)  
  31. #endif  
  32.   
  33. #define LONG_BITS (sizeof(long) * 8 )  
  34. #define LONG_FIELD_SIZE(bits) ((bits / LONG_BITS) + 1)  
  35.   
  36. static bool testBit(long bit, const long *field)  
  37. {  
  38.     return (field[bit / LONG_BITS] >> bit % LONG_BITS) & 1;  
  39. }  
  40.   
  41. QT_BEGIN_NAMESPACE  
  42.   
  43. Q_LOGGING_CATEGORY(lcDD, "qt.qpa.input")  
  44.   
  45. QDeviceDiscovery *QDeviceDiscovery::create(QDeviceTypes types, QObject *parent)  
  46. {  
  47.     return new QDeviceDiscoveryHotPlug(types, parent);  
  48. }  
  49.   
  50. QDeviceDiscoveryHotPlug::QDeviceDiscoveryHotPlug(QDeviceTypes types, QObject *parent)  
  51.     : QDeviceDiscovery(types, parent),m_fileWatcher(0)  
  52. {  
  53.     // 初始化文件监听器  
  54.     m_fileWatcher = new QFileSystemWatcher(this);  
  55.     m_fileWatcher->addPath(QString::fromLatin1(QT_EVDEV_DEVICE_PATH));// "dev/input/"  
  56.     connect(m_fileWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(handleHotPlugWatch(QString)));  
  57.   
  58.     qCDebug(lcDD) << "hotplug device discovery for type" << types;  
  59. }  
  60.   
  61. QStringList QDeviceDiscoveryHotPlug::scanConnectedDevices()  
  62. {  
  63.     m_devices.clear();  
  64.     QDir dir;  
  65.     dir.setFilter(QDir::System);  
  66.   
  67.     // check for input devices  
  68.     if (m_types & Device_InputMask) {  
  69.         dir.setPath(QString::fromLatin1(QT_EVDEV_DEVICE_PATH));  
  70.         foreach (const QString &deviceFile, dir.entryList()) {  
  71.             QString absoluteFilePath = dir.absolutePath() + QString::fromLatin1("/") + deviceFile;  
  72.             if (checkDeviceType(absoluteFilePath))  
  73.                 m_devices << absoluteFilePath;  
  74.         }  
  75.     }  
  76.   
  77.     // check for drm devices  
  78.     if (m_types & Device_VideoMask) {  
  79.         dir.setPath(QString::fromLatin1(QT_DRM_DEVICE_PATH));  
  80.         foreach (const QString &deviceFile, dir.entryList()) {  
  81.             QString absoluteFilePath = dir.absolutePath() + QString::fromLatin1("/") + deviceFile;  
  82.             if (checkDeviceType(absoluteFilePath))  
  83.                 m_devices << absoluteFilePath;  
  84.         }  
  85.     }  
  86.   
  87.     qCDebug(lcDD) << "Found matching devices" << m_devices;  
  88.   
  89.     return m_devices;  
  90. }  
  91.   
  92. bool QDeviceDiscoveryHotPlug::checkDeviceType(const QString &device)  
  93. {  
  94.     bool ret = false;  
  95.     int fd = QT_OPEN(device.toLocal8Bit().constData(), O_RDONLY | O_NDELAY, 0);  
  96.     if (!fd) {  
  97.         qWarning() << "Device discovery cannot open device" << device;  
  98.         return false;  
  99.     }  
  100.   
  101.     long bitsKey[LONG_FIELD_SIZE(KEY_CNT)];  
  102.     if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(bitsKey)), bitsKey) >= 0 ) {  
  103.         if (!ret && (m_types & Device_Keyboard)) {  
  104.             if (testBit(KEY_Q, bitsKey)) {  
  105.                 qCDebug(lcDD) << "Found keyboard at" << device;  
  106.                 ret = true;  
  107.             }  
  108.         }  
  109.   
  110.         if (!ret && (m_types & Device_Mouse)) {  
  111.             long bitsRel[LONG_FIELD_SIZE(REL_CNT)];  
  112.             if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(bitsRel)), bitsRel) >= 0 ) {  
  113.                 if (testBit(REL_X, bitsRel) && testBit(REL_Y, bitsRel) && testBit(BTN_MOUSE, bitsKey)) {  
  114.                     qCDebug(lcDD) << "Found mouse at" << device;  
  115.                     ret = true;  
  116.                 }  
  117.             }  
  118.         }  
  119.   
  120.         if (!ret && (m_types & (Device_Touchpad | Device_Touchscreen))) {  
  121.             long bitsAbs[LONG_FIELD_SIZE(ABS_CNT)];  
  122.             if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(bitsAbs)), bitsAbs) >= 0 ) {  
  123.                 if (testBit(ABS_X, bitsAbs) && testBit(ABS_Y, bitsAbs)) {  
  124.                     if ((m_types & Device_Touchpad) && testBit(BTN_TOOL_FINGER, bitsKey)) {  
  125.                         qCDebug(lcDD) << "Found touchpad at" << device;  
  126.                         ret = true;  
  127.                     } else if ((m_types & Device_Touchscreen) && testBit(BTN_TOUCH, bitsKey)) {  
  128.                         qCDebug(lcDD) << "Found touchscreen at" << device;  
  129.                         ret = true;  
  130.                     } else if ((m_types & Device_Tablet) && (testBit(BTN_STYLUS, bitsKey) || testBit(BTN_TOOL_PEN, bitsKey))) {  
  131.                         qCDebug(lcDD) << "Found tablet at" << device;  
  132.                         ret = true;  
  133.                     }  
  134.                 }  
  135.             }  
  136.         }  
  137.   
  138.         if (!ret && (m_types & Device_Joystick)) {  
  139.             long bitsAbs[LONG_FIELD_SIZE(ABS_CNT)];  
  140.             if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(bitsAbs)), bitsAbs) >= 0 ) {  
  141.                 if ((m_types & Device_Joystick)  
  142.                     && (testBit(BTN_A, bitsKey) || testBit(BTN_TRIGGER, bitsKey) || testBit(ABS_RX, bitsAbs))) {  
  143.                     qCDebug(lcDD) << "Found joystick/gamepad at" << device;  
  144.                     ret = true;  
  145.                 }  
  146.             }  
  147.         }  
  148.     }  
  149.   
  150.     if (!ret && (m_types & Device_DRM) && device.contains(QString::fromLatin1(QT_DRM_DEVICE_PREFIX)))  
  151.         ret = true;  
  152.   
  153.     QT_CLOSE(fd);  
  154.     return ret;  
  155. }  
  156.   
  157. void QDeviceDiscoveryHotPlug::handleHotPlugWatch(const QString &path)  
  158. {  
  159.     if(path.compare(QString::fromLatin1(QT_EVDEV_DEVICE_PATH)))  
  160.     {  
  161.         return;  
  162.     }  
  163.   
  164.     QStringList devices;  
  165.   
  166.     // 先移除原来的设备  
  167.     foreach (const QString &device, m_devices)  
  168.         deviceRemoved(device);  
  169.   
  170.     // 获取现在的设备  
  171.     // 注,这里获取的设备已经经过过滤,原因是在对该类进行实例化的时候  
  172.     // 已经传进了筛选参数,如:QDeviceDiscovery::Device_Keyboard  
  173.     devices = this->scanConnectedDevices();  
  174.   
  175.     // 重新添加设备  
  176.     foreach (const QString &device, devices)  
  177.         deviceDetected(device);  
  178. }  
  179.   
  180. QT_END_NAMESPACE  

2.qdevicediscovery_hotplug_p.h文件具体代码如下:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /**************************************************************************** 
  2. ** 
  3. ** usb input device hot plug function 
  4. ** by sn02241 
  5. ** 
  6. ****************************************************************************/  
  7.   
  8. #ifndef QDEVICEDISCOVERY_HOTPLUG_H  
  9. #define QDEVICEDISCOVERY_HOTPLUG_H  
  10.   
  11. //  
  12. //  W A R N I N G  
  13. //  -------------  
  14. //  
  15. // This file is not part of the Qt API.  It exists purely as an  
  16. // implementation detail.  This header file may change from version to  
  17. // version without notice, or even be removed.  
  18. //  
  19. // We mean it.  
  20. //  
  21.   
  22. #include "qdevicediscovery_p.h"  
  23. #include <QFileSystemWatcher>  
  24. #include <QStringList>  
  25.   
  26. QT_BEGIN_NAMESPACE  
  27.   
  28. class QDeviceDiscoveryHotPlug : public QDeviceDiscovery  
  29. {  
  30.     Q_OBJECT  
  31.   
  32. public:  
  33.     QDeviceDiscoveryHotPlug(QDeviceTypes types, QObject *parent = 0);  
  34.     QStringList scanConnectedDevices() Q_DECL_OVERRIDE;  
  35.   
  36. private slots:  
  37.     void handleHotPlugWatch(const QString &path);  
  38.   
  39. private:  
  40.     bool checkDeviceType(const QString &device);  
  41.   
  42.     // 用于检测鼠标键盘热插拔  
  43.     QFileSystemWatcher *m_fileWatcher;  
  44.   
  45.     // 原有的设备列表  
  46.     QStringList m_devices;  
  47. };  
  48.   
  49. QT_END_NAMESPACE  
  50.   
  51. #endif // QDEVICEDISCOVERY_HOTPLUG_H  

http://blog.csdn.net/shengzhadon/article/details/51455361http://blog.csdn.net/shengzhadon/article/details/51455361http://blog.csdn.net/shengzhadon/article/details/51455361

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 您好,要下载Qt5.5.1源码,您可以按照以下步骤操作: 1. 打开Qt官方网站:https://www.qt.io/downloads,点击 "下载"按钮。 2. 在下载页面中,选择“源代码”选项卡,并选择对应操作系统的Qt版本。 3. 在下载页面中会有一个 "开始下载"按钮,点击该按钮即可开始下载Qt5.5.1源码的压缩包。 4. 下载完成后,将压缩包解压到您希望存放Qt源码的目录中。 5. 打开解压后的文件夹,在该文件夹中找到 "configure" 文件,并双击运行。 6. 配置脚本将根据您的操作系统和编译器设置Qt编译环境。 7. 配置完成后,使用命令行或者IDE打开Qt源码文件夹。 8. 在Qt源码文件夹中,可以找到各个模块的源代码以及示例和文档资料。 这样,您就成功下载了Qt5.5.1的源码,并可以在自己的机器上进行阅读、学习或者二次开发。如果您需要根据自己的需求进行编译构建,可以参考Qt官方的编译指南进行操作。祝您学习愉快! ### 回答2: Qt 5.5.1是一个跨平台的应用程序开发框架,如果想要下载它的源码,可以按照以下步骤进行: 1. 打开Qt的官方网站(https://www.qt.io/),点击网站顶部的"Download"按钮。 2. 在下载页面上,选择"Archives"选项卡,找到"Qt 5.5.1"版本并点击它。 3. 在弹出的页面上,选择你的操作系统和编译器版本。如果你使用的是Windows操作系统,可以选择基于MSVC 2013或者MinGW编译器的版本,如果是Mac系统,可以选择基于Clang版本的Qt,如果是Linux系统,可以选择基于GCC版本的Qt。 4. 根据你的选择,点击相应的下载链接,开始下载相应的离线安装包。 5. 下载完成后,解压安装包,你将得到Qt 5.5.1的源码文件。 另外,Qt的源码也可以通过版本控制工具Git进行获取。你可以在Qt的官方Git仓库(https://code.qt.io/cgit/qt/qt5.git/)中找到Qt 5.5.1的源码,然后根据Git的用法进行克隆或者下载源码。 需要注意的是,Qt的源码下载可能会比较大,所以下载时间可能会比较长,而且需要一定的网络带宽和存储空间来存储源码。 ### 回答3: 您可以通过以下步骤下载qt5.5.1源码: 1. 打开Qt官方网站(https://www.qt.io/),并点击顶部菜单栏中的“下载”按钮。 2. 在下载页面中,您可以看到不同版本的Qt可用于下载。向下滚动页面,直到找到下方的“历史Qt版本”部分。 3. 在“历史Qt版本”部分中,找到并点击“5.5.1版本”的链接。 4. 进入5.5.1版本的下载页面后,您将看到不同的Qt安装程序。寻找一个标有“源代码”或“src”的选项,并点击下载链接。 5. 下载源代码包后,您可以解压缩它以获取Qt 5.5.1的源代码。 请注意,Qt 5.5.1是一个旧版本,可能已经过时并且不再接收官方支持。如果您正在寻找最新版本的Qt源代码,建议您查看Qt官方网站上可用的最新版本。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值