src/joystick/SDL_gamecontroller.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 28 Aug 2017 01:42:18 -0700
changeset 11386 d5c2d689bf6d
parent 11284 3db78361e751
child 11532 4af4e3986438
permissions -rw-r--r--
Fixed build when Wayland is dynamically loaded
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2017 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_joystick_c.h"
    29 #include "SDL_hints.h"
    30 #include "SDL_gamecontrollerdb.h"
    31 
    32 #if !SDL_EVENTS_DISABLED
    33 #include "../events/SDL_events_c.h"
    34 #endif
    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 typedef struct
    42 {
    43     SDL_GameControllerBindType inputType;
    44     union
    45     {
    46         int button;
    47 
    48         struct {
    49             int axis;
    50             int axis_min;
    51             int axis_max;
    52         } axis;
    53 
    54         struct {
    55             int hat;
    56             int hat_mask;
    57         } hat;
    58 
    59     } input;
    60 
    61     SDL_GameControllerBindType outputType;
    62     union
    63     {
    64         SDL_GameControllerButton button;
    65 
    66         struct {
    67             SDL_GameControllerAxis axis;
    68             int axis_min;
    69             int axis_max;
    70         } axis;
    71 
    72     } output;
    73 
    74 } SDL_ExtendedGameControllerBind;
    75 
    76 /* our hard coded list of mapping support */
    77 typedef enum
    78 {
    79     SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT,
    80     SDL_CONTROLLER_MAPPING_PRIORITY_API,
    81     SDL_CONTROLLER_MAPPING_PRIORITY_USER,
    82 } SDL_ControllerMappingPriority;
    83 
    84 typedef struct _ControllerMapping_t
    85 {
    86     SDL_JoystickGUID guid;
    87     char *name;
    88     char *mapping;
    89     SDL_ControllerMappingPriority priority;
    90     struct _ControllerMapping_t *next;
    91 } ControllerMapping_t;
    92 
    93 static SDL_JoystickGUID s_zeroGUID;
    94 static ControllerMapping_t *s_pSupportedControllers = NULL;
    95 static ControllerMapping_t *s_pXInputMapping = NULL;
    96 static ControllerMapping_t *s_pEmscriptenMapping = NULL;
    97 
    98 /* The SDL game controller structure */
    99 struct _SDL_GameController
   100 {
   101     SDL_Joystick *joystick; /* underlying joystick device */
   102     int ref_count;
   103 
   104     SDL_JoystickGUID guid;
   105     const char *name;
   106     int num_bindings;
   107     SDL_ExtendedGameControllerBind *bindings;
   108     SDL_ExtendedGameControllerBind **last_match_axis;
   109     Uint8 *last_hat_mask;
   110 
   111     struct _SDL_GameController *next; /* pointer to next game controller we have allocated */
   112 };
   113 
   114 
   115 typedef struct
   116 {
   117     int num_entries;
   118     int max_entries;
   119     Uint32 *entries;
   120 } SDL_vidpid_list;
   121 
   122 static SDL_vidpid_list SDL_allowed_controllers;
   123 static SDL_vidpid_list SDL_ignored_controllers;
   124 
   125 static void
   126 SDL_LoadVIDPIDListFromHint(const char *hint, SDL_vidpid_list *list)
   127 {
   128     Uint32 entry;
   129     char *spot;
   130     char *file = NULL;
   131 
   132     list->num_entries = 0;
   133 
   134     if (hint && *hint == '@') {
   135         spot = file = (char *)SDL_LoadFile(hint+1, NULL);
   136     } else {
   137         spot = (char *)hint;
   138     }
   139 
   140     if (!spot) {
   141         return;
   142     }
   143 
   144     while ((spot = SDL_strstr(spot, "0x")) != NULL) {
   145         entry = (Uint16)SDL_strtol(spot, &spot, 0);
   146         entry <<= 16;
   147         spot = SDL_strstr(spot, "0x");
   148         if (!spot) {
   149             break;
   150         }
   151         entry |= (Uint16)SDL_strtol(spot, &spot, 0);
   152 
   153         if (list->num_entries == list->max_entries) {
   154             int max_entries = list->max_entries + 16;
   155             Uint32 *entries = (Uint32 *)SDL_realloc(list->entries, max_entries*sizeof(*list->entries));
   156             if (entries == NULL) {
   157                 /* Out of memory, go with what we have already */
   158                 break;
   159             }
   160             list->entries = entries;
   161             list->max_entries = max_entries;
   162         }
   163         list->entries[list->num_entries++] = entry;
   164     }
   165 
   166     if (file) {
   167         SDL_free(file);
   168     }
   169 }
   170 
   171 static void SDLCALL
   172 SDL_GameControllerIgnoreDevicesChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
   173 {
   174     SDL_LoadVIDPIDListFromHint(hint, &SDL_ignored_controllers);
   175 }
   176 
   177 static void SDLCALL
   178 SDL_GameControllerIgnoreDevicesExceptChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
   179 {
   180     SDL_LoadVIDPIDListFromHint(hint, &SDL_allowed_controllers);
   181 }
   182 
   183 static int SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis, Sint16 value);
   184 static int SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button, Uint8 state);
   185 
   186 /*
   187  * If there is an existing add event in the queue, it needs to be modified
   188  * to have the right value for which, because the number of controllers in
   189  * the system is now one less.
   190  */
   191 static void UpdateEventsForDeviceRemoval()
   192 {
   193     int i, num_events;
   194     SDL_Event *events;
   195 
   196     num_events = SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEADDED);
   197     if (num_events <= 0) {
   198         return;
   199     }
   200 
   201     events = SDL_stack_alloc(SDL_Event, num_events);
   202     if (!events) {
   203         return;
   204     }
   205 
   206     num_events = SDL_PeepEvents(events, num_events, SDL_GETEVENT, SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEADDED);
   207     for (i = 0; i < num_events; ++i) {
   208         --events[i].cdevice.which;
   209     }
   210     SDL_PeepEvents(events, num_events, SDL_ADDEVENT, 0, 0);
   211 
   212     SDL_stack_free(events);
   213 }
   214 
   215 static SDL_bool HasSameOutput(SDL_ExtendedGameControllerBind *a, SDL_ExtendedGameControllerBind *b)
   216 {
   217     if (a->outputType != b->outputType) {
   218         return SDL_FALSE;
   219     }
   220 
   221     if (a->outputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
   222         return (a->output.axis.axis == b->output.axis.axis);
   223     } else {
   224         return (a->output.button == b->output.button);
   225     }
   226 }
   227 
   228 static void ResetOutput(SDL_GameController *gamecontroller, SDL_ExtendedGameControllerBind *bind)
   229 {
   230     if (bind->outputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
   231         SDL_PrivateGameControllerAxis(gamecontroller, bind->output.axis.axis, 0);
   232     } else {
   233         SDL_PrivateGameControllerButton(gamecontroller, bind->output.button, SDL_RELEASED);
   234     }
   235 }
   236 
   237 static void HandleJoystickAxis(SDL_GameController *gamecontroller, int axis, int value)
   238 {
   239     int i;
   240     SDL_ExtendedGameControllerBind *last_match = gamecontroller->last_match_axis[axis];
   241     SDL_ExtendedGameControllerBind *match = NULL;
   242 
   243     for (i = 0; i < gamecontroller->num_bindings; ++i) {
   244         SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
   245         if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS &&
   246             axis == binding->input.axis.axis) {
   247             if (binding->input.axis.axis_min < binding->input.axis.axis_max) {
   248                 if (value >= binding->input.axis.axis_min &&
   249                     value <= binding->input.axis.axis_max) {
   250                     match = binding;
   251                     break;
   252                 }
   253             } else {
   254                 if (value >= binding->input.axis.axis_max &&
   255                     value <= binding->input.axis.axis_min) {
   256                     match = binding;
   257                     break;
   258                 }
   259             }
   260         }
   261     }
   262 
   263     if (last_match && (!match || !HasSameOutput(last_match, match))) {
   264         /* Clear the last input that this axis generated */
   265         ResetOutput(gamecontroller, last_match);
   266     }
   267 
   268     if (match) {
   269         if (match->outputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
   270             if (match->input.axis.axis_min != match->output.axis.axis_min || match->input.axis.axis_max != match->output.axis.axis_max) {
   271                 float normalized_value = (float)(value - match->input.axis.axis_min) / (match->input.axis.axis_max - match->input.axis.axis_min);
   272                 value = match->output.axis.axis_min + (int)(normalized_value * (match->output.axis.axis_max - match->output.axis.axis_min));
   273             }
   274             SDL_PrivateGameControllerAxis(gamecontroller, match->output.axis.axis, (Sint16)value);
   275         } else {
   276             Uint8 state;
   277             int threshold = match->input.axis.axis_min + (match->input.axis.axis_max - match->input.axis.axis_min) / 2;
   278             if (match->input.axis.axis_max < match->input.axis.axis_min) {
   279                 state = (value <= threshold) ? SDL_PRESSED : SDL_RELEASED;
   280             } else {
   281                 state = (value >= threshold) ? SDL_PRESSED : SDL_RELEASED;
   282             }
   283             SDL_PrivateGameControllerButton(gamecontroller, match->output.button, state);
   284         }
   285     }
   286     gamecontroller->last_match_axis[axis] = match;
   287 }
   288 
   289 static void HandleJoystickButton(SDL_GameController *gamecontroller, int button, Uint8 state)
   290 {
   291     int i;
   292 
   293     for (i = 0; i < gamecontroller->num_bindings; ++i) {
   294         SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
   295         if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON &&
   296             button == binding->input.button) {
   297             if (binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
   298                 int value = state ? binding->output.axis.axis_max : binding->output.axis.axis_min;
   299                 SDL_PrivateGameControllerAxis(gamecontroller, binding->output.axis.axis, (Sint16)value);
   300             } else {
   301                 SDL_PrivateGameControllerButton(gamecontroller, binding->output.button, state);
   302             }
   303             break;
   304         }
   305     }
   306 }
   307 
   308 static void HandleJoystickHat(SDL_GameController *gamecontroller, int hat, Uint8 value)
   309 {
   310     int i;
   311     Uint8 last_mask = gamecontroller->last_hat_mask[hat];
   312     Uint8 changed_mask = (last_mask ^ value);
   313 
   314     for (i = 0; i < gamecontroller->num_bindings; ++i) {
   315         SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
   316         if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT && hat == binding->input.hat.hat) {
   317             if ((changed_mask & binding->input.hat.hat_mask) != 0) {
   318                 if (value & binding->input.hat.hat_mask) {
   319                     if (binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
   320                         SDL_PrivateGameControllerAxis(gamecontroller, binding->output.axis.axis, (Sint16)binding->output.axis.axis_max);
   321                     } else {
   322                         SDL_PrivateGameControllerButton(gamecontroller, binding->output.button, SDL_PRESSED);
   323                     }
   324                 } else {
   325                     ResetOutput(gamecontroller, binding);
   326                 }
   327             }
   328         }
   329     }
   330     gamecontroller->last_hat_mask[hat] = value;
   331 }
   332 
   333 /*
   334  * Event filter to fire controller events from joystick ones
   335  */
   336 static int SDLCALL SDL_GameControllerEventWatcher(void *userdata, SDL_Event * event)
   337 {
   338     switch(event->type) {
   339     case SDL_JOYAXISMOTION:
   340         {
   341             SDL_GameController *controllerlist = SDL_gamecontrollers;
   342             while (controllerlist) {
   343                 if (controllerlist->joystick->instance_id == event->jaxis.which) {
   344                     HandleJoystickAxis(controllerlist, event->jaxis.axis, event->jaxis.value);
   345                     break;
   346                 }
   347                 controllerlist = controllerlist->next;
   348             }
   349         }
   350         break;
   351     case SDL_JOYBUTTONDOWN:
   352     case SDL_JOYBUTTONUP:
   353         {
   354             SDL_GameController *controllerlist = SDL_gamecontrollers;
   355             while (controllerlist) {
   356                 if (controllerlist->joystick->instance_id == event->jbutton.which) {
   357                     HandleJoystickButton(controllerlist, event->jbutton.button, event->jbutton.state);
   358                     break;
   359                 }
   360                 controllerlist = controllerlist->next;
   361             }
   362         }
   363         break;
   364     case SDL_JOYHATMOTION:
   365         {
   366             SDL_GameController *controllerlist = SDL_gamecontrollers;
   367             while (controllerlist) {
   368                 if (controllerlist->joystick->instance_id == event->jhat.which) {
   369                     HandleJoystickHat(controllerlist, event->jhat.hat, event->jhat.value);
   370                     break;
   371                 }
   372                 controllerlist = controllerlist->next;
   373             }
   374         }
   375         break;
   376     case SDL_JOYDEVICEADDED:
   377         {
   378             if (SDL_IsGameController(event->jdevice.which)) {
   379                 SDL_Event deviceevent;
   380                 deviceevent.type = SDL_CONTROLLERDEVICEADDED;
   381                 deviceevent.cdevice.which = event->jdevice.which;
   382                 SDL_PushEvent(&deviceevent);
   383             }
   384         }
   385         break;
   386     case SDL_JOYDEVICEREMOVED:
   387         {
   388             SDL_GameController *controllerlist = SDL_gamecontrollers;
   389             while (controllerlist) {
   390                 if (controllerlist->joystick->instance_id == event->jdevice.which) {
   391                     SDL_Event deviceevent;
   392 
   393                     deviceevent.type = SDL_CONTROLLERDEVICEREMOVED;
   394                     deviceevent.cdevice.which = event->jdevice.which;
   395                     SDL_PushEvent(&deviceevent);
   396 
   397                     UpdateEventsForDeviceRemoval();
   398                     break;
   399                 }
   400                 controllerlist = controllerlist->next;
   401             }
   402         }
   403         break;
   404     default:
   405         break;
   406     }
   407 
   408     return 1;
   409 }
   410 
   411 /*
   412  * Helper function to scan the mappings database for a controller with the specified GUID
   413  */
   414 static ControllerMapping_t *SDL_PrivateGetControllerMappingForGUID(SDL_JoystickGUID *guid)
   415 {
   416     ControllerMapping_t *pSupportedController = s_pSupportedControllers;
   417     while (pSupportedController) {
   418         if (SDL_memcmp(guid, &pSupportedController->guid, sizeof(*guid)) == 0) {
   419             return pSupportedController;
   420         }
   421         pSupportedController = pSupportedController->next;
   422     }
   423     return NULL;
   424 }
   425 
   426 static const char* map_StringForControllerAxis[] = {
   427     "leftx",
   428     "lefty",
   429     "rightx",
   430     "righty",
   431     "lefttrigger",
   432     "righttrigger",
   433     NULL
   434 };
   435 
   436 /*
   437  * convert a string to its enum equivalent
   438  */
   439 SDL_GameControllerAxis SDL_GameControllerGetAxisFromString(const char *pchString)
   440 {
   441     int entry;
   442 
   443     if (pchString && (*pchString == '+' || *pchString == '-')) {
   444         ++pchString;
   445     }
   446 
   447     if (!pchString || !pchString[0]) {
   448         return SDL_CONTROLLER_AXIS_INVALID;
   449     }
   450 
   451     for (entry = 0; map_StringForControllerAxis[entry]; ++entry) {
   452         if (!SDL_strcasecmp(pchString, map_StringForControllerAxis[entry]))
   453             return (SDL_GameControllerAxis) entry;
   454     }
   455     return SDL_CONTROLLER_AXIS_INVALID;
   456 }
   457 
   458 /*
   459  * convert an enum to its string equivalent
   460  */
   461 const char* SDL_GameControllerGetStringForAxis(SDL_GameControllerAxis axis)
   462 {
   463     if (axis > SDL_CONTROLLER_AXIS_INVALID && axis < SDL_CONTROLLER_AXIS_MAX) {
   464         return map_StringForControllerAxis[axis];
   465     }
   466     return NULL;
   467 }
   468 
   469 static const char* map_StringForControllerButton[] = {
   470     "a",
   471     "b",
   472     "x",
   473     "y",
   474     "back",
   475     "guide",
   476     "start",
   477     "leftstick",
   478     "rightstick",
   479     "leftshoulder",
   480     "rightshoulder",
   481     "dpup",
   482     "dpdown",
   483     "dpleft",
   484     "dpright",
   485     NULL
   486 };
   487 
   488 /*
   489  * convert a string to its enum equivalent
   490  */
   491 SDL_GameControllerButton SDL_GameControllerGetButtonFromString(const char *pchString)
   492 {
   493     int entry;
   494     if (!pchString || !pchString[0])
   495         return SDL_CONTROLLER_BUTTON_INVALID;
   496 
   497     for (entry = 0; map_StringForControllerButton[entry]; ++entry) {
   498         if (SDL_strcasecmp(pchString, map_StringForControllerButton[entry]) == 0)
   499             return (SDL_GameControllerButton) entry;
   500     }
   501     return SDL_CONTROLLER_BUTTON_INVALID;
   502 }
   503 
   504 /*
   505  * convert an enum to its string equivalent
   506  */
   507 const char* SDL_GameControllerGetStringForButton(SDL_GameControllerButton axis)
   508 {
   509     if (axis > SDL_CONTROLLER_BUTTON_INVALID && axis < SDL_CONTROLLER_BUTTON_MAX) {
   510         return map_StringForControllerButton[axis];
   511     }
   512     return NULL;
   513 }
   514 
   515 /*
   516  * given a controller button name and a joystick name update our mapping structure with it
   517  */
   518 static void SDL_PrivateGameControllerParseElement(SDL_GameController *gamecontroller, const char *szGameButton, const char *szJoystickButton)
   519 {
   520     SDL_ExtendedGameControllerBind bind;
   521     SDL_GameControllerButton button;
   522     SDL_GameControllerAxis axis;
   523     SDL_bool invert_input = SDL_FALSE;
   524     char half_axis_input = 0;
   525     char half_axis_output = 0;
   526 
   527     if (*szGameButton == '+' || *szGameButton == '-') {
   528         half_axis_output = *szGameButton++;
   529     }
   530 
   531     axis = SDL_GameControllerGetAxisFromString(szGameButton);
   532     button = SDL_GameControllerGetButtonFromString(szGameButton);
   533     if (axis != SDL_CONTROLLER_AXIS_INVALID) {
   534         bind.outputType = SDL_CONTROLLER_BINDTYPE_AXIS;
   535         bind.output.axis.axis = axis;
   536         if (axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT || axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT) {
   537             bind.output.axis.axis_min = 0;
   538             bind.output.axis.axis_max = SDL_JOYSTICK_AXIS_MAX;
   539         } else {
   540             if (half_axis_output == '+') {
   541                 bind.output.axis.axis_min = 0;
   542                 bind.output.axis.axis_max = SDL_JOYSTICK_AXIS_MAX;
   543             } else if (half_axis_output == '-') {
   544                 bind.output.axis.axis_min = 0;
   545                 bind.output.axis.axis_max = SDL_JOYSTICK_AXIS_MIN;
   546             } else {
   547                 bind.output.axis.axis_min = SDL_JOYSTICK_AXIS_MIN;
   548                 bind.output.axis.axis_max = SDL_JOYSTICK_AXIS_MAX;
   549             }
   550         }
   551     } else if (button != SDL_CONTROLLER_BUTTON_INVALID) {
   552         bind.outputType = SDL_CONTROLLER_BINDTYPE_BUTTON;
   553         bind.output.button = button;
   554     } else {
   555         SDL_SetError("Unexpected controller element %s", szGameButton);
   556         return;
   557     }
   558 
   559     if (*szJoystickButton == '+' || *szJoystickButton == '-') {
   560         half_axis_input = *szJoystickButton++;
   561     }
   562     if (szJoystickButton[SDL_strlen(szJoystickButton) - 1] == '~') {
   563         invert_input = SDL_TRUE;
   564     }
   565 
   566     if (szJoystickButton[0] == 'a' && SDL_isdigit(szJoystickButton[1])) {
   567         bind.inputType = SDL_CONTROLLER_BINDTYPE_AXIS;
   568         bind.input.axis.axis = SDL_atoi(&szJoystickButton[1]);
   569         if (half_axis_input == '+') {
   570             bind.input.axis.axis_min = 0;
   571             bind.input.axis.axis_max = SDL_JOYSTICK_AXIS_MAX;
   572         } else if (half_axis_input == '-') {
   573             bind.input.axis.axis_min = 0;
   574             bind.input.axis.axis_max = SDL_JOYSTICK_AXIS_MIN;
   575         } else {
   576             bind.input.axis.axis_min = SDL_JOYSTICK_AXIS_MIN;
   577             bind.input.axis.axis_max = SDL_JOYSTICK_AXIS_MAX;
   578         }
   579         if (invert_input) {
   580             int tmp = bind.input.axis.axis_min;
   581             bind.input.axis.axis_min = bind.input.axis.axis_max;
   582             bind.input.axis.axis_max = tmp;
   583         }
   584     } else if (szJoystickButton[0] == 'b' && SDL_isdigit(szJoystickButton[1])) {
   585         bind.inputType = SDL_CONTROLLER_BINDTYPE_BUTTON;
   586         bind.input.button = SDL_atoi(&szJoystickButton[1]);
   587     } else if (szJoystickButton[0] == 'h' && SDL_isdigit(szJoystickButton[1]) &&
   588                szJoystickButton[2] == '.' && SDL_isdigit(szJoystickButton[3])) {
   589         int hat = SDL_atoi(&szJoystickButton[1]);
   590         int mask = SDL_atoi(&szJoystickButton[3]);
   591         bind.inputType = SDL_CONTROLLER_BINDTYPE_HAT;
   592         bind.input.hat.hat = hat;
   593         bind.input.hat.hat_mask = mask;
   594     } else {
   595         SDL_SetError("Unexpected joystick element: %s", szJoystickButton);
   596         return;
   597     }
   598 
   599     ++gamecontroller->num_bindings;
   600     gamecontroller->bindings = (SDL_ExtendedGameControllerBind *)SDL_realloc(gamecontroller->bindings, gamecontroller->num_bindings * sizeof(*gamecontroller->bindings));
   601     if (!gamecontroller->bindings) {
   602         gamecontroller->num_bindings = 0;
   603         SDL_OutOfMemory();
   604         return;
   605     }
   606     gamecontroller->bindings[gamecontroller->num_bindings - 1] = bind;
   607 }
   608 
   609 
   610 /*
   611  * given a controller mapping string update our mapping object
   612  */
   613 static void
   614 SDL_PrivateGameControllerParseControllerConfigString(SDL_GameController *gamecontroller, const char *pchString)
   615 {
   616     char szGameButton[20];
   617     char szJoystickButton[20];
   618     SDL_bool bGameButton = SDL_TRUE;
   619     int i = 0;
   620     const char *pchPos = pchString;
   621 
   622     SDL_zero(szGameButton);
   623     SDL_zero(szJoystickButton);
   624 
   625     while (pchPos && *pchPos) {
   626         if (*pchPos == ':') {
   627             i = 0;
   628             bGameButton = SDL_FALSE;
   629         } else if (*pchPos == ' ') {
   630 
   631         } else if (*pchPos == ',') {
   632             i = 0;
   633             bGameButton = SDL_TRUE;
   634             SDL_PrivateGameControllerParseElement(gamecontroller, szGameButton, szJoystickButton);
   635             SDL_zero(szGameButton);
   636             SDL_zero(szJoystickButton);
   637 
   638         } else if (bGameButton) {
   639             if (i >= sizeof(szGameButton)) {
   640                 SDL_SetError("Button name too large: %s", szGameButton);
   641                 return;
   642             }
   643             szGameButton[i] = *pchPos;
   644             i++;
   645         } else {
   646             if (i >= sizeof(szJoystickButton)) {
   647                 SDL_SetError("Joystick button name too large: %s", szJoystickButton);
   648                 return;
   649             }
   650             szJoystickButton[i] = *pchPos;
   651             i++;
   652         }
   653         pchPos++;
   654     }
   655 
   656     SDL_PrivateGameControllerParseElement(gamecontroller, szGameButton, szJoystickButton);
   657 
   658 }
   659 
   660 /*
   661  * Make a new button mapping struct
   662  */
   663 static void SDL_PrivateLoadButtonMapping(SDL_GameController *gamecontroller, SDL_JoystickGUID guid, const char *pchName, const char *pchMapping)
   664 {
   665     int i;
   666 
   667     gamecontroller->guid = guid;
   668     gamecontroller->name = pchName;
   669     gamecontroller->num_bindings = 0;
   670     SDL_memset(gamecontroller->last_match_axis, 0, gamecontroller->joystick->naxes * sizeof(*gamecontroller->last_match_axis));
   671 
   672     SDL_PrivateGameControllerParseControllerConfigString(gamecontroller, pchMapping);
   673 
   674     /* Set the zero point for triggers */
   675     for (i = 0; i < gamecontroller->num_bindings; ++i) {
   676         SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
   677         if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS &&
   678             binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS &&
   679             (binding->output.axis.axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT ||
   680              binding->output.axis.axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT)) {
   681             if (binding->input.axis.axis < gamecontroller->joystick->naxes) {
   682                 gamecontroller->joystick->axes[binding->input.axis.axis].value =
   683                 gamecontroller->joystick->axes[binding->input.axis.axis].zero = (Sint16)binding->input.axis.axis_min;
   684             }
   685         }
   686     }
   687 }
   688 
   689 
   690 /*
   691  * grab the guid string from a mapping string
   692  */
   693 static char *SDL_PrivateGetControllerGUIDFromMappingString(const char *pMapping)
   694 {
   695     const char *pFirstComma = SDL_strchr(pMapping, ',');
   696     if (pFirstComma) {
   697         char *pchGUID = SDL_malloc(pFirstComma - pMapping + 1);
   698         if (!pchGUID) {
   699             SDL_OutOfMemory();
   700             return NULL;
   701         }
   702         SDL_memcpy(pchGUID, pMapping, pFirstComma - pMapping);
   703         pchGUID[pFirstComma - pMapping] = '\0';
   704 
   705         /* Convert old style GUIDs to the new style in 2.0.5 */
   706 #if __WIN32__
   707         if (SDL_strlen(pchGUID) == 32 &&
   708             SDL_memcmp(&pchGUID[20], "504944564944", 12) == 0) {
   709             SDL_memcpy(&pchGUID[20], "000000000000", 12);
   710             SDL_memcpy(&pchGUID[16], &pchGUID[4], 4);
   711             SDL_memcpy(&pchGUID[8], &pchGUID[0], 4);
   712             SDL_memcpy(&pchGUID[0], "03000000", 8);
   713         }
   714 #elif __MACOSX__
   715         if (SDL_strlen(pchGUID) == 32 &&
   716             SDL_memcmp(&pchGUID[4], "000000000000", 12) == 0 &&
   717             SDL_memcmp(&pchGUID[20], "000000000000", 12) == 0) {
   718             SDL_memcpy(&pchGUID[20], "000000000000", 12);
   719             SDL_memcpy(&pchGUID[8], &pchGUID[0], 4);
   720             SDL_memcpy(&pchGUID[0], "03000000", 8);
   721         }
   722 #endif
   723         return pchGUID;
   724     }
   725     return NULL;
   726 }
   727 
   728 
   729 /*
   730  * grab the name string from a mapping string
   731  */
   732 static char *SDL_PrivateGetControllerNameFromMappingString(const char *pMapping)
   733 {
   734     const char *pFirstComma, *pSecondComma;
   735     char *pchName;
   736 
   737     pFirstComma = SDL_strchr(pMapping, ',');
   738     if (!pFirstComma)
   739         return NULL;
   740 
   741     pSecondComma = SDL_strchr(pFirstComma + 1, ',');
   742     if (!pSecondComma)
   743         return NULL;
   744 
   745     pchName = SDL_malloc(pSecondComma - pFirstComma);
   746     if (!pchName) {
   747         SDL_OutOfMemory();
   748         return NULL;
   749     }
   750     SDL_memcpy(pchName, pFirstComma + 1, pSecondComma - pFirstComma);
   751     pchName[pSecondComma - pFirstComma - 1] = 0;
   752     return pchName;
   753 }
   754 
   755 
   756 /*
   757  * grab the button mapping string from a mapping string
   758  */
   759 static char *SDL_PrivateGetControllerMappingFromMappingString(const char *pMapping)
   760 {
   761     const char *pFirstComma, *pSecondComma;
   762 
   763     pFirstComma = SDL_strchr(pMapping, ',');
   764     if (!pFirstComma)
   765         return NULL;
   766 
   767     pSecondComma = SDL_strchr(pFirstComma + 1, ',');
   768     if (!pSecondComma)
   769         return NULL;
   770 
   771     return SDL_strdup(pSecondComma + 1); /* mapping is everything after the 3rd comma */
   772 }
   773 
   774 /*
   775  * Helper function to refresh a mapping
   776  */
   777 static void SDL_PrivateGameControllerRefreshMapping(ControllerMapping_t *pControllerMapping)
   778 {
   779     SDL_GameController *gamecontrollerlist = SDL_gamecontrollers;
   780     while (gamecontrollerlist) {
   781         if (!SDL_memcmp(&gamecontrollerlist->guid, &pControllerMapping->guid, sizeof(pControllerMapping->guid))) {
   782             SDL_Event event;
   783             event.type = SDL_CONTROLLERDEVICEREMAPPED;
   784             event.cdevice.which = gamecontrollerlist->joystick->instance_id;
   785             SDL_PushEvent(&event);
   786 
   787             /* Not really threadsafe.  Should this lock access within SDL_GameControllerEventWatcher? */
   788             SDL_PrivateLoadButtonMapping(gamecontrollerlist, pControllerMapping->guid, pControllerMapping->name, pControllerMapping->mapping);
   789         }
   790 
   791         gamecontrollerlist = gamecontrollerlist->next;
   792     }
   793 }
   794 
   795 /*
   796  * Helper function to add a mapping for a guid
   797  */
   798 static ControllerMapping_t *
   799 SDL_PrivateAddMappingForGUID(SDL_JoystickGUID jGUID, const char *mappingString, SDL_bool *existing, SDL_ControllerMappingPriority priority)
   800 {
   801     char *pchName;
   802     char *pchMapping;
   803     ControllerMapping_t *pControllerMapping;
   804 
   805     pchName = SDL_PrivateGetControllerNameFromMappingString(mappingString);
   806     if (!pchName) {
   807         SDL_SetError("Couldn't parse name from %s", mappingString);
   808         return NULL;
   809     }
   810 
   811     pchMapping = SDL_PrivateGetControllerMappingFromMappingString(mappingString);
   812     if (!pchMapping) {
   813         SDL_free(pchName);
   814         SDL_SetError("Couldn't parse %s", mappingString);
   815         return NULL;
   816     }
   817 
   818     pControllerMapping = SDL_PrivateGetControllerMappingForGUID(&jGUID);
   819     if (pControllerMapping) {
   820         /* Only overwrite the mapping if the priority is the same or higher. */
   821         if (pControllerMapping->priority <= priority) {
   822             /* Update existing mapping */
   823             SDL_free(pControllerMapping->name);
   824             pControllerMapping->name = pchName;
   825             SDL_free(pControllerMapping->mapping);
   826             pControllerMapping->mapping = pchMapping;
   827             pControllerMapping->priority = priority;
   828             /* refresh open controllers */
   829             SDL_PrivateGameControllerRefreshMapping(pControllerMapping);
   830         } else {
   831             SDL_free(pchName);
   832             SDL_free(pchMapping);
   833         }
   834         *existing = SDL_TRUE;
   835     } else {
   836         pControllerMapping = SDL_malloc(sizeof(*pControllerMapping));
   837         if (!pControllerMapping) {
   838             SDL_free(pchName);
   839             SDL_free(pchMapping);
   840             SDL_OutOfMemory();
   841             return NULL;
   842         }
   843         pControllerMapping->guid = jGUID;
   844         pControllerMapping->name = pchName;
   845         pControllerMapping->mapping = pchMapping;
   846         pControllerMapping->next = NULL;
   847         pControllerMapping->priority = priority;
   848 
   849         if (s_pSupportedControllers) {
   850             /* Add the mapping to the end of the list */
   851             ControllerMapping_t *pCurrMapping, *pPrevMapping;
   852 
   853             for ( pPrevMapping = s_pSupportedControllers, pCurrMapping = pPrevMapping->next;
   854                   pCurrMapping; 
   855                   pPrevMapping = pCurrMapping, pCurrMapping = pCurrMapping->next ) {
   856                 continue;
   857             }
   858             pPrevMapping->next = pControllerMapping;
   859         } else {
   860             s_pSupportedControllers = pControllerMapping;
   861         }
   862         *existing = SDL_FALSE;
   863     }
   864     return pControllerMapping;
   865 }
   866 
   867 /*
   868  * Helper function to determine pre-calculated offset to certain joystick mappings
   869  */
   870 static ControllerMapping_t *SDL_PrivateGetControllerMappingForNameAndGUID(const char *name, SDL_JoystickGUID guid)
   871 {
   872     ControllerMapping_t *mapping;
   873 
   874     mapping = SDL_PrivateGetControllerMappingForGUID(&guid);
   875 #if defined(SDL_JOYSTICK_EMSCRIPTEN)
   876     if (!mapping && s_pEmscriptenMapping) {
   877         mapping = s_pEmscriptenMapping;
   878     }
   879 #else
   880     (void) s_pEmscriptenMapping;  /* pacify ARMCC */
   881 #endif
   882 #ifdef __LINUX__
   883     if (!mapping && name) {
   884         if (SDL_strstr(name, "Xbox 360 Wireless Receiver")) {
   885             /* The Linux driver xpad.c maps the wireless dpad to buttons */
   886             SDL_bool existing;
   887             mapping = SDL_PrivateAddMappingForGUID(guid,
   888 "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,",
   889                           &existing, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT);
   890         }
   891     }
   892 #endif /* __LINUX__ */
   893 
   894     if (!mapping && name) {
   895         if (SDL_strstr(name, "Xbox") || SDL_strstr(name, "X-Box") || SDL_strstr(name, "XBOX")) {
   896             mapping = s_pXInputMapping;
   897         }
   898     }
   899     return mapping;
   900 }
   901 
   902 static ControllerMapping_t *SDL_PrivateGetControllerMapping(int device_index)
   903 {
   904     const char *name = SDL_JoystickNameForIndex(device_index);
   905     SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
   906     ControllerMapping_t *mapping = SDL_PrivateGetControllerMappingForNameAndGUID(name, guid);
   907 #if SDL_JOYSTICK_XINPUT
   908     if (!mapping && SDL_SYS_IsXInputGamepad_DeviceIndex(device_index)) {
   909         mapping = s_pXInputMapping;
   910     }
   911 #endif
   912     return mapping;
   913 }
   914 
   915 /*
   916  * Add or update an entry into the Mappings Database
   917  */
   918 int
   919 SDL_GameControllerAddMappingsFromRW(SDL_RWops * rw, int freerw)
   920 {
   921     const char *platform = SDL_GetPlatform();
   922     int controllers = 0;
   923     char *buf, *line, *line_end, *tmp, *comma, line_platform[64];
   924     size_t db_size, platform_len;
   925     
   926     if (rw == NULL) {
   927         return SDL_SetError("Invalid RWops");
   928     }
   929     db_size = (size_t)SDL_RWsize(rw);
   930     
   931     buf = (char *)SDL_malloc(db_size + 1);
   932     if (buf == NULL) {
   933         if (freerw) {
   934             SDL_RWclose(rw);
   935         }
   936         return SDL_SetError("Could not allocate space to read DB into memory");
   937     }
   938     
   939     if (SDL_RWread(rw, buf, db_size, 1) != 1) {
   940         if (freerw) {
   941             SDL_RWclose(rw);
   942         }
   943         SDL_free(buf);
   944         return SDL_SetError("Could not read DB");
   945     }
   946     
   947     if (freerw) {
   948         SDL_RWclose(rw);
   949     }
   950     
   951     buf[db_size] = '\0';
   952     line = buf;
   953     
   954     while (line < buf + db_size) {
   955         line_end = SDL_strchr(line, '\n');
   956         if (line_end != NULL) {
   957             *line_end = '\0';
   958         } else {
   959             line_end = buf + db_size;
   960         }
   961         
   962         /* Extract and verify the platform */
   963         tmp = SDL_strstr(line, SDL_CONTROLLER_PLATFORM_FIELD);
   964         if (tmp != NULL) {
   965             tmp += SDL_strlen(SDL_CONTROLLER_PLATFORM_FIELD);
   966             comma = SDL_strchr(tmp, ',');
   967             if (comma != NULL) {
   968                 platform_len = comma - tmp + 1;
   969                 if (platform_len + 1 < SDL_arraysize(line_platform)) {
   970                     SDL_strlcpy(line_platform, tmp, platform_len);
   971                     if (SDL_strncasecmp(line_platform, platform, platform_len) == 0 &&
   972                         SDL_GameControllerAddMapping(line) > 0) {
   973                         controllers++;
   974                     }
   975                 }
   976             }
   977         }
   978         
   979         line = line_end + 1;
   980     }
   981 
   982     SDL_free(buf);
   983     return controllers;
   984 }
   985 
   986 /*
   987  * Add or update an entry into the Mappings Database with a priority
   988  */
   989 static int
   990 SDL_PrivateGameControllerAddMapping(const char *mappingString, SDL_ControllerMappingPriority priority)
   991 {
   992     char *pchGUID;
   993     SDL_JoystickGUID jGUID;
   994     SDL_bool is_xinput_mapping = SDL_FALSE;
   995     SDL_bool is_emscripten_mapping = SDL_FALSE;
   996     SDL_bool existing = SDL_FALSE;
   997     ControllerMapping_t *pControllerMapping;
   998 
   999     if (!mappingString) {
  1000         return SDL_InvalidParamError("mappingString");
  1001     }
  1002 
  1003     pchGUID = SDL_PrivateGetControllerGUIDFromMappingString(mappingString);
  1004     if (!pchGUID) {
  1005         return SDL_SetError("Couldn't parse GUID from %s", mappingString);
  1006     }
  1007     if (!SDL_strcasecmp(pchGUID, "xinput")) {
  1008         is_xinput_mapping = SDL_TRUE;
  1009     }
  1010     if (!SDL_strcasecmp(pchGUID, "emscripten")) {
  1011         is_emscripten_mapping = SDL_TRUE;
  1012     }
  1013     jGUID = SDL_JoystickGetGUIDFromString(pchGUID);
  1014     SDL_free(pchGUID);
  1015 
  1016     pControllerMapping = SDL_PrivateAddMappingForGUID(jGUID, mappingString, &existing, priority);
  1017     if (!pControllerMapping) {
  1018         return -1;
  1019     }
  1020 
  1021     if (existing) {
  1022         return 0;
  1023     } else {
  1024         if (is_xinput_mapping) {
  1025             s_pXInputMapping = pControllerMapping;
  1026         }
  1027         if (is_emscripten_mapping) {
  1028             s_pEmscriptenMapping = pControllerMapping;
  1029         }
  1030         return 1;
  1031     }
  1032 }
  1033 
  1034 /*
  1035  * Add or update an entry into the Mappings Database
  1036  */
  1037 int
  1038 SDL_GameControllerAddMapping(const char *mappingString)
  1039 {
  1040     return SDL_PrivateGameControllerAddMapping(mappingString, SDL_CONTROLLER_MAPPING_PRIORITY_API);
  1041 }
  1042 
  1043 /*
  1044  *  Get the number of mappings installed
  1045  */
  1046 int
  1047 SDL_GameControllerNumMappings(void)
  1048 {
  1049     int num_mappings = 0;
  1050     ControllerMapping_t *mapping;
  1051 
  1052     for (mapping = s_pSupportedControllers; mapping; mapping = mapping->next) {
  1053         if (SDL_memcmp(&mapping->guid, &s_zeroGUID, sizeof(mapping->guid)) == 0) {
  1054             continue;
  1055         }
  1056         ++num_mappings;
  1057     }
  1058     return num_mappings;
  1059 }
  1060 
  1061 /*
  1062  *  Get the mapping at a particular index.
  1063  */
  1064 char *
  1065 SDL_GameControllerMappingForIndex(int mapping_index)
  1066 {
  1067     ControllerMapping_t *mapping;
  1068 
  1069     for (mapping = s_pSupportedControllers; mapping; mapping = mapping->next) {
  1070         if (SDL_memcmp(&mapping->guid, &s_zeroGUID, sizeof(mapping->guid)) == 0) {
  1071             continue;
  1072         }
  1073         if (mapping_index == 0) {
  1074             char *pMappingString;
  1075             char pchGUID[33];
  1076             size_t needed;
  1077 
  1078             SDL_JoystickGetGUIDString(mapping->guid, pchGUID, sizeof(pchGUID));
  1079             /* allocate enough memory for GUID + ',' + name + ',' + mapping + \0 */
  1080             needed = SDL_strlen(pchGUID) + 1 + SDL_strlen(mapping->name) + 1 + SDL_strlen(mapping->mapping) + 1;
  1081             pMappingString = SDL_malloc(needed);
  1082             if (!pMappingString) {
  1083                 SDL_OutOfMemory();
  1084                 return NULL;
  1085             }
  1086             SDL_snprintf(pMappingString, needed, "%s,%s,%s", pchGUID, mapping->name, mapping->mapping);
  1087             return pMappingString;
  1088         }
  1089         --mapping_index;
  1090     }
  1091     return NULL;
  1092 }
  1093 
  1094 /*
  1095  * Get the mapping string for this GUID
  1096  */
  1097 char *
  1098 SDL_GameControllerMappingForGUID(SDL_JoystickGUID guid)
  1099 {
  1100     char *pMappingString = NULL;
  1101     ControllerMapping_t *mapping = SDL_PrivateGetControllerMappingForGUID(&guid);
  1102     if (mapping) {
  1103         char pchGUID[33];
  1104         size_t needed;
  1105         SDL_JoystickGetGUIDString(guid, pchGUID, sizeof(pchGUID));
  1106         /* allocate enough memory for GUID + ',' + name + ',' + mapping + \0 */
  1107         needed = SDL_strlen(pchGUID) + 1 + SDL_strlen(mapping->name) + 1 + SDL_strlen(mapping->mapping) + 1;
  1108         pMappingString = SDL_malloc(needed);
  1109         if (!pMappingString) {
  1110             SDL_OutOfMemory();
  1111             return NULL;
  1112         }
  1113         SDL_snprintf(pMappingString, needed, "%s,%s,%s", pchGUID, mapping->name, mapping->mapping);
  1114     }
  1115     return pMappingString;
  1116 }
  1117 
  1118 /*
  1119  * Get the mapping string for this device
  1120  */
  1121 char *
  1122 SDL_GameControllerMapping(SDL_GameController * gamecontroller)
  1123 {
  1124     if (!gamecontroller) {
  1125         return NULL;
  1126     }
  1127 
  1128     return SDL_GameControllerMappingForGUID(gamecontroller->guid);
  1129 }
  1130 
  1131 static void
  1132 SDL_GameControllerLoadHints()
  1133 {
  1134     const char *hint = SDL_GetHint(SDL_HINT_GAMECONTROLLERCONFIG);
  1135     if (hint && hint[0]) {
  1136         size_t nchHints = SDL_strlen(hint);
  1137         char *pUserMappings = SDL_malloc(nchHints + 1);
  1138         char *pTempMappings = pUserMappings;
  1139         SDL_memcpy(pUserMappings, hint, nchHints);
  1140         pUserMappings[nchHints] = '\0';
  1141         while (pUserMappings) {
  1142             char *pchNewLine = NULL;
  1143 
  1144             pchNewLine = SDL_strchr(pUserMappings, '\n');
  1145             if (pchNewLine)
  1146                 *pchNewLine = '\0';
  1147 
  1148             SDL_PrivateGameControllerAddMapping(pUserMappings, SDL_CONTROLLER_MAPPING_PRIORITY_USER);
  1149 
  1150             if (pchNewLine) {
  1151                 pUserMappings = pchNewLine + 1;
  1152             } else {
  1153                 pUserMappings = NULL;
  1154             }
  1155         }
  1156         SDL_free(pTempMappings);
  1157     }
  1158 }
  1159 
  1160 /*
  1161  * Initialize the game controller system, mostly load our DB of controller config mappings
  1162  */
  1163 int
  1164 SDL_GameControllerInitMappings(void)
  1165 {
  1166     int i = 0;
  1167     const char *pMappingString = NULL;
  1168     pMappingString = s_ControllerMappings[i];
  1169     while (pMappingString) {
  1170         SDL_PrivateGameControllerAddMapping(pMappingString, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT);
  1171 
  1172         i++;
  1173         pMappingString = s_ControllerMappings[i];
  1174     }
  1175 
  1176     /* load in any user supplied config */
  1177     SDL_GameControllerLoadHints();
  1178 
  1179     SDL_AddHintCallback(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES,
  1180                         SDL_GameControllerIgnoreDevicesChanged, NULL);
  1181     SDL_AddHintCallback(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT,
  1182                         SDL_GameControllerIgnoreDevicesExceptChanged, NULL);
  1183 
  1184     return (0);
  1185 }
  1186 
  1187 int
  1188 SDL_GameControllerInit(void)
  1189 {
  1190     int i;
  1191 
  1192     /* watch for joy events and fire controller ones if needed */
  1193     SDL_AddEventWatch(SDL_GameControllerEventWatcher, NULL);
  1194 
  1195     /* Send added events for controllers currently attached */
  1196     for (i = 0; i < SDL_NumJoysticks(); ++i) {
  1197         if (SDL_IsGameController(i)) {
  1198             SDL_Event deviceevent;
  1199             deviceevent.type = SDL_CONTROLLERDEVICEADDED;
  1200             deviceevent.cdevice.which = i;
  1201             SDL_PushEvent(&deviceevent);
  1202         }
  1203     }
  1204 
  1205     return (0);
  1206 }
  1207 
  1208 
  1209 /*
  1210  * Get the implementation dependent name of a controller
  1211  */
  1212 const char *
  1213 SDL_GameControllerNameForIndex(int device_index)
  1214 {
  1215     ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(device_index);
  1216     if (pSupportedController) {
  1217         return pSupportedController->name;
  1218     }
  1219     return NULL;
  1220 }
  1221 
  1222 
  1223 /*
  1224  * Return 1 if the joystick with this name and GUID is a supported controller
  1225  */
  1226 SDL_bool
  1227 SDL_IsGameControllerNameAndGUID(const char *name, SDL_JoystickGUID guid)
  1228 {
  1229     ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMappingForNameAndGUID(name, guid);
  1230     if (pSupportedController) {
  1231         return SDL_TRUE;
  1232     }
  1233     return SDL_FALSE;
  1234 }
  1235 
  1236 /*
  1237  * Return 1 if the joystick at this device index is a supported controller
  1238  */
  1239 SDL_bool
  1240 SDL_IsGameController(int device_index)
  1241 {
  1242     ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(device_index);
  1243     if (pSupportedController) {
  1244         return SDL_TRUE;
  1245     }
  1246     return SDL_FALSE;
  1247 }
  1248 
  1249 /*
  1250  * Return 1 if the game controller should be ignored by SDL
  1251  */
  1252 SDL_bool SDL_ShouldIgnoreGameController(const char *name, SDL_JoystickGUID guid)
  1253 {
  1254     int i;
  1255     Uint16 vendor;
  1256     Uint16 product;
  1257     Uint32 vidpid;
  1258 
  1259     if (SDL_allowed_controllers.num_entries == 0 &&
  1260         SDL_ignored_controllers.num_entries == 0) {
  1261         return SDL_FALSE;
  1262     }
  1263 
  1264     SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL);
  1265     vidpid = MAKE_VIDPID(vendor, product);
  1266 
  1267     if (SDL_GetHintBoolean("SDL_GAMECONTROLLER_ALLOW_STEAM_VIRTUAL_GAMEPAD", SDL_FALSE)) {
  1268         /* We shouldn't ignore Steam's virtual gamepad since it's using the hints to filter out the real controllers so it can remap input for the virtual controller */
  1269         SDL_bool bSteamVirtualGamepad = SDL_FALSE;
  1270 #if defined(__LINUX__)
  1271         bSteamVirtualGamepad = (vendor == 0x28DE && product == 0x11FF);
  1272 #elif defined(__MACOSX__)
  1273         bSteamVirtualGamepad = (SDL_strncmp(name, "GamePad-", 8) == 0);
  1274 #elif defined(__WIN32__)
  1275         /* We can't tell on Windows, but Steam will block others in input hooks */
  1276         bSteamVirtualGamepad = SDL_TRUE;
  1277 #endif
  1278         if (bSteamVirtualGamepad) {
  1279             return SDL_FALSE;
  1280         }
  1281     }
  1282 
  1283     if (SDL_allowed_controllers.num_entries > 0) {
  1284         for (i = 0; i < SDL_allowed_controllers.num_entries; ++i) {
  1285             if (vidpid == SDL_allowed_controllers.entries[i]) {
  1286                 return SDL_FALSE;
  1287             }
  1288         }
  1289         return SDL_TRUE;
  1290     } else {
  1291         for (i = 0; i < SDL_ignored_controllers.num_entries; ++i) {
  1292             if (vidpid == SDL_ignored_controllers.entries[i]) {
  1293                 return SDL_TRUE;
  1294             }
  1295         }
  1296         return SDL_FALSE;
  1297     }
  1298 }
  1299 
  1300 /*
  1301  * Open a controller for use - the index passed as an argument refers to
  1302  * the N'th controller on the system.  This index is the value which will
  1303  * identify this controller in future controller events.
  1304  *
  1305  * This function returns a controller identifier, or NULL if an error occurred.
  1306  */
  1307 SDL_GameController *
  1308 SDL_GameControllerOpen(int device_index)
  1309 {
  1310     SDL_GameController *gamecontroller;
  1311     SDL_GameController *gamecontrollerlist;
  1312     ControllerMapping_t *pSupportedController = NULL;
  1313 
  1314     if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
  1315         SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
  1316         return (NULL);
  1317     }
  1318 
  1319     SDL_LockJoystickList();
  1320 
  1321     gamecontrollerlist = SDL_gamecontrollers;
  1322     /* If the controller is already open, return it */
  1323     while (gamecontrollerlist) {
  1324         if (SDL_SYS_GetInstanceIdOfDeviceIndex(device_index) == gamecontrollerlist->joystick->instance_id) {
  1325                 gamecontroller = gamecontrollerlist;
  1326                 ++gamecontroller->ref_count;
  1327                 SDL_UnlockJoystickList();
  1328                 return (gamecontroller);
  1329         }
  1330         gamecontrollerlist = gamecontrollerlist->next;
  1331     }
  1332 
  1333     /* Find a controller mapping */
  1334     pSupportedController =  SDL_PrivateGetControllerMapping(device_index);
  1335     if (!pSupportedController) {
  1336         SDL_SetError("Couldn't find mapping for device (%d)", device_index);
  1337         SDL_UnlockJoystickList();
  1338         return NULL;
  1339     }
  1340 
  1341     /* Create and initialize the controller */
  1342     gamecontroller = (SDL_GameController *) SDL_calloc(1, sizeof(*gamecontroller));
  1343     if (gamecontroller == NULL) {
  1344         SDL_OutOfMemory();
  1345         SDL_UnlockJoystickList();
  1346         return NULL;
  1347     }
  1348 
  1349     gamecontroller->joystick = SDL_JoystickOpen(device_index);
  1350     if (!gamecontroller->joystick) {
  1351         SDL_free(gamecontroller);
  1352         SDL_UnlockJoystickList();
  1353         return NULL;
  1354     }
  1355 
  1356     if (gamecontroller->joystick->naxes) {
  1357         gamecontroller->last_match_axis = (SDL_ExtendedGameControllerBind **)SDL_calloc(gamecontroller->joystick->naxes, sizeof(*gamecontroller->last_match_axis));
  1358         if (!gamecontroller->last_match_axis) {
  1359             SDL_OutOfMemory();
  1360             SDL_JoystickClose(gamecontroller->joystick);
  1361             SDL_free(gamecontroller);
  1362             SDL_UnlockJoystickList();
  1363             return NULL;
  1364         }
  1365     }
  1366     if (gamecontroller->joystick->nhats) {
  1367         gamecontroller->last_hat_mask = (Uint8 *)SDL_calloc(gamecontroller->joystick->nhats, sizeof(*gamecontroller->last_hat_mask));
  1368         if (!gamecontroller->last_hat_mask) {
  1369             SDL_OutOfMemory();
  1370             SDL_JoystickClose(gamecontroller->joystick);
  1371             SDL_free(gamecontroller->last_match_axis);
  1372             SDL_free(gamecontroller);
  1373             SDL_UnlockJoystickList();
  1374             return NULL;
  1375         }
  1376     }
  1377 
  1378     SDL_PrivateLoadButtonMapping(gamecontroller, pSupportedController->guid, pSupportedController->name, pSupportedController->mapping);
  1379 
  1380     /* Add the controller to list */
  1381     ++gamecontroller->ref_count;
  1382     /* Link the controller in the list */
  1383     gamecontroller->next = SDL_gamecontrollers;
  1384     SDL_gamecontrollers = gamecontroller;
  1385 
  1386     SDL_UnlockJoystickList();
  1387 
  1388     return (gamecontroller);
  1389 }
  1390 
  1391 /*
  1392  * Manually pump for controller updates.
  1393  */
  1394 void
  1395 SDL_GameControllerUpdate(void)
  1396 {
  1397     /* Just for API completeness; the joystick API does all the work. */
  1398     SDL_JoystickUpdate();
  1399 }
  1400 
  1401 /*
  1402  * Get the current state of an axis control on a controller
  1403  */
  1404 Sint16
  1405 SDL_GameControllerGetAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis)
  1406 {
  1407     int i;
  1408 
  1409     if (!gamecontroller)
  1410         return 0;
  1411 
  1412     for (i = 0; i < gamecontroller->num_bindings; ++i) {
  1413         SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
  1414         if (binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS && binding->output.axis.axis == axis) {
  1415             int value = 0;
  1416             SDL_bool valid_input_range;
  1417             SDL_bool valid_output_range;
  1418 
  1419             if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
  1420                 value = SDL_JoystickGetAxis(gamecontroller->joystick, binding->input.axis.axis);
  1421                 if (binding->input.axis.axis_min < binding->input.axis.axis_max) {
  1422                     valid_input_range = (value >= binding->input.axis.axis_min && value <= binding->input.axis.axis_max);
  1423                 } else {
  1424                     valid_input_range = (value >= binding->input.axis.axis_max && value <= binding->input.axis.axis_min);
  1425                 }
  1426                 if (valid_input_range) {
  1427                     if (binding->input.axis.axis_min != binding->output.axis.axis_min || binding->input.axis.axis_max != binding->output.axis.axis_max) {
  1428                         float normalized_value = (float)(value - binding->input.axis.axis_min) / (binding->input.axis.axis_max - binding->input.axis.axis_min);
  1429                         value = binding->output.axis.axis_min + (int)(normalized_value * (binding->output.axis.axis_max - binding->output.axis.axis_min));
  1430                     }
  1431                 }
  1432             } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
  1433                 value = SDL_JoystickGetButton(gamecontroller->joystick, binding->input.button);
  1434                 if (value == SDL_PRESSED) {
  1435                     value = binding->output.axis.axis_max;
  1436                 }
  1437             } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
  1438                 int hat_mask = SDL_JoystickGetHat(gamecontroller->joystick, binding->input.hat.hat);
  1439                 if (hat_mask & binding->input.hat.hat_mask) {
  1440                     value = binding->output.axis.axis_max;
  1441                 }
  1442             }
  1443 
  1444             if (binding->output.axis.axis_min < binding->output.axis.axis_max) {
  1445                 valid_output_range = (value >= binding->output.axis.axis_min && value <= binding->output.axis.axis_max);
  1446             } else {
  1447                 valid_output_range = (value >= binding->output.axis.axis_max && value <= binding->output.axis.axis_min);
  1448             }
  1449             /* If the value is zero, there might be another binding that makes it non-zero */
  1450             if (value != 0 && valid_output_range) {
  1451                 return (Sint16)value;
  1452             }
  1453         }
  1454     }
  1455     return 0;
  1456 }
  1457 
  1458 /*
  1459  * Get the current state of a button on a controller
  1460  */
  1461 Uint8
  1462 SDL_GameControllerGetButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button)
  1463 {
  1464     int i;
  1465 
  1466     if (!gamecontroller)
  1467         return 0;
  1468 
  1469     for (i = 0; i < gamecontroller->num_bindings; ++i) {
  1470         SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
  1471         if (binding->outputType == SDL_CONTROLLER_BINDTYPE_BUTTON && binding->output.button == button) {
  1472             if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
  1473                 SDL_bool valid_input_range;
  1474 
  1475                 int value = SDL_JoystickGetAxis(gamecontroller->joystick, binding->input.axis.axis);
  1476                 int threshold = binding->input.axis.axis_min + (binding->input.axis.axis_max - binding->input.axis.axis_min) / 2;
  1477                 if (binding->input.axis.axis_min < binding->input.axis.axis_max) {
  1478                     valid_input_range = (value >= binding->input.axis.axis_min && value <= binding->input.axis.axis_max);
  1479                     if (valid_input_range) {
  1480                         return (value >= threshold) ? SDL_PRESSED : SDL_RELEASED;
  1481                     }
  1482                 } else {
  1483                     valid_input_range = (value >= binding->input.axis.axis_max && value <= binding->input.axis.axis_min);
  1484                     if (valid_input_range) {
  1485                         return (value <= threshold) ? SDL_PRESSED : SDL_RELEASED;
  1486                     }
  1487                 }
  1488             } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
  1489                 return SDL_JoystickGetButton(gamecontroller->joystick, binding->input.button);
  1490             } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
  1491                 int hat_mask = SDL_JoystickGetHat(gamecontroller->joystick, binding->input.hat.hat);
  1492                 return (hat_mask & binding->input.hat.hat_mask) ? SDL_PRESSED : SDL_RELEASED;
  1493             }
  1494         }
  1495     }
  1496     return SDL_RELEASED;
  1497 }
  1498 
  1499 const char *
  1500 SDL_GameControllerName(SDL_GameController * gamecontroller)
  1501 {
  1502     if (!gamecontroller)
  1503         return NULL;
  1504 
  1505     return gamecontroller->name;
  1506 }
  1507 
  1508 Uint16
  1509 SDL_GameControllerGetVendor(SDL_GameController * gamecontroller)
  1510 {
  1511     return SDL_JoystickGetVendor(SDL_GameControllerGetJoystick(gamecontroller));
  1512 }
  1513 
  1514 Uint16
  1515 SDL_GameControllerGetProduct(SDL_GameController * gamecontroller)
  1516 {
  1517     return SDL_JoystickGetProduct(SDL_GameControllerGetJoystick(gamecontroller));
  1518 }
  1519 
  1520 Uint16
  1521 SDL_GameControllerGetProductVersion(SDL_GameController * gamecontroller)
  1522 {
  1523     return SDL_JoystickGetProductVersion(SDL_GameControllerGetJoystick(gamecontroller));
  1524 }
  1525 
  1526 /*
  1527  * Return if the controller in question is currently attached to the system,
  1528  *  \return 0 if not plugged in, 1 if still present.
  1529  */
  1530 SDL_bool
  1531 SDL_GameControllerGetAttached(SDL_GameController * gamecontroller)
  1532 {
  1533     if (!gamecontroller)
  1534         return SDL_FALSE;
  1535 
  1536     return SDL_JoystickGetAttached(gamecontroller->joystick);
  1537 }
  1538 
  1539 /*
  1540  * Get the joystick for this controller
  1541  */
  1542 SDL_Joystick *SDL_GameControllerGetJoystick(SDL_GameController * gamecontroller)
  1543 {
  1544     if (!gamecontroller)
  1545         return NULL;
  1546 
  1547     return gamecontroller->joystick;
  1548 }
  1549 
  1550 
  1551 /*
  1552  * Find the SDL_GameController that owns this instance id
  1553  */
  1554 SDL_GameController *
  1555 SDL_GameControllerFromInstanceID(SDL_JoystickID joyid)
  1556 {
  1557     SDL_GameController *gamecontroller;
  1558 
  1559     SDL_LockJoystickList();
  1560     gamecontroller = SDL_gamecontrollers;
  1561     while (gamecontroller) {
  1562         if (gamecontroller->joystick->instance_id == joyid) {
  1563             SDL_UnlockJoystickList();
  1564             return gamecontroller;
  1565         }
  1566         gamecontroller = gamecontroller->next;
  1567     }
  1568     SDL_UnlockJoystickList();
  1569     return NULL;
  1570 }
  1571 
  1572 
  1573 /*
  1574  * Get the SDL joystick layer binding for this controller axis mapping
  1575  */
  1576 SDL_GameControllerButtonBind SDL_GameControllerGetBindForAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis)
  1577 {
  1578     int i;
  1579     SDL_GameControllerButtonBind bind;
  1580     SDL_zero(bind);
  1581 
  1582     if (!gamecontroller || axis == SDL_CONTROLLER_AXIS_INVALID)
  1583         return bind;
  1584 
  1585     for (i = 0; i < gamecontroller->num_bindings; ++i) {
  1586         SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
  1587         if (binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS && binding->output.axis.axis == axis) {
  1588             bind.bindType = binding->inputType;
  1589             if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
  1590                 /* FIXME: There might be multiple axes bound now that we have axis ranges... */
  1591                 bind.value.axis = binding->input.axis.axis;
  1592             } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
  1593                 bind.value.button = binding->input.button;
  1594             } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
  1595                 bind.value.hat.hat = binding->input.hat.hat;
  1596                 bind.value.hat.hat_mask = binding->input.hat.hat_mask;
  1597             }
  1598             break;
  1599         }
  1600     }
  1601     return bind;
  1602 }
  1603 
  1604 
  1605 /*
  1606  * Get the SDL joystick layer binding for this controller button mapping
  1607  */
  1608 SDL_GameControllerButtonBind SDL_GameControllerGetBindForButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button)
  1609 {
  1610     int i;
  1611     SDL_GameControllerButtonBind bind;
  1612     SDL_zero(bind);
  1613 
  1614     if (!gamecontroller || button == SDL_CONTROLLER_BUTTON_INVALID)
  1615         return bind;
  1616 
  1617     for (i = 0; i < gamecontroller->num_bindings; ++i) {
  1618         SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
  1619         if (binding->outputType == SDL_CONTROLLER_BINDTYPE_BUTTON && binding->output.button == button) {
  1620             bind.bindType = binding->inputType;
  1621             if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
  1622                 bind.value.axis = binding->input.axis.axis;
  1623             } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
  1624                 bind.value.button = binding->input.button;
  1625             } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
  1626                 bind.value.hat.hat = binding->input.hat.hat;
  1627                 bind.value.hat.hat_mask = binding->input.hat.hat_mask;
  1628             }
  1629             break;
  1630         }
  1631     }
  1632     return bind;
  1633 }
  1634 
  1635 
  1636 void
  1637 SDL_GameControllerClose(SDL_GameController * gamecontroller)
  1638 {
  1639     SDL_GameController *gamecontrollerlist, *gamecontrollerlistprev;
  1640 
  1641     if (!gamecontroller)
  1642         return;
  1643 
  1644     SDL_LockJoystickList();
  1645 
  1646     /* First decrement ref count */
  1647     if (--gamecontroller->ref_count > 0) {
  1648         SDL_UnlockJoystickList();
  1649         return;
  1650     }
  1651 
  1652     SDL_JoystickClose(gamecontroller->joystick);
  1653 
  1654     gamecontrollerlist = SDL_gamecontrollers;
  1655     gamecontrollerlistprev = NULL;
  1656     while (gamecontrollerlist) {
  1657         if (gamecontroller == gamecontrollerlist) {
  1658             if (gamecontrollerlistprev) {
  1659                 /* unlink this entry */
  1660                 gamecontrollerlistprev->next = gamecontrollerlist->next;
  1661             } else {
  1662                 SDL_gamecontrollers = gamecontroller->next;
  1663             }
  1664             break;
  1665         }
  1666         gamecontrollerlistprev = gamecontrollerlist;
  1667         gamecontrollerlist = gamecontrollerlist->next;
  1668     }
  1669 
  1670     SDL_free(gamecontroller->bindings);
  1671     SDL_free(gamecontroller->last_match_axis);
  1672     SDL_free(gamecontroller->last_hat_mask);
  1673     SDL_free(gamecontroller);
  1674 
  1675     SDL_UnlockJoystickList();
  1676 }
  1677 
  1678 
  1679 /*
  1680  * Quit the controller subsystem
  1681  */
  1682 void
  1683 SDL_GameControllerQuit(void)
  1684 {
  1685     SDL_LockJoystickList();
  1686     while (SDL_gamecontrollers) {
  1687         SDL_gamecontrollers->ref_count = 1;
  1688         SDL_GameControllerClose(SDL_gamecontrollers);
  1689     }
  1690     SDL_UnlockJoystickList();
  1691 }
  1692 
  1693 void
  1694 SDL_GameControllerQuitMappings(void)
  1695 {
  1696     ControllerMapping_t *pControllerMap;
  1697 
  1698     while (s_pSupportedControllers) {
  1699         pControllerMap = s_pSupportedControllers;
  1700         s_pSupportedControllers = s_pSupportedControllers->next;
  1701         SDL_free(pControllerMap->name);
  1702         SDL_free(pControllerMap->mapping);
  1703         SDL_free(pControllerMap);
  1704     }
  1705 
  1706     SDL_DelEventWatch(SDL_GameControllerEventWatcher, NULL);
  1707 
  1708     SDL_DelHintCallback(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES,
  1709                         SDL_GameControllerIgnoreDevicesChanged, NULL);
  1710     SDL_DelHintCallback(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT,
  1711                         SDL_GameControllerIgnoreDevicesExceptChanged, NULL);
  1712 
  1713     if (SDL_allowed_controllers.entries) {
  1714         SDL_free(SDL_allowed_controllers.entries);
  1715         SDL_zero(SDL_allowed_controllers);
  1716     }
  1717     if (SDL_ignored_controllers.entries) {
  1718         SDL_free(SDL_ignored_controllers.entries);
  1719         SDL_zero(SDL_ignored_controllers);
  1720     }
  1721 }
  1722 
  1723 /*
  1724  * Event filter to transform joystick events into appropriate game controller ones
  1725  */
  1726 static int
  1727 SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis, Sint16 value)
  1728 {
  1729     int posted;
  1730 
  1731     /* translate the event, if desired */
  1732     posted = 0;
  1733 #if !SDL_EVENTS_DISABLED
  1734     if (SDL_GetEventState(SDL_CONTROLLERAXISMOTION) == SDL_ENABLE) {
  1735         SDL_Event event;
  1736         event.type = SDL_CONTROLLERAXISMOTION;
  1737         event.caxis.which = gamecontroller->joystick->instance_id;
  1738         event.caxis.axis = axis;
  1739         event.caxis.value = value;
  1740         posted = SDL_PushEvent(&event) == 1;
  1741     }
  1742 #endif /* !SDL_EVENTS_DISABLED */
  1743     return (posted);
  1744 }
  1745 
  1746 
  1747 /*
  1748  * Event filter to transform joystick events into appropriate game controller ones
  1749  */
  1750 static int
  1751 SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button, Uint8 state)
  1752 {
  1753     int posted;
  1754 #if !SDL_EVENTS_DISABLED
  1755     SDL_Event event;
  1756 
  1757     if (button == SDL_CONTROLLER_BUTTON_INVALID)
  1758         return (0);
  1759 
  1760     switch (state) {
  1761     case SDL_PRESSED:
  1762         event.type = SDL_CONTROLLERBUTTONDOWN;
  1763         break;
  1764     case SDL_RELEASED:
  1765         event.type = SDL_CONTROLLERBUTTONUP;
  1766         break;
  1767     default:
  1768         /* Invalid state -- bail */
  1769         return (0);
  1770     }
  1771 #endif /* !SDL_EVENTS_DISABLED */
  1772 
  1773     /* translate the event, if desired */
  1774     posted = 0;
  1775 #if !SDL_EVENTS_DISABLED
  1776     if (SDL_GetEventState(event.type) == SDL_ENABLE) {
  1777         event.cbutton.which = gamecontroller->joystick->instance_id;
  1778         event.cbutton.button = button;
  1779         event.cbutton.state = state;
  1780         posted = SDL_PushEvent(&event) == 1;
  1781     }
  1782 #endif /* !SDL_EVENTS_DISABLED */
  1783     return (posted);
  1784 }
  1785 
  1786 /*
  1787  * Turn off controller events
  1788  */
  1789 int
  1790 SDL_GameControllerEventState(int state)
  1791 {
  1792 #if SDL_EVENTS_DISABLED
  1793     return SDL_IGNORE;
  1794 #else
  1795     const Uint32 event_list[] = {
  1796         SDL_CONTROLLERAXISMOTION, SDL_CONTROLLERBUTTONDOWN, SDL_CONTROLLERBUTTONUP,
  1797         SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEREMOVED, SDL_CONTROLLERDEVICEREMAPPED,
  1798     };
  1799     unsigned int i;
  1800 
  1801     switch (state) {
  1802     case SDL_QUERY:
  1803         state = SDL_IGNORE;
  1804         for (i = 0; i < SDL_arraysize(event_list); ++i) {
  1805             state = SDL_EventState(event_list[i], SDL_QUERY);
  1806             if (state == SDL_ENABLE) {
  1807                 break;
  1808             }
  1809         }
  1810         break;
  1811     default:
  1812         for (i = 0; i < SDL_arraysize(event_list); ++i) {
  1813             SDL_EventState(event_list[i], state);
  1814         }
  1815         break;
  1816     }
  1817     return (state);
  1818 #endif /* SDL_EVENTS_DISABLED */
  1819 }
  1820 
  1821 /* vi: set ts=4 sw=4 expandtab: */