-
Notifications
You must be signed in to change notification settings - Fork 462
support multipe usage/usage-pairs on MacOS #65
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -189,6 +189,15 @@ static void register_error(hid_device *dev, const char *op) | |||||
| } | ||||||
| #endif | ||||||
|
|
||||||
| static CFArrayRef get_array_property(IOHIDDeviceRef device, CFStringRef key) | ||||||
| { | ||||||
| CFTypeRef ref = IOHIDDeviceGetProperty(device, key); | ||||||
| if (ref != NULL && CFGetTypeID(ref) == CFArrayGetTypeID()) { | ||||||
| return (CFArrayRef)ref; | ||||||
| } else { | ||||||
| return NULL; | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| static int32_t get_int_property(IOHIDDeviceRef device, CFStringRef key) | ||||||
| { | ||||||
|
|
@@ -205,6 +214,11 @@ static int32_t get_int_property(IOHIDDeviceRef device, CFStringRef key) | |||||
| return 0; | ||||||
| } | ||||||
|
|
||||||
| static CFArrayRef get_usage_pairs(IOHIDDeviceRef device) | ||||||
| { | ||||||
| return get_array_property(device, CFSTR(kIOHIDDeviceUsagePairsKey)); | ||||||
| } | ||||||
|
|
||||||
| static unsigned short get_vendor_id(IOHIDDeviceRef device) | ||||||
| { | ||||||
| return get_int_property(device, CFSTR(kIOHIDVendorIDKey)); | ||||||
|
|
@@ -392,6 +406,117 @@ static void process_pending_events(void) { | |||||
| } while(res != kCFRunLoopRunFinished && res != kCFRunLoopRunTimedOut); | ||||||
| } | ||||||
|
|
||||||
| static struct hid_device_info *create_device_info_with_usage(IOHIDDeviceRef dev, int32_t usage_page, int32_t usage) | ||||||
| { | ||||||
| unsigned short dev_vid; | ||||||
| unsigned short dev_pid; | ||||||
| int BUF_LEN = 256; | ||||||
| wchar_t buf[BUF_LEN]; | ||||||
|
|
||||||
| struct hid_device_info *cur_dev; | ||||||
| io_object_t iokit_dev; | ||||||
| kern_return_t res; | ||||||
| io_string_t path; | ||||||
|
|
||||||
| if (dev == NULL) { | ||||||
| return NULL; | ||||||
| } | ||||||
|
|
||||||
| cur_dev = (struct hid_device_info *)calloc(1, sizeof(struct hid_device_info)); | ||||||
|
|
||||||
| dev_vid = get_vendor_id(dev); | ||||||
| dev_pid = get_product_id(dev); | ||||||
|
|
||||||
| cur_dev->usage_page = usage_page; | ||||||
| cur_dev->usage = usage; | ||||||
|
|
||||||
| /* Fill out the record */ | ||||||
| cur_dev->next = NULL; | ||||||
|
|
||||||
| /* Fill in the path (IOService plane) */ | ||||||
| iokit_dev = hidapi_IOHIDDeviceGetService(dev); | ||||||
| res = IORegistryEntryGetPath(iokit_dev, kIOServicePlane, path); | ||||||
| if (res == KERN_SUCCESS) | ||||||
| cur_dev->path = strdup(path); | ||||||
| else | ||||||
| cur_dev->path = strdup(""); | ||||||
|
|
||||||
| /* Serial Number */ | ||||||
| get_serial_number(dev, buf, BUF_LEN); | ||||||
| cur_dev->serial_number = dup_wcs(buf); | ||||||
|
|
||||||
| /* Manufacturer and Product strings */ | ||||||
| get_manufacturer_string(dev, buf, BUF_LEN); | ||||||
| cur_dev->manufacturer_string = dup_wcs(buf); | ||||||
| get_product_string(dev, buf, BUF_LEN); | ||||||
| cur_dev->product_string = dup_wcs(buf); | ||||||
|
|
||||||
| /* VID/PID */ | ||||||
| cur_dev->vendor_id = dev_vid; | ||||||
| cur_dev->product_id = dev_pid; | ||||||
|
|
||||||
| /* Release Number */ | ||||||
| cur_dev->release_number = get_int_property(dev, CFSTR(kIOHIDVersionNumberKey)); | ||||||
|
|
||||||
| /* Interface Number (Unsupported on Mac)*/ | ||||||
| cur_dev->interface_number = -1; | ||||||
|
|
||||||
| return cur_dev; | ||||||
| } | ||||||
|
|
||||||
| static struct hid_device_info *create_device_info(IOHIDDeviceRef device) | ||||||
| { | ||||||
| struct hid_device_info *root = NULL; | ||||||
| CFArrayRef usage_pairs = get_usage_pairs(device); | ||||||
|
|
||||||
| #ifdef DEBUG | ||||||
| // CFShow(usage_pairs); | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove |
||||||
| #endif | ||||||
|
|
||||||
| if (usage_pairs != NULL) { | ||||||
| struct hid_device_info *cur = NULL; | ||||||
| struct hid_device_info *next = NULL; | ||||||
| for (CFIndex i = 0; i < CFArrayGetCount(usage_pairs); i++) { | ||||||
| CFTypeRef dict = CFArrayGetValueAtIndex(usage_pairs, i); | ||||||
| if (CFGetTypeID(dict) != CFDictionaryGetTypeID()) { | ||||||
| continue; | ||||||
| } | ||||||
| #ifdef DEBUG | ||||||
| // CFShow(dict); | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove |
||||||
| #endif | ||||||
| CFTypeRef usage_page_ref, usage_ref; | ||||||
| int32_t usage_page, usage; | ||||||
|
|
||||||
| if (!CFDictionaryGetValueIfPresent((CFDictionaryRef)dict, CFSTR(kIOHIDDeviceUsagePageKey), &usage_page_ref) || | ||||||
| !CFDictionaryGetValueIfPresent((CFDictionaryRef)dict, CFSTR(kIOHIDDeviceUsageKey), &usage_ref) || | ||||||
| CFGetTypeID(usage_page_ref) != CFNumberGetTypeID() || | ||||||
| CFGetTypeID(usage_ref) != CFNumberGetTypeID() || | ||||||
| !CFNumberGetValue((CFNumberRef)usage_page_ref, kCFNumberIntType, &usage_page) || | ||||||
| !CFNumberGetValue((CFNumberRef)usage_ref, kCFNumberIntType, &usage)) { | ||||||
| continue; | ||||||
| } | ||||||
| next = create_device_info_with_usage(device, usage_page, usage); | ||||||
| if (cur == NULL) { | ||||||
| root = next; | ||||||
| } | ||||||
| else { | ||||||
| cur->next = next; | ||||||
| } | ||||||
| cur = next; | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| if (root == NULL) { | ||||||
| /* error when generating or parsing usage pairs */ | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| int32_t usage_page = get_int_property(device, CFSTR(kIOHIDPrimaryUsagePageKey)); | ||||||
| int32_t usage = get_int_property(device, CFSTR(kIOHIDPrimaryUsageKey)); | ||||||
|
|
||||||
| root = create_device_info_with_usage(device, usage_page, usage); | ||||||
| } | ||||||
|
|
||||||
| return root; | ||||||
| } | ||||||
|
|
||||||
| struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id) | ||||||
| { | ||||||
| struct hid_device_info *root = NULL; /* return object */ | ||||||
|
|
@@ -407,7 +532,30 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, | |||||
| process_pending_events(); | ||||||
|
|
||||||
| /* Get a list of the Devices */ | ||||||
| IOHIDManagerSetDeviceMatching(hid_mgr, NULL); | ||||||
| CFMutableDictionaryRef matching = NULL; | ||||||
| if (vendor_id != 0 || product_id != 0) { | ||||||
| matching = CFDictionaryCreateMutable(kCFAllocatorDefault, kIOHIDOptionsTypeNone, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | ||||||
|
|
||||||
| if (vendor_id != 0) { | ||||||
| CFNumberRef v = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &vendor_id); | ||||||
| CFDictionarySetValue(matching, CFSTR(kIOHIDVendorIDKey), v); | ||||||
| CFRelease(v); | ||||||
| } | ||||||
|
|
||||||
| if (product_id != 0) { | ||||||
| CFNumberRef p = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &product_id); | ||||||
| CFDictionarySetValue(matching, CFSTR(kIOHIDProductIDKey), p); | ||||||
| CFRelease(p); | ||||||
| } | ||||||
| #ifdef DEBUG | ||||||
| // CFShow(matching); | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove |
||||||
| #endif | ||||||
| } | ||||||
| IOHIDManagerSetDeviceMatching(hid_mgr, matching); | ||||||
| if (matching != NULL) { | ||||||
| CFRelease(matching); | ||||||
| } | ||||||
|
|
||||||
| CFSetRef device_set = IOHIDManagerCopyDevices(hid_mgr); | ||||||
|
|
||||||
| /* Convert the list into a C array so we can iterate easily. */ | ||||||
|
|
@@ -417,81 +565,32 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, | |||||
|
|
||||||
| /* Iterate over each device, making an entry for it. */ | ||||||
| for (i = 0; i < num_devices; i++) { | ||||||
| unsigned short dev_vid; | ||||||
| unsigned short dev_pid; | ||||||
| #define BUF_LEN 256 | ||||||
| wchar_t buf[BUF_LEN]; | ||||||
|
|
||||||
| IOHIDDeviceRef dev = device_array[i]; | ||||||
| #ifdef DEBUG | ||||||
| // CFShow(dev); | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove |
||||||
| #endif | ||||||
|
|
||||||
| if (!dev) { | ||||||
| continue; | ||||||
| } | ||||||
| dev_vid = get_vendor_id(dev); | ||||||
| dev_pid = get_product_id(dev); | ||||||
|
|
||||||
| /* Check the VID/PID against the arguments */ | ||||||
| if ((vendor_id == 0x0 || vendor_id == dev_vid) && | ||||||
| (product_id == 0x0 || product_id == dev_pid)) { | ||||||
| struct hid_device_info *tmp; | ||||||
| bool is_usb_hid; /* Is this an actual HID usb device */ | ||||||
| io_object_t iokit_dev; | ||||||
| kern_return_t res; | ||||||
| io_string_t path; | ||||||
|
|
||||||
| /* VID/PID match. Create the record. */ | ||||||
| tmp = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info)); | ||||||
| if (cur_dev) { | ||||||
| cur_dev->next = tmp; | ||||||
| } | ||||||
| else { | ||||||
| root = tmp; | ||||||
| } | ||||||
| cur_dev = tmp; | ||||||
|
|
||||||
| is_usb_hid = get_int_property(dev, CFSTR(kUSBInterfaceClass)) == kUSBHIDClass; | ||||||
|
|
||||||
| /* Get the Usage Page and Usage for this device. */ | ||||||
| cur_dev->usage_page = get_int_property(dev, CFSTR(kIOHIDPrimaryUsagePageKey)); | ||||||
| cur_dev->usage = get_int_property(dev, CFSTR(kIOHIDPrimaryUsageKey)); | ||||||
|
|
||||||
| /* Fill out the record */ | ||||||
| cur_dev->next = NULL; | ||||||
|
|
||||||
| /* Fill in the path (IOService plane) */ | ||||||
| iokit_dev = hidapi_IOHIDDeviceGetService(dev); | ||||||
| res = IORegistryEntryGetPath(iokit_dev, kIOServicePlane, path); | ||||||
| if (res == KERN_SUCCESS) | ||||||
| cur_dev->path = strdup(path); | ||||||
| else | ||||||
| cur_dev->path = strdup(""); | ||||||
|
|
||||||
| /* Serial Number */ | ||||||
| get_serial_number(dev, buf, BUF_LEN); | ||||||
| cur_dev->serial_number = dup_wcs(buf); | ||||||
|
|
||||||
| /* Manufacturer and Product strings */ | ||||||
| get_manufacturer_string(dev, buf, BUF_LEN); | ||||||
| cur_dev->manufacturer_string = dup_wcs(buf); | ||||||
| get_product_string(dev, buf, BUF_LEN); | ||||||
| cur_dev->product_string = dup_wcs(buf); | ||||||
|
|
||||||
| /* VID/PID */ | ||||||
| cur_dev->vendor_id = dev_vid; | ||||||
| cur_dev->product_id = dev_pid; | ||||||
|
|
||||||
| /* Release Number */ | ||||||
| cur_dev->release_number = get_int_property(dev, CFSTR(kIOHIDVersionNumberKey)); | ||||||
|
|
||||||
| /* We can only retrieve the interface number for USB HID devices. | ||||||
| * IOKit always seems to return 0 when querying a standard USB device | ||||||
| * for its interface. */ | ||||||
| if (is_usb_hid) { | ||||||
| /* Get the interface number */ | ||||||
| cur_dev->interface_number = get_int_property(dev, CFSTR(kUSBInterfaceNumber)); | ||||||
| } else { | ||||||
| cur_dev->interface_number = -1; | ||||||
| } | ||||||
| if (!dev) { | ||||||
| continue; | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| } | ||||||
|
|
||||||
| struct hid_device_info *tmp = create_device_info(dev); | ||||||
| if (tmp == NULL) { | ||||||
| continue; | ||||||
| } | ||||||
|
|
||||||
| if (cur_dev) { | ||||||
| cur_dev->next = tmp; | ||||||
| } | ||||||
| else { | ||||||
| root = tmp; | ||||||
| } | ||||||
| cur_dev = tmp; | ||||||
|
|
||||||
| /* move the pointer to the tail of returnd list */ | ||||||
| while (cur_dev->next != NULL) { | ||||||
| cur_dev = cur_dev->next; | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| } | ||||||
| } | ||||||
|
|
||||||
|
|
||||||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is supported now
please see: 00e6e45#diff-5cbb2d1918d13a205b0b45fa24166f42
update accordingly