hid: Only enumerate IOHIDDevices that are likely to be joysticks Touching HID devices with keyboard usages will trigger a keyboard capture permission prompt on macOS 11+. See #4887 Like the IOKit joystick backend, we accept HID devices that have joystick, gamepad, or multi-axis controller usages. We also allow the Valve VID for the Steam Controller, just like the Windows HIDAPI implementation does.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
diff --git a/src/hidapi/mac/hid.c b/src/hidapi/mac/hid.c
index 1ad042d..3d0ad30 100644
--- a/src/hidapi/mac/hid.c
+++ b/src/hidapi/mac/hid.c
@@ -33,6 +33,8 @@
#include "../hidapi/hidapi.h"
+#define VALVE_USB_VID 0x28DE
+
/* Barrier implementation because Mac OSX doesn't have pthread_barrier.
It also doesn't have clock_gettime(). So much for POSIX and SUSv2.
This implementation came from Brent Priddy and was posted on
@@ -399,20 +401,86 @@ static void hid_device_removal_callback(void *context, IOReturn result,
}
}
+static CFDictionaryRef
+create_usage_match(const UInt32 page, const UInt32 usage, int *okay)
+{
+ CFDictionaryRef retval = NULL;
+ CFNumberRef pageNumRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &page);
+ CFNumberRef usageNumRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage);
+ const void *keys[2] = { (void *) CFSTR(kIOHIDDeviceUsagePageKey), (void *) CFSTR(kIOHIDDeviceUsageKey) };
+ const void *vals[2] = { (void *) pageNumRef, (void *) usageNumRef };
+
+ if (pageNumRef && usageNumRef) {
+ retval = CFDictionaryCreate(kCFAllocatorDefault, keys, vals, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ }
+
+ if (pageNumRef) {
+ CFRelease(pageNumRef);
+ }
+ if (usageNumRef) {
+ CFRelease(usageNumRef);
+ }
+
+ if (!retval) {
+ *okay = 0;
+ }
+
+ return retval;
+}
+
+static CFDictionaryRef
+create_vendor_match(const UInt32 vendor, int *okay)
+{
+ CFDictionaryRef retval = NULL;
+ CFNumberRef vidNumRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &vendor);
+ const void *keys[1] = { (void *) CFSTR(kIOHIDVendorIDKey) };
+ const void *vals[1] = { (void *) vidNumRef };
+
+ if (vidNumRef) {
+ retval = CFDictionaryCreate(kCFAllocatorDefault, keys, vals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ CFRelease(vidNumRef);
+ }
+
+ if (!retval) {
+ *okay = 0;
+ }
+
+ return retval;
+}
+
/* Initialize the IOHIDManager. Return 0 for success and -1 for failure. */
static int init_hid_manager(void)
{
+ int okay = 1;
+ const void *vals[] = {
+ (void *) create_usage_match(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick, &okay),
+ (void *) create_usage_match(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad, &okay),
+ (void *) create_usage_match(kHIDPage_GenericDesktop, kHIDUsage_GD_MultiAxisController, &okay),
+ (void *) create_vendor_match(VALVE_USB_VID, &okay),
+ };
+ const size_t numElements = SDL_arraysize(vals);
+ CFArrayRef matchingArray = okay ? CFArrayCreate(kCFAllocatorDefault, vals, numElements, &kCFTypeArrayCallBacks) : NULL;
+ size_t i;
+
+ for (i = 0; i < numElements; i++) {
+ if (vals[i]) {
+ CFRelease((CFTypeRef) vals[i]);
+ }
+ }
/* Initialize all the HID Manager Objects */
hid_mgr = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
if (hid_mgr) {
- IOHIDManagerSetDeviceMatching(hid_mgr, NULL);
+ IOHIDManagerSetDeviceMatchingMultiple(hid_mgr, matchingArray);
IOHIDManagerScheduleWithRunLoop(hid_mgr, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
IOHIDManagerRegisterDeviceRemovalCallback(hid_mgr, hid_device_removal_callback, NULL);
- return 0;
}
- return -1;
+ if (matchingArray != NULL) {
+ CFRelease(matchingArray);
+ }
+
+ return hid_mgr ? 0 : -1;
}
/* Initialize the IOHIDManager if necessary. This is the public function, and