src/joystick/SDL_gamecontroller.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 14 Jul 2013 18:17:28 -0700
changeset 7523 9e9ab1dc3811
parent 7422 172b0c6e51d6
child 7677 871d43c6968a
child 8477 ad08f0d710f3
permissions -rw-r--r--
Fixed bug 1919 - Window icon disappears as soon as a renderer is created

Sebastian

Setting a window icon works just fine until a renderer is added to the window.
After adding the renderer the icon disappears.

Reproduce by:
- Take the example code from the wiki: http://wiki.libsdl.org/moin.fcg/SDL_SetWindowIcon

- Add the following two lines after SDL_FreeSurface(surface);
SDL_Delay(1000);
SDL_Renderer* ren = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);

-compile and run

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