From 816c3726699e142233f3544fff73df6443f52ecd Mon Sep 17 00:00:00 2001 From: Ryan Date: Wed, 15 May 2024 16:09:27 +1000 Subject: [PATCH] Add Raw HID device detection (#473) --- macos/QMK Toolbox.xcodeproj/project.pbxproj | 8 +++ macos/QMK Toolbox/HID/HIDConsoleDevice.swift | 45 ++----------- .../HID/HIDConsoleViewController.swift | 32 ++++++---- macos/QMK Toolbox/HID/HIDDevice.swift | 53 ++++++++++++++++ macos/QMK Toolbox/HID/HIDListener.swift | 39 +++++++++--- macos/QMK Toolbox/HID/RawDevice.swift | 3 + macos/QMK Toolbox/USB/USBListener.swift | 2 +- windows/QMK Toolbox/Hid/BaseHidDevice.cs | 63 +++++++++++++++++++ windows/QMK Toolbox/Hid/HidConsoleDevice.cs | 48 +------------- windows/QMK Toolbox/Hid/HidConsoleWindow.cs | 41 +++++++----- windows/QMK Toolbox/Hid/HidListener.cs | 49 +++++++++++---- windows/QMK Toolbox/Hid/RawDevice.cs | 11 ++++ 12 files changed, 259 insertions(+), 135 deletions(-) create mode 100644 macos/QMK Toolbox/HID/HIDDevice.swift create mode 100644 macos/QMK Toolbox/HID/RawDevice.swift create mode 100644 windows/QMK Toolbox/Hid/BaseHidDevice.cs create mode 100644 windows/QMK Toolbox/Hid/RawDevice.cs diff --git a/macos/QMK Toolbox.xcodeproj/project.pbxproj b/macos/QMK Toolbox.xcodeproj/project.pbxproj index 41886d18d4..b3c6f6e014 100644 --- a/macos/QMK Toolbox.xcodeproj/project.pbxproj +++ b/macos/QMK Toolbox.xcodeproj/project.pbxproj @@ -56,6 +56,8 @@ 3AAB20AB283BEEC700029ABD /* LogTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AAB20AA283BEEC700029ABD /* LogTextView.swift */; }; 3AB09F1D28B46672006CC212 /* GD32VDFUDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AB09F1C28B46672006CC212 /* GD32VDFUDevice.swift */; }; 3AB4BC9D2495540A00204A3F /* bootloadHID in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3AB4BC9C2495540A00204A3F /* bootloadHID */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 3AB657102B9EABB4007805DD /* RawDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AB6570F2B9EABB4007805DD /* RawDevice.swift */; }; + 3AB657122B9EAC34007805DD /* HIDDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AB657112B9EAC34007805DD /* HIDDevice.swift */; }; 3AE86EF8294C9CEC00008D3E /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3AE86EFA294C9CEC00008D3E /* Main.storyboard */; }; 9BE10718275F4CFE00C708D5 /* wb32-dfu-updater_cli in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9BE10717275F4CFE00C708D5 /* wb32-dfu-updater_cli */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; C93A0FF42292232E0006C88F /* reset.eep in Resources */ = {isa = PBXBuildFile; fileRef = C93A0FF32292232D0006C88F /* reset.eep */; }; @@ -147,6 +149,8 @@ 3AAB20AA283BEEC700029ABD /* LogTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogTextView.swift; sourceTree = ""; }; 3AB09F1C28B46672006CC212 /* GD32VDFUDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GD32VDFUDevice.swift; sourceTree = ""; }; 3AB4BC9C2495540A00204A3F /* bootloadHID */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = bootloadHID; sourceTree = ""; }; + 3AB6570F2B9EABB4007805DD /* RawDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RawDevice.swift; sourceTree = ""; }; + 3AB657112B9EAC34007805DD /* HIDDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HIDDevice.swift; sourceTree = ""; }; 3AE86EF9294C9CEC00008D3E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 3AFD4BCF281AB83C00ADCB65 /* libhidapi.0.14.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; path = libhidapi.0.14.0.dylib; sourceTree = ""; }; 9BE10717275F4CFE00C708D5 /* wb32-dfu-updater_cli */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = "wb32-dfu-updater_cli"; sourceTree = ""; }; @@ -217,6 +221,8 @@ 3A8DE019284636780012063A /* HIDConsoleDevice.swift */, 3A708D99284901F500394E52 /* HIDListener.swift */, 3A92873C292CF7A10015D961 /* HIDConsoleViewController.swift */, + 3AB657112B9EAC34007805DD /* HIDDevice.swift */, + 3AB6570F2B9EABB4007805DD /* RawDevice.swift */, ); path = HID; sourceTree = ""; @@ -371,6 +377,7 @@ buildActionMask = 2147483647; files = ( 3A8DE01A284636780012063A /* HIDConsoleDevice.swift in Sources */, + 3AB657102B9EABB4007805DD /* RawDevice.swift in Sources */, 3A708D9A284901F500394E52 /* HIDListener.swift in Sources */, 3A92873D292CF7A10015D961 /* HIDConsoleViewController.swift in Sources */, 3A37607A283E769300C19B3F /* KeyView.swift in Sources */, @@ -390,6 +397,7 @@ 3A32CF5F284142D10016D7B7 /* STM32DFUDevice.swift in Sources */, 3A32CF61284143990016D7B7 /* STM32DuinoDevice.swift in Sources */, 3A32CF63284143EC0016D7B7 /* USBAspDevice.swift in Sources */, + 3AB657122B9EAC34007805DD /* HIDDevice.swift in Sources */, 3A32CF652841445E0016D7B7 /* USBTinyISPDevice.swift in Sources */, 3A32CF672841451D0016D7B7 /* WB32DFUDevice.swift in Sources */, 3A5A916C28410F53004DD9BD /* USBDevice.swift in Sources */, diff --git a/macos/QMK Toolbox/HID/HIDConsoleDevice.swift b/macos/QMK Toolbox/HID/HIDConsoleDevice.swift index 9b0962d2ae..4f32d2f7aa 100644 --- a/macos/QMK Toolbox/HID/HIDConsoleDevice.swift +++ b/macos/QMK Toolbox/HID/HIDConsoleDevice.swift @@ -4,37 +4,14 @@ protocol HIDConsoleDeviceDelegate: AnyObject { func consoleDevice(_ device: HIDConsoleDevice, didReceiveReport report: String) } -class HIDConsoleDevice: Equatable, CustomStringConvertible { +class HIDConsoleDevice: HIDDevice { weak var delegate: HIDConsoleDeviceDelegate? private var reportBuffer: UnsafeMutablePointer private var reportBufferSize: Int = 0 - let hidDevice: IOHIDDevice - - var manufacturer: String? { - HIDConsoleDevice.stringProperty(kIOHIDManufacturerKey, for: hidDevice) - } - - var product: String? { - HIDConsoleDevice.stringProperty(kIOHIDProductKey, for: hidDevice) - } - - var vendorID: UInt16 { - HIDConsoleDevice.uint16Property(kIOHIDVendorIDKey, for: hidDevice) - } - - var productID: UInt16 { - HIDConsoleDevice.uint16Property(kIOHIDProductIDKey, for: hidDevice) - } - - var revisionBCD: UInt16 { - HIDConsoleDevice.uint16Property(kIOHIDVersionNumberKey, for: hidDevice) - } - - init(_ device: IOHIDDevice) { - hidDevice = device + override init(_ device: IOHIDDevice) { reportBufferSize = IOHIDDeviceGetProperty(device, kIOHIDMaxInputReportSizeKey as CFString) as! Int reportBuffer = UnsafeMutablePointer.allocate(capacity: reportBufferSize) @@ -44,6 +21,8 @@ class HIDConsoleDevice: Equatable, CustomStringConvertible { device.reportReceived(reportData) } + super.init(device) + let unsafeSelf = Unmanaged.passRetained(self).toOpaque() IOHIDDeviceRegisterInputReportCallback(hidDevice, reportBuffer, reportBufferSize, inputReportCallback, unsafeSelf) } @@ -75,20 +54,4 @@ class HIDConsoleDevice: Equatable, CustomStringConvertible { delegate?.consoleDevice(self, didReceiveReport: completedLine) } } - - var description: String { - String(format: "%@ %@ (%04X:%04X:%04X)", manufacturer ?? "", product ?? "", vendorID, productID, revisionBCD) - } - - static func == (lhs: HIDConsoleDevice, rhs: HIDConsoleDevice) -> Bool { - return lhs.hidDevice === rhs.hidDevice - } - - static func stringProperty(_ propertyName: String, for device: IOHIDDevice) -> String? { - return IOHIDDeviceGetProperty(device, propertyName as CFString) as! String? - } - - static func uint16Property(_ propertyName: String, for device: IOHIDDevice) -> UInt16 { - return (IOHIDDeviceGetProperty(device, propertyName as CFString) as! NSNumber?)!.uint16Value - } } diff --git a/macos/QMK Toolbox/HID/HIDConsoleViewController.swift b/macos/QMK Toolbox/HID/HIDConsoleViewController.swift index 101dca4182..27ad31c44d 100644 --- a/macos/QMK Toolbox/HID/HIDConsoleViewController.swift +++ b/macos/QMK Toolbox/HID/HIDConsoleViewController.swift @@ -24,28 +24,36 @@ class HIDConsoleViewController: NSViewController, HIDListenerDelegate { var hidListener: HIDListener! var lastReportedDevice: HIDConsoleDevice? - - func hidDeviceDidConnect(_ device: HIDConsoleDevice) { - lastReportedDevice = device - updateConsoleList() - logTextView.logHID("HID console connected: \(device)") + func hidDeviceDidConnect(_ device: HIDDevice) { + if device is HIDConsoleDevice { + lastReportedDevice = (device as! HIDConsoleDevice) + updateConsoleList() + logTextView.logHID("HID console connected: \(device)") + } else { + logTextView.logHID("Raw HID device connected: \(device)") + } } - func hidDeviceDidDisconnect(_ device: HIDConsoleDevice) { - lastReportedDevice = nil - updateConsoleList() - logTextView.logHID("HID console disconnected: \(device)") + func hidDeviceDidDisconnect(_ device: HIDDevice) { + if device is HIDConsoleDevice { + lastReportedDevice = nil + updateConsoleList() + logTextView.logHID("HID console disconnected: \(device)") + } else { + logTextView.logHID("Raw HID device disconnected: \(device)") + } } func consoleDevice(_ device: HIDConsoleDevice, didReceiveReport report: String) { let selectedDevice = consoleListBox.indexOfSelectedItem - if selectedDevice == 0 || hidListener.devices[selectedDevice - 1] == device { + let consoleDevices = hidListener.devices.filter { $0 is HIDConsoleDevice } + if selectedDevice == 0 || consoleDevices[selectedDevice - 1] == device { if lastReportedDevice != device { logTextView.logHID("\(device.manufacturer ?? "") \(device.product ?? "")") lastReportedDevice = device } + logTextView.logHIDOutput(report) } - logTextView.logHIDOutput(report) } func updateConsoleList() { @@ -53,7 +61,7 @@ class HIDConsoleViewController: NSViewController, HIDListenerDelegate { consoleListBox.deselectItem(at: selectedItem) consoleListBox.removeAllItems() - hidListener.devices.forEach { device in + hidListener.devices.filter { $0 is HIDConsoleDevice }.forEach { device in consoleListBox.addItem(withObjectValue: device.description) } diff --git a/macos/QMK Toolbox/HID/HIDDevice.swift b/macos/QMK Toolbox/HID/HIDDevice.swift new file mode 100644 index 0000000000..2525db4100 --- /dev/null +++ b/macos/QMK Toolbox/HID/HIDDevice.swift @@ -0,0 +1,53 @@ +import Foundation + +class HIDDevice: Equatable, CustomStringConvertible { + let hidDevice: IOHIDDevice + + var usagePage: UInt16 { + HIDDevice.uint16Property(kIOHIDDeviceUsagePageKey, for: hidDevice)! + } + + var usage: UInt16 { + HIDDevice.uint16Property(kIOHIDDeviceUsageKey, for: hidDevice)! + } + + var manufacturer: String? { + HIDDevice.stringProperty(kIOHIDManufacturerKey, for: hidDevice) + } + + var product: String? { + HIDDevice.stringProperty(kIOHIDProductKey, for: hidDevice) + } + + var vendorID: UInt16 { + HIDDevice.uint16Property(kIOHIDVendorIDKey, for: hidDevice)! + } + + var productID: UInt16 { + HIDDevice.uint16Property(kIOHIDProductIDKey, for: hidDevice)! + } + + var revisionBCD: UInt16 { + HIDDevice.uint16Property(kIOHIDVersionNumberKey, for: hidDevice)! + } + + init(_ device: IOHIDDevice) { + hidDevice = device + } + + var description: String { + String(format: "%@ %@ (%04X:%04X:%04X)", manufacturer ?? "", product ?? "", vendorID, productID, revisionBCD) + } + + static func == (lhs: HIDDevice, rhs: HIDDevice) -> Bool { + return lhs.hidDevice === rhs.hidDevice + } + + static func stringProperty(_ propertyName: String, for device: IOHIDDevice) -> String? { + return IOHIDDeviceGetProperty(device, propertyName as CFString) as! String? + } + + static func uint16Property(_ propertyName: String, for device: IOHIDDevice) -> UInt16? { + return (IOHIDDeviceGetProperty(device, propertyName as CFString) as! NSNumber?)!.uint16Value + } +} diff --git a/macos/QMK Toolbox/HID/HIDListener.swift b/macos/QMK Toolbox/HID/HIDListener.swift index 3c0c7ceb40..4b50cbdf7e 100644 --- a/macos/QMK Toolbox/HID/HIDListener.swift +++ b/macos/QMK Toolbox/HID/HIDListener.swift @@ -3,11 +3,13 @@ import IOKit.hid let CONSOLE_USAGE_PAGE: UInt16 = 0xFF31 let CONSOLE_USAGE: UInt16 = 0x0074 +let RAW_USAGE_PAGE: UInt16 = 0xFF60 +let RAW_USAGE: UInt16 = 0x0061 protocol HIDListenerDelegate: AnyObject { - func hidDeviceDidConnect(_ device: HIDConsoleDevice) + func hidDeviceDidConnect(_ device: HIDDevice) - func hidDeviceDidDisconnect(_ device: HIDConsoleDevice) + func hidDeviceDidDisconnect(_ device: HIDDevice) func consoleDevice(_ device: HIDConsoleDevice, didReceiveReport report: String) } @@ -17,12 +19,11 @@ class HIDListener: HIDConsoleDeviceDelegate { private var hidManager: IOHIDManager - var devices: [HIDConsoleDevice] = [] + var devices: [HIDDevice] = [] init() { hidManager = IOHIDManagerCreate(kCFAllocatorDefault, IOOptionBits(kIOHIDOptionsTypeNone)) - let consoleMatcher = [kIOHIDDeviceUsagePageKey: CONSOLE_USAGE_PAGE, kIOHIDDeviceUsageKey: CONSOLE_USAGE] - IOHIDManagerSetDeviceMatching(hidManager, consoleMatcher as CFDictionary?) + IOHIDManagerSetDeviceMatching(hidManager, nil) } func start() { @@ -49,10 +50,17 @@ class HIDListener: HIDConsoleDeviceDelegate { return } - let consoleDevice = HIDConsoleDevice(device) - consoleDevice.delegate = self - devices.append(consoleDevice) - delegate?.hidDeviceDidConnect(consoleDevice) + guard let hidDevice = createDevice(device) else { + return + } + + devices.append(hidDevice) + + if hidDevice is HIDConsoleDevice { + (hidDevice as! HIDConsoleDevice).delegate = self + } + + delegate?.hidDeviceDidConnect(hidDevice) } func deviceDisconnected(_ device: IOHIDDevice) { @@ -75,4 +83,17 @@ class HIDListener: HIDConsoleDeviceDelegate { IOHIDManagerUnscheduleFromRunLoop(hidManager, CFRunLoopGetCurrent(), CFRunLoopMode.defaultMode.rawValue) IOHIDManagerClose(hidManager, IOOptionBits(kIOHIDOptionsTypeNone)) } + + func createDevice(_ d: IOHIDDevice) -> HIDDevice? { + let usagePage = HIDDevice.uint16Property(kIOHIDPrimaryUsagePageKey, for: d) + let usage = HIDDevice.uint16Property(kIOHIDPrimaryUsageKey, for: d) + + if usagePage == CONSOLE_USAGE_PAGE && usage == CONSOLE_USAGE { + return HIDConsoleDevice(d) + } else if usagePage == RAW_USAGE_PAGE && usage == RAW_USAGE { + return RawDevice(d) + } + + return nil + } } diff --git a/macos/QMK Toolbox/HID/RawDevice.swift b/macos/QMK Toolbox/HID/RawDevice.swift new file mode 100644 index 0000000000..f92f08c6df --- /dev/null +++ b/macos/QMK Toolbox/HID/RawDevice.swift @@ -0,0 +1,3 @@ +import Foundation + +class RawDevice: HIDDevice {} diff --git a/macos/QMK Toolbox/USB/USBListener.swift b/macos/QMK Toolbox/USB/USBListener.swift index bbc28671ea..a124eedf64 100644 --- a/macos/QMK Toolbox/USB/USBListener.swift +++ b/macos/QMK Toolbox/USB/USBListener.swift @@ -193,7 +193,7 @@ class USBListener: BootloaderDeviceDelegate { if productID == 0xB007 { return .kiibohdDfu } - break; + break case 0x1EAF: // Leaflabs if productID == 0x0003 { return .stm32duino diff --git a/windows/QMK Toolbox/Hid/BaseHidDevice.cs b/windows/QMK Toolbox/Hid/BaseHidDevice.cs new file mode 100644 index 0000000000..0f217f015c --- /dev/null +++ b/windows/QMK Toolbox/Hid/BaseHidDevice.cs @@ -0,0 +1,63 @@ +using HidLibrary; +using System.Linq; +using System.Text; + +namespace QMK_Toolbox.Hid +{ + public abstract class BaseHidDevice + { + public IHidDevice HidDevice { get; } + + public string ManufacturerString { get; } + + public string ProductString { get; } + + public ushort VendorId { get; } + + public ushort ProductId { get; } + + public ushort RevisionBcd { get; } + + public ushort UsagePage { get; } + + public ushort Usage { get; } + + public BaseHidDevice(IHidDevice device) + { + HidDevice = device; + HidDevice.OpenDevice(); + + ManufacturerString = GetManufacturerString(HidDevice); + ProductString = GetProductString(HidDevice); + + VendorId = (ushort)HidDevice.Attributes.VendorId; + ProductId = (ushort)HidDevice.Attributes.ProductId; + RevisionBcd = (ushort)HidDevice.Attributes.Version; + UsagePage = (ushort)HidDevice.Capabilities.UsagePage; + Usage = (ushort)HidDevice.Capabilities.Usage; + + HidDevice.CloseDevice(); + } + + public override string ToString() + { + return $"{ManufacturerString} {ProductString} ({VendorId:X4}:{ProductId:X4}:{RevisionBcd:X4})"; + } + + private static string GetManufacturerString(IHidDevice d) + { + if (d == null) return ""; + + d.ReadManufacturer(out var bs); + return Encoding.Default.GetString(bs.Where(b => b > 0).ToArray()); + } + + private static string GetProductString(IHidDevice d) + { + if (d == null) return ""; + + d.ReadProduct(out var bs); + return Encoding.Default.GetString(bs.Where(b => b > 0).ToArray()); + } + } +} diff --git a/windows/QMK Toolbox/Hid/HidConsoleDevice.cs b/windows/QMK Toolbox/Hid/HidConsoleDevice.cs index b1cc0d016f..1b363e184b 100644 --- a/windows/QMK Toolbox/Hid/HidConsoleDevice.cs +++ b/windows/QMK Toolbox/Hid/HidConsoleDevice.cs @@ -6,43 +6,15 @@ namespace QMK_Toolbox.Hid { - public class HidConsoleDevice + public class HidConsoleDevice : BaseHidDevice { public delegate void HidConsoleReportReceivedDelegate(HidConsoleDevice device, string data); public HidConsoleReportReceivedDelegate consoleReportReceived; - public IHidDevice HidDevice { get; } - - public string ManufacturerString { get; } - - public string ProductString { get; } - - public ushort VendorId { get; } - - public ushort ProductId { get; } - - public ushort RevisionBcd { get; } - - public HidConsoleDevice(IHidDevice device) + public HidConsoleDevice(IHidDevice device) : base(device) { - HidDevice = device; - HidDevice.OpenDevice(); - - ManufacturerString = GetManufacturerString(HidDevice); - ProductString = GetProductString(HidDevice); - VendorId = (ushort)HidDevice.Attributes.VendorId; - ProductId = (ushort)HidDevice.Attributes.ProductId; - RevisionBcd = (ushort)HidDevice.Attributes.Version; - RegisterReportTask(); - - HidDevice.CloseDevice(); - } - - public override string ToString() - { - return $"{ManufacturerString} {ProductString} ({VendorId:X4}:{ProductId:X4}:{RevisionBcd:X4})"; } private void RegisterReportTask() @@ -90,21 +62,5 @@ private void HidDeviceReportEvent(HidReport report) RegisterReportTask(); } } - - private static string GetManufacturerString(IHidDevice d) - { - if (d == null) return ""; - - d.ReadManufacturer(out var bs); - return Encoding.Default.GetString(bs.Where(b => b > 0).ToArray()); - } - - private static string GetProductString(IHidDevice d) - { - if (d == null) return ""; - - d.ReadProduct(out var bs); - return Encoding.Default.GetString(bs.Where(b => b > 0).ToArray()); - } } } diff --git a/windows/QMK Toolbox/Hid/HidConsoleWindow.cs b/windows/QMK Toolbox/Hid/HidConsoleWindow.cs index ff9c550175..1fc91ee3e0 100644 --- a/windows/QMK Toolbox/Hid/HidConsoleWindow.cs +++ b/windows/QMK Toolbox/Hid/HidConsoleWindow.cs @@ -1,5 +1,6 @@ using System; using System.ComponentModel; +using System.Linq; using System.Windows.Forms; namespace QMK_Toolbox.Hid @@ -49,23 +50,37 @@ private void HidConsoleWindow_FormClosing(object sender, FormClosingEventArgs e) private HidConsoleDevice lastReportedDevice; - private void HidDeviceConnected(HidConsoleDevice device) + private void HidDeviceConnected(BaseHidDevice device) { Invoke(new Action(() => { - lastReportedDevice = device; - UpdateConsoleList(); - logTextBox.LogHid($"HID console connected: {device}"); + if (device is HidConsoleDevice) + { + lastReportedDevice = device as HidConsoleDevice; + UpdateConsoleList(); + logTextBox.LogHid($"HID console connected: {device}"); + } + else + { + logTextBox.LogHid($"Raw HID device connected: {device}"); + } })); } - private void HidDeviceDisconnected(HidConsoleDevice device) + private void HidDeviceDisconnected(BaseHidDevice device) { Invoke(new Action(() => { - lastReportedDevice = null; - UpdateConsoleList(); - logTextBox.LogHid($"HID console disconnected: {device}"); + if (device is HidConsoleDevice) + { + lastReportedDevice = null; + UpdateConsoleList(); + logTextBox.LogHid($"HID console disconnected: {device}"); + } + else + { + logTextBox.LogHid($"Raw HID device disconnected: {device}"); + } })); } @@ -74,7 +89,8 @@ private void ConsoleReportReceived(HidConsoleDevice device, string report) Invoke(new Action(() => { int selectedDevice = consoleList.SelectedIndex; - if (selectedDevice == 0 || hidListener.Devices[selectedDevice - 1] == device) + var consoleDevices = hidListener.Devices.Where(d => d is HidConsoleDevice).ToList(); + if (selectedDevice == 0 || consoleDevices[selectedDevice - 1] == device) { if (lastReportedDevice != device) { @@ -91,12 +107,9 @@ private void UpdateConsoleList() var selected = consoleList.SelectedIndex != -1 ? consoleList.SelectedIndex : 0; consoleList.Items.Clear(); - foreach (var device in hidListener.Devices) + foreach (var device in hidListener.Devices.Where(d => d is HidConsoleDevice)) { - if (device != null) - { - consoleList.Items.Add(device.ToString()); - } + consoleList.Items.Add(device.ToString()); } if (consoleList.Items.Count > 0) diff --git a/windows/QMK Toolbox/Hid/HidListener.cs b/windows/QMK Toolbox/Hid/HidListener.cs index 2984523cd8..8b8b8ebf16 100644 --- a/windows/QMK Toolbox/Hid/HidListener.cs +++ b/windows/QMK Toolbox/Hid/HidListener.cs @@ -11,9 +11,12 @@ public class HidListener : IDisposable private const ushort ConsoleUsagePage = 0xFF31; private const ushort ConsoleUsage = 0x0074; - public List Devices { get; private set; } + private const ushort RawUsagePage = 0xFF60; + private const ushort RawUsage = 0x0061; - public delegate void HidDeviceEventDelegate(HidConsoleDevice device); + public List Devices { get; private set; } + + public delegate void HidDeviceEventDelegate(BaseHidDevice device); public delegate void HidConsoleReportReceivedDelegate(HidConsoleDevice device, string data); public HidDeviceEventDelegate hidDeviceConnected; @@ -24,9 +27,7 @@ private void EnumerateHidDevices(bool connected) { var enumeratedDevices = HidDevices.Enumerate() .Where(d => d.IsConnected) - .Where(d => d.Capabilities.InputReportByteLength > 0) - .Where(d => (ushort)d.Capabilities.UsagePage == ConsoleUsagePage) - .Where(d => (ushort)d.Capabilities.Usage == ConsoleUsage); + .Where(d => d.Capabilities.InputReportByteLength > 0); if (connected) { @@ -36,12 +37,18 @@ private void EnumerateHidDevices(bool connected) if (device != null && !listed) { - HidConsoleDevice hidDevice = new(device) + BaseHidDevice hidDevice = CreateDevice(device); + + if (hidDevice != null) { - consoleReportReceived = HidConsoleReportReceived - }; - Devices.Add(hidDevice); - hidDeviceConnected?.Invoke(hidDevice); + Devices.Add(hidDevice); + + if (hidDevice is HidConsoleDevice) + { + (hidDevice as HidConsoleDevice).consoleReportReceived = HidConsoleReportReceived; + } + hidDeviceConnected?.Invoke(hidDevice); + } } } } @@ -58,7 +65,11 @@ private void EnumerateHidDevices(bool connected) device.HidDevice.CloseDevice(); } Devices.Remove(device); - device.consoleReportReceived = null; + + if (device is HidConsoleDevice) + { + (device as HidConsoleDevice).consoleReportReceived = null; + } hidDeviceDisconnected?.Invoke(device); } } @@ -92,7 +103,7 @@ private void HidDeviceWmiEvent(object sender, EventArrivedEventArgs e) public void Start() { - Devices ??= new List(); + Devices ??= new List(); EnumerateHidDevices(true); deviceConnectedWatcher ??= CreateManagementEventWatcher("__InstanceCreationEvent"); @@ -126,5 +137,19 @@ public void Dispose() deviceDisconnectedWatcher?.Dispose(); GC.SuppressFinalize(this); } + + private static BaseHidDevice CreateDevice(HidDevice d) + { + if ((ushort)d.Capabilities.UsagePage == ConsoleUsagePage && (ushort)d.Capabilities.Usage == ConsoleUsage) + { + return new HidConsoleDevice(d); + } + else if ((ushort)d.Capabilities.UsagePage == RawUsagePage && (ushort)d.Capabilities.Usage == RawUsage) + { + return new RawDevice(d); + } + + return null; + } } } diff --git a/windows/QMK Toolbox/Hid/RawDevice.cs b/windows/QMK Toolbox/Hid/RawDevice.cs new file mode 100644 index 0000000000..50702105b4 --- /dev/null +++ b/windows/QMK Toolbox/Hid/RawDevice.cs @@ -0,0 +1,11 @@ +using HidLibrary; + +namespace QMK_Toolbox.Hid +{ + public class RawDevice : BaseHidDevice + { + public RawDevice(IHidDevice device) : base(device) + { + } + } +}