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