diff --git a/input/drivers_hid/iohidmanager_hid.c b/input/drivers_hid/iohidmanager_hid.c index 46de742897..30470b97e6 100644 --- a/input/drivers_hid/iohidmanager_hid.c +++ b/input/drivers_hid/iohidmanager_hid.c @@ -56,6 +56,7 @@ struct iohidmanager_hid_adapter apple_input_rec_t *hats; apple_input_rec_t *buttons; uint8_t data[2048]; + uint32_t uniqueId; }; CFComparisonResult iohidmanager_sort_elements(const void *val1, const void *val2, void *context) @@ -485,6 +486,14 @@ static uint32_t iohidmanager_hid_device_get_location_id(IOHIDDeviceRef device) CFSTR(kIOHIDLocationIDKey)); } +static uint32_t iohidmanager_hid_device_get_unique_id(IOHIDDeviceRef device) +{ + /* osx seems to assign an unique id to each device when they are plugged in + * the id change if device is unplugged/plugged, but it's unique amongst the + * other device plugged */ + return iohidmanager_hid_device_get_int_property(device,CFSTR(kIOHIDUniqueIDKey)); +} + static void iohidmanager_hid_device_get_product_string( IOHIDDeviceRef device, char *buf, size_t len) { @@ -495,6 +504,9 @@ static void iohidmanager_hid_device_get_product_string( CFStringGetCString(ref, buf, len, kCFStringEncodingUTF8); } + + + static void iohidmanager_hid_device_add_autodetect(unsigned idx, const char *device_name, const char *driver_name, uint16_t dev_vid, uint16_t dev_pid) @@ -512,10 +524,24 @@ static void iohidmanager_hid_device_add_autodetect(unsigned idx, RARCH_LOG("Port %d: %s.\n", idx, device_name); } -static void iohidmanager_hid_device_add(void *data, IOReturn result, - void *sender, IOHIDDeviceRef device) +static void iohidmanager_hid_device_add_device(IOHIDDeviceRef device, iohidmanager_hid_t* hid) { int i; + + /* get device unique id */ + uint32_t deviceUniqueId = iohidmanager_hid_device_get_unique_id(device); + + /* check if pad was already registered previously (by deterministic method) + * if so do not re-add the pad */ + for (i=0; islots[i].data; + if (a == NULL) + continue; + if (a->uniqueId == deviceUniqueId) + return; + } + IOReturn ret; uint16_t dev_vid, dev_pid; CFArrayRef elements_raw; @@ -527,8 +553,6 @@ static void iohidmanager_hid_device_add(void *data, IOReturn result, apple_input_rec_t *tmp = NULL; apple_input_rec_t *tmpButtons = NULL; apple_input_rec_t *tmpAxes = NULL; - iohidmanager_hid_t *hid = (iohidmanager_hid_t*) - hid_driver_get_data(); struct iohidmanager_hid_adapter *adapter = (struct iohidmanager_hid_adapter*) calloc(1, sizeof(*adapter)); @@ -557,6 +581,7 @@ static void iohidmanager_hid_device_add(void *data, IOReturn result, dev_vid = iohidmanager_hid_device_get_vendor_id (device); dev_pid = iohidmanager_hid_device_get_product_id (device); + adapter->uniqueId = deviceUniqueId; adapter->slot = pad_connection_pad_init(hid->slots, adapter->name, dev_vid, dev_pid, adapter, @@ -788,6 +813,14 @@ error: } } + +static void iohidmanager_hid_device_add(void *data, IOReturn result, + void* sender, IOHIDDeviceRef device) +{ + iohidmanager_hid_t *hid = (iohidmanager_hid_t*) hid_driver_get_data(); + iohidmanager_hid_device_add_device(device, hid); +} + static void iohidmanager_hid_append_matching_dictionary( CFMutableArrayRef array, uint32_t page, uint32_t use) @@ -841,6 +874,16 @@ static int iohidmanager_hid_manager_free(iohidmanager_hid_t *hid) return 0; } +static int iohidmanager_hid_manager_set_device_matching( + iohidmanager_hid_t *hid) +{ + /* deterministically add all device currently plugged when lanching retroarch + * order by location id which seems to correspond to usb port number */ + CFSetRef set = IOHIDManagerCopyDevices(hid->ptr); + CFIndex num_devices = CFSetGetCount(set); + IOHIDDeviceRef *device_array = calloc(num_devices, sizeof(IOHIDDeviceRef)); + CFSetGetValues(set, (const void **) device_array); + /* re order device by location id */ typedef struct hid_list { @@ -848,28 +891,85 @@ static int iohidmanager_hid_manager_free(iohidmanager_hid_t *hid) uint32_t lid; struct hid_list *next; } hid_list_t; + + hid_list_t* devList = NULL; + for (long i=0; idevice = dev; + devList->lid = iohidmanager_hid_device_get_location_id(dev); + devList->next = NULL; + } + else + { + hid_list_t * new = (hid_list_t *)malloc(sizeof(hid_list_t)); + new->device = dev; + new->lid = iohidmanager_hid_device_get_location_id(dev); + new->next = NULL; -static int iohidmanager_hid_manager_set_device_matching( - iohidmanager_hid_t *hid) -{ - CFMutableArrayRef matcher = CFArrayCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeArrayCallBacks); + hid_list_t * ptr = devList; + if ( new->lid < ptr->lid ) + { + new->next = ptr; + devList = new; + } + else + { + while ( ( ptr->lid < new->lid ) && (ptr->next != NULL) ) + { + ptr = ptr->next; + } + new->next = ptr->next; + ptr->next = new; + } + } + } + } - if (!matcher) - return -1; + /* register devices */ + hid_list_t * ptr = devList; + while (ptr != NULL) + { + iohidmanager_hid_device_add_device(ptr->device, hid); + + //printf("%d\n",ptr->lid); + ptr = ptr->next; + free(devList); + devList = ptr; + } + free(device_array); - iohidmanager_hid_append_matching_dictionary(matcher, - kHIDPage_GenericDesktop, - kHIDUsage_GD_Joystick); - iohidmanager_hid_append_matching_dictionary(matcher, - kHIDPage_GenericDesktop, - kHIDUsage_GD_GamePad); - IOHIDManagerSetDeviceMatchingMultiple(hid->ptr, matcher); - IOHIDManagerRegisterDeviceMatchingCallback(hid->ptr, - iohidmanager_hid_device_add, 0); + /* register call back to dynamically add device plugged when retroarch is + * running + * those will be added after the one plugged when retroarch was launched, + * and by order they are plugged in (so not deterministic) */ + CFMutableArrayRef matcher = CFArrayCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeArrayCallBacks); - CFRelease(matcher); + if (!matcher) + return -1; + + iohidmanager_hid_append_matching_dictionary(matcher, + kHIDPage_GenericDesktop, + kHIDUsage_GD_Joystick); + iohidmanager_hid_append_matching_dictionary(matcher, + kHIDPage_GenericDesktop, + kHIDUsage_GD_GamePad); + + IOHIDManagerSetDeviceMatchingMultiple(hid->ptr, matcher); + IOHIDManagerRegisterDeviceMatchingCallback(hid->ptr, + iohidmanager_hid_device_add, 0); + + CFRelease(matcher); return 0; }