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