如何使用 IOKit 写入 IOHIDDevice 端点

How to write to IOHIDDevice endpoint with IOKit

我正在为 Mac OS Catalina 编写桌面应用程序。目前已获得 GPL 许可。我可能会在未来让它获得麻省理工学院的许可,但那是次要的。它是用 Swift 编写的,支持一些使用用户 space IOKit 的游戏手柄。我使用 HID APIs 使其适用于 Dualshock 4 和 Xbox 360 控制器。现在我正在实现对 Xbox One 控制器的支持,但它需要在开始发送报告(0x05、0x20)之前接收一个字节序列。我在几个 C/C++ kext 项目中看到了这一点,但我正在努力弄清楚如何在用户 space 的应用程序中执行此操作。我能够获得 IOHIDDevice 但我无法弄清楚如何从那里获得端点。这甚至可以从 HID 级别完成,还是我需要使用较低级别 API,如 USB 或蓝牙?我想避免为此使用 libusb,因为我已经让它与其他控制器一起工作。

我发现的其他建议是关于这个问题的:Gamepad and joystick support on Mac OS X in user space 但没有提供 Mac 的示例代码。替换设备描述符对我来说听起来有点矫枉过正来完成这个。此外,它建议使用 libusb。

我的部分代码:

let hidManager = IOHIDManagerCreate(kCFAllocatorDefault, IOOptionBits(kIOHIDOptionsTypeNone))
let deviceCriteria:NSArray = [
    [
        kIOHIDDeviceUsagePageKey: kHIDPage_GenericDesktop,
        kIOHIDDeviceUsageKey: kHIDUsage_GD_GamePad
    ]
]
IOHIDManagerSetDeviceMatchingMultiple(hidManager, deviceCriteria)
IOHIDManagerScheduleWithRunLoop(hidManager, CFRunLoopGetCurrent(), CFRunLoopMode.defaultMode.rawValue)
IOHIDManagerOpen(hidManager, IOOptionBits(kIOHIDOptionsTypeNone))
IOHIDManagerRegisterDeviceMatchingCallback(...)

func hidDeviceAddedCallback(_ result:IOReturn, sender:UnsafeMutableRawPointer, device:IOHIDDevice) {
    // from here I usually send hid reports using IOHIDDeviceSetReport(device, kIOHIDReportTypeOutput, etc...)
    // but now I need to write directly to and endpoint of an interface
}

您可以使用 IOHIDDeviceGetService(). You can then walk up the I/O registry provider chain 获取与 IOHIDDevice 对应的 IOService 对象的引用,以查找基础 IOUSBInterface/IOUSBHostInterface 对象。但是,通用 HID 驱动程序可能已经获得了对 USB 接口的独占访问权,因此如果不先启动 HID 驱动程序,可能不会允许在管道上提交传输。