支持GCController和IOHIDDeviceRef

时间:2015-11-03 21:22:05

标签: macos hid iokit mfi gamecontroller

我正在开发支持游戏控制器的OS X应用程序。它必须支持源自IOKit HID和GameController.framework的控制器。 问题我面临的是大多数MFi GameController.framework兼容控制器也是隐藏设备。因此,MFi控制器在控制器列表中出现两次,包括GCController和IOHIDDevice。有没有办法在它们之间建立连接,忽略HID设备?

GCController对象具有私有属性deviceRef,它指向底层隐藏设备,从而可以识别和忽略HID层中的设备。问题是deviceRef是私有财产,因此我无法在App Store应用中使用它。

理想的解决方案是识别IOHIDDeviceRef是MFi设备的一种方法,所以我可以在我的HID层中完全跳过它。

2 个答案:

答案 0 :(得分:4)

我正在试验GCController,最后找到了一个hacky解决方案。这可能是区分使用GameController框架的控制器和使用IOKit的控制器的唯一方法:

  1. 每当新控制器连接到Mac时,分别使用IOHIDDeviceRef和GCController实例为IOKit和GameController调用连接回调。

  2. 获取IOHIDDeviceRef的供应商ID和产品ID:

  3. 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);
    1. 获取GCController实例的供应商ID和产品ID有点棘手(和hacky),但我在几个版本的macOS上使用许多设备测试它并且它可以工作。首先,您必须声明在IOKit / hidsystem / IOHIDServiceClient.h中定义的IOHIDServiceClientCopyProperty函数。 IOHIDServiceClient.h仅包含在MacOSX sdk 10.12中,因此您必须定义用于早期版本SDK的函数:
    2. typedef struct CF_BRIDGED_TYPE(id) __IOHIDServiceClient * IOHIDServiceClientRef;
      extern "C" CFTypeRef _Nullable IOHIDServiceClientCopyProperty(IOHIDServiceClientRef service, CFStringRef key);
      1. 要获取实际ID,首先必须调用受保护的方法&#34; hidServices&#34; GCController,它将返回一个指向GCCControllerHIDServiceInfo实例的指针数组。 GCCControllerHIDServiceInfo是一个内部类,它有两个方法:&#34; inputData&#34;和&#34;服务&#34; (我们感兴趣的)。该数组通常只有一个元素,因此我们调用它的服务方法来获取设备的IOHIDServiceClientRef实例。您可以通过调用IOHIDServiceClientCopyProperty来获取它的供应商ID和产品ID,其他所有内容都类似于IOKit:
      2. 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);
                }
            }
        }
        1. 您要做的最后一件事实际上是将供应商ID和产品ID与支持一个或另一个框架的设备列表进行比较。目前,我只知道两个支持GameController框架的设备(如果你知道任何其他GameController框架兼容设备,请告诉我):
          • SteelSeries Nimbus:供应商ID = 0x1038,产品ID = 0x1420
          • HoriPad Ultimate:供应商ID = 0x0F0D,产品ID = 0x0090
        2. 您可以在Ouzel engine

          中查看上述完整代码

答案 1 :(得分:2)

Mac OS 11及更高版本上的

GCController具有SQL_USER="abc_user"的{​​{1}} API。为了支持早期的系统,我建议猫王建议什么。您还可以参考处理这两种情况的WebKit的source code