• pyqt5_windows_hid_auto_detect_hotplug


    pyqt5 implements hid hotplug auto detect in Windows OS

    before using this code should install below package:

    pip --install hidapi

    pip --install PyQt5

    1. import sys
    2. import ctypes
    3. from ctypes.wintypes import MSG
    4. import ctypes.wintypes as wintypes
    5. import hid
    6. from PyQt5.QtWidgets import *
    7. from PyQt5.QtCore import *
    8. NULL = 0
    9. INVALID_HANDLE_VALUE = -1
    10. DEVICE_NOTIFY_WINDOW_HANDLE = 0x00000000
    11. WM_DEVICECHANGE = 0x0219
    12. DBT_DEVTYP_DEVICEINTERFACE = 5
    13. DBT_DEVICEREMOVECOMPLETE = 0x8004
    14. DBT_DEVICEARRIVAL = 0x8000
    15. user32 = ctypes.windll.user32
    16. RegisterDeviceNotification = user32.RegisterDeviceNotificationW
    17. UnregisterDeviceNotification = user32.UnregisterDeviceNotification
    18. class GUID(ctypes.Structure):
    19. _pack_ = 1
    20. _fields_ = [("Data1", ctypes.c_ulong),
    21. ("Data2", ctypes.c_ushort),
    22. ("Data3", ctypes.c_ushort),
    23. ("Data4", ctypes.c_ubyte * 8)]
    24. class DEV_BROADCAST_DEVICEINTERFACE(ctypes.Structure):
    25. _pack_ = 1
    26. _fields_ = [("dbcc_size", wintypes.DWORD),
    27. ("dbcc_devicetype", wintypes.DWORD),
    28. ("dbcc_reserved", wintypes.DWORD),
    29. ("dbcc_classguid", GUID),
    30. ("dbcc_name", ctypes.c_wchar * 260)]
    31. class DEV_BROADCAST_HDR(ctypes.Structure):
    32. _fields_ = [("dbch_size", wintypes.DWORD),
    33. ("dbch_devicetype", wintypes.DWORD),
    34. ("dbch_reserved", wintypes.DWORD)]
    35. # GUID_DEVCLASS_PORTS = GUID(0x4D36E978, 0xE325, 0x11CE,
    36. # (ctypes.c_ubyte * 8)(0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18))
    37. GUID_DEVINTERFACE_USB_DEVICE = GUID(0xA5DCBF10, 0x6530, 0x11D2,
    38. (ctypes.c_ubyte * 8)(0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED))
    39. target_pid = 0xfe07
    40. target_vid = 0x1a86
    41. class Window(QWidget):
    42. hidBdg = hid.device() # add hid device object
    43. hidStatus = False # False - hid open failed
    44. # True - hid open successful
    45. def __init__(self, parent=None):
    46. super(Window, self).__init__(parent)
    47. self.setupNotification()
    48. self.initUI()
    49. def initUI(self):
    50. self.resize(QSize(600, 320))
    51. self.setWindowTitle("Device Notify")
    52. vbox = QVBoxLayout(self)
    53. vbox.addWidget(QLabel("Log window:", self))
    54. self.logEdit = QPlainTextEdit(self)
    55. vbox.addWidget(self.logEdit)
    56. self.setLayout(vbox)
    57. self.open_hid()
    58. def setupNotification(self):
    59. dbh = DEV_BROADCAST_DEVICEINTERFACE()
    60. dbh.dbcc_size = ctypes.sizeof(DEV_BROADCAST_DEVICEINTERFACE)
    61. dbh.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE
    62. dbh.dbcc_classguid = GUID_DEVINTERFACE_USB_DEVICE # GUID_DEVCLASS_PORTS
    63. self.hNofity = RegisterDeviceNotification(int(self.winId()),
    64. ctypes.byref(dbh),
    65. DEVICE_NOTIFY_WINDOW_HANDLE)
    66. if self.hNofity == NULL:
    67. print(ctypes.FormatError(), int(self.winId()))
    68. print("RegisterDeviceNotification failed")
    69. else:
    70. print("register successfully")
    71. def nativeEvent(self, eventType, msg):
    72. message = MSG.from_address(msg.__int__())
    73. if message.message == WM_DEVICECHANGE:
    74. self.onDeviceChanged(message.wParam, message.lParam)
    75. return False, 0
    76. def onDeviceChanged(self, wParam, lParam):
    77. if DBT_DEVICEARRIVAL == wParam:
    78. dev_info = ctypes.cast(lParam, ctypes.POINTER(DEV_BROADCAST_DEVICEINTERFACE)).contents
    79. device_path = ctypes.c_wchar_p(dev_info.dbcc_name).value
    80. cycCnt = 0
    81. if f"VID_{target_vid:04X}&PID_{target_pid:04X}" in device_path:
    82. while (self.open_hid() is not True) and (cycCnt < 5):
    83. self.open_hid()
    84. cycCnt += 1
    85. print(f'Target USB device inserted')
    86. elif DBT_DEVICEREMOVECOMPLETE == wParam:
    87. dev_info = ctypes.cast(lParam, ctypes.POINTER(DEV_BROADCAST_DEVICEINTERFACE)).contents
    88. device_path = ctypes.c_wchar_p(dev_info.dbcc_name).value
    89. if f"VID_{target_vid:04X}&PID_{target_pid:04X}" in device_path:
    90. self.close_hid()
    91. print(f'Target USB device removed')
    92. def open_hid(self):
    93. try:
    94. if self.hidStatus == False:
    95. self.hidBdg.open(0x1A86, 0xFE07)
    96. self.hidBdg.set_nonblocking(1)
    97. self.hidStatus = True
    98. self.logEdit.appendHtml("Device Arrival: connected")
    99. return self.hidStatus
    100. else:
    101. return self.hidStatus
    102. except:
    103. self.logEdit.appendHtml("Open HID failed:")
    104. self.hidStatus = False
    105. return self.hidStatus
    106. def close_hid(self):
    107. try:
    108. if self.hidStatus == True:
    109. self.hidBdg.close()
    110. self.hidStatus = False
    111. self.logEdit.appendHtml("Device Removed: disconnected")
    112. return self.hidStatus
    113. else:
    114. return self.hidStatus
    115. except:
    116. self.logEdit.appendHtml("Close HID failed:")
    117. self.hidStatus = True
    118. if __name__ == '__main__':
    119. app = QApplication(sys.argv)
    120. w = Window()
    121. w.show()
    122. sys.exit(app.exec_())

  • 相关阅读:
    技术分享 | app自动化测试(Android)-- 特殊控件 Toast 识别
    vue基础难点总结
    【C++】抽象类和虚基类,虚函数和纯虚函数
    Helm实战案例二:在Kubernetes(k8s)上使用helm安装部署日志管理系统EFK
    2022年3月19日:有关版本控制与 Git 结合使用的简介--Git介绍
    Maven入门
    实时渲染器不止lumion,Chaos Vantage你值得一试
    内网穿透frp简单安装
    Docker的Cgroup资源限制
    盒子(Box, ACM/ICPC NEERC 2004, UVa1587)rust解法
  • 原文地址:https://blog.csdn.net/phenixyf/article/details/134456242