Commit d1e6a2ebe6a48b50431b20a4a85edfbe36090f0d

Sam Lantinga 2015-12-09T12:11:40

Added broad support for wireless XBox 360 controllers on Linux

diff --git a/src/joystick/SDL_gamecontroller.c b/src/joystick/SDL_gamecontroller.c
index 37e0a8b..be181ca 100644
--- a/src/joystick/SDL_gamecontroller.c
+++ b/src/joystick/SDL_gamecontroller.c
@@ -254,36 +254,6 @@ ControllerMapping_t *SDL_PrivateGetControllerMappingForGUID(SDL_JoystickGUID *gu
     return NULL;
 }
 
-/*
- * Helper function to determine pre-calculated offset to certain joystick mappings
- */
-ControllerMapping_t *SDL_PrivateGetControllerMapping(int device_index)
-{
-    SDL_JoystickGUID jGUID = SDL_JoystickGetDeviceGUID(device_index);
-    ControllerMapping_t *mapping;
-
-    mapping = SDL_PrivateGetControllerMappingForGUID(&jGUID);
-#if SDL_JOYSTICK_XINPUT
-    if (!mapping && SDL_SYS_IsXInputGamepad_DeviceIndex(device_index)) {
-        mapping = s_pXInputMapping;
-    }
-#endif
-#if defined(SDL_JOYSTICK_EMSCRIPTEN)
-    if (!mapping && s_pEmscriptenMapping) {
-        mapping = s_pEmscriptenMapping;
-    }
-#endif
-    if (!mapping) {
-        const char *name = SDL_JoystickNameForIndex(device_index);
-        if (name) {
-            if (SDL_strstr(name, "Xbox") || SDL_strstr(name, "X-Box")) {
-                mapping = s_pXInputMapping;
-            }
-        }
-    }
-    return mapping;
-}
-
 static const char* map_StringForControllerAxis[] = {
     "leftx",
     "lefty",
@@ -581,6 +551,9 @@ char *SDL_PrivateGetControllerMappingFromMappingString(const char *pMapping)
     return SDL_strdup(pSecondComma + 1); /* mapping is everything after the 3rd comma */
 }
 
+/*
+ * Helper function to refresh a mapping
+ */
 void SDL_PrivateGameControllerRefreshMapping(ControllerMapping_t *pControllerMapping)
 {
     SDL_GameController *gamecontrollerlist = SDL_gamecontrollers;
@@ -600,6 +573,102 @@ void SDL_PrivateGameControllerRefreshMapping(ControllerMapping_t *pControllerMap
 }
 
 /*
+ * Helper function to add a mapping for a guid
+ */
+static ControllerMapping_t *
+SDL_PrivateAddMappingForGUID(SDL_JoystickGUID jGUID, const char *mappingString, SDL_bool *existing)
+{
+    char *pchName;
+    char *pchMapping;
+    ControllerMapping_t *pControllerMapping;
+
+    pchName = SDL_PrivateGetControllerNameFromMappingString(mappingString);
+    if (!pchName) {
+        SDL_SetError("Couldn't parse name from %s", mappingString);
+        return NULL;
+    }
+
+    pchMapping = SDL_PrivateGetControllerMappingFromMappingString(mappingString);
+    if (!pchMapping) {
+        SDL_free(pchName);
+        SDL_SetError("Couldn't parse %s", mappingString);
+        return NULL;
+    }
+
+    pControllerMapping = SDL_PrivateGetControllerMappingForGUID(&jGUID);
+    if (pControllerMapping) {
+        /* Update existing mapping */
+        SDL_free(pControllerMapping->name);
+        pControllerMapping->name = pchName;
+        SDL_free(pControllerMapping->mapping);
+        pControllerMapping->mapping = pchMapping;
+        /* refresh open controllers */
+        SDL_PrivateGameControllerRefreshMapping(pControllerMapping);
+        *existing = SDL_TRUE;
+    } else {
+        pControllerMapping = SDL_malloc(sizeof(*pControllerMapping));
+        if (!pControllerMapping) {
+            SDL_free(pchName);
+            SDL_free(pchMapping);
+            SDL_OutOfMemory();
+            return NULL;
+        }
+        pControllerMapping->guid = jGUID;
+        pControllerMapping->name = pchName;
+        pControllerMapping->mapping = pchMapping;
+        pControllerMapping->next = s_pSupportedControllers;
+        s_pSupportedControllers = pControllerMapping;
+        *existing = SDL_FALSE;
+    }
+    return pControllerMapping;
+}
+
+/*
+ * Helper function to determine pre-calculated offset to certain joystick mappings
+ */
+ControllerMapping_t *SDL_PrivateGetControllerMapping(int device_index)
+{
+    SDL_JoystickGUID jGUID = SDL_JoystickGetDeviceGUID(device_index);
+    ControllerMapping_t *mapping;
+
+    mapping = SDL_PrivateGetControllerMappingForGUID(&jGUID);
+#if SDL_JOYSTICK_XINPUT
+    if (!mapping && SDL_SYS_IsXInputGamepad_DeviceIndex(device_index)) {
+        mapping = s_pXInputMapping;
+    }
+#endif
+#if defined(SDL_JOYSTICK_EMSCRIPTEN)
+    if (!mapping && s_pEmscriptenMapping) {
+        mapping = s_pEmscriptenMapping;
+    }
+#endif
+#ifdef __LINUX__
+    if (!mapping) {
+        const char *name = SDL_JoystickNameForIndex(device_index);
+        if (name) {
+            if (SDL_strstr(name, "Xbox 360 Wireless Receiver")) {
+                /* The Linux driver xpad.c maps the wireless dpad to buttons */
+                SDL_bool existing;
+                mapping = SDL_PrivateAddMappingForGUID(jGUID,
+"none,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+                              &existing);
+            }
+        }
+    }
+#endif /* __LINUX__ */
+
+    if (!mapping) {
+        const char *name = SDL_JoystickNameForIndex(device_index);
+        if (name) {
+            if (SDL_strstr(name, "Xbox") || SDL_strstr(name, "X-Box")) {
+                mapping = s_pXInputMapping;
+            }
+        }
+    }
+    return mapping;
+}
+
+/*
  * Add or update an entry into the Mappings Database
  */
 int
@@ -677,12 +746,11 @@ int
 SDL_GameControllerAddMapping(const char *mappingString)
 {
     char *pchGUID;
-    char *pchName;
-    char *pchMapping;
     SDL_JoystickGUID jGUID;
-    ControllerMapping_t *pControllerMapping;
     SDL_bool is_xinput_mapping = SDL_FALSE;
     SDL_bool is_emscripten_mapping = SDL_FALSE;
+    SDL_bool existing = SDL_FALSE;
+    ControllerMapping_t *pControllerMapping;
 
     if (!mappingString) {
         return SDL_InvalidParamError("mappingString");
@@ -701,46 +769,20 @@ SDL_GameControllerAddMapping(const char *mappingString)
     jGUID = SDL_JoystickGetGUIDFromString(pchGUID);
     SDL_free(pchGUID);
 
-    pchName = SDL_PrivateGetControllerNameFromMappingString(mappingString);
-    if (!pchName) {
-        return SDL_SetError("Couldn't parse name from %s", mappingString);
-    }
-
-    pchMapping = SDL_PrivateGetControllerMappingFromMappingString(mappingString);
-    if (!pchMapping) {
-        SDL_free(pchName);
-        return SDL_SetError("Couldn't parse %s", mappingString);
+    pControllerMapping = SDL_PrivateAddMappingForGUID(jGUID, mappingString, &existing);
+    if (!pControllerMapping) {
+        return -1;
     }
 
-    pControllerMapping = SDL_PrivateGetControllerMappingForGUID(&jGUID);
-
-    if (pControllerMapping) {
-        /* Update existing mapping */
-        SDL_free(pControllerMapping->name);
-        pControllerMapping->name = pchName;
-        SDL_free(pControllerMapping->mapping);
-        pControllerMapping->mapping = pchMapping;
-        /* refresh open controllers */
-        SDL_PrivateGameControllerRefreshMapping(pControllerMapping);
+    if (existing) {
         return 0;
     } else {
-        pControllerMapping = SDL_malloc(sizeof(*pControllerMapping));
-        if (!pControllerMapping) {
-            SDL_free(pchName);
-            SDL_free(pchMapping);
-            return SDL_OutOfMemory();
-        }
         if (is_xinput_mapping) {
             s_pXInputMapping = pControllerMapping;
         }
         if (is_emscripten_mapping) {
             s_pEmscriptenMapping = pControllerMapping;
         }
-        pControllerMapping->guid = jGUID;
-        pControllerMapping->name = pchName;
-        pControllerMapping->mapping = pchMapping;
-        pControllerMapping->next = s_pSupportedControllers;
-        s_pSupportedControllers = pControllerMapping;
         return 1;
     }
 }
diff --git a/src/joystick/SDL_gamecontrollerdb.h b/src/joystick/SDL_gamecontrollerdb.h
index 8f42f6b..4f4c124 100644
--- a/src/joystick/SDL_gamecontrollerdb.h
+++ b/src/joystick/SDL_gamecontrollerdb.h
@@ -83,8 +83,6 @@ static const char *s_ControllerMappings [] =
     "050000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
     "03000000de280000fc11000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
     "03000000de280000ff11000001000000,Valve Streaming Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
-    "030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
-    "030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
     "xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
     "030000005e040000d102000001010000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
 #endif