src/joystick/SDL_gamecontroller.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 25 Jan 2013 14:25:19 -0800
changeset 6823 e9d312d26979
parent 6738 b408d5a406a3
child 6841 90bba8d8e42a
permissions -rw-r--r--
Fixed crash when the game controller mapping hint is set - the hint was duplicated and not null terminated.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "SDL_config.h"
    22 
    23 /* This is the game controller API for Simple DirectMedia Layer */
    24 
    25 #include "SDL_events.h"
    26 #include "SDL_assert.h"
    27 #include "SDL_sysjoystick.h"
    28 #include "SDL_hints.h"
    29 
    30 #if !SDL_EVENTS_DISABLED
    31 #include "../events/SDL_events_c.h"
    32 #endif
    33 #define ABS(_x) ((_x) < 0 ? -(_x) : (_x))
    34 
    35 
    36 /* a list of currently opened game controllers */
    37 static SDL_GameController *SDL_gamecontrollers = NULL;
    38 
    39 /* keep track of the hat and mask value that transforms this hat movement into a button press */
    40 struct _SDL_HatAsButton
    41 {
    42 	int hat;
    43 	Uint8 mask;
    44 };
    45 
    46 #define k_nMaxReverseEntries 20
    47 
    48 /* our in memory mapping db between joystick objects and controller mappings*/
    49 struct _SDL_ControllerMapping
    50 {
    51 	SDL_JoystickGUID guid;
    52 	const char *name;
    53 
    54 	// mapping of axis/button id to controller version
    55 	int axes[SDL_CONTROLLER_AXIS_MAX];
    56 	int buttons[SDL_CONTROLLER_BUTTON_MAX];
    57 
    58 	int axesasbutton[SDL_CONTROLLER_BUTTON_MAX];
    59 	struct _SDL_HatAsButton hatasbutton[SDL_CONTROLLER_BUTTON_MAX];
    60 	int buttonasaxis[SDL_CONTROLLER_AXIS_MAX];
    61 
    62 	// reverse mapping, joystick indices to buttons
    63 	SDL_CONTROLLER_AXIS raxes[k_nMaxReverseEntries];
    64 	SDL_CONTROLLER_BUTTON rbuttons[k_nMaxReverseEntries];
    65 	SDL_CONTROLLER_BUTTON raxesasbutton[k_nMaxReverseEntries];
    66 	struct _SDL_HatAsButton rhatasbutton[k_nMaxReverseEntries];
    67 	SDL_CONTROLLER_AXIS rbuttonasaxis[k_nMaxReverseEntries];
    68 };
    69 
    70 
    71 /* our hard coded list of mapping support */
    72 typedef struct _ControllerMapping_t
    73 {
    74 	SDL_JoystickGUID guid;
    75 	char *name;
    76 	const char *mapping;
    77 	struct _ControllerMapping_t *next;
    78 } ControllerMapping_t;
    79 
    80 
    81 /* default mappings we support */
    82 const char *s_ControllerMappings [] =
    83 {
    84 #ifdef SDL_JOYSTICK_DINPUT
    85 	"xinput,X360 Controller,a:b10,b:b11,y:b13,x:b12,start:b4,guide:b14,back:b5,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftshoulder:b8,rightshoulder:b9,leftstick:b6,rightstick:b7,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5",
    86 	"341a3608000000000000504944564944,Afterglow PS3 Controller,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7",
    87 	"88880803000000000000504944564944,PS3,a:b2,b:b1,x:b0,y:b3,start:b11,back:b8,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.4,dpdown:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b6,righttrigger:b7,guide:b12",
    88 	"25090500000000000000504944564944,PS3 DualShock,a:b2,b:b1,x:b0,y:b3,start:b8,guide:,back:b9,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.4,dpdown:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5",
    89 #elif defined(__MACOSX__)
    90 	"5e040000000000008e02000000000000,X360 Controller,a:b0,b:b1,y:b3,x:b2,start:b8,guide:b10,back:b9,dpup:b11,dpleft:b13,dpdown:b12,dpright:b14,leftshoulder:b4,rightshoulder:b5,leftstick:b6,rightstick:b7,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5",
    91 	"4c050000000000006802000000000000,PS3 Controller,a:b14,b:b13,x:b12,y:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b6,dpdown:b7,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9",
    92 #elif defined(__LINUX__)
    93 	
    94 #endif
    95 	NULL
    96 };
    97 
    98 static ControllerMapping_t *s_pSupportedControllers = NULL;
    99 #ifdef SDL_JOYSTICK_DINPUT
   100 static ControllerMapping_t *s_pXInputMapping = NULL;
   101 #endif
   102 
   103 /* The SDL game controller structure */
   104 struct _SDL_GameController
   105 {
   106 	SDL_Joystick *joystick;	/* underlying joystick device */
   107 	int ref_count;
   108 	struct _SDL_ControllerMapping mapping; /* the mapping object for this controller */
   109 	struct _SDL_GameController *next; /* pointer to next game controller we have allocated */
   110 };
   111 
   112 
   113 int SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_CONTROLLER_AXIS axis, Sint16 value);
   114 int	SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_CONTROLLER_BUTTON button, Uint8 state);
   115 
   116 /*
   117  * Event filter to fire controller events from joystick ones
   118  */
   119 int SDL_GameControllerEventWatcher(void *userdata, SDL_Event * event)
   120 {
   121 	switch( event->type )
   122 	{
   123 	case SDL_JOYAXISMOTION:
   124 		{
   125 			SDL_GameController *controllerlist = SDL_gamecontrollers;
   126 			while ( controllerlist )
   127 			{
   128 				if ( controllerlist->joystick->instance_id == event->jaxis.which )
   129 				{
   130 					if ( controllerlist->mapping.raxes[event->jaxis.axis] >= 0 ) // simple axis to axis, send it through
   131 					{
   132 						SDL_PrivateGameControllerAxis( controllerlist, controllerlist->mapping.raxes[event->jaxis.axis], event->jaxis.value );
   133 					}
   134 					else if ( controllerlist->mapping.raxesasbutton[event->jaxis.axis] >= 0 ) // simlate an axis as a button
   135 					{
   136 						SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.raxesasbutton[event->jaxis.axis], ABS(event->jaxis.value) > 32768/2 ? 1 : 0 );
   137 					}
   138 					break;
   139 				}
   140 				controllerlist = controllerlist->next;
   141 			}
   142 		}
   143 		break;
   144 	case SDL_JOYBUTTONDOWN:
   145 	case SDL_JOYBUTTONUP:
   146 		{
   147 			SDL_GameController *controllerlist = SDL_gamecontrollers;
   148 			while ( controllerlist )
   149 			{
   150 				if ( controllerlist->joystick->instance_id == event->jbutton.which )
   151 				{
   152 					if ( controllerlist->mapping.rbuttons[event->jbutton.button] >= 0 ) // simple button as button
   153 					{
   154 						SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rbuttons[event->jbutton.button], event->jbutton.state );
   155 					}
   156 					else if ( controllerlist->mapping.rbuttonasaxis[event->jbutton.button] >= 0 ) // an button pretending to be an axis
   157 					{
   158 						SDL_PrivateGameControllerAxis( controllerlist, controllerlist->mapping.rbuttonasaxis[event->jbutton.button], event->jbutton.state > 0 ? 32768 : 0 );
   159 					}
   160 					break;
   161 				}
   162 				controllerlist = controllerlist->next;
   163 			}
   164 		}
   165 		break;
   166 	case SDL_JOYHATMOTION:
   167 		{
   168 			if ( event->jhat.hat == 0 ) // BUGBUG - multiple hat support??
   169 			{
   170 				SDL_GameController *controllerlist = SDL_gamecontrollers;
   171 				while ( controllerlist )
   172 				{
   173 					if ( controllerlist->joystick->instance_id == event->jhat.which )
   174 					{
   175 						static Uint8 bHatsDown = 0;
   176 						if ( event->jhat.value == 0 )
   177 						{
   178 							if ( bHatsDown & SDL_HAT_DOWN )
   179 								SDL_PrivateGameControllerButton( controllerlist, SDL_CONTROLLER_BUTTON_DPAD_DOWN, 0 );
   180 							if ( bHatsDown & SDL_HAT_UP )
   181 								SDL_PrivateGameControllerButton( controllerlist, SDL_CONTROLLER_BUTTON_DPAD_UP, 0 );
   182 							if ( bHatsDown & SDL_HAT_LEFT )
   183 								SDL_PrivateGameControllerButton( controllerlist, SDL_CONTROLLER_BUTTON_DPAD_LEFT, 0 );
   184 							if ( bHatsDown & SDL_HAT_RIGHT )
   185 								SDL_PrivateGameControllerButton( controllerlist, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, 0 );
   186 							bHatsDown = 0;
   187 						}
   188 						else if ( controllerlist->mapping.rhatasbutton[event->jhat.value].hat >= 0 )
   189 						{
   190 							bHatsDown |= event->jhat.value;
   191 							SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[event->jhat.value].hat, (event->jhat.value & controllerlist->mapping.rhatasbutton[event->jhat.value].mask) > 0 ? 1 : 0 );
   192 						}
   193 						break;
   194 					}
   195 					controllerlist = controllerlist->next;
   196 				}
   197 			}
   198 		}
   199 		break;
   200 	case SDL_JOYDEVICEADDED:
   201 		{
   202 			if ( SDL_IsGameController(event->jdevice.which ) )
   203 			{
   204 				SDL_Event deviceevent;
   205 				deviceevent.type = SDL_CONTROLLERDEVICEADDED;
   206 				deviceevent.cdevice.which = event->jdevice.which;
   207 				SDL_PushEvent(&deviceevent);
   208 			}
   209 		}
   210 		break;
   211 	case SDL_JOYDEVICEREMOVED:
   212 		{
   213 			SDL_GameController *controllerlist = SDL_gamecontrollers;
   214 			while ( controllerlist )
   215 			{
   216 				if ( controllerlist->joystick->instance_id == event->jdevice.which )
   217 				{
   218 					SDL_Event deviceevent;
   219 					deviceevent.type = SDL_CONTROLLERDEVICEREMOVED;
   220 					deviceevent.cdevice.which = event->jdevice.which;
   221 					SDL_PushEvent(&deviceevent);
   222 					break;
   223 				}
   224 				controllerlist = controllerlist->next;
   225 			}
   226 		}
   227 		break;
   228 	default:
   229 		break;
   230 	}
   231 
   232 	return 1;
   233 }
   234 
   235 /*
   236  * Helper function to determine pre-caclulated offset to certain joystick mappings
   237  */
   238 ControllerMapping_t *SDL_PrivateGetControllerMapping(int device_index)
   239 {
   240 #ifdef SDL_JOYSTICK_DINPUT
   241 	if ( SDL_SYS_IsXInputDeviceIndex(device_index) && s_pXInputMapping )
   242 	{
   243 		return s_pXInputMapping;
   244 	}
   245 #endif
   246 	return NULL;
   247 }
   248 
   249 
   250 /*
   251  * convert a string to its enum equivalent
   252  */
   253 SDL_CONTROLLER_AXIS SDL_GameControllerGetAxisFromString( const char *pchString )
   254 {
   255 	if ( !pchString || !pchString[0] )
   256 		return SDL_CONTROLLER_AXIS_INVALID;
   257 
   258 	if ( !SDL_strcasecmp( pchString, "leftx" ) )
   259 		return SDL_CONTROLLER_AXIS_LEFTX;
   260 	else if ( !SDL_strcasecmp( pchString, "lefty" ) )
   261 		return SDL_CONTROLLER_AXIS_LEFTY;
   262 	else if ( !SDL_strcasecmp( pchString, "rightx" ) )
   263 		return SDL_CONTROLLER_AXIS_RIGHTX;
   264 	else if ( !SDL_strcasecmp( pchString, "righty" ) )
   265 		return SDL_CONTROLLER_AXIS_RIGHTY;
   266 	else if ( !SDL_strcasecmp( pchString, "lefttrigger" ) )
   267 		return SDL_CONTROLLER_AXIS_TRIGGERLEFT;
   268 	else if ( !SDL_strcasecmp( pchString, "righttrigger" ) )
   269 		return SDL_CONTROLLER_AXIS_TRIGGERRIGHT;
   270 	else
   271 		return SDL_CONTROLLER_AXIS_INVALID;
   272 }
   273 
   274 
   275 /*
   276  * convert a string to its enum equivalent
   277  */
   278 SDL_CONTROLLER_BUTTON SDL_GameControllerGetButtonFromString( const char *pchString )
   279 {
   280 	if ( !pchString || !pchString[0] )
   281 		return SDL_CONTROLLER_BUTTON_INVALID;
   282 
   283 	if ( !SDL_strcasecmp( pchString, "a" ) )
   284 		return SDL_CONTROLLER_BUTTON_A;
   285 	else if ( !SDL_strcasecmp( pchString, "b" ) )
   286 		return SDL_CONTROLLER_BUTTON_B;
   287 	else if ( !SDL_strcasecmp( pchString, "x" ) )
   288 		return SDL_CONTROLLER_BUTTON_X;
   289 	else if ( !SDL_strcasecmp( pchString, "y" ) )
   290 		return SDL_CONTROLLER_BUTTON_Y;
   291 	else if ( !SDL_strcasecmp( pchString, "start" ) )
   292 		return SDL_CONTROLLER_BUTTON_START;
   293 	else if ( !SDL_strcasecmp( pchString, "guide" ) )
   294 		return SDL_CONTROLLER_BUTTON_GUIDE;
   295 	else if ( !SDL_strcasecmp( pchString, "back" ) )
   296 		return SDL_CONTROLLER_BUTTON_BACK;
   297 	else if ( !SDL_strcasecmp( pchString, "dpup" ) )
   298 		return SDL_CONTROLLER_BUTTON_DPAD_UP;
   299 	else if ( !SDL_strcasecmp( pchString, "dpdown" ) )
   300 		return SDL_CONTROLLER_BUTTON_DPAD_DOWN;
   301 	else if ( !SDL_strcasecmp( pchString, "dpleft" ) )
   302 		return SDL_CONTROLLER_BUTTON_DPAD_LEFT;
   303 	else if ( !SDL_strcasecmp( pchString, "dpright" ) )
   304 		return SDL_CONTROLLER_BUTTON_DPAD_RIGHT;
   305 	else if ( !SDL_strcasecmp( pchString, "leftshoulder" ) )
   306 		return SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
   307 	else if ( !SDL_strcasecmp( pchString, "rightshoulder" ) )
   308 		return SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
   309 	else if ( !SDL_strcasecmp( pchString, "leftstick" ) )
   310 		return SDL_CONTROLLER_BUTTON_LEFTSTICK;
   311 	else if ( !SDL_strcasecmp( pchString, "rightstick" ) )
   312 		return SDL_CONTROLLER_BUTTON_RIGHTSTICK;
   313 	else
   314 		return SDL_CONTROLLER_BUTTON_INVALID;
   315 }
   316 
   317 
   318 /*
   319  * given a controller button name and a joystick name update our mapping structure with it
   320  */
   321 void SDL_PrivateGameControllerParseButton( const char *szGameButton, const char *szJoystickButton, struct _SDL_ControllerMapping *pMapping )
   322 {
   323 	int iSDLButton = 0;
   324 	SDL_CONTROLLER_BUTTON button;
   325 	SDL_CONTROLLER_AXIS axis;
   326 	button = SDL_GameControllerGetButtonFromString( szGameButton );
   327 	axis = SDL_GameControllerGetAxisFromString( szGameButton );
   328 	iSDLButton = SDL_atoi( &szJoystickButton[1] );
   329 
   330 	if ( iSDLButton >= k_nMaxReverseEntries )
   331 	{
   332 		SDL_SetError("Button index too large: %d", iSDLButton );
   333 		return;
   334 	}
   335 
   336 	if ( szJoystickButton[0] == 'a' )
   337 	{
   338 		if ( axis != SDL_CONTROLLER_AXIS_INVALID )
   339 		{
   340 			pMapping->axes[ axis ] = iSDLButton;
   341 			pMapping->raxes[ iSDLButton ] = axis;
   342 		}
   343 		else if ( button != SDL_CONTROLLER_BUTTON_INVALID )
   344 		{
   345 			pMapping->buttonasaxis[ button ] = iSDLButton;
   346 			pMapping->rbuttonasaxis[ iSDLButton ] = button;
   347 		}
   348 		else
   349 		{
   350 			SDL_assert( !"How did we get here?" );
   351 		}
   352 
   353 	}
   354 	else if ( szJoystickButton[0] == 'b' )
   355 	{
   356 		if ( button != SDL_CONTROLLER_BUTTON_INVALID )
   357 		{
   358 			pMapping->buttons[ button ] = iSDLButton;
   359 			pMapping->rbuttons[ iSDLButton ] = button;
   360 		}
   361 		else if ( axis != SDL_CONTROLLER_AXIS_INVALID )
   362 		{
   363 			pMapping->buttonasaxis[ axis ] = iSDLButton;
   364 			pMapping->rbuttonasaxis[ iSDLButton ] = axis;
   365 		}
   366 		else
   367 		{
   368 			SDL_assert( !"How did we get here?" );
   369 		}
   370 	}
   371 	else if ( szJoystickButton[0] == 'h' )
   372 	{
   373 		int hat = SDL_atoi( &szJoystickButton[1] );
   374 		int mask = SDL_atoi( &szJoystickButton[3] );
   375 
   376 		if ( button != SDL_CONTROLLER_BUTTON_INVALID )
   377 		{
   378 			pMapping->hatasbutton[ button ].hat = hat;
   379 			pMapping->hatasbutton[ button ].mask = mask;
   380 			pMapping->rhatasbutton[ mask ].hat = button;
   381 			pMapping->rhatasbutton[ mask ].mask = mask;
   382 		}
   383 		else if ( axis != SDL_CONTROLLER_AXIS_INVALID )
   384 		{
   385 			SDL_assert( !"Support hat as axis" );
   386 		}
   387 		else
   388 		{
   389 			SDL_assert( !"How did we get here?" );
   390 		}
   391 	}
   392 
   393 }
   394 
   395 
   396 /*
   397  * given a controller mapping string update our mapping object
   398  */
   399 static void
   400 SDL_PrivateGameControllerParseControllerConfigString( struct _SDL_ControllerMapping *pMapping, const char *pchString )
   401 {
   402 	char szGameButton[20];
   403 	char szJoystickButton[20];
   404 	SDL_bool bGameButton = SDL_TRUE;
   405 	int i = 0;
   406 	const char *pchPos = pchString;
   407 
   408 	SDL_memset( szGameButton, 0x0, sizeof(szGameButton) );
   409 	SDL_memset( szJoystickButton, 0x0, sizeof(szJoystickButton) );
   410 
   411 	while ( pchPos && *pchPos )
   412 	{
   413 		if ( *pchPos == ':' )
   414 		{
   415 			i = 0;
   416 			bGameButton = SDL_FALSE;
   417 		}
   418 		else if ( *pchPos == ' ' )
   419 		{
   420 
   421 		}
   422 		else if ( *pchPos == ',' )
   423 		{
   424 			i = 0;
   425 			bGameButton = SDL_TRUE;
   426 			SDL_PrivateGameControllerParseButton( szGameButton, szJoystickButton, pMapping );
   427 			SDL_memset( szGameButton, 0x0, sizeof(szGameButton) );
   428 			SDL_memset( szJoystickButton, 0x0, sizeof(szJoystickButton) );
   429 
   430 		}
   431 		else if ( bGameButton )
   432 		{
   433 			if ( i >=  sizeof(szGameButton))
   434 			{
   435 				SDL_SetError( "Button name too large: %s", szGameButton );
   436 				return;
   437 			}
   438 			szGameButton[i] = *pchPos;
   439 			i++;
   440 		}
   441 		else
   442 		{
   443 			if ( i >=  sizeof(szJoystickButton))
   444 			{
   445 				SDL_SetError( "Joystick button name too large: %s", szJoystickButton );
   446 				return;
   447 			}
   448 			szJoystickButton[i] = *pchPos;
   449 			i++;
   450 		}
   451 		pchPos++;
   452 	}
   453 
   454 	SDL_PrivateGameControllerParseButton( szGameButton, szJoystickButton, pMapping );
   455 
   456 }
   457 
   458 /*
   459  * Make a new button mapping struct
   460  */
   461 void SDL_PrivateLoadButtonMapping( struct _SDL_ControllerMapping *pMapping, SDL_JoystickGUID guid, const char *pchName, const char *pchMapping )
   462 {
   463 	int j;
   464 
   465 	pMapping->guid = guid;
   466 	pMapping->name = pchName;
   467 
   468 	// set all the button mappings to non defaults
   469 	for ( j = 0; j < SDL_CONTROLLER_AXIS_MAX; j++ )
   470 	{
   471 		pMapping->axes[j] = -1;
   472 		pMapping->buttonasaxis[j] = -1;
   473 	}
   474 	for ( j = 0; j < SDL_CONTROLLER_BUTTON_MAX; j++ )
   475 	{
   476 		pMapping->buttons[j] = -1;
   477 		pMapping->axesasbutton[j] = -1;
   478 		pMapping->hatasbutton[j].hat = -1;
   479 	}
   480 
   481 	for ( j = 0; j < k_nMaxReverseEntries; j++ )
   482 	{
   483 		pMapping->raxes[j] = SDL_CONTROLLER_AXIS_INVALID;
   484 		pMapping->rbuttons[j] = SDL_CONTROLLER_BUTTON_INVALID;
   485 		pMapping->raxesasbutton[j] = SDL_CONTROLLER_BUTTON_INVALID;
   486 		pMapping->rhatasbutton[j].hat = -1;
   487 		pMapping->rbuttonasaxis[j] = SDL_CONTROLLER_AXIS_INVALID;
   488 	}
   489 
   490 	SDL_PrivateGameControllerParseControllerConfigString( pMapping, pchMapping );
   491 }
   492 
   493 
   494 /*
   495  * grab the guid string from a mapping string
   496  */
   497 char *SDL_PrivateGetControllerGUIDFromMappingString( const char *pMapping )
   498 {
   499 	const char *pFirstComma = SDL_strchr( pMapping, ',' );
   500 	if ( pFirstComma )
   501 	{
   502 		char *pchGUID = SDL_malloc( pFirstComma - pMapping + 1 );
   503 		if ( !pchGUID )
   504 		{
   505 			SDL_OutOfMemory();
   506 			return NULL;
   507 		}
   508 		SDL_memcpy( pchGUID, pMapping, pFirstComma - pMapping );
   509 		pchGUID[ pFirstComma - pMapping ] = 0;
   510 		return pchGUID;
   511 	}
   512 	return NULL;
   513 }
   514 
   515 
   516 /*
   517  * grab the name string from a mapping string
   518  */
   519 char *SDL_PrivateGetControllerNameFromMappingString( const char *pMapping )
   520 {
   521 	const char *pFirstComma, *pSecondComma;
   522     char *pchName;
   523 
   524     pFirstComma = SDL_strchr( pMapping, ',' );
   525     if ( !pFirstComma )
   526         return NULL;
   527 
   528 	pSecondComma = SDL_strchr( pFirstComma + 1, ',' );
   529     if ( !pSecondComma )
   530         return NULL;
   531 
   532     pchName = SDL_malloc( pSecondComma - pFirstComma );
   533     if ( !pchName )
   534     {
   535         SDL_OutOfMemory();
   536         return NULL;
   537     }
   538     SDL_memcpy( pchName, pFirstComma + 1, pSecondComma - pFirstComma );
   539     pchName[ pSecondComma - pFirstComma - 1 ] = 0;
   540     return pchName;
   541 }
   542 
   543 
   544 /*
   545  * grab the button mapping string from a mapping string
   546  */
   547 const char *SDL_PrivateGetControllerMappingFromMappingString( const char *pMapping )
   548 {
   549 	const char *pFirstComma, *pSecondComma;
   550 
   551     pFirstComma = SDL_strchr( pMapping, ',' );
   552     if ( !pFirstComma )
   553         return NULL;
   554 
   555 	pSecondComma = SDL_strchr( pFirstComma + 1, ',' );
   556     if ( !pSecondComma )
   557         return NULL;
   558 
   559     return pSecondComma + 1; /* mapping is everything after the 3rd comma, no need to malloc it */
   560 }
   561 
   562 
   563 /*
   564  * Initialize the game controller system, mostly load our DB of controller config mappings
   565  */
   566 int
   567 SDL_GameControllerInit(void)
   568 {
   569 	int i = 0;
   570 	const char *pMappingString = NULL;
   571 	s_pSupportedControllers = NULL;
   572 	pMappingString = s_ControllerMappings[i];
   573 	while ( pMappingString )
   574 	{
   575 		ControllerMapping_t *pControllerMapping;
   576 		char *pchGUID;
   577 		char *pchName;
   578 		const char *pchMapping;
   579 		pControllerMapping = SDL_malloc( sizeof(*pControllerMapping) );
   580 		if ( !pControllerMapping )
   581 		{
   582 			SDL_OutOfMemory();
   583 			return -1;
   584 		}
   585 
   586 		pchGUID = SDL_PrivateGetControllerGUIDFromMappingString( pMappingString );
   587 		pchName = SDL_PrivateGetControllerNameFromMappingString( pMappingString );
   588 		pchMapping = SDL_PrivateGetControllerMappingFromMappingString( pMappingString );
   589 		if ( pchGUID && pchName )
   590 		{
   591 #ifdef SDL_JOYSTICK_DINPUT
   592 			if ( !SDL_strcasecmp( pchGUID, "xinput" ) )
   593 			{
   594 				s_pXInputMapping = pControllerMapping;
   595 			}
   596 #endif
   597 			pControllerMapping->guid = SDL_JoystickGetGUIDFromString( pchGUID );
   598 			pControllerMapping->name = pchName;
   599 			pControllerMapping->mapping = pchMapping;
   600 			pControllerMapping->next = s_pSupportedControllers;
   601 			s_pSupportedControllers = pControllerMapping;
   602 
   603 			SDL_free( pchGUID );
   604 		}
   605 
   606 		i++;
   607 		pMappingString = s_ControllerMappings[i];
   608 	}
   609 
   610 	// load in any user supplied config
   611 	{
   612 		const char *hint = SDL_GetHint(SDL_HINT_GAMECONTROLLERCONFIG);
   613 		if ( hint && hint[0] )
   614 		{
   615 			int nchHints = SDL_strlen( hint );
   616 			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 */
   617 			SDL_memcpy( pUserMappings, hint, nchHints + 1 );
   618 			while ( pUserMappings )
   619 			{
   620 				char *pchGUID;
   621 				char *pchName;
   622 				const char *pchMapping;
   623 				char *pchNewLine = NULL;
   624 				ControllerMapping_t *pControllerMapping;
   625 
   626 				pchNewLine = SDL_strchr( pUserMappings, '\n' );
   627 				if ( pchNewLine )
   628 					*pchNewLine = '\0';
   629 
   630 				pControllerMapping = SDL_malloc( sizeof(*pControllerMapping) );
   631 				if ( !pControllerMapping )
   632 				{
   633 					SDL_OutOfMemory();
   634 					return -1;
   635 				}
   636 
   637 				pchGUID = SDL_PrivateGetControllerGUIDFromMappingString( pUserMappings );
   638 				pchName = SDL_PrivateGetControllerNameFromMappingString( pUserMappings );
   639 				pchMapping = SDL_PrivateGetControllerMappingFromMappingString( pUserMappings );
   640 
   641 				if ( pchGUID && pchName )
   642 				{
   643 #ifdef SDL_JOYSTICK_DINPUT
   644 					if ( !SDL_strcasecmp( pchGUID, "xinput" ) )
   645 					{
   646 						s_pXInputMapping = pControllerMapping;
   647 					}
   648 #endif
   649 
   650 					pControllerMapping->guid = SDL_JoystickGetGUIDFromString( pchGUID );
   651 					pControllerMapping->name = pchName;
   652 					pControllerMapping->mapping = pchMapping;
   653 					pControllerMapping->next = s_pSupportedControllers;
   654 					s_pSupportedControllers = pControllerMapping;
   655 
   656 					SDL_free( pchGUID );
   657 				}
   658 
   659 				if ( pchNewLine )
   660 					pUserMappings = pchNewLine + 1;
   661 				else
   662 					pUserMappings = NULL;
   663 			}
   664 		}
   665 	}
   666 
   667 	/* watch for joy events and fire controller ones if needed */
   668 	SDL_AddEventWatch( SDL_GameControllerEventWatcher, NULL );
   669 	return (0);
   670 }
   671 
   672 
   673 /*
   674  * Get the implementation dependent name of a controller
   675  */
   676 const char *
   677 SDL_GameControllerNameForIndex(int device_index)
   678 {
   679 	ControllerMapping_t *pSupportedController =  SDL_PrivateGetControllerMapping(device_index);
   680 	if ( pSupportedController )
   681 	{
   682 		return pSupportedController->name;
   683 	}
   684 	else
   685 	{
   686 		SDL_JoystickGUID jGUID = SDL_JoystickGetDeviceGUID( device_index );
   687 		pSupportedController = s_pSupportedControllers;
   688 		while ( pSupportedController )
   689 		{
   690 			if ( !SDL_memcmp( &jGUID, &pSupportedController->guid, sizeof(jGUID) ) )
   691 			{
   692 				return pSupportedController->name;
   693 			}
   694 			pSupportedController = pSupportedController->next;
   695 		}
   696 	}
   697     return NULL;
   698 }
   699 
   700 
   701 /*
   702  * Return 1 if the joystick at this device index is a supported controller
   703  */
   704 int SDL_IsGameController(int device_index)
   705 {
   706 	ControllerMapping_t *pSupportedController =  SDL_PrivateGetControllerMapping(device_index);
   707 	if ( pSupportedController )
   708 	{
   709 		return 1;
   710 	}
   711 	else
   712 	{
   713 		SDL_JoystickGUID jGUID = SDL_JoystickGetDeviceGUID( device_index );
   714 		pSupportedController = s_pSupportedControllers;
   715 		// debug code to help get the guid string for a new joystick
   716 		/* char szGUID[33];
   717 		SDL_JoystickGetGUIDString( jGUID, szGUID, sizeof(szGUID) );
   718 		printf( "%s\n", pchGUID );
   719 		SDL_free( pchGUID );*/
   720 		while ( pSupportedController )
   721 		{
   722 			if ( !SDL_memcmp( &jGUID, &pSupportedController->guid, sizeof(jGUID) ) )
   723 			{
   724 				return 1;
   725 			}
   726 			pSupportedController = pSupportedController->next;
   727 		}
   728 	}
   729 	return 0;
   730 }
   731 
   732 /*
   733  * Open a controller for use - the index passed as an argument refers to
   734  * the N'th controller on the system.  This index is the value which will
   735  * identify this controller in future controller events.
   736  *
   737  * This function returns a controller identifier, or NULL if an error occurred.
   738  */
   739 SDL_GameController *
   740 SDL_GameControllerOpen(int device_index)
   741 {
   742     SDL_GameController *gamecontroller;
   743 	SDL_GameController *gamecontrollerlist;
   744 	ControllerMapping_t *pSupportedController = NULL;
   745 
   746     if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
   747         SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
   748         return (NULL);
   749     }
   750 
   751 	gamecontrollerlist = SDL_gamecontrollers;
   752     // If the controller is already open, return it 
   753 	while ( gamecontrollerlist )
   754 	{
   755 		if ( SDL_SYS_GetInstanceIdOfDeviceIndex(device_index) == gamecontrollerlist->joystick->instance_id ) {
   756 				gamecontroller = gamecontrollerlist;
   757 				++gamecontroller->ref_count;
   758 				return (gamecontroller);
   759 		}
   760 		gamecontrollerlist = gamecontrollerlist->next;
   761     }
   762 
   763     // Create and initialize the joystick 
   764     gamecontroller = (SDL_GameController *) SDL_malloc((sizeof *gamecontroller));
   765     if (gamecontroller == NULL) {
   766         SDL_OutOfMemory();
   767         return NULL;
   768     }
   769 
   770 	pSupportedController =  SDL_PrivateGetControllerMapping(device_index);
   771 	if ( !pSupportedController )
   772 	{
   773 		SDL_JoystickGUID jGUID;
   774 
   775 		jGUID = SDL_JoystickGetDeviceGUID( device_index );
   776 		pSupportedController = s_pSupportedControllers;
   777 		while ( pSupportedController )
   778 		{
   779 			if ( !SDL_memcmp( &jGUID, &pSupportedController->guid, sizeof(jGUID) ) )
   780 			{
   781 				break;
   782 			}
   783 
   784 			pSupportedController = pSupportedController->next;
   785 		}
   786 	}
   787 
   788 	if ( !pSupportedController )
   789 	{
   790 		SDL_SetError("Couldn't find mapping for device (%d)", device_index );
   791 		return (NULL);
   792 	}
   793 
   794     SDL_memset(gamecontroller, 0, (sizeof *gamecontroller));
   795     gamecontroller->joystick = SDL_JoystickOpen(device_index);
   796 	if ( !gamecontroller->joystick ) {
   797         SDL_free(gamecontroller);
   798         return NULL;
   799     }
   800 
   801 	SDL_PrivateLoadButtonMapping( &gamecontroller->mapping, pSupportedController->guid, pSupportedController->name, pSupportedController->mapping );
   802 
   803     // Add joystick to list 
   804     ++gamecontroller->ref_count;
   805 	// Link the joystick in the list 
   806 	gamecontroller->next = SDL_gamecontrollers;
   807 	SDL_gamecontrollers = gamecontroller;
   808 
   809 	SDL_SYS_JoystickUpdate( gamecontroller->joystick );
   810 
   811     return (gamecontroller);
   812 }
   813 
   814 
   815 /*
   816  * Get the current state of an axis control on a controller
   817  */
   818 Sint16
   819 SDL_GameControllerGetAxis(SDL_GameController * gamecontroller, SDL_CONTROLLER_AXIS axis)
   820 {
   821 	if ( !gamecontroller )
   822 		return 0;
   823 
   824 	if (gamecontroller->mapping.axes[axis] >= 0 )
   825 	{
   826 		return ( SDL_JoystickGetAxis( gamecontroller->joystick, gamecontroller->mapping.axes[axis]) );
   827 	}
   828 	else if (gamecontroller->mapping.buttonasaxis[axis] >= 0 )
   829 	{
   830 		Uint8 value;
   831 		value = SDL_JoystickGetButton( gamecontroller->joystick, gamecontroller->mapping.buttonasaxis[axis] );
   832 		if ( value > 0 )
   833 			return 32767;
   834 		return 0;
   835 	}
   836 	return 0;
   837 }
   838 
   839 
   840 /*
   841  * Get the current state of a button on a controller
   842  */
   843 Uint8
   844 SDL_GameControllerGetButton(SDL_GameController * gamecontroller, SDL_CONTROLLER_BUTTON button)
   845 {
   846 	if ( !gamecontroller )
   847 		return 0;
   848 
   849 	if ( gamecontroller->mapping.buttons[button] >= 0 )
   850 	{
   851 		return ( SDL_JoystickGetButton( gamecontroller->joystick, gamecontroller->mapping.buttons[button] ) );
   852 	}
   853 	else if ( gamecontroller->mapping.axesasbutton[button] >= 0 )
   854 	{
   855 		Sint16 value;
   856 		value = SDL_JoystickGetAxis( gamecontroller->joystick, gamecontroller->mapping.axesasbutton[button] );
   857 		if ( ABS(value) > 32768/2 )
   858 			return 1;
   859 		return 0;
   860 	}
   861 	else if ( gamecontroller->mapping.hatasbutton[button].hat >= 0 )
   862 	{
   863 		Uint8 value;
   864 		value = SDL_JoystickGetHat( gamecontroller->joystick, gamecontroller->mapping.hatasbutton[button].hat );
   865 		
   866 		if ( value & gamecontroller->mapping.hatasbutton[button].mask )
   867 			return 1;
   868 		return 0;
   869 	}
   870 
   871 	return 0;
   872 }
   873 
   874 /*
   875  * Return if the joystick in question is currently attached to the system,
   876  *  \return 0 if not plugged in, 1 if still present.
   877  */
   878 int
   879 SDL_GameControllerGetAttached( SDL_GameController * gamecontroller )
   880 {
   881 	if ( !gamecontroller )
   882 		return 0;
   883 
   884 	return SDL_JoystickGetAttached(gamecontroller->joystick);
   885 }
   886 
   887 
   888 /*
   889  * Get the number of multi-dimensional axis controls on a joystick
   890  */
   891 const char *
   892 SDL_GameControllerName(SDL_GameController * gamecontroller)
   893 {
   894 	if ( !gamecontroller )
   895 		return NULL;
   896 
   897     return (gamecontroller->mapping.name);
   898 }
   899 
   900 
   901 /*
   902  * Get the joystick for this controller
   903  */
   904 SDL_Joystick *SDL_GameControllerGetJoystick(SDL_GameController * gamecontroller)
   905 {
   906 	if ( !gamecontroller )
   907 		return NULL;
   908 
   909 	return gamecontroller->joystick;
   910 }
   911 
   912 /**
   913  *  get the sdl joystick layer binding for this controller axi mapping
   914  */
   915 SDL_GameControllerButtonBind SDL_GameControllerGetBindForAxis( SDL_GameController * gamecontroller, SDL_CONTROLLER_AXIS axis )
   916 {
   917 	SDL_GameControllerButtonBind bind;
   918 	SDL_memset( &bind, 0x0, sizeof(bind) );
   919 
   920 	if ( !gamecontroller || axis == SDL_CONTROLLER_AXIS_INVALID )
   921 		return bind;
   922 
   923 	if (gamecontroller->mapping.axes[axis] >= 0 )
   924 	{
   925 		bind.m_eBindType = SDL_CONTROLLER_BINDTYPE_AXIS;
   926 		bind.button = gamecontroller->mapping.axes[axis];
   927 	}
   928 	else if (gamecontroller->mapping.buttonasaxis[axis] >= 0 )
   929 	{
   930 		bind.m_eBindType = SDL_CONTROLLER_BINDTYPE_BUTTON;
   931 		bind.button = gamecontroller->mapping.buttonasaxis[axis];
   932 	}
   933 
   934 	return bind;
   935 }
   936 
   937 
   938 /**
   939  *  get the sdl joystick layer binding for this controller button mapping
   940  */
   941 SDL_GameControllerButtonBind SDL_GameControllerGetBindForButton( SDL_GameController * gamecontroller, SDL_CONTROLLER_BUTTON button )
   942 {
   943 	SDL_GameControllerButtonBind bind;
   944 	SDL_memset( &bind, 0x0, sizeof(bind) );
   945 
   946 	if ( !gamecontroller || button == SDL_CONTROLLER_BUTTON_INVALID )
   947 		return bind;
   948 
   949 	if ( gamecontroller->mapping.buttons[button] >= 0 )
   950 	{
   951 		bind.m_eBindType = SDL_CONTROLLER_BINDTYPE_BUTTON;
   952 		bind.button = gamecontroller->mapping.buttons[button];
   953 	}
   954 	else if ( gamecontroller->mapping.axesasbutton[button] >= 0 )
   955 	{
   956 		bind.m_eBindType = SDL_CONTROLLER_BINDTYPE_AXIS;
   957 		bind.axis = gamecontroller->mapping.axesasbutton[button];
   958 	}
   959 	else if ( gamecontroller->mapping.hatasbutton[button].hat >= 0 )
   960 	{
   961 		bind.m_eBindType = SDL_CONTROLLER_BINDTYPE_HAT;
   962 		bind.hat.hat = gamecontroller->mapping.hatasbutton[button].hat;
   963 		bind.hat.hat_mask = gamecontroller->mapping.hatasbutton[button].mask;
   964 	}
   965 
   966 	return bind;
   967 }
   968 
   969 
   970 /*
   971  * Close a joystick previously opened with SDL_JoystickOpen()
   972  */
   973 void
   974 SDL_GameControllerClose(SDL_GameController * gamecontroller)
   975 {
   976 	SDL_GameController *gamecontrollerlist, *gamecontrollerlistprev;
   977 
   978 	if ( !gamecontroller )
   979 		return;
   980 
   981 	// First decrement ref count 
   982     if (--gamecontroller->ref_count > 0) {
   983         return;
   984     }
   985 
   986 	SDL_JoystickClose( gamecontroller->joystick );
   987 	
   988 	gamecontrollerlist = SDL_gamecontrollers;
   989 	gamecontrollerlistprev = NULL;
   990 	while ( gamecontrollerlist )
   991 	{
   992 		if (gamecontroller == gamecontrollerlist) 
   993 		{
   994 			if ( gamecontrollerlistprev )
   995 			{
   996 				// unlink this entry
   997 				gamecontrollerlistprev->next = gamecontrollerlist->next;
   998 			}
   999 			else
  1000 			{
  1001 				SDL_gamecontrollers = gamecontroller->next;
  1002 			}
  1003 
  1004 			break;
  1005 		}
  1006 		gamecontrollerlistprev = gamecontrollerlist;
  1007 		gamecontrollerlist = gamecontrollerlist->next;
  1008 	}
  1009  
  1010     SDL_free(gamecontroller);
  1011 }
  1012 
  1013 
  1014 /*
  1015  * Quit the controller subsystem
  1016  */
  1017 void
  1018 SDL_GameControllerQuit(void)
  1019 {
  1020 	ControllerMapping_t *pControllerMap;
  1021 	while ( SDL_gamecontrollers )
  1022 	{
  1023 		SDL_gamecontrollers->ref_count = 1;
  1024         SDL_GameControllerClose(SDL_gamecontrollers);
  1025  	}
  1026 
  1027 	pControllerMap = s_pSupportedControllers;
  1028 	while ( s_pSupportedControllers )
  1029 	{
  1030 		pControllerMap = s_pSupportedControllers;
  1031 		s_pSupportedControllers = s_pSupportedControllers->next;
  1032 		SDL_free( pControllerMap->name );
  1033 		SDL_free( pControllerMap );
  1034 	}
  1035 
  1036 	SDL_DelEventWatch( SDL_GameControllerEventWatcher, NULL );
  1037 
  1038 }
  1039 
  1040 /*
  1041  * Event filter to transform joystick events into appropriate game controller ones
  1042  */
  1043 int
  1044 SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_CONTROLLER_AXIS axis, Sint16 value)
  1045 {
  1046 	int posted;
  1047 
  1048     /* translate the event, if desired */
  1049     posted = 0;
  1050 #if !SDL_EVENTS_DISABLED
  1051     if (SDL_GetEventState(SDL_CONTROLLERAXISMOTION) == SDL_ENABLE) {
  1052         SDL_Event event;
  1053         event.type = SDL_CONTROLLERAXISMOTION;
  1054         event.caxis.which = gamecontroller->joystick->instance_id;
  1055         event.caxis.axis = axis;
  1056         event.caxis.value = value;
  1057 		posted = SDL_PushEvent(&event) == 1;
  1058     }
  1059 #endif /* !SDL_EVENTS_DISABLED */
  1060     return (posted);
  1061 }
  1062 
  1063 
  1064 /*
  1065  * Event filter to transform joystick events into appropriate game controller ones
  1066  */
  1067 int
  1068 SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_CONTROLLER_BUTTON button, Uint8 state)
  1069 {
  1070     int posted;
  1071 #if !SDL_EVENTS_DISABLED
  1072 	SDL_Event event;
  1073 
  1074     switch (state) {
  1075     case SDL_PRESSED:
  1076         event.type = SDL_CONTROLLERBUTTONDOWN;
  1077         break;
  1078     case SDL_RELEASED:
  1079         event.type = SDL_CONTROLLERBUTTONUP;
  1080         break;
  1081     default:
  1082         /* Invalid state -- bail */
  1083         return (0);
  1084     }
  1085 #endif /* !SDL_EVENTS_DISABLED */
  1086 
  1087     /* translate the event, if desired */
  1088     posted = 0;
  1089 #if !SDL_EVENTS_DISABLED
  1090     if (SDL_GetEventState(event.type) == SDL_ENABLE) {
  1091         event.cbutton.which = gamecontroller->joystick->instance_id;
  1092         event.cbutton.button = button;
  1093         event.cbutton.state = state;
  1094 		posted = SDL_PushEvent(&event) == 1;
  1095     }
  1096 #endif /* !SDL_EVENTS_DISABLED */
  1097     return (posted);
  1098 }
  1099 
  1100 /*
  1101  * Turn off controller events
  1102  */
  1103 int
  1104 SDL_GameControllerEventState(int state)
  1105 {
  1106 #if SDL_EVENTS_DISABLED
  1107     return SDL_IGNORE;
  1108 #else
  1109     const Uint32 event_list[] = {
  1110         SDL_CONTROLLERAXISMOTION, SDL_CONTROLLERBUTTONDOWN, SDL_CONTROLLERBUTTONUP,
  1111         SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEREMOVED,
  1112     };
  1113     unsigned int i;
  1114 
  1115     switch (state) {
  1116     case SDL_QUERY:
  1117         state = SDL_IGNORE;
  1118         for (i = 0; i < SDL_arraysize(event_list); ++i) {
  1119             state = SDL_EventState(event_list[i], SDL_QUERY);
  1120             if (state == SDL_ENABLE) {
  1121                 break;
  1122             }
  1123         }
  1124         break;
  1125     default:
  1126         for (i = 0; i < SDL_arraysize(event_list); ++i) {
  1127             SDL_EventState(event_list[i], state);
  1128         }
  1129         break;
  1130     }
  1131     return (state);
  1132 #endif /* SDL_EVENTS_DISABLED */
  1133 }
  1134 
  1135 
  1136 /* vi: set ts=4 sw=4 expandtab: */