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