src/joystick/SDL_gamecontroller.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 02 Mar 2018 10:56:21 -0800
changeset 11916 e85247c4a60b
parent 11811 5d94cb6b24d3
child 11921 88a2982221ec
permissions -rw-r--r--
Use the real controller name for game controllers on iOS and Apple TV
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2018 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 
   915     if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
   916         SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
   917         SDL_UnlockJoysticks();
   918         return (NULL);
   919     }
   920 
   921     name = SDL_JoystickNameForIndex(device_index);
   922     guid = SDL_JoystickGetDeviceGUID(device_index);
   923     mapping = SDL_PrivateGetControllerMappingForNameAndGUID(name, guid);
   924 #if SDL_JOYSTICK_XINPUT
   925     if (!mapping && SDL_SYS_IsXInputGamepad_DeviceIndex(device_index)) {
   926         mapping = s_pXInputMapping;
   927     }
   928 #endif
   929 #if defined(__ANDROID__)
   930     if (!mapping && SDL_SYS_IsDPAD_DeviceIndex(device_index)) {
   931         SDL_bool existing;
   932         char mapping_string[1024];
   933         SDL_snprintf(mapping_string, sizeof(mapping_string), "none,%s,a:b0,b:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,", name);
   934         mapping = SDL_PrivateAddMappingForGUID(guid, mapping_string,
   935                           &existing, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT);
   936     }
   937 #endif /* __ANDROID__ */
   938     SDL_UnlockJoysticks();
   939     return mapping;
   940 }
   941 
   942 /*
   943  * Add or update an entry into the Mappings Database
   944  */
   945 int
   946 SDL_GameControllerAddMappingsFromRW(SDL_RWops * rw, int freerw)
   947 {
   948     const char *platform = SDL_GetPlatform();
   949     int controllers = 0;
   950     char *buf, *line, *line_end, *tmp, *comma, line_platform[64];
   951     size_t db_size, platform_len;
   952     
   953     if (rw == NULL) {
   954         return SDL_SetError("Invalid RWops");
   955     }
   956     db_size = (size_t)SDL_RWsize(rw);
   957     
   958     buf = (char *)SDL_malloc(db_size + 1);
   959     if (buf == NULL) {
   960         if (freerw) {
   961             SDL_RWclose(rw);
   962         }
   963         return SDL_SetError("Could not allocate space to read DB into memory");
   964     }
   965     
   966     if (SDL_RWread(rw, buf, db_size, 1) != 1) {
   967         if (freerw) {
   968             SDL_RWclose(rw);
   969         }
   970         SDL_free(buf);
   971         return SDL_SetError("Could not read DB");
   972     }
   973     
   974     if (freerw) {
   975         SDL_RWclose(rw);
   976     }
   977     
   978     buf[db_size] = '\0';
   979     line = buf;
   980     
   981     while (line < buf + db_size) {
   982         line_end = SDL_strchr(line, '\n');
   983         if (line_end != NULL) {
   984             *line_end = '\0';
   985         } else {
   986             line_end = buf + db_size;
   987         }
   988         
   989         /* Extract and verify the platform */
   990         tmp = SDL_strstr(line, SDL_CONTROLLER_PLATFORM_FIELD);
   991         if (tmp != NULL) {
   992             tmp += SDL_strlen(SDL_CONTROLLER_PLATFORM_FIELD);
   993             comma = SDL_strchr(tmp, ',');
   994             if (comma != NULL) {
   995                 platform_len = comma - tmp + 1;
   996                 if (platform_len + 1 < SDL_arraysize(line_platform)) {
   997                     SDL_strlcpy(line_platform, tmp, platform_len);
   998                     if (SDL_strncasecmp(line_platform, platform, platform_len) == 0 &&
   999                         SDL_GameControllerAddMapping(line) > 0) {
  1000                         controllers++;
  1001                     }
  1002                 }
  1003             }
  1004         }
  1005         
  1006         line = line_end + 1;
  1007     }
  1008 
  1009     SDL_free(buf);
  1010     return controllers;
  1011 }
  1012 
  1013 /*
  1014  * Add or update an entry into the Mappings Database with a priority
  1015  */
  1016 static int
  1017 SDL_PrivateGameControllerAddMapping(const char *mappingString, SDL_ControllerMappingPriority priority)
  1018 {
  1019     char *pchGUID;
  1020     SDL_JoystickGUID jGUID;
  1021     SDL_bool is_xinput_mapping = SDL_FALSE;
  1022     SDL_bool is_emscripten_mapping = SDL_FALSE;
  1023     SDL_bool existing = SDL_FALSE;
  1024     ControllerMapping_t *pControllerMapping;
  1025 
  1026     if (!mappingString) {
  1027         return SDL_InvalidParamError("mappingString");
  1028     }
  1029 
  1030     pchGUID = SDL_PrivateGetControllerGUIDFromMappingString(mappingString);
  1031     if (!pchGUID) {
  1032         return SDL_SetError("Couldn't parse GUID from %s", mappingString);
  1033     }
  1034     if (!SDL_strcasecmp(pchGUID, "xinput")) {
  1035         is_xinput_mapping = SDL_TRUE;
  1036     }
  1037     if (!SDL_strcasecmp(pchGUID, "emscripten")) {
  1038         is_emscripten_mapping = SDL_TRUE;
  1039     }
  1040     jGUID = SDL_JoystickGetGUIDFromString(pchGUID);
  1041     SDL_free(pchGUID);
  1042 
  1043     pControllerMapping = SDL_PrivateAddMappingForGUID(jGUID, mappingString, &existing, priority);
  1044     if (!pControllerMapping) {
  1045         return -1;
  1046     }
  1047 
  1048     if (existing) {
  1049         return 0;
  1050     } else {
  1051         if (is_xinput_mapping) {
  1052             s_pXInputMapping = pControllerMapping;
  1053         }
  1054         if (is_emscripten_mapping) {
  1055             s_pEmscriptenMapping = pControllerMapping;
  1056         }
  1057         return 1;
  1058     }
  1059 }
  1060 
  1061 /*
  1062  * Add or update an entry into the Mappings Database
  1063  */
  1064 int
  1065 SDL_GameControllerAddMapping(const char *mappingString)
  1066 {
  1067     return SDL_PrivateGameControllerAddMapping(mappingString, SDL_CONTROLLER_MAPPING_PRIORITY_API);
  1068 }
  1069 
  1070 /*
  1071  *  Get the number of mappings installed
  1072  */
  1073 int
  1074 SDL_GameControllerNumMappings(void)
  1075 {
  1076     int num_mappings = 0;
  1077     ControllerMapping_t *mapping;
  1078 
  1079     for (mapping = s_pSupportedControllers; mapping; mapping = mapping->next) {
  1080         if (SDL_memcmp(&mapping->guid, &s_zeroGUID, sizeof(mapping->guid)) == 0) {
  1081             continue;
  1082         }
  1083         ++num_mappings;
  1084     }
  1085     return num_mappings;
  1086 }
  1087 
  1088 /*
  1089  *  Get the mapping at a particular index.
  1090  */
  1091 char *
  1092 SDL_GameControllerMappingForIndex(int mapping_index)
  1093 {
  1094     ControllerMapping_t *mapping;
  1095 
  1096     for (mapping = s_pSupportedControllers; mapping; mapping = mapping->next) {
  1097         if (SDL_memcmp(&mapping->guid, &s_zeroGUID, sizeof(mapping->guid)) == 0) {
  1098             continue;
  1099         }
  1100         if (mapping_index == 0) {
  1101             char *pMappingString;
  1102             char pchGUID[33];
  1103             size_t needed;
  1104 
  1105             SDL_JoystickGetGUIDString(mapping->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             return pMappingString;
  1115         }
  1116         --mapping_index;
  1117     }
  1118     return NULL;
  1119 }
  1120 
  1121 /*
  1122  * Get the mapping string for this GUID
  1123  */
  1124 char *
  1125 SDL_GameControllerMappingForGUID(SDL_JoystickGUID guid)
  1126 {
  1127     char *pMappingString = NULL;
  1128     ControllerMapping_t *mapping = SDL_PrivateGetControllerMappingForGUID(&guid);
  1129     if (mapping) {
  1130         char pchGUID[33];
  1131         size_t needed;
  1132         SDL_JoystickGetGUIDString(guid, pchGUID, sizeof(pchGUID));
  1133         /* allocate enough memory for GUID + ',' + name + ',' + mapping + \0 */
  1134         needed = SDL_strlen(pchGUID) + 1 + SDL_strlen(mapping->name) + 1 + SDL_strlen(mapping->mapping) + 1;
  1135         pMappingString = SDL_malloc(needed);
  1136         if (!pMappingString) {
  1137             SDL_OutOfMemory();
  1138             return NULL;
  1139         }
  1140         SDL_snprintf(pMappingString, needed, "%s,%s,%s", pchGUID, mapping->name, mapping->mapping);
  1141     }
  1142     return pMappingString;
  1143 }
  1144 
  1145 /*
  1146  * Get the mapping string for this device
  1147  */
  1148 char *
  1149 SDL_GameControllerMapping(SDL_GameController * gamecontroller)
  1150 {
  1151     if (!gamecontroller) {
  1152         return NULL;
  1153     }
  1154 
  1155     return SDL_GameControllerMappingForGUID(gamecontroller->guid);
  1156 }
  1157 
  1158 static void
  1159 SDL_GameControllerLoadHints()
  1160 {
  1161     const char *hint = SDL_GetHint(SDL_HINT_GAMECONTROLLERCONFIG);
  1162     if (hint && hint[0]) {
  1163         size_t nchHints = SDL_strlen(hint);
  1164         char *pUserMappings = SDL_malloc(nchHints + 1);
  1165         char *pTempMappings = pUserMappings;
  1166         SDL_memcpy(pUserMappings, hint, nchHints);
  1167         pUserMappings[nchHints] = '\0';
  1168         while (pUserMappings) {
  1169             char *pchNewLine = NULL;
  1170 
  1171             pchNewLine = SDL_strchr(pUserMappings, '\n');
  1172             if (pchNewLine)
  1173                 *pchNewLine = '\0';
  1174 
  1175             SDL_PrivateGameControllerAddMapping(pUserMappings, SDL_CONTROLLER_MAPPING_PRIORITY_USER);
  1176 
  1177             if (pchNewLine) {
  1178                 pUserMappings = pchNewLine + 1;
  1179             } else {
  1180                 pUserMappings = NULL;
  1181             }
  1182         }
  1183         SDL_free(pTempMappings);
  1184     }
  1185 }
  1186 
  1187 /*
  1188  * Fill the given buffer with the expected controller mapping filepath. 
  1189  * Usually this will just be CONTROLLER_MAPPING_FILE, but for Android,
  1190  * we want to get the internal storage path.
  1191  */
  1192 static SDL_bool SDL_GetControllerMappingFilePath(char *path, size_t size)
  1193 {
  1194 #ifdef CONTROLLER_MAPPING_FILE
  1195 #define STRING(X) SDL_STRINGIFY_ARG(X)
  1196     return SDL_strlcpy(path, STRING(CONTROLLER_MAPPING_FILE), size) < size;
  1197 #elif defined(__ANDROID__)
  1198     return SDL_snprintf(path, size, "%s/controller_map.txt", SDL_AndroidGetInternalStoragePath()) < size;
  1199 #else
  1200     return SDL_FALSE;
  1201 #endif
  1202 }
  1203 
  1204 /*
  1205  * Initialize the game controller system, mostly load our DB of controller config mappings
  1206  */
  1207 int
  1208 SDL_GameControllerInitMappings(void)
  1209 {
  1210     char szControllerMapPath[1024];
  1211     int i = 0;
  1212     const char *pMappingString = NULL;
  1213     pMappingString = s_ControllerMappings[i];
  1214     while (pMappingString) {
  1215         SDL_PrivateGameControllerAddMapping(pMappingString, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT);
  1216 
  1217         i++;
  1218         pMappingString = s_ControllerMappings[i];
  1219     }
  1220 
  1221     if (SDL_GetControllerMappingFilePath(szControllerMapPath, sizeof(szControllerMapPath))) {
  1222         SDL_GameControllerAddMappingsFromFile(szControllerMapPath);        
  1223     }
  1224 
  1225     /* load in any user supplied config */
  1226     SDL_GameControllerLoadHints();
  1227 
  1228     SDL_AddHintCallback(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES,
  1229                         SDL_GameControllerIgnoreDevicesChanged, NULL);
  1230     SDL_AddHintCallback(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT,
  1231                         SDL_GameControllerIgnoreDevicesExceptChanged, NULL);
  1232 
  1233     return (0);
  1234 }
  1235 
  1236 int
  1237 SDL_GameControllerInit(void)
  1238 {
  1239     int i;
  1240 
  1241     /* watch for joy events and fire controller ones if needed */
  1242     SDL_AddEventWatch(SDL_GameControllerEventWatcher, NULL);
  1243 
  1244     /* Send added events for controllers currently attached */
  1245     for (i = 0; i < SDL_NumJoysticks(); ++i) {
  1246         if (SDL_IsGameController(i)) {
  1247             SDL_Event deviceevent;
  1248             deviceevent.type = SDL_CONTROLLERDEVICEADDED;
  1249             deviceevent.cdevice.which = i;
  1250             SDL_PushEvent(&deviceevent);
  1251         }
  1252     }
  1253 
  1254     return (0);
  1255 }
  1256 
  1257 
  1258 /*
  1259  * Get the implementation dependent name of a controller
  1260  */
  1261 const char *
  1262 SDL_GameControllerNameForIndex(int device_index)
  1263 {
  1264     ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(device_index);
  1265     if (pSupportedController) {
  1266         if (SDL_strcmp(pSupportedController->name, "*") == 0) {
  1267             return SDL_JoystickNameForIndex(device_index);
  1268         } else {
  1269             return pSupportedController->name;
  1270         }
  1271     }
  1272     return NULL;
  1273 }
  1274 
  1275 
  1276 /*
  1277  * Return 1 if the joystick with this name and GUID is a supported controller
  1278  */
  1279 SDL_bool
  1280 SDL_IsGameControllerNameAndGUID(const char *name, SDL_JoystickGUID guid)
  1281 {
  1282     ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMappingForNameAndGUID(name, guid);
  1283     if (pSupportedController) {
  1284         return SDL_TRUE;
  1285     }
  1286     return SDL_FALSE;
  1287 }
  1288 
  1289 /*
  1290  * Return 1 if the joystick at this device index is a supported controller
  1291  */
  1292 SDL_bool
  1293 SDL_IsGameController(int device_index)
  1294 {
  1295     ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(device_index);
  1296     if (pSupportedController) {
  1297         return SDL_TRUE;
  1298     }
  1299     return SDL_FALSE;
  1300 }
  1301 
  1302 /*
  1303  * Return 1 if the game controller should be ignored by SDL
  1304  */
  1305 SDL_bool SDL_ShouldIgnoreGameController(const char *name, SDL_JoystickGUID guid)
  1306 {
  1307     int i;
  1308     Uint16 vendor;
  1309     Uint16 product;
  1310     Uint32 vidpid;
  1311 
  1312     if (SDL_allowed_controllers.num_entries == 0 &&
  1313         SDL_ignored_controllers.num_entries == 0) {
  1314         return SDL_FALSE;
  1315     }
  1316 
  1317     SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL);
  1318     vidpid = MAKE_VIDPID(vendor, product);
  1319 
  1320     if (SDL_GetHintBoolean("SDL_GAMECONTROLLER_ALLOW_STEAM_VIRTUAL_GAMEPAD", SDL_FALSE)) {
  1321         /* 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 */
  1322         SDL_bool bSteamVirtualGamepad = SDL_FALSE;
  1323 #if defined(__LINUX__)
  1324         bSteamVirtualGamepad = (vendor == 0x28DE && product == 0x11FF);
  1325 #elif defined(__MACOSX__)
  1326         bSteamVirtualGamepad = (SDL_strncmp(name, "GamePad-", 8) == 0);
  1327 #elif defined(__WIN32__)
  1328         /* We can't tell on Windows, but Steam will block others in input hooks */
  1329         bSteamVirtualGamepad = SDL_TRUE;
  1330 #endif
  1331         if (bSteamVirtualGamepad) {
  1332             return SDL_FALSE;
  1333         }
  1334     }
  1335 
  1336     if (SDL_allowed_controllers.num_entries > 0) {
  1337         for (i = 0; i < SDL_allowed_controllers.num_entries; ++i) {
  1338             if (vidpid == SDL_allowed_controllers.entries[i]) {
  1339                 return SDL_FALSE;
  1340             }
  1341         }
  1342         return SDL_TRUE;
  1343     } else {
  1344         for (i = 0; i < SDL_ignored_controllers.num_entries; ++i) {
  1345             if (vidpid == SDL_ignored_controllers.entries[i]) {
  1346                 return SDL_TRUE;
  1347             }
  1348         }
  1349         return SDL_FALSE;
  1350     }
  1351 }
  1352 
  1353 /*
  1354  * Open a controller for use - the index passed as an argument refers to
  1355  * the N'th controller on the system.  This index is the value which will
  1356  * identify this controller in future controller events.
  1357  *
  1358  * This function returns a controller identifier, or NULL if an error occurred.
  1359  */
  1360 SDL_GameController *
  1361 SDL_GameControllerOpen(int device_index)
  1362 {
  1363     SDL_GameController *gamecontroller;
  1364     SDL_GameController *gamecontrollerlist;
  1365     ControllerMapping_t *pSupportedController = NULL;
  1366 
  1367     SDL_LockJoysticks();
  1368 
  1369     if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
  1370         SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
  1371         SDL_UnlockJoysticks();
  1372         return (NULL);
  1373     }
  1374 
  1375     gamecontrollerlist = SDL_gamecontrollers;
  1376     /* If the controller is already open, return it */
  1377     while (gamecontrollerlist) {
  1378         if (SDL_SYS_GetInstanceIdOfDeviceIndex(device_index) == gamecontrollerlist->joystick->instance_id) {
  1379                 gamecontroller = gamecontrollerlist;
  1380                 ++gamecontroller->ref_count;
  1381                 SDL_UnlockJoysticks();
  1382                 return (gamecontroller);
  1383         }
  1384         gamecontrollerlist = gamecontrollerlist->next;
  1385     }
  1386 
  1387     /* Find a controller mapping */
  1388     pSupportedController =  SDL_PrivateGetControllerMapping(device_index);
  1389     if (!pSupportedController) {
  1390         SDL_SetError("Couldn't find mapping for device (%d)", device_index);
  1391         SDL_UnlockJoysticks();
  1392         return NULL;
  1393     }
  1394 
  1395     /* Create and initialize the controller */
  1396     gamecontroller = (SDL_GameController *) SDL_calloc(1, sizeof(*gamecontroller));
  1397     if (gamecontroller == NULL) {
  1398         SDL_OutOfMemory();
  1399         SDL_UnlockJoysticks();
  1400         return NULL;
  1401     }
  1402 
  1403     gamecontroller->joystick = SDL_JoystickOpen(device_index);
  1404     if (!gamecontroller->joystick) {
  1405         SDL_free(gamecontroller);
  1406         SDL_UnlockJoysticks();
  1407         return NULL;
  1408     }
  1409 
  1410     if (gamecontroller->joystick->naxes) {
  1411         gamecontroller->last_match_axis = (SDL_ExtendedGameControllerBind **)SDL_calloc(gamecontroller->joystick->naxes, sizeof(*gamecontroller->last_match_axis));
  1412         if (!gamecontroller->last_match_axis) {
  1413             SDL_OutOfMemory();
  1414             SDL_JoystickClose(gamecontroller->joystick);
  1415             SDL_free(gamecontroller);
  1416             SDL_UnlockJoysticks();
  1417             return NULL;
  1418         }
  1419     }
  1420     if (gamecontroller->joystick->nhats) {
  1421         gamecontroller->last_hat_mask = (Uint8 *)SDL_calloc(gamecontroller->joystick->nhats, sizeof(*gamecontroller->last_hat_mask));
  1422         if (!gamecontroller->last_hat_mask) {
  1423             SDL_OutOfMemory();
  1424             SDL_JoystickClose(gamecontroller->joystick);
  1425             SDL_free(gamecontroller->last_match_axis);
  1426             SDL_free(gamecontroller);
  1427             SDL_UnlockJoysticks();
  1428             return NULL;
  1429         }
  1430     }
  1431 
  1432     SDL_PrivateLoadButtonMapping(gamecontroller, pSupportedController->guid, pSupportedController->name, pSupportedController->mapping);
  1433 
  1434     /* Add the controller to list */
  1435     ++gamecontroller->ref_count;
  1436     /* Link the controller in the list */
  1437     gamecontroller->next = SDL_gamecontrollers;
  1438     SDL_gamecontrollers = gamecontroller;
  1439 
  1440     SDL_UnlockJoysticks();
  1441 
  1442     return (gamecontroller);
  1443 }
  1444 
  1445 /*
  1446  * Manually pump for controller updates.
  1447  */
  1448 void
  1449 SDL_GameControllerUpdate(void)
  1450 {
  1451     /* Just for API completeness; the joystick API does all the work. */
  1452     SDL_JoystickUpdate();
  1453 }
  1454 
  1455 /*
  1456  * Get the current state of an axis control on a controller
  1457  */
  1458 Sint16
  1459 SDL_GameControllerGetAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis)
  1460 {
  1461     int i;
  1462 
  1463     if (!gamecontroller)
  1464         return 0;
  1465 
  1466     for (i = 0; i < gamecontroller->num_bindings; ++i) {
  1467         SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
  1468         if (binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS && binding->output.axis.axis == axis) {
  1469             int value = 0;
  1470             SDL_bool valid_input_range;
  1471             SDL_bool valid_output_range;
  1472 
  1473             if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
  1474                 value = SDL_JoystickGetAxis(gamecontroller->joystick, binding->input.axis.axis);
  1475                 if (binding->input.axis.axis_min < binding->input.axis.axis_max) {
  1476                     valid_input_range = (value >= binding->input.axis.axis_min && value <= binding->input.axis.axis_max);
  1477                 } else {
  1478                     valid_input_range = (value >= binding->input.axis.axis_max && value <= binding->input.axis.axis_min);
  1479                 }
  1480                 if (valid_input_range) {
  1481                     if (binding->input.axis.axis_min != binding->output.axis.axis_min || binding->input.axis.axis_max != binding->output.axis.axis_max) {
  1482                         float normalized_value = (float)(value - binding->input.axis.axis_min) / (binding->input.axis.axis_max - binding->input.axis.axis_min);
  1483                         value = binding->output.axis.axis_min + (int)(normalized_value * (binding->output.axis.axis_max - binding->output.axis.axis_min));
  1484                     }
  1485                 }
  1486             } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
  1487                 value = SDL_JoystickGetButton(gamecontroller->joystick, binding->input.button);
  1488                 if (value == SDL_PRESSED) {
  1489                     value = binding->output.axis.axis_max;
  1490                 }
  1491             } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
  1492                 int hat_mask = SDL_JoystickGetHat(gamecontroller->joystick, binding->input.hat.hat);
  1493                 if (hat_mask & binding->input.hat.hat_mask) {
  1494                     value = binding->output.axis.axis_max;
  1495                 }
  1496             }
  1497 
  1498             if (binding->output.axis.axis_min < binding->output.axis.axis_max) {
  1499                 valid_output_range = (value >= binding->output.axis.axis_min && value <= binding->output.axis.axis_max);
  1500             } else {
  1501                 valid_output_range = (value >= binding->output.axis.axis_max && value <= binding->output.axis.axis_min);
  1502             }
  1503             /* If the value is zero, there might be another binding that makes it non-zero */
  1504             if (value != 0 && valid_output_range) {
  1505                 return (Sint16)value;
  1506             }
  1507         }
  1508     }
  1509     return 0;
  1510 }
  1511 
  1512 /*
  1513  * Get the current state of a button on a controller
  1514  */
  1515 Uint8
  1516 SDL_GameControllerGetButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button)
  1517 {
  1518     int i;
  1519 
  1520     if (!gamecontroller)
  1521         return 0;
  1522 
  1523     for (i = 0; i < gamecontroller->num_bindings; ++i) {
  1524         SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
  1525         if (binding->outputType == SDL_CONTROLLER_BINDTYPE_BUTTON && binding->output.button == button) {
  1526             if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
  1527                 SDL_bool valid_input_range;
  1528 
  1529                 int value = SDL_JoystickGetAxis(gamecontroller->joystick, binding->input.axis.axis);
  1530                 int threshold = binding->input.axis.axis_min + (binding->input.axis.axis_max - binding->input.axis.axis_min) / 2;
  1531                 if (binding->input.axis.axis_min < binding->input.axis.axis_max) {
  1532                     valid_input_range = (value >= binding->input.axis.axis_min && value <= binding->input.axis.axis_max);
  1533                     if (valid_input_range) {
  1534                         return (value >= threshold) ? SDL_PRESSED : SDL_RELEASED;
  1535                     }
  1536                 } else {
  1537                     valid_input_range = (value >= binding->input.axis.axis_max && value <= binding->input.axis.axis_min);
  1538                     if (valid_input_range) {
  1539                         return (value <= threshold) ? SDL_PRESSED : SDL_RELEASED;
  1540                     }
  1541                 }
  1542             } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
  1543                 return SDL_JoystickGetButton(gamecontroller->joystick, binding->input.button);
  1544             } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
  1545                 int hat_mask = SDL_JoystickGetHat(gamecontroller->joystick, binding->input.hat.hat);
  1546                 return (hat_mask & binding->input.hat.hat_mask) ? SDL_PRESSED : SDL_RELEASED;
  1547             }
  1548         }
  1549     }
  1550     return SDL_RELEASED;
  1551 }
  1552 
  1553 const char *
  1554 SDL_GameControllerName(SDL_GameController * gamecontroller)
  1555 {
  1556     if (!gamecontroller)
  1557         return NULL;
  1558 
  1559     if (SDL_strcmp(gamecontroller->name, "*") == 0) {
  1560         return SDL_JoystickName(SDL_GameControllerGetJoystick(gamecontroller));
  1561     } else {
  1562         return gamecontroller->name;
  1563     }
  1564 }
  1565 
  1566 Uint16
  1567 SDL_GameControllerGetVendor(SDL_GameController * gamecontroller)
  1568 {
  1569     return SDL_JoystickGetVendor(SDL_GameControllerGetJoystick(gamecontroller));
  1570 }
  1571 
  1572 Uint16
  1573 SDL_GameControllerGetProduct(SDL_GameController * gamecontroller)
  1574 {
  1575     return SDL_JoystickGetProduct(SDL_GameControllerGetJoystick(gamecontroller));
  1576 }
  1577 
  1578 Uint16
  1579 SDL_GameControllerGetProductVersion(SDL_GameController * gamecontroller)
  1580 {
  1581     return SDL_JoystickGetProductVersion(SDL_GameControllerGetJoystick(gamecontroller));
  1582 }
  1583 
  1584 /*
  1585  * Return if the controller in question is currently attached to the system,
  1586  *  \return 0 if not plugged in, 1 if still present.
  1587  */
  1588 SDL_bool
  1589 SDL_GameControllerGetAttached(SDL_GameController * gamecontroller)
  1590 {
  1591     if (!gamecontroller)
  1592         return SDL_FALSE;
  1593 
  1594     return SDL_JoystickGetAttached(gamecontroller->joystick);
  1595 }
  1596 
  1597 /*
  1598  * Get the joystick for this controller
  1599  */
  1600 SDL_Joystick *SDL_GameControllerGetJoystick(SDL_GameController * gamecontroller)
  1601 {
  1602     if (!gamecontroller)
  1603         return NULL;
  1604 
  1605     return gamecontroller->joystick;
  1606 }
  1607 
  1608 
  1609 /*
  1610  * Find the SDL_GameController that owns this instance id
  1611  */
  1612 SDL_GameController *
  1613 SDL_GameControllerFromInstanceID(SDL_JoystickID joyid)
  1614 {
  1615     SDL_GameController *gamecontroller;
  1616 
  1617     SDL_LockJoysticks();
  1618     gamecontroller = SDL_gamecontrollers;
  1619     while (gamecontroller) {
  1620         if (gamecontroller->joystick->instance_id == joyid) {
  1621             SDL_UnlockJoysticks();
  1622             return gamecontroller;
  1623         }
  1624         gamecontroller = gamecontroller->next;
  1625     }
  1626     SDL_UnlockJoysticks();
  1627     return NULL;
  1628 }
  1629 
  1630 
  1631 /*
  1632  * Get the SDL joystick layer binding for this controller axis mapping
  1633  */
  1634 SDL_GameControllerButtonBind SDL_GameControllerGetBindForAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis)
  1635 {
  1636     int i;
  1637     SDL_GameControllerButtonBind bind;
  1638     SDL_zero(bind);
  1639 
  1640     if (!gamecontroller || axis == SDL_CONTROLLER_AXIS_INVALID)
  1641         return bind;
  1642 
  1643     for (i = 0; i < gamecontroller->num_bindings; ++i) {
  1644         SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
  1645         if (binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS && binding->output.axis.axis == axis) {
  1646             bind.bindType = binding->inputType;
  1647             if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
  1648                 /* FIXME: There might be multiple axes bound now that we have axis ranges... */
  1649                 bind.value.axis = binding->input.axis.axis;
  1650             } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
  1651                 bind.value.button = binding->input.button;
  1652             } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
  1653                 bind.value.hat.hat = binding->input.hat.hat;
  1654                 bind.value.hat.hat_mask = binding->input.hat.hat_mask;
  1655             }
  1656             break;
  1657         }
  1658     }
  1659     return bind;
  1660 }
  1661 
  1662 
  1663 /*
  1664  * Get the SDL joystick layer binding for this controller button mapping
  1665  */
  1666 SDL_GameControllerButtonBind SDL_GameControllerGetBindForButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button)
  1667 {
  1668     int i;
  1669     SDL_GameControllerButtonBind bind;
  1670     SDL_zero(bind);
  1671 
  1672     if (!gamecontroller || button == SDL_CONTROLLER_BUTTON_INVALID)
  1673         return bind;
  1674 
  1675     for (i = 0; i < gamecontroller->num_bindings; ++i) {
  1676         SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
  1677         if (binding->outputType == SDL_CONTROLLER_BINDTYPE_BUTTON && binding->output.button == button) {
  1678             bind.bindType = binding->inputType;
  1679             if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
  1680                 bind.value.axis = binding->input.axis.axis;
  1681             } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
  1682                 bind.value.button = binding->input.button;
  1683             } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
  1684                 bind.value.hat.hat = binding->input.hat.hat;
  1685                 bind.value.hat.hat_mask = binding->input.hat.hat_mask;
  1686             }
  1687             break;
  1688         }
  1689     }
  1690     return bind;
  1691 }
  1692 
  1693 
  1694 void
  1695 SDL_GameControllerClose(SDL_GameController * gamecontroller)
  1696 {
  1697     SDL_GameController *gamecontrollerlist, *gamecontrollerlistprev;
  1698 
  1699     if (!gamecontroller)
  1700         return;
  1701 
  1702     SDL_LockJoysticks();
  1703 
  1704     /* First decrement ref count */
  1705     if (--gamecontroller->ref_count > 0) {
  1706         SDL_UnlockJoysticks();
  1707         return;
  1708     }
  1709 
  1710     SDL_JoystickClose(gamecontroller->joystick);
  1711 
  1712     gamecontrollerlist = SDL_gamecontrollers;
  1713     gamecontrollerlistprev = NULL;
  1714     while (gamecontrollerlist) {
  1715         if (gamecontroller == gamecontrollerlist) {
  1716             if (gamecontrollerlistprev) {
  1717                 /* unlink this entry */
  1718                 gamecontrollerlistprev->next = gamecontrollerlist->next;
  1719             } else {
  1720                 SDL_gamecontrollers = gamecontroller->next;
  1721             }
  1722             break;
  1723         }
  1724         gamecontrollerlistprev = gamecontrollerlist;
  1725         gamecontrollerlist = gamecontrollerlist->next;
  1726     }
  1727 
  1728     SDL_free(gamecontroller->bindings);
  1729     SDL_free(gamecontroller->last_match_axis);
  1730     SDL_free(gamecontroller->last_hat_mask);
  1731     SDL_free(gamecontroller);
  1732 
  1733     SDL_UnlockJoysticks();
  1734 }
  1735 
  1736 
  1737 /*
  1738  * Quit the controller subsystem
  1739  */
  1740 void
  1741 SDL_GameControllerQuit(void)
  1742 {
  1743     SDL_LockJoysticks();
  1744     while (SDL_gamecontrollers) {
  1745         SDL_gamecontrollers->ref_count = 1;
  1746         SDL_GameControllerClose(SDL_gamecontrollers);
  1747     }
  1748     SDL_UnlockJoysticks();
  1749 }
  1750 
  1751 void
  1752 SDL_GameControllerQuitMappings(void)
  1753 {
  1754     ControllerMapping_t *pControllerMap;
  1755 
  1756     while (s_pSupportedControllers) {
  1757         pControllerMap = s_pSupportedControllers;
  1758         s_pSupportedControllers = s_pSupportedControllers->next;
  1759         SDL_free(pControllerMap->name);
  1760         SDL_free(pControllerMap->mapping);
  1761         SDL_free(pControllerMap);
  1762     }
  1763 
  1764     SDL_DelEventWatch(SDL_GameControllerEventWatcher, NULL);
  1765 
  1766     SDL_DelHintCallback(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES,
  1767                         SDL_GameControllerIgnoreDevicesChanged, NULL);
  1768     SDL_DelHintCallback(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT,
  1769                         SDL_GameControllerIgnoreDevicesExceptChanged, NULL);
  1770 
  1771     if (SDL_allowed_controllers.entries) {
  1772         SDL_free(SDL_allowed_controllers.entries);
  1773         SDL_zero(SDL_allowed_controllers);
  1774     }
  1775     if (SDL_ignored_controllers.entries) {
  1776         SDL_free(SDL_ignored_controllers.entries);
  1777         SDL_zero(SDL_ignored_controllers);
  1778     }
  1779 }
  1780 
  1781 /*
  1782  * Event filter to transform joystick events into appropriate game controller ones
  1783  */
  1784 static int
  1785 SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis, Sint16 value)
  1786 {
  1787     int posted;
  1788 
  1789     /* translate the event, if desired */
  1790     posted = 0;
  1791 #if !SDL_EVENTS_DISABLED
  1792     if (SDL_GetEventState(SDL_CONTROLLERAXISMOTION) == SDL_ENABLE) {
  1793         SDL_Event event;
  1794         event.type = SDL_CONTROLLERAXISMOTION;
  1795         event.caxis.which = gamecontroller->joystick->instance_id;
  1796         event.caxis.axis = axis;
  1797         event.caxis.value = value;
  1798         posted = SDL_PushEvent(&event) == 1;
  1799     }
  1800 #endif /* !SDL_EVENTS_DISABLED */
  1801     return (posted);
  1802 }
  1803 
  1804 
  1805 /*
  1806  * Event filter to transform joystick events into appropriate game controller ones
  1807  */
  1808 static int
  1809 SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button, Uint8 state)
  1810 {
  1811     int posted;
  1812 #if !SDL_EVENTS_DISABLED
  1813     SDL_Event event;
  1814 
  1815     if (button == SDL_CONTROLLER_BUTTON_INVALID)
  1816         return (0);
  1817 
  1818     switch (state) {
  1819     case SDL_PRESSED:
  1820         event.type = SDL_CONTROLLERBUTTONDOWN;
  1821         break;
  1822     case SDL_RELEASED:
  1823         event.type = SDL_CONTROLLERBUTTONUP;
  1824         break;
  1825     default:
  1826         /* Invalid state -- bail */
  1827         return (0);
  1828     }
  1829 #endif /* !SDL_EVENTS_DISABLED */
  1830 
  1831     /* translate the event, if desired */
  1832     posted = 0;
  1833 #if !SDL_EVENTS_DISABLED
  1834     if (SDL_GetEventState(event.type) == SDL_ENABLE) {
  1835         event.cbutton.which = gamecontroller->joystick->instance_id;
  1836         event.cbutton.button = button;
  1837         event.cbutton.state = state;
  1838         posted = SDL_PushEvent(&event) == 1;
  1839     }
  1840 #endif /* !SDL_EVENTS_DISABLED */
  1841     return (posted);
  1842 }
  1843 
  1844 /*
  1845  * Turn off controller events
  1846  */
  1847 int
  1848 SDL_GameControllerEventState(int state)
  1849 {
  1850 #if SDL_EVENTS_DISABLED
  1851     return SDL_IGNORE;
  1852 #else
  1853     const Uint32 event_list[] = {
  1854         SDL_CONTROLLERAXISMOTION, SDL_CONTROLLERBUTTONDOWN, SDL_CONTROLLERBUTTONUP,
  1855         SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEREMOVED, SDL_CONTROLLERDEVICEREMAPPED,
  1856     };
  1857     unsigned int i;
  1858 
  1859     switch (state) {
  1860     case SDL_QUERY:
  1861         state = SDL_IGNORE;
  1862         for (i = 0; i < SDL_arraysize(event_list); ++i) {
  1863             state = SDL_EventState(event_list[i], SDL_QUERY);
  1864             if (state == SDL_ENABLE) {
  1865                 break;
  1866             }
  1867         }
  1868         break;
  1869     default:
  1870         for (i = 0; i < SDL_arraysize(event_list); ++i) {
  1871             SDL_EventState(event_list[i], state);
  1872         }
  1873         break;
  1874     }
  1875     return (state);
  1876 #endif /* SDL_EVENTS_DISABLED */
  1877 }
  1878 
  1879 /* vi: set ts=4 sw=4 expandtab: */