同时支持 GCController 和 IOHIDDeviceRef
Supporting both GCController and IOHIDDeviceRef
我正在开发 OS X 应用程序,它支持游戏控制器。它必须支持源自 IOKit HID 和 GameController.framework 的控制器。
我面临的问题是大多数 MFi GameController.framework 兼容控制器也是隐藏设备。因此,MFi 控制器在控制器列表中出现了两次,分别是 GCController 和 IOHIDDevice。有没有办法在它们之间建立联系,忽略 HID 设备?
GCController对象有private属性deviceRef
,指向底层hid设备,使得识别和忽略HID层设备成为可能。问题是 deviceRef
是私有的 属性,所以我不能在 App Store 应用程序中使用它。
理想的解决方案是识别 IOHIDDeviceRef 是 MFi 设备,这样我就可以在我的 HID 层中完全跳过它。
我正在试验 GCController 并最终找到了一个 hacky 解决方案。这可能是区分使用 GameController 框架的控制器和使用 IOKit 的控制器的唯一方法:
每当新控制器连接到 Mac 时,分别使用 IOHIDDeviceRef 和 GCController 实例为 IOKit 和 GameController 调用连接回调。
获取 IOHIDDeviceRef 的供应商 ID 和产品 ID:
CFNumberRef vendor = static_cast<CFNumberRef>(IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVendorIDKey));
if (vendor) CFNumberGetValue(vendor, kCFNumberSInt32Type, &vendorId);
CFNumberRef product = static_cast<CFNumberRef>(IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductIDKey)));
if (product) CFNumberGetValue(product, kCFNumberSInt32Type, &productId);
- 获取 GCController 实例的供应商 ID 和产品 ID 有点棘手(而且很棘手),但我在几个版本的 macOS 上用许多设备测试了它并且它有效。首先,您必须声明在 IOKit/hidsystem/IOHIDServiceClient.h 中定义的 IOHIDServiceClientCopyProperty 函数。 IOHIDServiceClient.h 仅包含在 MacOSX SDK 10.12 中,因此您必须定义用于早期版本 SDK 的函数:
typedef struct CF_BRIDGED_TYPE(id) __IOHIDServiceClient * IOHIDServiceClientRef;
extern "C" CFTypeRef _Nullable IOHIDServiceClientCopyProperty(IOHIDServiceClientRef service, CFStringRef key);
- 要获取实际 ID,您首先必须调用 GCController 的受保护方法 "hidServices",这将 return 指向 GCCControllerHIDServiceInfo 实例的指针数组。 GCCControllerHIDServiceInfo 是一个内部的 class,它有两个方法:"inputData" 和 "service"(我们感兴趣)。该数组通常只有一个元素,因此我们调用它的服务方法来获取设备的 IOHIDServiceClientRef 实例。您可以通过调用 IOHIDServiceClientCopyProperty 来获取它的供应商 ID 和产品 ID,其他一切与 IOKit 类似:
if (class_respondsToSelector(object_getClass(controller), sel_getUid("hidServices")))
{
NSArray* hidServices = reinterpret_cast<NSArray* (*)(id, SEL)>(objc_msgSend)(controller, sel_getUid("hidServices"));
if (hidServices && [hidServices count] > 0)
{
IOHIDServiceClientRef service = reinterpret_cast<IOHIDServiceClientRef (*)(id, SEL)>(objc_msgSend)([hidServices firstObject], sel_getUid("service"));
CFNumberRef vendor = static_cast<CFNumberRef>(IOHIDServiceClientCopyProperty(service, CFSTR(kIOHIDVendorIDKey)));
if (vendor)
{
CFNumberGetValue(vendor, kCFNumberSInt32Type, &vendorId);
CFRelease(vendor);
}
CFNumberRef product = static_cast<CFNumberRef>(IOHIDServiceClientCopyProperty(service, CFSTR(kIOHIDProductIDKey)));
if (product)
{
CFNumberGetValue(product, kCFNumberSInt32Type, &productId);
CFRelease(product);
}
}
}
- 您要做的最后一件事实际上是将供应商 ID 和产品 ID 与支持一个或另一个框架的设备列表进行比较。目前,我只知道两种支持 GameController 框架的设备(如果您知道任何其他 GameController 框架兼容设备,请告诉我):
- SteelSeries Nimbus:供应商 ID = 0x1038,产品 ID = 0x1420
- HoriPad Ultimate:供应商 ID = 0x0F0D,产品 ID = 0x0090
您可以在 Ouzel engine.
中查看上述完整代码
macOS 11 及更高版本上的 GCController 有 +[GCController supportsHIDDevice:]
API 需要 IOHIDDeviceRef
。为了支持早期的系统,我会建议 Elviss 的建议。您还可以参考处理这两种情况的 WebKit 的 source code。
我正在开发 OS X 应用程序,它支持游戏控制器。它必须支持源自 IOKit HID 和 GameController.framework 的控制器。 我面临的问题是大多数 MFi GameController.framework 兼容控制器也是隐藏设备。因此,MFi 控制器在控制器列表中出现了两次,分别是 GCController 和 IOHIDDevice。有没有办法在它们之间建立联系,忽略 HID 设备?
GCController对象有private属性deviceRef
,指向底层hid设备,使得识别和忽略HID层设备成为可能。问题是 deviceRef
是私有的 属性,所以我不能在 App Store 应用程序中使用它。
理想的解决方案是识别 IOHIDDeviceRef 是 MFi 设备,这样我就可以在我的 HID 层中完全跳过它。
我正在试验 GCController 并最终找到了一个 hacky 解决方案。这可能是区分使用 GameController 框架的控制器和使用 IOKit 的控制器的唯一方法:
每当新控制器连接到 Mac 时,分别使用 IOHIDDeviceRef 和 GCController 实例为 IOKit 和 GameController 调用连接回调。
获取 IOHIDDeviceRef 的供应商 ID 和产品 ID:
CFNumberRef vendor = static_cast<CFNumberRef>(IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVendorIDKey));
if (vendor) CFNumberGetValue(vendor, kCFNumberSInt32Type, &vendorId);
CFNumberRef product = static_cast<CFNumberRef>(IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductIDKey)));
if (product) CFNumberGetValue(product, kCFNumberSInt32Type, &productId);
- 获取 GCController 实例的供应商 ID 和产品 ID 有点棘手(而且很棘手),但我在几个版本的 macOS 上用许多设备测试了它并且它有效。首先,您必须声明在 IOKit/hidsystem/IOHIDServiceClient.h 中定义的 IOHIDServiceClientCopyProperty 函数。 IOHIDServiceClient.h 仅包含在 MacOSX SDK 10.12 中,因此您必须定义用于早期版本 SDK 的函数:
typedef struct CF_BRIDGED_TYPE(id) __IOHIDServiceClient * IOHIDServiceClientRef;
extern "C" CFTypeRef _Nullable IOHIDServiceClientCopyProperty(IOHIDServiceClientRef service, CFStringRef key);
- 要获取实际 ID,您首先必须调用 GCController 的受保护方法 "hidServices",这将 return 指向 GCCControllerHIDServiceInfo 实例的指针数组。 GCCControllerHIDServiceInfo 是一个内部的 class,它有两个方法:"inputData" 和 "service"(我们感兴趣)。该数组通常只有一个元素,因此我们调用它的服务方法来获取设备的 IOHIDServiceClientRef 实例。您可以通过调用 IOHIDServiceClientCopyProperty 来获取它的供应商 ID 和产品 ID,其他一切与 IOKit 类似:
if (class_respondsToSelector(object_getClass(controller), sel_getUid("hidServices")))
{
NSArray* hidServices = reinterpret_cast<NSArray* (*)(id, SEL)>(objc_msgSend)(controller, sel_getUid("hidServices"));
if (hidServices && [hidServices count] > 0)
{
IOHIDServiceClientRef service = reinterpret_cast<IOHIDServiceClientRef (*)(id, SEL)>(objc_msgSend)([hidServices firstObject], sel_getUid("service"));
CFNumberRef vendor = static_cast<CFNumberRef>(IOHIDServiceClientCopyProperty(service, CFSTR(kIOHIDVendorIDKey)));
if (vendor)
{
CFNumberGetValue(vendor, kCFNumberSInt32Type, &vendorId);
CFRelease(vendor);
}
CFNumberRef product = static_cast<CFNumberRef>(IOHIDServiceClientCopyProperty(service, CFSTR(kIOHIDProductIDKey)));
if (product)
{
CFNumberGetValue(product, kCFNumberSInt32Type, &productId);
CFRelease(product);
}
}
}
- 您要做的最后一件事实际上是将供应商 ID 和产品 ID 与支持一个或另一个框架的设备列表进行比较。目前,我只知道两种支持 GameController 框架的设备(如果您知道任何其他 GameController 框架兼容设备,请告诉我):
- SteelSeries Nimbus:供应商 ID = 0x1038,产品 ID = 0x1420
- HoriPad Ultimate:供应商 ID = 0x0F0D,产品 ID = 0x0090
您可以在 Ouzel engine.
中查看上述完整代码macOS 11 及更高版本上的 GCController 有 +[GCController supportsHIDDevice:]
API 需要 IOHIDDeviceRef
。为了支持早期的系统,我会建议 Elviss 的建议。您还可以参考处理这两种情况的 WebKit 的 source code。