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