Commit dd5d85a4e7bd571b38178d42427a78a962c310a1

Sam Lantinga 2016-11-29T06:36:57

Added an API to iterate over game controller mappings

diff --git a/include/SDL_gamecontroller.h b/include/SDL_gamecontroller.h
index 96d64e0..56051a8 100644
--- a/include/SDL_gamecontroller.h
+++ b/include/SDL_gamecontroller.h
@@ -136,6 +136,20 @@ extern DECLSPEC int SDLCALL SDL_GameControllerAddMappingsFromRW(SDL_RWops * rw, 
 extern DECLSPEC int SDLCALL SDL_GameControllerAddMapping(const char* mappingString);
 
 /**
+ *  Get the number of mappings installed
+ *
+ *  \return the number of mappings
+ */
+extern DECLSPEC int SDLCALL SDL_GameControllerNumMappings();
+
+/**
+ *  Get the mapping at a particular index.
+ *
+ *  \return the mapping string.  Must be freed with SDL_free().  Returns NULL if the index is out of range.
+ */
+extern DECLSPEC char * SDLCALL SDL_GameControllerMappingForIndex(int mapping_index);
+
+/**
  *  Get a mapping string for a GUID
  *
  *  \return the mapping string.  Must be freed with SDL_free().  Returns NULL if no mapping is available
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index 3b02257..2e20661 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -622,3 +622,5 @@
 #define SDL_GameControllerGetProduct SDL_GameControllerGetProduct_REAL
 #define SDL_GameControllerGetProductVersion SDL_GameControllerGetProductVersion_REAL
 #define SDL_HasNEON SDL_HasNEON_REAL
+#define SDL_GameControllerNumMappings SDL_GameControllerNumMappings_REAL
+#define SDL_GameControllerMappingForIndex SDL_GameControllerMappingForIndex_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index b225d2a..d6a2ea2 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -654,3 +654,5 @@ SDL_DYNAPI_PROC(Uint16,SDL_GameControllerGetVendor,(SDL_GameController *a),(a),r
 SDL_DYNAPI_PROC(Uint16,SDL_GameControllerGetProduct,(SDL_GameController *a),(a),return)
 SDL_DYNAPI_PROC(Uint16,SDL_GameControllerGetProductVersion,(SDL_GameController *a),(a),return)
 SDL_DYNAPI_PROC(SDL_bool,SDL_HasNEON,(void),(),return)
+SDL_DYNAPI_PROC(int,SDL_GameControllerNumMappings,(void),(),return)
+SDL_DYNAPI_PROC(char*,SDL_GameControllerMappingForIndex,(int a),(a),return)
diff --git a/src/joystick/SDL_gamecontroller.c b/src/joystick/SDL_gamecontroller.c
index f8c5ad7..3d9d967 100644
--- a/src/joystick/SDL_gamecontroller.c
+++ b/src/joystick/SDL_gamecontroller.c
@@ -96,6 +96,7 @@ typedef struct _ControllerMapping_t
     struct _ControllerMapping_t *next;
 } ControllerMapping_t;
 
+static SDL_JoystickGUID s_zeroGUID;
 static ControllerMapping_t *s_pSupportedControllers = NULL;
 static ControllerMapping_t *s_pXInputMapping = NULL;
 static ControllerMapping_t *s_pEmscriptenMapping = NULL;
@@ -872,6 +873,57 @@ SDL_GameControllerAddMapping(const char *mappingString)
     return SDL_PrivateGameControllerAddMapping(mappingString, SDL_CONTROLLER_MAPPING_PRIORITY_API);
 }
 
+/**
+ *  Get the number of mappings installed
+ */
+int
+SDL_GameControllerNumMappings()
+{
+    int num_mappings = 0;
+    ControllerMapping_t *mapping;
+
+    for (mapping = s_pSupportedControllers; mapping; mapping = mapping->next) {
+        if (SDL_memcmp(&mapping->guid, &s_zeroGUID, sizeof(mapping->guid)) == 0) {
+            continue;
+        }
+        ++num_mappings;
+    }
+    return num_mappings;
+}
+
+/**
+ *  Get the mapping at a particular index.
+ */
+char *
+SDL_GameControllerMappingForIndex(int mapping_index)
+{
+    ControllerMapping_t *mapping;
+
+    for (mapping = s_pSupportedControllers; mapping; mapping = mapping->next) {
+        if (SDL_memcmp(&mapping->guid, &s_zeroGUID, sizeof(mapping->guid)) == 0) {
+            continue;
+        }
+        if (mapping_index == 0) {
+            char *pMappingString;
+            char pchGUID[33];
+            size_t needed;
+
+            SDL_JoystickGetGUIDString(mapping->guid, pchGUID, sizeof(pchGUID));
+            /* allocate enough memory for GUID + ',' + name + ',' + mapping + \0 */
+            needed = SDL_strlen(pchGUID) + 1 + SDL_strlen(mapping->name) + 1 + SDL_strlen(mapping->mapping) + 1;
+            pMappingString = SDL_malloc(needed);
+            if (!pMappingString) {
+                SDL_OutOfMemory();
+                return NULL;
+            }
+            SDL_snprintf(pMappingString, needed, "%s,%s,%s", pchGUID, mapping->name, mapping->mapping);
+            return pMappingString;
+        }
+        --mapping_index;
+    }
+    return NULL;
+}
+
 /*
  * Get the mapping string for this GUID
  */
diff --git a/test/testgamecontroller.c b/test/testgamecontroller.c
index 34785d5..bd63565 100644
--- a/test/testgamecontroller.c
+++ b/test/testgamecontroller.c
@@ -259,6 +259,17 @@ main(int argc, char *argv[])
     
     SDL_GameControllerAddMappingsFromFile("gamecontrollerdb.txt");
 
+    /* Print information about the mappings */
+    SDL_Log("Supported mappings:\n");
+    for (i = 0; i < SDL_GameControllerNumMappings(); ++i) {
+        char *mapping = SDL_GameControllerMappingForIndex(i);
+        if (mapping) {
+            SDL_Log("\t%s\n", mapping);
+            SDL_free(mapping);
+        }
+    }
+    SDL_Log("\n");
+
     /* Print information about the controller */
     for (i = 0; i < SDL_NumJoysticks(); ++i) {
         const char *name;