Просмотр исходного кода

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.
Ryan C. Gordon 12 лет назад
Родитель
Сommit
b67b970db1
2 измененных файлов с 38 добавлено и 18 удалено
  1. 37 18
      src/joystick/darwin/SDL_sysjoystick.c
  2. 1 0
      src/joystick/darwin/SDL_sysjoystick_c.h

+ 37 - 18
src/joystick/darwin/SDL_sysjoystick.c

@@ -149,6 +149,17 @@ AddHIDElements(CFArrayRef array, recDevice *pDevice)
     CFArrayApplyFunction(array, range, AddHIDElement, pDevice);
     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. */
 /* See if we care about this HID element, and if so, note it in our recDevice. */
 static void
 static void
 AddHIDElement(const void *value, void *parameter)
 AddHIDElement(const void *value, void *parameter)
@@ -158,6 +169,7 @@ AddHIDElement(const void *value, void *parameter)
     const CFTypeID elementTypeID = refElement ? CFGetTypeID(refElement) : 0;
     const CFTypeID elementTypeID = refElement ? CFGetTypeID(refElement) : 0;
 
 
     if (refElement && (elementTypeID == IOHIDElementGetTypeID())) {
     if (refElement && (elementTypeID == IOHIDElementGetTypeID())) {
+        const IOHIDElementCookie cookie = IOHIDElementGetCookie(refElement);
         const uint32_t usagePage = IOHIDElementGetUsagePage(refElement);
         const uint32_t usagePage = IOHIDElementGetUsagePage(refElement);
         const uint32_t usage = IOHIDElementGetUsage(refElement);
         const uint32_t usage = IOHIDElementGetUsage(refElement);
         recElement *element = NULL;
         recElement *element = NULL;
@@ -180,18 +192,22 @@ AddHIDElement(const void *value, void *parameter)
                             case kHIDUsage_GD_Slider:
                             case kHIDUsage_GD_Slider:
                             case kHIDUsage_GD_Dial:
                             case kHIDUsage_GD_Dial:
                             case kHIDUsage_GD_Wheel:
                             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;
                                 break;
 
 
                             case kHIDUsage_GD_Hatswitch:
                             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;
                                 break;
                         }
                         }
@@ -201,10 +217,12 @@ AddHIDElement(const void *value, void *parameter)
                         switch (usage) {
                         switch (usage) {
                             case kHIDUsage_Sim_Rudder:
                             case kHIDUsage_Sim_Rudder:
                             case kHIDUsage_Sim_Throttle:
                             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;
                                 break;
 
 
@@ -214,10 +232,12 @@ AddHIDElement(const void *value, void *parameter)
                         break;
                         break;
 
 
                     case kHIDPage_Button:
                     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;
                         break;
 
 
@@ -227,7 +247,6 @@ AddHIDElement(const void *value, void *parameter)
             }
             }
             break;
             break;
 
 
-            #if 0  /* !!! FIXME: this causes everything to get added twice on a DualShock 4. */
             case kIOHIDElementTypeCollection: {
             case kIOHIDElementTypeCollection: {
                 CFArrayRef array = IOHIDElementGetChildren(refElement);
                 CFArrayRef array = IOHIDElementGetChildren(refElement);
                 if (array) {
                 if (array) {
@@ -235,7 +254,6 @@ AddHIDElement(const void *value, void *parameter)
                 }
                 }
             }
             }
             break;
             break;
-            #endif
 
 
             default:
             default:
                 break;
                 break;
@@ -261,6 +279,7 @@ AddHIDElement(const void *value, void *parameter)
 
 
             element->minReport = element->min = (SInt32) IOHIDElementGetLogicalMin(refElement);
             element->minReport = element->min = (SInt32) IOHIDElementGetLogicalMin(refElement);
             element->maxReport = element->max = (SInt32) IOHIDElementGetLogicalMax(refElement);
             element->maxReport = element->max = (SInt32) IOHIDElementGetLogicalMax(refElement);
+            element->cookie = IOHIDElementGetCookie(refElement);
 
 
             pDevice->elements++;
             pDevice->elements++;
         }
         }

+ 1 - 0
src/joystick/darwin/SDL_sysjoystick_c.h

@@ -27,6 +27,7 @@
 struct recElement
 struct recElement
 {
 {
     IOHIDElementRef elementRef;
     IOHIDElementRef elementRef;
+    IOHIDElementCookie cookie;
     uint32_t usagePage, usage;      /* HID usage */
     uint32_t usagePage, usage;      /* HID usage */
     SInt32 min;                   /* reported min value possible */
     SInt32 min;                   /* reported min value possible */
     SInt32 max;                   /* reported max value possible */
     SInt32 max;                   /* reported max value possible */