src/joystick/SDL_gamecontroller.c
author Sam Lantinga
Tue, 11 Dec 2012 12:16:28 -0800
changeset 6744 4ac2bb6dc80c
parent 6738 b408d5a406a3
child 6823 e9d312d26979
permissions -rw-r--r--
Fixed joystick GUID renaming for other platforms
     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 = SDL_strchr( pMapping, ',' );
   522 	const char *pSecondComma = SDL_strchr( pFirstComma + 1, ',' );
   523 	if ( pFirstComma && pSecondComma )
   524 	{
   525 		char *pchName = SDL_malloc( pSecondComma - pFirstComma );
   526 		if ( !pchName )
   527 		{
   528 			SDL_OutOfMemory();
   529 			return NULL;
   530 		}
   531 		SDL_memcpy( pchName, pFirstComma + 1, pSecondComma - pFirstComma );
   532 		pchName[ pSecondComma - pFirstComma - 1 ] = 0;
   533 		return pchName;
   534 	}
   535 	return NULL;
   536 }
   537 
   538 
   539 /*
   540  * grab the button mapping string from a mapping string
   541  */
   542 const char *SDL_PrivateGetControllerMappingFromMappingString( const char *pMapping )
   543 {
   544 	const char *pFirstComma = SDL_strchr( pMapping, ',' );
   545 	const char *pSecondComma = SDL_strchr( pFirstComma + 1, ',' );
   546 	if ( pSecondComma )
   547 		return pSecondComma + 1; // mapping is everything after the 3rd comma, no need to malloc it
   548 	else
   549 		return NULL;
   550 }
   551 
   552 
   553 /*
   554  * Initialize the game controller system, mostly load our DB of controller config mappings
   555  */
   556 int
   557 SDL_GameControllerInit(void)
   558 {
   559 	int i = 0;
   560 	const char *pMappingString = NULL;
   561 	s_pSupportedControllers = NULL;
   562 	pMappingString = s_ControllerMappings[i];
   563 	while ( pMappingString )
   564 	{
   565 		ControllerMapping_t *pControllerMapping;
   566 		char *pchGUID;
   567 		char *pchName;
   568 		const char *pchMapping;
   569 		pControllerMapping = SDL_malloc( sizeof(*pControllerMapping) );
   570 		if ( !pControllerMapping )
   571 		{
   572 			SDL_OutOfMemory();
   573 			return -1;
   574 		}
   575 
   576 		pchGUID = SDL_PrivateGetControllerGUIDFromMappingString( pMappingString );
   577 		pchName = SDL_PrivateGetControllerNameFromMappingString( pMappingString );
   578 		pchMapping = SDL_PrivateGetControllerMappingFromMappingString( pMappingString );
   579 		if ( pchGUID && pchName )
   580 		{
   581 #ifdef SDL_JOYSTICK_DINPUT
   582 			if ( !SDL_strcasecmp( pchGUID, "xinput" ) )
   583 			{
   584 				s_pXInputMapping = pControllerMapping;
   585 			}
   586 #endif
   587 			pControllerMapping->guid = SDL_JoystickGetGUIDFromString( pchGUID );
   588 			pControllerMapping->name = pchName;
   589 			pControllerMapping->mapping = pchMapping;
   590 			pControllerMapping->next = s_pSupportedControllers;
   591 			s_pSupportedControllers = pControllerMapping;
   592 
   593 			SDL_free( pchGUID );
   594 		}
   595 
   596 		i++;
   597 		pMappingString = s_ControllerMappings[i];
   598 	}
   599 
   600 	// load in any user supplied config
   601 	{
   602 		const char *hint = SDL_GetHint(SDL_HINT_GAMECONTROLLERCONFIG);
   603 		if ( hint && hint[0] )
   604 		{
   605 			int nchHints = SDL_strlen( hint );
   606 			char *pUserMappings = SDL_malloc( nchHints + 1 );
   607 			SDL_memcpy( pUserMappings, hint, nchHints );
   608 			while ( pUserMappings )
   609 			{
   610 				char *pchGUID;
   611 				char *pchName;
   612 				const char *pchMapping;
   613 				char *pchNewLine = NULL;
   614 				ControllerMapping_t *pControllerMapping;
   615 
   616 				pchNewLine = SDL_strchr( pUserMappings, '\n' );
   617 				if ( pchNewLine )
   618 					*pchNewLine = '\0';
   619 
   620 				pControllerMapping = SDL_malloc( sizeof(*pControllerMapping) );
   621 				if ( !pControllerMapping )
   622 				{
   623 					SDL_OutOfMemory();
   624 					return -1;
   625 				}
   626 
   627 				pchGUID = SDL_PrivateGetControllerGUIDFromMappingString( pUserMappings );
   628 				pchName = SDL_PrivateGetControllerNameFromMappingString( pUserMappings );
   629 				pchMapping = SDL_PrivateGetControllerMappingFromMappingString( pUserMappings );
   630 
   631 				if ( pchGUID && pchName )
   632 				{
   633 #ifdef SDL_JOYSTICK_DINPUT
   634 					if ( !SDL_strcasecmp( pchGUID, "xinput" ) )
   635 					{
   636 						s_pXInputMapping = pControllerMapping;
   637 					}
   638 #endif
   639 
   640 					pControllerMapping->guid = SDL_JoystickGetGUIDFromString( pchGUID );
   641 					pControllerMapping->name = pchName;
   642 					pControllerMapping->mapping = pchMapping;
   643 					pControllerMapping->next = s_pSupportedControllers;
   644 					s_pSupportedControllers = pControllerMapping;
   645 
   646 					SDL_free( pchGUID );
   647 				}
   648 
   649 				if ( pchNewLine )
   650 					pUserMappings = pchNewLine + 1;
   651 				else
   652 					pUserMappings = NULL;
   653 			}
   654 		}
   655 	}
   656 
   657 	/* watch for joy events and fire controller ones if needed */
   658 	SDL_AddEventWatch( SDL_GameControllerEventWatcher, NULL );
   659 	return (0);
   660 }
   661 
   662 
   663 /*
   664  * Get the implementation dependent name of a controller
   665  */
   666 const char *
   667 SDL_GameControllerNameForIndex(int device_index)
   668 {
   669 	ControllerMapping_t *pSupportedController =  SDL_PrivateGetControllerMapping(device_index);
   670 	if ( pSupportedController )
   671 	{
   672 		return pSupportedController->name;
   673 	}
   674 	else
   675 	{
   676 		SDL_JoystickGUID jGUID = SDL_JoystickGetDeviceGUID( device_index );
   677 		pSupportedController = s_pSupportedControllers;
   678 		while ( pSupportedController )
   679 		{
   680 			if ( !SDL_memcmp( &jGUID, &pSupportedController->guid, sizeof(jGUID) ) )
   681 			{
   682 				return pSupportedController->name;
   683 			}
   684 			pSupportedController = pSupportedController->next;
   685 		}
   686 	}
   687     return NULL;
   688 }
   689 
   690 
   691 /*
   692  * Return 1 if the joystick at this device index is a supported controller
   693  */
   694 int SDL_IsGameController(int device_index)
   695 {
   696 	ControllerMapping_t *pSupportedController =  SDL_PrivateGetControllerMapping(device_index);
   697 	if ( pSupportedController )
   698 	{
   699 		return 1;
   700 	}
   701 	else
   702 	{
   703 		SDL_JoystickGUID jGUID = SDL_JoystickGetDeviceGUID( device_index );
   704 		pSupportedController = s_pSupportedControllers;
   705 		// debug code to help get the guid string for a new joystick
   706 		/* char szGUID[33];
   707 		SDL_JoystickGetGUIDString( jGUID, szGUID, sizeof(szGUID) );
   708 		printf( "%s\n", pchGUID );
   709 		SDL_free( pchGUID );*/
   710 		while ( pSupportedController )
   711 		{
   712 			if ( !SDL_memcmp( &jGUID, &pSupportedController->guid, sizeof(jGUID) ) )
   713 			{
   714 				return 1;
   715 			}
   716 			pSupportedController = pSupportedController->next;
   717 		}
   718 	}
   719 	return 0;
   720 }
   721 
   722 /*
   723  * Open a controller for use - the index passed as an argument refers to
   724  * the N'th controller on the system.  This index is the value which will
   725  * identify this controller in future controller events.
   726  *
   727  * This function returns a controller identifier, or NULL if an error occurred.
   728  */
   729 SDL_GameController *
   730 SDL_GameControllerOpen(int device_index)
   731 {
   732     SDL_GameController *gamecontroller;
   733 	SDL_GameController *gamecontrollerlist;
   734 	ControllerMapping_t *pSupportedController = NULL;
   735 
   736     if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
   737         SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
   738         return (NULL);
   739     }
   740 
   741 	gamecontrollerlist = SDL_gamecontrollers;
   742     // If the controller is already open, return it 
   743 	while ( gamecontrollerlist )
   744 	{
   745 		if ( SDL_SYS_GetInstanceIdOfDeviceIndex(device_index) == gamecontrollerlist->joystick->instance_id ) {
   746 				gamecontroller = gamecontrollerlist;
   747 				++gamecontroller->ref_count;
   748 				return (gamecontroller);
   749 		}
   750 		gamecontrollerlist = gamecontrollerlist->next;
   751     }
   752 
   753     // Create and initialize the joystick 
   754     gamecontroller = (SDL_GameController *) SDL_malloc((sizeof *gamecontroller));
   755     if (gamecontroller == NULL) {
   756         SDL_OutOfMemory();
   757         return NULL;
   758     }
   759 
   760 	pSupportedController =  SDL_PrivateGetControllerMapping(device_index);
   761 	if ( !pSupportedController )
   762 	{
   763 		SDL_JoystickGUID jGUID;
   764 
   765 		jGUID = SDL_JoystickGetDeviceGUID( device_index );
   766 		pSupportedController = s_pSupportedControllers;
   767 		while ( pSupportedController )
   768 		{
   769 			if ( !SDL_memcmp( &jGUID, &pSupportedController->guid, sizeof(jGUID) ) )
   770 			{
   771 				break;
   772 			}
   773 
   774 			pSupportedController = pSupportedController->next;
   775 		}
   776 	}
   777 
   778 	if ( !pSupportedController )
   779 	{
   780 		SDL_SetError("Couldn't find mapping for device (%d)", device_index );
   781 		return (NULL);
   782 	}
   783 
   784     SDL_memset(gamecontroller, 0, (sizeof *gamecontroller));
   785     gamecontroller->joystick = SDL_JoystickOpen(device_index);
   786 	if ( !gamecontroller->joystick ) {
   787         SDL_free(gamecontroller);
   788         return NULL;
   789     }
   790 
   791 	SDL_PrivateLoadButtonMapping( &gamecontroller->mapping, pSupportedController->guid, pSupportedController->name, pSupportedController->mapping );
   792 
   793     // Add joystick to list 
   794     ++gamecontroller->ref_count;
   795 	// Link the joystick in the list 
   796 	gamecontroller->next = SDL_gamecontrollers;
   797 	SDL_gamecontrollers = gamecontroller;
   798 
   799 	SDL_SYS_JoystickUpdate( gamecontroller->joystick );
   800 
   801     return (gamecontroller);
   802 }
   803 
   804 
   805 /*
   806  * Get the current state of an axis control on a controller
   807  */
   808 Sint16
   809 SDL_GameControllerGetAxis(SDL_GameController * gamecontroller, SDL_CONTROLLER_AXIS axis)
   810 {
   811 	if ( !gamecontroller )
   812 		return 0;
   813 
   814 	if (gamecontroller->mapping.axes[axis] >= 0 )
   815 	{
   816 		return ( SDL_JoystickGetAxis( gamecontroller->joystick, gamecontroller->mapping.axes[axis]) );
   817 	}
   818 	else if (gamecontroller->mapping.buttonasaxis[axis] >= 0 )
   819 	{
   820 		Uint8 value;
   821 		value = SDL_JoystickGetButton( gamecontroller->joystick, gamecontroller->mapping.buttonasaxis[axis] );
   822 		if ( value > 0 )
   823 			return 32767;
   824 		return 0;
   825 	}
   826 	return 0;
   827 }
   828 
   829 
   830 /*
   831  * Get the current state of a button on a controller
   832  */
   833 Uint8
   834 SDL_GameControllerGetButton(SDL_GameController * gamecontroller, SDL_CONTROLLER_BUTTON button)
   835 {
   836 	if ( !gamecontroller )
   837 		return 0;
   838 
   839 	if ( gamecontroller->mapping.buttons[button] >= 0 )
   840 	{
   841 		return ( SDL_JoystickGetButton( gamecontroller->joystick, gamecontroller->mapping.buttons[button] ) );
   842 	}
   843 	else if ( gamecontroller->mapping.axesasbutton[button] >= 0 )
   844 	{
   845 		Sint16 value;
   846 		value = SDL_JoystickGetAxis( gamecontroller->joystick, gamecontroller->mapping.axesasbutton[button] );
   847 		if ( ABS(value) > 32768/2 )
   848 			return 1;
   849 		return 0;
   850 	}
   851 	else if ( gamecontroller->mapping.hatasbutton[button].hat >= 0 )
   852 	{
   853 		Uint8 value;
   854 		value = SDL_JoystickGetHat( gamecontroller->joystick, gamecontroller->mapping.hatasbutton[button].hat );
   855 		
   856 		if ( value & gamecontroller->mapping.hatasbutton[button].mask )
   857 			return 1;
   858 		return 0;
   859 	}
   860 
   861 	return 0;
   862 }
   863 
   864 /*
   865  * Return if the joystick in question is currently attached to the system,
   866  *  \return 0 if not plugged in, 1 if still present.
   867  */
   868 int
   869 SDL_GameControllerGetAttached( SDL_GameController * gamecontroller )
   870 {
   871 	if ( !gamecontroller )
   872 		return 0;
   873 
   874 	return SDL_JoystickGetAttached(gamecontroller->joystick);
   875 }
   876 
   877 
   878 /*
   879  * Get the number of multi-dimensional axis controls on a joystick
   880  */
   881 const char *
   882 SDL_GameControllerName(SDL_GameController * gamecontroller)
   883 {
   884 	if ( !gamecontroller )
   885 		return NULL;
   886 
   887     return (gamecontroller->mapping.name);
   888 }
   889 
   890 
   891 /*
   892  * Get the joystick for this controller
   893  */
   894 SDL_Joystick *SDL_GameControllerGetJoystick(SDL_GameController * gamecontroller)
   895 {
   896 	if ( !gamecontroller )
   897 		return NULL;
   898 
   899 	return gamecontroller->joystick;
   900 }
   901 
   902 /**
   903  *  get the sdl joystick layer binding for this controller axi mapping
   904  */
   905 SDL_GameControllerButtonBind SDL_GameControllerGetBindForAxis( SDL_GameController * gamecontroller, SDL_CONTROLLER_AXIS axis )
   906 {
   907 	SDL_GameControllerButtonBind bind;
   908 	SDL_memset( &bind, 0x0, sizeof(bind) );
   909 
   910 	if ( !gamecontroller || axis == SDL_CONTROLLER_AXIS_INVALID )
   911 		return bind;
   912 
   913 	if (gamecontroller->mapping.axes[axis] >= 0 )
   914 	{
   915 		bind.m_eBindType = SDL_CONTROLLER_BINDTYPE_AXIS;
   916 		bind.button = gamecontroller->mapping.axes[axis];
   917 	}
   918 	else if (gamecontroller->mapping.buttonasaxis[axis] >= 0 )
   919 	{
   920 		bind.m_eBindType = SDL_CONTROLLER_BINDTYPE_BUTTON;
   921 		bind.button = gamecontroller->mapping.buttonasaxis[axis];
   922 	}
   923 
   924 	return bind;
   925 }
   926 
   927 
   928 /**
   929  *  get the sdl joystick layer binding for this controller button mapping
   930  */
   931 SDL_GameControllerButtonBind SDL_GameControllerGetBindForButton( SDL_GameController * gamecontroller, SDL_CONTROLLER_BUTTON button )
   932 {
   933 	SDL_GameControllerButtonBind bind;
   934 	SDL_memset( &bind, 0x0, sizeof(bind) );
   935 
   936 	if ( !gamecontroller || button == SDL_CONTROLLER_BUTTON_INVALID )
   937 		return bind;
   938 
   939 	if ( gamecontroller->mapping.buttons[button] >= 0 )
   940 	{
   941 		bind.m_eBindType = SDL_CONTROLLER_BINDTYPE_BUTTON;
   942 		bind.button = gamecontroller->mapping.buttons[button];
   943 	}
   944 	else if ( gamecontroller->mapping.axesasbutton[button] >= 0 )
   945 	{
   946 		bind.m_eBindType = SDL_CONTROLLER_BINDTYPE_AXIS;
   947 		bind.axis = gamecontroller->mapping.axesasbutton[button];
   948 	}
   949 	else if ( gamecontroller->mapping.hatasbutton[button].hat >= 0 )
   950 	{
   951 		bind.m_eBindType = SDL_CONTROLLER_BINDTYPE_HAT;
   952 		bind.hat.hat = gamecontroller->mapping.hatasbutton[button].hat;
   953 		bind.hat.hat_mask = gamecontroller->mapping.hatasbutton[button].mask;
   954 	}
   955 
   956 	return bind;
   957 }
   958 
   959 
   960 /*
   961  * Close a joystick previously opened with SDL_JoystickOpen()
   962  */
   963 void
   964 SDL_GameControllerClose(SDL_GameController * gamecontroller)
   965 {
   966 	SDL_GameController *gamecontrollerlist, *gamecontrollerlistprev;
   967 
   968 	if ( !gamecontroller )
   969 		return;
   970 
   971 	// First decrement ref count 
   972     if (--gamecontroller->ref_count > 0) {
   973         return;
   974     }
   975 
   976 	SDL_JoystickClose( gamecontroller->joystick );
   977 	
   978 	gamecontrollerlist = SDL_gamecontrollers;
   979 	gamecontrollerlistprev = NULL;
   980 	while ( gamecontrollerlist )
   981 	{
   982 		if (gamecontroller == gamecontrollerlist) 
   983 		{
   984 			if ( gamecontrollerlistprev )
   985 			{
   986 				// unlink this entry
   987 				gamecontrollerlistprev->next = gamecontrollerlist->next;
   988 			}
   989 			else
   990 			{
   991 				SDL_gamecontrollers = gamecontroller->next;
   992 			}
   993 
   994 			break;
   995 		}
   996 		gamecontrollerlistprev = gamecontrollerlist;
   997 		gamecontrollerlist = gamecontrollerlist->next;
   998 	}
   999  
  1000     SDL_free(gamecontroller);
  1001 }
  1002 
  1003 
  1004 /*
  1005  * Quit the controller subsystem
  1006  */
  1007 void
  1008 SDL_GameControllerQuit(void)
  1009 {
  1010 	ControllerMapping_t *pControllerMap;
  1011 	while ( SDL_gamecontrollers )
  1012 	{
  1013 		SDL_gamecontrollers->ref_count = 1;
  1014         SDL_GameControllerClose(SDL_gamecontrollers);
  1015  	}
  1016 
  1017 	pControllerMap = s_pSupportedControllers;
  1018 	while ( s_pSupportedControllers )
  1019 	{
  1020 		pControllerMap = s_pSupportedControllers;
  1021 		s_pSupportedControllers = s_pSupportedControllers->next;
  1022 		SDL_free( pControllerMap->name );
  1023 		SDL_free( pControllerMap );
  1024 	}
  1025 
  1026 	SDL_DelEventWatch( SDL_GameControllerEventWatcher, NULL );
  1027 
  1028 }
  1029 
  1030 /*
  1031  * Event filter to transform joystick events into appropriate game controller ones
  1032  */
  1033 int
  1034 SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_CONTROLLER_AXIS axis, Sint16 value)
  1035 {
  1036 	int posted;
  1037 
  1038     /* translate the event, if desired */
  1039     posted = 0;
  1040 #if !SDL_EVENTS_DISABLED
  1041     if (SDL_GetEventState(SDL_CONTROLLERAXISMOTION) == SDL_ENABLE) {
  1042         SDL_Event event;
  1043         event.type = SDL_CONTROLLERAXISMOTION;
  1044         event.caxis.which = gamecontroller->joystick->instance_id;
  1045         event.caxis.axis = axis;
  1046         event.caxis.value = value;
  1047 		posted = SDL_PushEvent(&event) == 1;
  1048     }
  1049 #endif /* !SDL_EVENTS_DISABLED */
  1050     return (posted);
  1051 }
  1052 
  1053 
  1054 /*
  1055  * Event filter to transform joystick events into appropriate game controller ones
  1056  */
  1057 int
  1058 SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_CONTROLLER_BUTTON button, Uint8 state)
  1059 {
  1060     int posted;
  1061 #if !SDL_EVENTS_DISABLED
  1062 	SDL_Event event;
  1063 
  1064     switch (state) {
  1065     case SDL_PRESSED:
  1066         event.type = SDL_CONTROLLERBUTTONDOWN;
  1067         break;
  1068     case SDL_RELEASED:
  1069         event.type = SDL_CONTROLLERBUTTONUP;
  1070         break;
  1071     default:
  1072         /* Invalid state -- bail */
  1073         return (0);
  1074     }
  1075 #endif /* !SDL_EVENTS_DISABLED */
  1076 
  1077     /* translate the event, if desired */
  1078     posted = 0;
  1079 #if !SDL_EVENTS_DISABLED
  1080     if (SDL_GetEventState(event.type) == SDL_ENABLE) {
  1081         event.cbutton.which = gamecontroller->joystick->instance_id;
  1082         event.cbutton.button = button;
  1083         event.cbutton.state = state;
  1084 		posted = SDL_PushEvent(&event) == 1;
  1085     }
  1086 #endif /* !SDL_EVENTS_DISABLED */
  1087     return (posted);
  1088 }
  1089 
  1090 /*
  1091  * Turn off controller events
  1092  */
  1093 int
  1094 SDL_GameControllerEventState(int state)
  1095 {
  1096 #if SDL_EVENTS_DISABLED
  1097     return SDL_IGNORE;
  1098 #else
  1099     const Uint32 event_list[] = {
  1100         SDL_CONTROLLERAXISMOTION, SDL_CONTROLLERBUTTONDOWN, SDL_CONTROLLERBUTTONUP,
  1101         SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEREMOVED,
  1102     };
  1103     unsigned int i;
  1104 
  1105     switch (state) {
  1106     case SDL_QUERY:
  1107         state = SDL_IGNORE;
  1108         for (i = 0; i < SDL_arraysize(event_list); ++i) {
  1109             state = SDL_EventState(event_list[i], SDL_QUERY);
  1110             if (state == SDL_ENABLE) {
  1111                 break;
  1112             }
  1113         }
  1114         break;
  1115     default:
  1116         for (i = 0; i < SDL_arraysize(event_list); ++i) {
  1117             SDL_EventState(event_list[i], state);
  1118         }
  1119         break;
  1120     }
  1121     return (state);
  1122 #endif /* SDL_EVENTS_DISABLED */
  1123 }
  1124 
  1125 
  1126 /* vi: set ts=4 sw=4 expandtab: */