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