src/joystick/SDL_gamecontroller.c
author Philipp Wiesemann <philipp.wiesemann@arcor.de>
Sat, 19 Nov 2016 23:27:37 +0100
changeset 10632 e5f5afc9f3fb
parent 10609 d702ecbd8ba7
child 10661 74b42fb2a9e4
permissions -rw-r--r--
Fixed two memory leaks if added game controller mapping has lower priority.

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