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