I get it. The way to do this is to use the full-featured keyboard (0x01) (06) (and the keyboard (07)) to use with the IOHIDManagerSetDeviceMatchingMultiple, and then the Keyboard / Keyboard Usage (0x07) material gets called back.
For example, to configure HIDManager for all keyboards / keyboards, you can do something like:
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);
Where myCreateDeviceMatchingDictionary is something like:
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; }
And myHIDKeyboardCallback looks something like this:
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);
Note that the callback appears to be called several times for each click or release, but with usage identifiers outside the normal range, which means "if (scancode <4 || scancode> 231)".