Я понял это. Способ сделать это - использовать клавиатуру (0x01) Generic Desktop Page (06) (и Keypad (07) для полноты) для использования с IOHIDManagerSetDeviceMatchingMultiple, а затем обратный вызов входного значения получает содержимое Keyboard / Keypad Usage Page (0x07).
Например, чтобы настроить HIDManager для всех клавиатур / клавиатур, можно сделать что-то вроде:
IOHIDManagerRef hidManager = IOHIDManagerCreate(kCFAllocatorDefault,
kIOHIDOptionsTypeNone);
CFMutableDictionaryRef keyboard =
myCreateDeviceMatchingDictionary(0x01, 6);
CFMutableDictionaryRef keypad =
myCreateDeviceMatchingDictionary(0x01, 7);
CFMutableDictionaryRef matchesList[] = {
keyboard,
keypad,
};
CFArrayRef matches = CFArrayCreate(kCFAllocatorDefault,
(const void **)matchesList, 2, NULL);
IOHIDManagerSetDeviceMatchingMultiple(hidManager, matches);
IOHIDManagerRegisterInputValueCallback(hidManager,
myHIDKeyboardCallback, NULL);
IOHIDManagerScheduleWithRunLoop(hidManager, CFRunLoopGetMain(),
kCFRunLoopDefaultMode);
IOHIDManagerOpen(hidManager, kIOHIDOptionsTypeNone);
Где myCreateDeviceMatchingDictionary выглядит примерно так:
CFMutableDictionaryRef myCreateDeviceMatchingDictionary(UInt32 usagePage,
UInt32 usage) {
CFMutableDictionaryRef ret = CFDictionaryCreateMutable(kCFAllocatorDefault,
0, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (!ret)
return NULL;
CFNumberRef pageNumberRef = CFNumberCreate(kCFAllocatorDefault,
kCFNumberIntType, &usagePage );
if (!pageNumberRef) {
CFRelease(ret);
return NULL;
}
CFDictionarySetValue(ret, CFSTR(kIOHIDDeviceUsagePageKey), pageNumberRef);
CFRelease(pageNumberRef);
CFNumberRef usageNumberRef = CFNumberCreate(kCFAllocatorDefault,
kCFNumberIntType, &usage);
if (!usageNumberRef) {
CFRelease(ret);
return NULL;
}
CFDictionarySetValue(ret, CFSTR(kIOHIDDeviceUsageKey), usageNumberRef);
CFRelease(usageNumberRef);
return ret;
}
И myHIDKeyboardCallback - это что-то вроде:
void myHIDKeyboardCallback(void *context, IOReturn result, void *sender,
IOHIDValueRef value) {
IOHIDElementRef elem = IOHIDValueGetElement(value);
if (IOHIDElementGetUsagePage(elem) != 0x07)
return;
uint32_t scancode = IOHIDElementGetUsage(elem);
if (scancode < 4 || scancode > 231)
return;
long pressed = IOHIDValueGetIntegerValue(value);
// ... Do something ...
}
Обратите внимание, что обратный вызов, кажется, вызывается несколько раз за одно нажатие или выпуск, но с идентификаторами использования, выходящими за пределы нормального диапазона, для чего и используется "if (scancode <4 || scancode> 231)".