Поддержка как GCController, так и IOHIDDeviceRef

Я работаю над приложением OS X, которое поддерживает игровые контроллеры. Он должен поддерживать контроллеры как из IOKit HID, так и из GameController.framework. Проблема, с которой я столкнулся, заключается в том, что большинство контроллеров, совместимых с MFi GameController.framework, также являются скрытыми устройствами. Таким образом, контроллеры MFi появляются в списке контроллеров дважды, как GCController, так и IOHIDDevice. Есть ли способ установить связь между ними, чтобы игнорировать HID-устройство?

Объекты GCController имеют закрытое свойство deviceRef, которое указывает на базовое скрытое устройство, что позволяет распознавать и игнорировать устройство на уровне HID. Проблема в том, что deviceRef является частной собственностью, поэтому я не могу использовать его в приложении App Store.

Идеальным решением был бы способ определить, что IOHIDDeviceRef является устройством MFi, поэтому я могу полностью пропустить его на своем уровне HID.


person Shchvova    schedule 03.11.2015    source источник
comment
У меня нет под рукой устройства с поддержкой GCController, но проверили ли вы свойства IOHIDDevice в реестре ввода-вывода, чтобы увидеть, есть ли там какие-либо намеки на структуру Game Controller? (используйте IORegistryExplorer или ioreg или IOJones). Если нет, то создание частного устройства deviceRef кажется ошибкой, поэтому я бы отправил радар с запросом на надежный общедоступный способ сопоставления HID-устройства с GCController.   -  person pmdj    schedule 04.11.2015
comment
Просто сам столкнулся с такой потребностью. Вы когда-нибудь находили решение?   -  person Toji    schedule 24.08.2016
comment
Нет, я этого не делал. Я разговаривал с ребятами из Apple на Apple TV Tech Talks, они сказали мне, что решения не будет. Мое предложение состоит в том, чтобы сделать пару эвристик, чтобы проверить, одинаковы ли устройства.   -  person Shchvova    schedule 31.08.2016
comment
Я знаю, что это не универсальный подход, но я планирую создать базу данных идентификаторов поставщиков/продуктов (github.com/elnormous/ouzel/blob/master/ouzel/input/macos/) и проверьте, поддерживает ли устройство GCController.   -  person Elviss Strazdins    schedule 19.07.2017


Ответы (2)


Я экспериментировал с GCController и, наконец, нашел хакерское решение. Вот, пожалуй, единственный способ отличить контроллеры, использующие фреймворк GameController, от контроллеров, использующих IOKit:

  1. Всякий раз, когда к Mac подключается новый контроллер, для IOKit и GameController вызываются обратные вызовы подключения с экземплярами IOHIDDeviceRef и GCController соответственно.

  2. Получите идентификатор поставщика и идентификатор продукта IOHIDDeviceRef:

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 немного сложно (и хакерски), но я протестировал его на многих устройствах в нескольких версиях macOS, и он работает. Во-первых, вы должны объявить функцию IOHIDServiceClientCopyProperty, которая определена в IOKit/hidsystem/IOHIDServiceClient.h. IOHIDServiceClient.h включен только в MacOSX sdk 10.12, поэтому вам придется определить функцию для использования с более ранними версиями SDK:
typedef struct CF_BRIDGED_TYPE(id) __IOHIDServiceClient * IOHIDServiceClientRef;
extern "C" CFTypeRef _Nullable IOHIDServiceClientCopyProperty(IOHIDServiceClientRef service, CFStringRef key);
  1. Чтобы получить фактический идентификатор, вам сначала нужно вызвать защищенный метод «hidServices» GCController, который вернет массив указателей на экземпляры GCCControllerHIDServiceInfo. GCCControllerHIDServiceInfo — это внутренний класс, который имеет два метода: «inputData» и «service» (который нас интересует). Массив обычно содержит только один элемент, поэтому мы вызываем его сервисный метод, чтобы получить экземпляр IOHIDServiceClientRef устройства. Вы можете получить идентификатор поставщика и идентификатор продукта, вызвав IOHIDServiceClientCopyProperty, все остальное аналогично 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);
        }
    }
}
  1. The last thing you have to do is actually compare the vendor ID and product ID to a list of devices that support one or another framework. For now, I know only two devices that support GameController framework (If you know any other GameController framework compatible devices, please let me know):
    • SteelSeries Nimbus: Vendor ID = 0x1038, Product ID = 0x1420
    • HoriPad Ultimate: идентификатор поставщика = 0x0F0D, идентификатор продукта = 0x0090

Вы можете увидеть полный код, описанный выше, в Двигатель Ouzel.

person Elviss Strazdins    schedule 03.08.2017

GCController в macOS 11 и более поздних версиях имеет +[GCController supportsHIDDevice:] API, который принимает файл IOHIDDeviceRef. Для поддержки более ранних систем я бы посоветовал то, что предлагает Элвис. Вы также можете обратиться к исходному коду WebKit. который обрабатывает оба случая.

person Zorg    schedule 25.11.2020