Mac joystick: ignore duplicate HID elements.
authorRyan C. Gordon <icculus@icculus.org>
Sat, 22 Feb 2014 21:15:34 -0500
changeset 8242 f6a2b1a6932b
parent 8241 b6d5a589ce3f
child 8243 f905dd0f0f83
Mac joystick: ignore duplicate HID elements. The DualShock 4 has all elements listed twice: once in the top-level list of elements, and once in an "Application Collection" element at the top-level. Each element has a proper cookie with a unique value, so now we descend into each element collections, but before we add an element to the device's list, we make sure we don't already have one with that cookie, probably from another collection or a buggy device.
src/joystick/darwin/SDL_sysjoystick.c
src/joystick/darwin/SDL_sysjoystick_c.h
--- a/src/joystick/darwin/SDL_sysjoystick.c	Sat Feb 22 19:10:45 2014 -0800
+++ b/src/joystick/darwin/SDL_sysjoystick.c	Sat Feb 22 21:15:34 2014 -0500
@@ -149,6 +149,17 @@
     CFArrayApplyFunction(array, range, AddHIDElement, pDevice);
 }
 
+static SDL_bool
+ElementAlreadyAdded(const IOHIDElementCookie cookie, const recElement *listitem) {
+    while (listitem) {
+        if (listitem->cookie == cookie) {
+            return SDL_TRUE;
+        }
+        listitem = listitem->pNext;
+    }
+    return SDL_FALSE;
+}
+
 /* See if we care about this HID element, and if so, note it in our recDevice. */
 static void
 AddHIDElement(const void *value, void *parameter)
@@ -158,6 +169,7 @@
     const CFTypeID elementTypeID = refElement ? CFGetTypeID(refElement) : 0;
 
     if (refElement && (elementTypeID == IOHIDElementGetTypeID())) {
+        const IOHIDElementCookie cookie = IOHIDElementGetCookie(refElement);
         const uint32_t usagePage = IOHIDElementGetUsagePage(refElement);
         const uint32_t usage = IOHIDElementGetUsage(refElement);
         recElement *element = NULL;
@@ -180,18 +192,22 @@
                             case kHIDUsage_GD_Slider:
                             case kHIDUsage_GD_Dial:
                             case kHIDUsage_GD_Wheel:
-                                element = (recElement *) SDL_calloc(1, sizeof (recElement));
-                                if (element) {
-                                    pDevice->axes++;
-                                    headElement = &(pDevice->firstAxis);
+                                if (!ElementAlreadyAdded(cookie, pDevice->firstAxis)) {
+                                    element = (recElement *) SDL_calloc(1, sizeof (recElement));
+                                    if (element) {
+                                        pDevice->axes++;
+                                        headElement = &(pDevice->firstAxis);
+                                    }
                                 }
                                 break;
 
                             case kHIDUsage_GD_Hatswitch:
-                                element = (recElement *) SDL_calloc(1, sizeof (recElement));
-                                if (element) {
-                                    pDevice->hats++;
-                                    headElement = &(pDevice->firstHat);
+                                if (!ElementAlreadyAdded(cookie, pDevice->firstHat)) {
+                                    element = (recElement *) SDL_calloc(1, sizeof (recElement));
+                                    if (element) {
+                                        pDevice->hats++;
+                                        headElement = &(pDevice->firstHat);
+                                    }
                                 }
                                 break;
                         }
@@ -201,10 +217,12 @@
                         switch (usage) {
                             case kHIDUsage_Sim_Rudder:
                             case kHIDUsage_Sim_Throttle:
-                                element = (recElement *) SDL_calloc(1, sizeof (recElement));
-                                if (element) {
-                                    pDevice->axes++;
-                                    headElement = &(pDevice->firstAxis);
+                                if (!ElementAlreadyAdded(cookie, pDevice->firstAxis)) {
+                                    element = (recElement *) SDL_calloc(1, sizeof (recElement));
+                                    if (element) {
+                                        pDevice->axes++;
+                                        headElement = &(pDevice->firstAxis);
+                                    }
                                 }
                                 break;
 
@@ -214,10 +232,12 @@
                         break;
 
                     case kHIDPage_Button:
-                        element = (recElement *) SDL_calloc(1, sizeof (recElement));
-                        if (element) {
-                            pDevice->buttons++;
-                            headElement = &(pDevice->firstButton);
+                        if (!ElementAlreadyAdded(cookie, pDevice->firstButton)) {
+                            element = (recElement *) SDL_calloc(1, sizeof (recElement));
+                            if (element) {
+                                pDevice->buttons++;
+                                headElement = &(pDevice->firstButton);
+                            }
                         }
                         break;
 
@@ -227,7 +247,6 @@
             }
             break;
 
-            #if 0  /* !!! FIXME: this causes everything to get added twice on a DualShock 4. */
             case kIOHIDElementTypeCollection: {
                 CFArrayRef array = IOHIDElementGetChildren(refElement);
                 if (array) {
@@ -235,7 +254,6 @@
                 }
             }
             break;
-            #endif
 
             default:
                 break;
@@ -261,6 +279,7 @@
 
             element->minReport = element->min = (SInt32) IOHIDElementGetLogicalMin(refElement);
             element->maxReport = element->max = (SInt32) IOHIDElementGetLogicalMax(refElement);
+            element->cookie = IOHIDElementGetCookie(refElement);
 
             pDevice->elements++;
         }
--- a/src/joystick/darwin/SDL_sysjoystick_c.h	Sat Feb 22 19:10:45 2014 -0800
+++ b/src/joystick/darwin/SDL_sysjoystick_c.h	Sat Feb 22 21:15:34 2014 -0500
@@ -27,6 +27,7 @@
 struct recElement
 {
     IOHIDElementRef elementRef;
+    IOHIDElementCookie cookie;
     uint32_t usagePage, usage;      /* HID usage */
     SInt32 min;                   /* reported min value possible */
     SInt32 max;                   /* reported max value possible */