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.youkuaiyun.com/shengzhadon/article/details/51455361http://blog.youkuaiyun.com/shengzhadon/article/details/51455361http://blog.youkuaiyun.com/shengzhadon/article/details/51455361

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值