add new gamecontroller APIs
authorEdward Rudd <urkle@outoforder.cc>
Tue, 05 Mar 2013 17:59:36 -0500
changeset 6964c8aa24f05042
parent 6963 4658b1101200
child 6965 ab4bb4e99961
add new gamecontroller APIs

- add mappings after init (or even before w/o using the hint)
- get string for axis
- get string for button
- get mapping string for controller or for GUID
- new event to notify when a controller is remapped. (e.g. mapping was changed via the AddMapping method)
include/SDL_events.h
include/SDL_gamecontroller.h
src/joystick/SDL_gamecontroller.c
     1.1 --- a/include/SDL_events.h	Mon Mar 04 20:27:51 2013 -0800
     1.2 +++ b/include/SDL_events.h	Tue Mar 05 17:59:36 2013 -0500
     1.3 @@ -100,6 +100,7 @@
     1.4  	SDL_CONTROLLERBUTTONUP,            /**< Game controller button released */
     1.5  	SDL_CONTROLLERDEVICEADDED,         /**< A new Game controller has been inserted into the system */
     1.6  	SDL_CONTROLLERDEVICEREMOVED,       /**< An opened Game controller has been removed */
     1.7 +	SDL_CONTROLLERDEVICEREMAPPED,      /**< The controller mapping was updated */
     1.8  
     1.9      /* Touch events */
    1.10      SDL_FINGERDOWN      = 0x700,
    1.11 @@ -358,9 +359,9 @@
    1.12   */
    1.13  typedef struct SDL_ControllerDeviceEvent
    1.14  {
    1.15 -	Uint32 type;        /**< ::SDL_CONTROLLERDEVICEADDED or ::SDL_CONTROLLERDEVICEREMOVED */
    1.16 +	Uint32 type;        /**< ::SDL_CONTROLLERDEVICEADDED, ::SDL_CONTROLLERDEVICEREMOVED, or ::SDL_CONTROLLERDEVICEREMAPPED */
    1.17  	Uint32 timestamp;
    1.18 -	Uint32 which;       /**< The joystick device index for the ADDED event, instance id for the REMOVED event */
    1.19 +	Uint32 which;       /**< The joystick device index for the ADDED event, instance id for the REMOVED or REMAPPED event */
    1.20  } SDL_ControllerDeviceEvent;
    1.21  
    1.22  
    1.23 @@ -484,7 +485,7 @@
    1.24      SDL_JoyHatEvent jhat;           /**< Joystick hat event data */
    1.25      SDL_JoyButtonEvent jbutton;     /**< Joystick button event data */
    1.26      SDL_JoyDeviceEvent jdevice;     /**< Joystick device change event data */
    1.27 -	SDL_ControllerAxisEvent caxis;		/**< Game Controller button event data */
    1.28 +	SDL_ControllerAxisEvent caxis;		/**< Game Controller axis event data */
    1.29  	SDL_ControllerButtonEvent cbutton;  /**< Game Controller button event data */
    1.30  	SDL_ControllerDeviceEvent cdevice;  /**< Game Controller device event data */
    1.31      SDL_QuitEvent quit;             /**< Quit request event data */
     2.1 --- a/include/SDL_gamecontroller.h	Mon Mar 04 20:27:51 2013 -0800
     2.2 +++ b/include/SDL_gamecontroller.h	Tue Mar 05 17:59:36 2013 -0500
     2.3 @@ -90,7 +90,7 @@
     2.4   *		}
     2.5   *  }
     2.6   *
     2.7 - *  Using the SDL_HINT_GAMECONTROLLERCONFIG hint you can add support for controllers SDL is unaware of or cause an existing controller to have a different binding. The format is:
     2.8 + *  Using the SDL_HINT_GAMECONTROLLERCONFIG hint or the SDL_GameControllerAddMapping you can add support for controllers SDL is unaware of or cause an existing controller to have a different binding. The format is:
     2.9   *	guid,name,mappings
    2.10   *
    2.11   *  Where GUID is the string value from SDL_JoystickGetGUIDString(), name is the human readable string for the device and mappings are controller mappings to joystick ones.
    2.12 @@ -106,6 +106,26 @@
    2.13   *
    2.14   */
    2.15  
    2.16 +/**
    2.17 + *  Add or update an existing mapping configuration
    2.18 + *
    2.19 + * \return 1 if mapping is added, 0 if updated, -1 on error
    2.20 + */
    2.21 +extern DECLSPEC int SDLCALL SDL_GameControllerAddMapping( const char* mappingSring );
    2.22 +
    2.23 +/**
    2.24 + *  Get a mapping string for a GUID
    2.25 + *
    2.26 + *  \return the mapping string.  Must be freed with SDL_free.  Returns NULL if no mapping is available
    2.27 + */
    2.28 +extern DECLSPEC char * SDLCALL SDL_GameControllerMappingForGUID( SDL_JoystickGUID guid );
    2.29 +
    2.30 +/**
    2.31 + *  Get a mapping string for an open GameController
    2.32 + *
    2.33 + *  \return the mapping string.  Must be freed with SDL_free.  Returns NULL if no mapping is available
    2.34 + */
    2.35 +extern DECLSPEC char * SDLCALL SDL_GameControllerMapping( SDL_GameController * gamecontroller );
    2.36  
    2.37  /**
    2.38   *  Is the joystick on this index supported by the game controller interface?
    2.39 @@ -187,6 +207,11 @@
    2.40  extern DECLSPEC SDL_GameControllerAxis SDLCALL SDL_GameControllerGetAxisFromString(const char *pchString);
    2.41  
    2.42  /**
    2.43 + *  turn this axis enum into a string mapping
    2.44 + */
    2.45 +extern DECLSPEC const char* SDLCALL SDL_GameControllerGetStringForAxis(SDL_GameControllerAxis axis);
    2.46 +
    2.47 +/**
    2.48   *  Get the SDL joystick layer binding for this controller button mapping
    2.49   */
    2.50  extern DECLSPEC SDL_GameControllerButtonBind SDLCALL
    2.51 @@ -233,6 +258,10 @@
    2.52   */
    2.53  extern DECLSPEC SDL_GameControllerButton SDLCALL SDL_GameControllerGetButtonFromString(const char *pchString);
    2.54  
    2.55 +/**
    2.56 + *  turn this button enum into a string mapping
    2.57 + */
    2.58 +extern DECLSPEC const char* SDLCALL SDL_GameControllerGetStringForButton(SDL_GameControllerButton button);
    2.59  
    2.60  /**
    2.61   *  Get the SDL joystick layer binding for this controller button mapping
     3.1 --- a/src/joystick/SDL_gamecontroller.c	Mon Mar 04 20:27:51 2013 -0800
     3.2 +++ b/src/joystick/SDL_gamecontroller.c	Tue Mar 05 17:59:36 2013 -0500
     3.3 @@ -45,8 +45,10 @@
     3.4  
     3.5  #define k_nMaxReverseEntries 20
     3.6  
     3.7 -// We are encoding the "HAT" as 0xhm. where h == hat ID and m == mask
     3.8 -// MAX 4 hats supported
     3.9 +/**
    3.10 + * We are encoding the "HAT" as 0xhm. where h == hat ID and m == mask
    3.11 + * MAX 4 hats supported
    3.12 + */
    3.13  #define k_nMaxHatEntries 0x3f + 1
    3.14  
    3.15  /* our in memory mapping db between joystick objects and controller mappings*/
    3.16 @@ -79,7 +81,7 @@
    3.17  {
    3.18  	SDL_JoystickGUID guid;
    3.19  	char *name;
    3.20 -	const char *mapping;
    3.21 +	char *mapping;
    3.22  	struct _ControllerMapping_t *next;
    3.23  } ControllerMapping_t;
    3.24  
    3.25 @@ -262,14 +264,27 @@
    3.26  }
    3.27  
    3.28  /*
    3.29 + * Helper function to scan the mappings database for a controller with the specified GUID
    3.30 + */
    3.31 +ControllerMapping_t *SDL_PrivateGetControllerMappingForGUID(SDL_JoystickGUID *guid)
    3.32 +{
    3.33 +	ControllerMapping_t *pSupportedController = s_pSupportedControllers;
    3.34 +	while ( pSupportedController )
    3.35 +	{
    3.36 +		if ( !SDL_memcmp( guid, &pSupportedController->guid, sizeof(*guid) ) )
    3.37 +		{
    3.38 +			return pSupportedController;
    3.39 +		}
    3.40 +		pSupportedController = pSupportedController->next;
    3.41 +	}
    3.42 +        return NULL;
    3.43 +    }
    3.44 +
    3.45 +/*
    3.46   * Helper function to determine pre-caclulated offset to certain joystick mappings
    3.47   */
    3.48  ControllerMapping_t *SDL_PrivateGetControllerMapping(int device_index)
    3.49  {
    3.50 -    if ( (device_index < 0) || (device_index >= SDL_NumJoysticks()) ) {
    3.51 -        return NULL;
    3.52 -    }
    3.53 -
    3.54  #ifdef SDL_JOYSTICK_DINPUT
    3.55  	if ( SDL_SYS_IsXInputDeviceIndex(device_index) && s_pXInputMapping )
    3.56  	{
    3.57 @@ -279,87 +294,98 @@
    3.58  #endif
    3.59  	{
    3.60  		SDL_JoystickGUID jGUID = SDL_JoystickGetDeviceGUID( device_index );
    3.61 -		ControllerMapping_t *pSupportedController = s_pSupportedControllers;
    3.62 -		while ( pSupportedController )
    3.63 -		{
    3.64 -			if ( !SDL_memcmp( &jGUID, &pSupportedController->guid, sizeof(jGUID) ) )
    3.65 -			{
    3.66 -				return pSupportedController;
    3.67 -			}
    3.68 -			pSupportedController = pSupportedController->next;
    3.69 -		}
    3.70 +		return SDL_PrivateGetControllerMappingForGUID(&jGUID);
    3.71  	}
    3.72  
    3.73  	return NULL;
    3.74  }
    3.75  
    3.76 +static const char* map_StringForControllerAxis[] = {
    3.77 +    "leftx",
    3.78 +    "lefty",
    3.79 +    "rightx",
    3.80 +    "righty",
    3.81 +    "lefttrigger",
    3.82 +    "righttrigger",
    3.83 +    NULL
    3.84 +};
    3.85 +
    3.86  /*
    3.87   * convert a string to its enum equivalent
    3.88   */
    3.89  SDL_GameControllerAxis SDL_GameControllerGetAxisFromString( const char *pchString )
    3.90  {
    3.91 +    int entry;
    3.92  	if ( !pchString || !pchString[0] )
    3.93  		return SDL_CONTROLLER_AXIS_INVALID;
    3.94  
    3.95 -	if ( !SDL_strcasecmp( pchString, "leftx" ) )
    3.96 -		return SDL_CONTROLLER_AXIS_LEFTX;
    3.97 -	else if ( !SDL_strcasecmp( pchString, "lefty" ) )
    3.98 -		return SDL_CONTROLLER_AXIS_LEFTY;
    3.99 -	else if ( !SDL_strcasecmp( pchString, "rightx" ) )
   3.100 -		return SDL_CONTROLLER_AXIS_RIGHTX;
   3.101 -	else if ( !SDL_strcasecmp( pchString, "righty" ) )
   3.102 -		return SDL_CONTROLLER_AXIS_RIGHTY;
   3.103 -	else if ( !SDL_strcasecmp( pchString, "lefttrigger" ) )
   3.104 -		return SDL_CONTROLLER_AXIS_TRIGGERLEFT;
   3.105 -	else if ( !SDL_strcasecmp( pchString, "righttrigger" ) )
   3.106 -		return SDL_CONTROLLER_AXIS_TRIGGERRIGHT;
   3.107 -	else
   3.108 +    for ( entry = 0; map_StringForControllerAxis[entry]; ++entry)
   3.109 +    {
   3.110 +        if ( !SDL_strcasecmp( pchString, map_StringForControllerAxis[entry] ) )
   3.111 +            return entry;
   3.112 +    }
   3.113  		return SDL_CONTROLLER_AXIS_INVALID;
   3.114  }
   3.115  
   3.116 +/*
   3.117 + * convert an enum to its string equivalent
   3.118 + */
   3.119 +const char* SDL_GameControllerGetStringForAxis( SDL_GameControllerAxis axis )
   3.120 +{
   3.121 +    if (axis > SDL_CONTROLLER_AXIS_INVALID && axis < SDL_CONTROLLER_AXIS_MAX)
   3.122 +    {
   3.123 +        return map_StringForControllerAxis[axis];
   3.124 +    }
   3.125 +    return NULL;
   3.126 +}
   3.127 +
   3.128 +static const char* map_StringForControllerButton[] = {
   3.129 +    "a",
   3.130 +    "b",
   3.131 +    "x",
   3.132 +    "y",
   3.133 +    "back",
   3.134 +    "guide",
   3.135 +    "start",
   3.136 +    "leftstick",
   3.137 +    "rightstick",
   3.138 +    "leftshoulder",
   3.139 +    "rightshoulder",
   3.140 +    "dpup",
   3.141 +    "dpdown",
   3.142 +    "dpleft",
   3.143 +    "dpright",
   3.144 +    NULL
   3.145 +};
   3.146  
   3.147  /*
   3.148   * convert a string to its enum equivalent
   3.149   */
   3.150  SDL_GameControllerButton SDL_GameControllerGetButtonFromString( const char *pchString )
   3.151  {
   3.152 +    int entry;
   3.153  	if ( !pchString || !pchString[0] )
   3.154  		return SDL_CONTROLLER_BUTTON_INVALID;
   3.155  
   3.156 -	if ( !SDL_strcasecmp( pchString, "a" ) )
   3.157 -		return SDL_CONTROLLER_BUTTON_A;
   3.158 -	else if ( !SDL_strcasecmp( pchString, "b" ) )
   3.159 -		return SDL_CONTROLLER_BUTTON_B;
   3.160 -	else if ( !SDL_strcasecmp( pchString, "x" ) )
   3.161 -		return SDL_CONTROLLER_BUTTON_X;
   3.162 -	else if ( !SDL_strcasecmp( pchString, "y" ) )
   3.163 -		return SDL_CONTROLLER_BUTTON_Y;
   3.164 -	else if ( !SDL_strcasecmp( pchString, "start" ) )
   3.165 -		return SDL_CONTROLLER_BUTTON_START;
   3.166 -	else if ( !SDL_strcasecmp( pchString, "guide" ) )
   3.167 -		return SDL_CONTROLLER_BUTTON_GUIDE;
   3.168 -	else if ( !SDL_strcasecmp( pchString, "back" ) )
   3.169 -		return SDL_CONTROLLER_BUTTON_BACK;
   3.170 -	else if ( !SDL_strcasecmp( pchString, "dpup" ) )
   3.171 -		return SDL_CONTROLLER_BUTTON_DPAD_UP;
   3.172 -	else if ( !SDL_strcasecmp( pchString, "dpdown" ) )
   3.173 -		return SDL_CONTROLLER_BUTTON_DPAD_DOWN;
   3.174 -	else if ( !SDL_strcasecmp( pchString, "dpleft" ) )
   3.175 -		return SDL_CONTROLLER_BUTTON_DPAD_LEFT;
   3.176 -	else if ( !SDL_strcasecmp( pchString, "dpright" ) )
   3.177 -		return SDL_CONTROLLER_BUTTON_DPAD_RIGHT;
   3.178 -	else if ( !SDL_strcasecmp( pchString, "leftshoulder" ) )
   3.179 -		return SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
   3.180 -	else if ( !SDL_strcasecmp( pchString, "rightshoulder" ) )
   3.181 -		return SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
   3.182 -	else if ( !SDL_strcasecmp( pchString, "leftstick" ) )
   3.183 -		return SDL_CONTROLLER_BUTTON_LEFTSTICK;
   3.184 -	else if ( !SDL_strcasecmp( pchString, "rightstick" ) )
   3.185 -		return SDL_CONTROLLER_BUTTON_RIGHTSTICK;
   3.186 -	else
   3.187 -		return SDL_CONTROLLER_BUTTON_INVALID;
   3.188 +    for ( entry = 0; map_StringForControllerButton[entry]; ++entry)
   3.189 +	{
   3.190 +		if ( !SDL_strcasecmp( pchString, map_StringForControllerButton[entry] ) )
   3.191 +		return entry;
   3.192 +	}
   3.193 +	return SDL_CONTROLLER_BUTTON_INVALID;
   3.194  }
   3.195  
   3.196 +/*
   3.197 + * convert an enum to its string equivalent
   3.198 + */
   3.199 +const char* SDL_GameControllerGetStringForButton( SDL_GameControllerButton axis )
   3.200 +{
   3.201 +    if (axis > SDL_CONTROLLER_BUTTON_INVALID && axis < SDL_CONTROLLER_BUTTON_MAX)
   3.202 +    {
   3.203 +        return map_StringForControllerButton[axis];
   3.204 +    }
   3.205 +    return NULL;
   3.206 +}
   3.207  
   3.208  /*
   3.209   * given a controller button name and a joystick name update our mapping structure with it
   3.210 @@ -602,7 +628,7 @@
   3.211  /*
   3.212   * grab the button mapping string from a mapping string
   3.213   */
   3.214 -const char *SDL_PrivateGetControllerMappingFromMappingString( const char *pMapping )
   3.215 +char *SDL_PrivateGetControllerMappingFromMappingString( const char *pMapping )
   3.216  {
   3.217  	const char *pFirstComma, *pSecondComma;
   3.218  
   3.219 @@ -614,9 +640,126 @@
   3.220      if ( !pSecondComma )
   3.221          return NULL;
   3.222  
   3.223 -    return pSecondComma + 1; /* mapping is everything after the 3rd comma, no need to malloc it */
   3.224 +    return SDL_strdup(pSecondComma + 1); /* mapping is everything after the 3rd comma */
   3.225  }
   3.226  
   3.227 +void SDL_PrivateGameControllerRefreshMapping( ControllerMapping_t *pControllerMapping )
   3.228 +{
   3.229 +    SDL_GameController *gamecontrollerlist = SDL_gamecontrollers;
   3.230 +    while ( gamecontrollerlist )
   3.231 +    {
   3.232 +        if ( !SDL_memcmp( &gamecontrollerlist->mapping.guid, &pControllerMapping->guid, sizeof(pControllerMapping->guid) ) )
   3.233 +        {
   3.234 +            SDL_Event event;
   3.235 +            event.type = SDL_CONTROLLERDEVICEREMAPPED;
   3.236 +            event.cdevice.which = gamecontrollerlist->joystick->instance_id;
   3.237 +            SDL_PushEvent(&event);
   3.238 +            
   3.239 +            // Not really threadsafe.  Should this lock access within SDL_GameControllerEventWatcher?
   3.240 +            SDL_PrivateLoadButtonMapping(&gamecontrollerlist->mapping, pControllerMapping->guid, pControllerMapping->name, pControllerMapping->mapping);
   3.241 +        }
   3.242 +        
   3.243 +        gamecontrollerlist = gamecontrollerlist->next;
   3.244 +    }
   3.245 +}
   3.246 +
   3.247 +/*
   3.248 + * Add or update an entry into the Mappings Database
   3.249 + */
   3.250 +int
   3.251 +SDL_GameControllerAddMapping( const char *mappingString )
   3.252 +{
   3.253 +	char *pchGUID;
   3.254 +	char *pchName;
   3.255 +	char *pchMapping;
   3.256 +    SDL_JoystickGUID jGUID;
   3.257 +    ControllerMapping_t *pControllerMapping;
   3.258 +#ifdef SDL_JOYSTICK_DINPUT
   3.259 +    SDL_bool is_xinput_mapping = SDL_FALSE;
   3.260 +#endif
   3.261 +
   3.262 +	pchGUID = SDL_PrivateGetControllerGUIDFromMappingString( mappingString );
   3.263 +	if (!pchGUID) return -1;
   3.264 +#ifdef SDL_JOYSTICK_DINPUT
   3.265 +    if ( !SDL_strcasecmp( pchGUID, "xinput" ) ) {
   3.266 +        is_xinput_mapping = SDL_TRUE;
   3.267 +    }
   3.268 +#endif
   3.269 +    SDL_free(pchGUID);
   3.270 +
   3.271 +	jGUID = SDL_JoystickGetGUIDFromString(pchGUID);
   3.272 +
   3.273 +	pControllerMapping = SDL_PrivateGetControllerMappingForGUID(&jGUID);
   3.274 +
   3.275 +	pchName = SDL_PrivateGetControllerNameFromMappingString( mappingString );
   3.276 +	if (!pchName) return -1;
   3.277 +
   3.278 +	pchMapping = SDL_PrivateGetControllerMappingFromMappingString( mappingString );
   3.279 +	if (!pchMapping) {
   3.280 +		SDL_free( pchName );
   3.281 +		return -1;
   3.282 +	}
   3.283 +
   3.284 +	if (pControllerMapping) {
   3.285 +		// Update existing mapping
   3.286 +		SDL_free( pControllerMapping->name );
   3.287 +		pControllerMapping->name = pchName;
   3.288 +		SDL_free( pControllerMapping->mapping );
   3.289 +		pControllerMapping->mapping = pchMapping;
   3.290 +		// refresh open controllers
   3.291 +		SDL_PrivateGameControllerRefreshMapping( pControllerMapping );
   3.292 +		return 0;
   3.293 +	} else {
   3.294 +		pControllerMapping = SDL_malloc( sizeof(*pControllerMapping) );
   3.295 +		if (!pControllerMapping) {
   3.296 +			SDL_OutOfMemory();
   3.297 +			SDL_free( pchName );
   3.298 +			SDL_free( pchMapping );
   3.299 +			return -1;
   3.300 +		}
   3.301 +#ifdef SDL_JOYSTICK_DINPUT
   3.302 +		if ( is_xinput_mapping )
   3.303 +		{
   3.304 +			s_pXInputMapping = pControllerMapping;
   3.305 +		}
   3.306 +#endif
   3.307 +		pControllerMapping->guid = jGUID;
   3.308 +		pControllerMapping->name = pchName;
   3.309 +		pControllerMapping->mapping = pchMapping;
   3.310 +		pControllerMapping->next = s_pSupportedControllers;
   3.311 +		s_pSupportedControllers = pControllerMapping;
   3.312 +		return 1;
   3.313 +	}
   3.314 +}
   3.315 +
   3.316 +/*
   3.317 + * Get the mapping string for this GUID
   3.318 + */
   3.319 +char *
   3.320 +SDL_GameControllerMappingForGUID( SDL_JoystickGUID guid )
   3.321 +{
   3.322 +	char *pMappingString = NULL;
   3.323 +	ControllerMapping_t *mapping = SDL_PrivateGetControllerMappingForGUID(&guid);
   3.324 +	if (mapping) {
   3.325 +		char pchGUID[33];
   3.326 +        size_t needed;
   3.327 +		SDL_JoystickGetGUIDString(guid, pchGUID, sizeof(pchGUID));
   3.328 +		// allocate enough memory for GUID + ',' + name + ',' + mapping + \0
   3.329 +		needed = SDL_strlen(pchGUID) + 1 + SDL_strlen(mapping->name) + 1 + SDL_strlen(mapping->mapping) + 1;
   3.330 +		pMappingString = SDL_malloc( needed );
   3.331 +		SDL_snprintf( pMappingString, needed, "%s,%s,%s", pchGUID, mapping->name, mapping->mapping );
   3.332 +	}
   3.333 +	return pMappingString;
   3.334 +}
   3.335 +
   3.336 +/*
   3.337 + * Get the mapping string for this device
   3.338 + */
   3.339 +char *
   3.340 +SDL_GameControllerMapping( SDL_GameController * gamecontroller )
   3.341 +{
   3.342 +	return SDL_GameControllerMappingForGUID( gamecontroller->mapping.guid );
   3.343 +}
   3.344  
   3.345  /*
   3.346   * Initialize the game controller system, mostly load our DB of controller config mappings
   3.347 @@ -630,36 +773,7 @@
   3.348  	pMappingString = s_ControllerMappings[i];
   3.349  	while ( pMappingString )
   3.350  	{
   3.351 -		ControllerMapping_t *pControllerMapping;
   3.352 -		char *pchGUID;
   3.353 -		char *pchName;
   3.354 -		const char *pchMapping;
   3.355 -		pControllerMapping = SDL_malloc( sizeof(*pControllerMapping) );
   3.356 -		if ( !pControllerMapping )
   3.357 -		{
   3.358 -			SDL_OutOfMemory();
   3.359 -			return -1;
   3.360 -		}
   3.361 -
   3.362 -		pchGUID = SDL_PrivateGetControllerGUIDFromMappingString( pMappingString );
   3.363 -		pchName = SDL_PrivateGetControllerNameFromMappingString( pMappingString );
   3.364 -		pchMapping = SDL_PrivateGetControllerMappingFromMappingString( pMappingString );
   3.365 -		if ( pchGUID && pchName )
   3.366 -		{
   3.367 -#ifdef SDL_JOYSTICK_DINPUT
   3.368 -			if ( !SDL_strcasecmp( pchGUID, "xinput" ) )
   3.369 -			{
   3.370 -				s_pXInputMapping = pControllerMapping;
   3.371 -			}
   3.372 -#endif
   3.373 -			pControllerMapping->guid = SDL_JoystickGetGUIDFromString( pchGUID );
   3.374 -			pControllerMapping->name = pchName;
   3.375 -			pControllerMapping->mapping = pchMapping;
   3.376 -			pControllerMapping->next = s_pSupportedControllers;
   3.377 -			s_pSupportedControllers = pControllerMapping;
   3.378 -
   3.379 -			SDL_free( pchGUID );
   3.380 -		}
   3.381 +		SDL_GameControllerAddMapping( pMappingString );
   3.382  
   3.383  		i++;
   3.384  		pMappingString = s_ControllerMappings[i];
   3.385 @@ -671,54 +785,25 @@
   3.386  		if ( hint && hint[0] )
   3.387  		{
   3.388  			int nchHints = SDL_strlen( hint );
   3.389 -			char *pUserMappings = SDL_malloc( nchHints + 1 ); /* FIXME: memory leak, but we can't free it in this function because pchMapping below points into this memory */
   3.390 -			SDL_memcpy( pUserMappings, hint, nchHints + 1 );
   3.391 +			char *pUserMappings = SDL_malloc( nchHints + 1 );
   3.392 +			char *pTempMappings = pUserMappings;
   3.393 +			SDL_memcpy( pUserMappings, hint, nchHints );
   3.394  			while ( pUserMappings )
   3.395  			{
   3.396 -				char *pchGUID;
   3.397 -				char *pchName;
   3.398 -				const char *pchMapping;
   3.399  				char *pchNewLine = NULL;
   3.400 -				ControllerMapping_t *pControllerMapping;
   3.401  
   3.402  				pchNewLine = SDL_strchr( pUserMappings, '\n' );
   3.403  				if ( pchNewLine )
   3.404  					*pchNewLine = '\0';
   3.405  
   3.406 -				pControllerMapping = SDL_malloc( sizeof(*pControllerMapping) );
   3.407 -				if ( !pControllerMapping )
   3.408 -				{
   3.409 -					SDL_OutOfMemory();
   3.410 -					return -1;
   3.411 -				}
   3.412 -
   3.413 -				pchGUID = SDL_PrivateGetControllerGUIDFromMappingString( pUserMappings );
   3.414 -				pchName = SDL_PrivateGetControllerNameFromMappingString( pUserMappings );
   3.415 -				pchMapping = SDL_PrivateGetControllerMappingFromMappingString( pUserMappings );
   3.416 -
   3.417 -				if ( pchGUID && pchName )
   3.418 -				{
   3.419 -#ifdef SDL_JOYSTICK_DINPUT
   3.420 -					if ( !SDL_strcasecmp( pchGUID, "xinput" ) )
   3.421 -					{
   3.422 -						s_pXInputMapping = pControllerMapping;
   3.423 -					}
   3.424 -#endif
   3.425 -
   3.426 -					pControllerMapping->guid = SDL_JoystickGetGUIDFromString( pchGUID );
   3.427 -					pControllerMapping->name = pchName;
   3.428 -					pControllerMapping->mapping = pchMapping;
   3.429 -					pControllerMapping->next = s_pSupportedControllers;
   3.430 -					s_pSupportedControllers = pControllerMapping;
   3.431 -
   3.432 -					SDL_free( pchGUID );
   3.433 -				}
   3.434 +				SDL_GameControllerAddMapping( pUserMappings );
   3.435  
   3.436  				if ( pchNewLine )
   3.437  					pUserMappings = pchNewLine + 1;
   3.438  				else
   3.439  					pUserMappings = NULL;
   3.440  			}
   3.441 +			SDL_free(pTempMappings);
   3.442  		}
   3.443  	}
   3.444  
   3.445 @@ -1133,7 +1218,7 @@
   3.446  #else
   3.447      const Uint32 event_list[] = {
   3.448          SDL_CONTROLLERAXISMOTION, SDL_CONTROLLERBUTTONDOWN, SDL_CONTROLLERBUTTONUP,
   3.449 -        SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEREMOVED,
   3.450 +        SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEREMOVED, SDL_CONTROLLERDEVICEREMAPPED,
   3.451      };
   3.452      unsigned int i;
   3.453