IOKit:未收到来自与蓝牙连接的 DualShock 4 控制器的 HID 中断报告

Posted

技术标签:

【中文标题】IOKit:未收到来自与蓝牙连接的 DualShock 4 控制器的 HID 中断报告【英文标题】:IOKit: Not receiving HID interrupt reports from DualShock 4 controller connected with Bluetooth 【发布时间】:2015-06-12 00:56:51 【问题描述】:

简介

我正在努力使用IOKit 中的 HID 接口获得对PlayStation 4 Controller 的全面支持。控制器通过Bluetooth 连接。我可以打开与控制器的连接并开始接收报告,但是,一旦我向它发送报告,它就会突然停止。

为了完全控制 PS4 控制器(震动、触控板、LED),我一直在引用 the eleccelerator.com DualShock 4 page,其中包含有关可以/在 PS4 和 DS4 之间发送的报告的信息。

代码

首先,我创建一个IOHIDManager,它负责检测控制器。

self.hidManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
// Make sure we detect ANY type of 'game controller'
NSArray *criteria = [NSArray arrayWithObjects:
        CreateCriterion(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick),
        CreateCriterion(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad),
        CreateCriterion(kHIDPage_GenericDesktop, kHIDUsage_GD_MultiAxisController),
    nil];

IOHIDManagerSetDeviceMatchingMultiple(self.hidManager, (__bridge CFArrayRef)criteria);

IOHIDManagerScheduleWithRunLoop(self.hidManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
IOHIDManagerOpen(self.hidManager, kIOHIDOptionsTypeNone);

// Register callbacks
IOHIDManagerRegisterDeviceMatchingCallback(self.hidManager, ControllerConnected, (__bridge void *)self);
IOHIDManagerRegisterDeviceRemovalCallback(self.hidManager, ControllerDisconnected, (__bridge void *)self);

然后在接到ControllerConnected 的调用后,我创建了一个操纵杆类的实例,它初始化了IOHIDDeviceRef

- (void)registerDevice:(IOHIDDeviceRef)device 
    self.device = device;

    // Initialize the buffer
    self.receivedPacketMaxSize = 552; // When using Bluetooth
    self.receivedReport = (uint8_t *)calloc(self.receivedPacketMaxSize, sizeof(uint8_t));

    // Register the device report callback
    IOHIDDeviceScheduleWithRunLoop(self.device, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
    IOHIDDeviceRegisterInputReportCallback(self.device, self.receivedReport, self.receivedPacketMaxSize, ControllerReport, (__bridge void *)self);

    self.isValid = YES;

现在我确实接到了ControllerReport 的电话,但是我收到的报告属于0x01 类型,它们包含的内容有限(没有触控板或加速度计数据),但我想接收以下数据包输入0x11,其中包含来自控制器的所有数据。

为了切换控制器发送哪个数据包,网站声明This report is sent once the GET REPORT FEATURE 0x02 is received. 所以我发送该请求:

CFIndex len = self.receivedPacketMaxSize;
IOReturn featureMode2RequestError = IOHIDDeviceGetReport(self.device, kIOHIDReportTypeFeature, 0x02, self.receivedReport, &len);
if (featureMode2RequestError != kIOReturnSuccess) 
    NSLog(@"Could switch the controller to mode 2 :(");

此时,ControllerReport 停止被来自控制器的新报告调用。

我知道我能够向控制器发送数据,因为我能够发送改变 LED 颜色或设置震动速度的数据包。

问题

如何从 PS4 控制器获取更长的 0x11 报告?

我的尝试

我尝试过使用IOHIDDeviceGetReportWithCallbackIOHIDDeviceGetReport,但总是得到kIOReturnUnsupported 的回复。

我还在... it starts sending input reports in report 17. Since report 17 is undefined ... 形式的控制器的linux 驱动程序的源代码中找到了一些对这个问题的引用,但是我不知道如何告诉IOKit 处理报告17 (0x11)。

【问题讨论】:

我不能告诉你为什么你会看到那个特定的问题以及如何解决它,但如果我正在调试这个,我会检查IOKit HID family和IOKit userlib HID源代码和跟踪设备报告的路径。一旦你找到了它们被忽略的地方,解决它应该不会太难。 我现在有一个解决方案。由于这似乎是由框架中的错误引起的,因此我将在秋季 macOS 发布时再试一次。但是,如果问题仍然存在,我怀疑我是否有资源来查找和解决问题。 【参考方案1】:

问题在于 IOHIDDeviceGetReport kIOHIDReportTypeOutput 通过中断端点发送输出报告; DS4 期望它通过控制端点。 AFAIK 在 OS X 上没有任何方法可以通过 ctrl 端点输出 GetReport(没有编写 kext 来覆盖它)。

【讨论】:

以上是关于IOKit:未收到来自与蓝牙连接的 DualShock 4 控制器的 HID 中断报告的主要内容,如果未能解决你的问题,请参考以下文章

当应用程序未运行时,如何通过低功耗蓝牙接收消息?

IOKit驱动程序已加载但未启动

连接 throw stropes.js 时未收到来自 Openfire Xmpp 的通信

Android蓝牙LE:连接后未发现服务

Windows 10 蓝牙低功耗连接 c#

没有通过蓝牙收到 EA 通知