Fixed bug 3079 - Allow non destructive SDL_GameControllerAddMappingsFromFile
authorSam Lantinga <slouken@libsdl.org>
Fri, 11 Nov 2016 13:29:23 -0800
changeset 106058a059b7b01c4
parent 10604 27d0fb08d755
child 10606 c7209688838b
Fixed bug 3079 - Allow non destructive SDL_GameControllerAddMappingsFromFile

x414e54

It is a bit of a pain to update the library or rely on whatever version the user has on their computer for default mappings.

So providing an easily updatable text file via SDL_GameControllerAddMappingsFromFile is still currently the most viable way. However using this replaces all mappings provided by the SDL_HINT_GAMECONTROLLERCONFIG environment variable which may have come from the user's custom Steam mapping.

There should be an easy way for games to supply extra game controller mappings to fill in the differences between SDL versions without it clobbering the SDL_HINT_GAMECONTROLLERCONFIG environment variable.

Internally the mappings could use a priority system and if the priority is lower then it will not overwrite the mappings.

For now it just assumes SDL_HINT_GAMECONTROLLERCONFIG is the highest priority, the default hardcoded are the lowest and anything set via the API is medium.
src/joystick/SDL_gamecontroller.c
     1.1 --- a/src/joystick/SDL_gamecontroller.c	Fri Nov 11 13:14:00 2016 -0800
     1.2 +++ b/src/joystick/SDL_gamecontroller.c	Fri Nov 11 13:29:23 2016 -0800
     1.3 @@ -80,11 +80,19 @@
     1.4  
     1.5  
     1.6  /* our hard coded list of mapping support */
     1.7 +typedef enum
     1.8 +{
     1.9 +    SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT,
    1.10 +    SDL_CONTROLLER_MAPPING_PRIORITY_API,
    1.11 +    SDL_CONTROLLER_MAPPING_PRIORITY_USER,
    1.12 +} SDL_ControllerMappingPriority;
    1.13 +
    1.14  typedef struct _ControllerMapping_t
    1.15  {
    1.16      SDL_JoystickGUID guid;
    1.17      char *name;
    1.18      char *mapping;
    1.19 +    SDL_ControllerMappingPriority priority;
    1.20      struct _ControllerMapping_t *next;
    1.21  } ControllerMapping_t;
    1.22  
    1.23 @@ -636,7 +644,7 @@
    1.24   * Helper function to add a mapping for a guid
    1.25   */
    1.26  static ControllerMapping_t *
    1.27 -SDL_PrivateAddMappingForGUID(SDL_JoystickGUID jGUID, const char *mappingString, SDL_bool *existing)
    1.28 +SDL_PrivateAddMappingForGUID(SDL_JoystickGUID jGUID, const char *mappingString, SDL_bool *existing, SDL_ControllerMappingPriority priority)
    1.29  {
    1.30      char *pchName;
    1.31      char *pchMapping;
    1.32 @@ -657,13 +665,17 @@
    1.33  
    1.34      pControllerMapping = SDL_PrivateGetControllerMappingForGUID(&jGUID);
    1.35      if (pControllerMapping) {
    1.36 -        /* Update existing mapping */
    1.37 -        SDL_free(pControllerMapping->name);
    1.38 -        pControllerMapping->name = pchName;
    1.39 -        SDL_free(pControllerMapping->mapping);
    1.40 -        pControllerMapping->mapping = pchMapping;
    1.41 -        /* refresh open controllers */
    1.42 -        SDL_PrivateGameControllerRefreshMapping(pControllerMapping);
    1.43 +        /* Only overwrite the mapping if the priority is the same or higher. */
    1.44 +        if (pControllerMapping->priority <= priority) {
    1.45 +            /* Update existing mapping */
    1.46 +            SDL_free(pControllerMapping->name);
    1.47 +            pControllerMapping->name = pchName;
    1.48 +            SDL_free(pControllerMapping->mapping);
    1.49 +            pControllerMapping->mapping = pchMapping;
    1.50 +            pControllerMapping->priority = priority;
    1.51 +            /* refresh open controllers */
    1.52 +            SDL_PrivateGameControllerRefreshMapping(pControllerMapping);
    1.53 +        }
    1.54          *existing = SDL_TRUE;
    1.55      } else {
    1.56          pControllerMapping = SDL_malloc(sizeof(*pControllerMapping));
    1.57 @@ -677,6 +689,7 @@
    1.58          pControllerMapping->name = pchName;
    1.59          pControllerMapping->mapping = pchMapping;
    1.60          pControllerMapping->next = s_pSupportedControllers;
    1.61 +        pControllerMapping->priority = priority;
    1.62          s_pSupportedControllers = pControllerMapping;
    1.63          *existing = SDL_FALSE;
    1.64      }
    1.65 @@ -711,7 +724,7 @@
    1.66                  SDL_bool existing;
    1.67                  mapping = SDL_PrivateAddMappingForGUID(jGUID,
    1.68  "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,",
    1.69 -                              &existing);
    1.70 +                              &existing, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT);
    1.71              }
    1.72          }
    1.73      }
    1.74 @@ -800,10 +813,10 @@
    1.75  }
    1.76  
    1.77  /*
    1.78 - * Add or update an entry into the Mappings Database
    1.79 + * Add or update an entry into the Mappings Database with a priority
    1.80   */
    1.81 -int
    1.82 -SDL_GameControllerAddMapping(const char *mappingString)
    1.83 +static int
    1.84 +SDL_PrivateGameControllerAddMapping(const char *mappingString, SDL_ControllerMappingPriority priority)
    1.85  {
    1.86      char *pchGUID;
    1.87      SDL_JoystickGUID jGUID;
    1.88 @@ -829,7 +842,7 @@
    1.89      jGUID = SDL_JoystickGetGUIDFromString(pchGUID);
    1.90      SDL_free(pchGUID);
    1.91  
    1.92 -    pControllerMapping = SDL_PrivateAddMappingForGUID(jGUID, mappingString, &existing);
    1.93 +    pControllerMapping = SDL_PrivateAddMappingForGUID(jGUID, mappingString, &existing, priority);
    1.94      if (!pControllerMapping) {
    1.95          return -1;
    1.96      }
    1.97 @@ -848,6 +861,15 @@
    1.98  }
    1.99  
   1.100  /*
   1.101 + * Add or update an entry into the Mappings Database
   1.102 + */
   1.103 +int
   1.104 +SDL_GameControllerAddMapping(const char *mappingString)
   1.105 +{
   1.106 +    return SDL_PrivateGameControllerAddMapping(mappingString, SDL_CONTROLLER_MAPPING_PRIORITY_API);
   1.107 +}
   1.108 +
   1.109 +/*
   1.110   * Get the mapping string for this GUID
   1.111   */
   1.112  char *
   1.113 @@ -901,7 +923,7 @@
   1.114              if (pchNewLine)
   1.115                  *pchNewLine = '\0';
   1.116  
   1.117 -            SDL_GameControllerAddMapping(pUserMappings);
   1.118 +            SDL_PrivateGameControllerAddMapping(pUserMappings, SDL_CONTROLLER_MAPPING_PRIORITY_USER);
   1.119  
   1.120              if (pchNewLine) {
   1.121                  pUserMappings = pchNewLine + 1;
   1.122 @@ -923,7 +945,7 @@
   1.123      const char *pMappingString = NULL;
   1.124      pMappingString = s_ControllerMappings[i];
   1.125      while (pMappingString) {
   1.126 -        SDL_GameControllerAddMapping(pMappingString);
   1.127 +        SDL_PrivateGameControllerAddMapping(pMappingString, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT);
   1.128  
   1.129          i++;
   1.130          pMappingString = s_ControllerMappings[i];