src/joystick/SDL_gamecontroller.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 03 Jan 2018 10:03:25 -0800
changeset 11811 5d94cb6b24d3
parent 11781 c2f3e4187c9d
child 11916 e85247c4a60b
permissions -rw-r--r--
Updated copyright for 2018
     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         return pSupportedController->name;
  1267     }
  1268     return NULL;
  1269 }
  1270 
  1271 
  1272 /*
  1273  * Return 1 if the joystick with this name and GUID is a supported controller
  1274  */
  1275 SDL_bool
  1276 SDL_IsGameControllerNameAndGUID(const char *name, SDL_JoystickGUID guid)
  1277 {
  1278     ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMappingForNameAndGUID(name, guid);
  1279     if (pSupportedController) {
  1280         return SDL_TRUE;
  1281     }
  1282     return SDL_FALSE;
  1283 }
  1284 
  1285 /*
  1286  * Return 1 if the joystick at this device index is a supported controller
  1287  */
  1288 SDL_bool
  1289 SDL_IsGameController(int device_index)
  1290 {
  1291     ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(device_index);
  1292     if (pSupportedController) {
  1293         return SDL_TRUE;
  1294     }
  1295     return SDL_FALSE;
  1296 }
  1297 
  1298 /*
  1299  * Return 1 if the game controller should be ignored by SDL
  1300  */
  1301 SDL_bool SDL_ShouldIgnoreGameController(const char *name, SDL_JoystickGUID guid)
  1302 {
  1303     int i;
  1304     Uint16 vendor;
  1305     Uint16 product;
  1306     Uint32 vidpid;
  1307 
  1308     if (SDL_allowed_controllers.num_entries == 0 &&
  1309         SDL_ignored_controllers.num_entries == 0) {
  1310         return SDL_FALSE;
  1311     }
  1312 
  1313     SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL);
  1314     vidpid = MAKE_VIDPID(vendor, product);
  1315 
  1316     if (SDL_GetHintBoolean("SDL_GAMECONTROLLER_ALLOW_STEAM_VIRTUAL_GAMEPAD", SDL_FALSE)) {
  1317         /* 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 */
  1318         SDL_bool bSteamVirtualGamepad = SDL_FALSE;
  1319 #if defined(__LINUX__)
  1320         bSteamVirtualGamepad = (vendor == 0x28DE && product == 0x11FF);
  1321 #elif defined(__MACOSX__)
  1322         bSteamVirtualGamepad = (SDL_strncmp(name, "GamePad-", 8) == 0);
  1323 #elif defined(__WIN32__)
  1324         /* We can't tell on Windows, but Steam will block others in input hooks */
  1325         bSteamVirtualGamepad = SDL_TRUE;
  1326 #endif
  1327         if (bSteamVirtualGamepad) {
  1328             return SDL_FALSE;
  1329         }
  1330     }
  1331 
  1332     if (SDL_allowed_controllers.num_entries > 0) {
  1333         for (i = 0; i < SDL_allowed_controllers.num_entries; ++i) {
  1334             if (vidpid == SDL_allowed_controllers.entries[i]) {
  1335                 return SDL_FALSE;
  1336             }
  1337         }
  1338         return SDL_TRUE;
  1339     } else {
  1340         for (i = 0; i < SDL_ignored_controllers.num_entries; ++i) {
  1341             if (vidpid == SDL_ignored_controllers.entries[i]) {
  1342                 return SDL_TRUE;
  1343             }
  1344         }
  1345         return SDL_FALSE;
  1346     }
  1347 }
  1348 
  1349 /*
  1350  * Open a controller for use - the index passed as an argument refers to
  1351  * the N'th controller on the system.  This index is the value which will
  1352  * identify this controller in future controller events.
  1353  *
  1354  * This function returns a controller identifier, or NULL if an error occurred.
  1355  */
  1356 SDL_GameController *
  1357 SDL_GameControllerOpen(int device_index)
  1358 {
  1359     SDL_GameController *gamecontroller;
  1360     SDL_GameController *gamecontrollerlist;
  1361     ControllerMapping_t *pSupportedController = NULL;
  1362 
  1363     SDL_LockJoysticks();
  1364 
  1365     if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
  1366         SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
  1367         SDL_UnlockJoysticks();
  1368         return (NULL);
  1369     }
  1370 
  1371     gamecontrollerlist = SDL_gamecontrollers;
  1372     /* If the controller is already open, return it */
  1373     while (gamecontrollerlist) {
  1374         if (SDL_SYS_GetInstanceIdOfDeviceIndex(device_index) == gamecontrollerlist->joystick->instance_id) {
  1375                 gamecontroller = gamecontrollerlist;
  1376                 ++gamecontroller->ref_count;
  1377                 SDL_UnlockJoysticks();
  1378                 return (gamecontroller);
  1379         }
  1380         gamecontrollerlist = gamecontrollerlist->next;
  1381     }
  1382 
  1383     /* Find a controller mapping */
  1384     pSupportedController =  SDL_PrivateGetControllerMapping(device_index);
  1385     if (!pSupportedController) {
  1386         SDL_SetError("Couldn't find mapping for device (%d)", device_index);
  1387         SDL_UnlockJoysticks();
  1388         return NULL;
  1389     }
  1390 
  1391     /* Create and initialize the controller */
  1392     gamecontroller = (SDL_GameController *) SDL_calloc(1, sizeof(*gamecontroller));
  1393     if (gamecontroller == NULL) {
  1394         SDL_OutOfMemory();
  1395         SDL_UnlockJoysticks();
  1396         return NULL;
  1397     }
  1398 
  1399     gamecontroller->joystick = SDL_JoystickOpen(device_index);
  1400     if (!gamecontroller->joystick) {
  1401         SDL_free(gamecontroller);
  1402         SDL_UnlockJoysticks();
  1403         return NULL;
  1404     }
  1405 
  1406     if (gamecontroller->joystick->naxes) {
  1407         gamecontroller->last_match_axis = (SDL_ExtendedGameControllerBind **)SDL_calloc(gamecontroller->joystick->naxes, sizeof(*gamecontroller->last_match_axis));
  1408         if (!gamecontroller->last_match_axis) {
  1409             SDL_OutOfMemory();
  1410             SDL_JoystickClose(gamecontroller->joystick);
  1411             SDL_free(gamecontroller);
  1412             SDL_UnlockJoysticks();
  1413             return NULL;
  1414         }
  1415     }
  1416     if (gamecontroller->joystick->nhats) {
  1417         gamecontroller->last_hat_mask = (Uint8 *)SDL_calloc(gamecontroller->joystick->nhats, sizeof(*gamecontroller->last_hat_mask));
  1418         if (!gamecontroller->last_hat_mask) {
  1419             SDL_OutOfMemory();
  1420             SDL_JoystickClose(gamecontroller->joystick);
  1421             SDL_free(gamecontroller->last_match_axis);
  1422             SDL_free(gamecontroller);
  1423             SDL_UnlockJoysticks();
  1424             return NULL;
  1425         }
  1426     }
  1427 
  1428     SDL_PrivateLoadButtonMapping(gamecontroller, pSupportedController->guid, pSupportedController->name, pSupportedController->mapping);
  1429 
  1430     /* Add the controller to list */
  1431     ++gamecontroller->ref_count;
  1432     /* Link the controller in the list */
  1433     gamecontroller->next = SDL_gamecontrollers;
  1434     SDL_gamecontrollers = gamecontroller;
  1435 
  1436     SDL_UnlockJoysticks();
  1437 
  1438     return (gamecontroller);
  1439 }
  1440 
  1441 /*
  1442  * Manually pump for controller updates.
  1443  */
  1444 void
  1445 SDL_GameControllerUpdate(void)
  1446 {
  1447     /* Just for API completeness; the joystick API does all the work. */
  1448     SDL_JoystickUpdate();
  1449 }
  1450 
  1451 /*
  1452  * Get the current state of an axis control on a controller
  1453  */
  1454 Sint16
  1455 SDL_GameControllerGetAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis)
  1456 {
  1457     int i;
  1458 
  1459     if (!gamecontroller)
  1460         return 0;
  1461 
  1462     for (i = 0; i < gamecontroller->num_bindings; ++i) {
  1463         SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
  1464         if (binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS && binding->output.axis.axis == axis) {
  1465             int value = 0;
  1466             SDL_bool valid_input_range;
  1467             SDL_bool valid_output_range;
  1468 
  1469             if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
  1470                 value = SDL_JoystickGetAxis(gamecontroller->joystick, binding->input.axis.axis);
  1471                 if (binding->input.axis.axis_min < binding->input.axis.axis_max) {
  1472                     valid_input_range = (value >= binding->input.axis.axis_min && value <= binding->input.axis.axis_max);
  1473                 } else {
  1474                     valid_input_range = (value >= binding->input.axis.axis_max && value <= binding->input.axis.axis_min);
  1475                 }
  1476                 if (valid_input_range) {
  1477                     if (binding->input.axis.axis_min != binding->output.axis.axis_min || binding->input.axis.axis_max != binding->output.axis.axis_max) {
  1478                         float normalized_value = (float)(value - binding->input.axis.axis_min) / (binding->input.axis.axis_max - binding->input.axis.axis_min);
  1479                         value = binding->output.axis.axis_min + (int)(normalized_value * (binding->output.axis.axis_max - binding->output.axis.axis_min));
  1480                     }
  1481                 }
  1482             } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
  1483                 value = SDL_JoystickGetButton(gamecontroller->joystick, binding->input.button);
  1484                 if (value == SDL_PRESSED) {
  1485                     value = binding->output.axis.axis_max;
  1486                 }
  1487             } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
  1488                 int hat_mask = SDL_JoystickGetHat(gamecontroller->joystick, binding->input.hat.hat);
  1489                 if (hat_mask & binding->input.hat.hat_mask) {
  1490                     value = binding->output.axis.axis_max;
  1491                 }
  1492             }
  1493 
  1494             if (binding->output.axis.axis_min < binding->output.axis.axis_max) {
  1495                 valid_output_range = (value >= binding->output.axis.axis_min && value <= binding->output.axis.axis_max);
  1496             } else {
  1497                 valid_output_range = (value >= binding->output.axis.axis_max && value <= binding->output.axis.axis_min);
  1498             }
  1499             /* If the value is zero, there might be another binding that makes it non-zero */
  1500             if (value != 0 && valid_output_range) {
  1501                 return (Sint16)value;
  1502             }
  1503         }
  1504     }
  1505     return 0;
  1506 }
  1507 
  1508 /*
  1509  * Get the current state of a button on a controller
  1510  */
  1511 Uint8
  1512 SDL_GameControllerGetButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button)
  1513 {
  1514     int i;
  1515 
  1516     if (!gamecontroller)
  1517         return 0;
  1518 
  1519     for (i = 0; i < gamecontroller->num_bindings; ++i) {
  1520         SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
  1521         if (binding->outputType == SDL_CONTROLLER_BINDTYPE_BUTTON && binding->output.button == button) {
  1522             if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
  1523                 SDL_bool valid_input_range;
  1524 
  1525                 int value = SDL_JoystickGetAxis(gamecontroller->joystick, binding->input.axis.axis);
  1526                 int threshold = binding->input.axis.axis_min + (binding->input.axis.axis_max - binding->input.axis.axis_min) / 2;
  1527                 if (binding->input.axis.axis_min < binding->input.axis.axis_max) {
  1528                     valid_input_range = (value >= binding->input.axis.axis_min && value <= binding->input.axis.axis_max);
  1529                     if (valid_input_range) {
  1530                         return (value >= threshold) ? SDL_PRESSED : SDL_RELEASED;
  1531                     }
  1532                 } else {
  1533                     valid_input_range = (value >= binding->input.axis.axis_max && value <= binding->input.axis.axis_min);
  1534                     if (valid_input_range) {
  1535                         return (value <= threshold) ? SDL_PRESSED : SDL_RELEASED;
  1536                     }
  1537                 }
  1538             } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
  1539                 return SDL_JoystickGetButton(gamecontroller->joystick, binding->input.button);
  1540             } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
  1541                 int hat_mask = SDL_JoystickGetHat(gamecontroller->joystick, binding->input.hat.hat);
  1542                 return (hat_mask & binding->input.hat.hat_mask) ? SDL_PRESSED : SDL_RELEASED;
  1543             }
  1544         }
  1545     }
  1546     return SDL_RELEASED;
  1547 }
  1548 
  1549 const char *
  1550 SDL_GameControllerName(SDL_GameController * gamecontroller)
  1551 {
  1552     if (!gamecontroller)
  1553         return NULL;
  1554 
  1555     return gamecontroller->name;
  1556 }
  1557 
  1558 Uint16
  1559 SDL_GameControllerGetVendor(SDL_GameController * gamecontroller)
  1560 {
  1561     return SDL_JoystickGetVendor(SDL_GameControllerGetJoystick(gamecontroller));
  1562 }
  1563 
  1564 Uint16
  1565 SDL_GameControllerGetProduct(SDL_GameController * gamecontroller)
  1566 {
  1567     return SDL_JoystickGetProduct(SDL_GameControllerGetJoystick(gamecontroller));
  1568 }
  1569 
  1570 Uint16
  1571 SDL_GameControllerGetProductVersion(SDL_GameController * gamecontroller)
  1572 {
  1573     return SDL_JoystickGetProductVersion(SDL_GameControllerGetJoystick(gamecontroller));
  1574 }
  1575 
  1576 /*
  1577  * Return if the controller in question is currently attached to the system,
  1578  *  \return 0 if not plugged in, 1 if still present.
  1579  */
  1580 SDL_bool
  1581 SDL_GameControllerGetAttached(SDL_GameController * gamecontroller)
  1582 {
  1583     if (!gamecontroller)
  1584         return SDL_FALSE;
  1585 
  1586     return SDL_JoystickGetAttached(gamecontroller->joystick);
  1587 }
  1588 
  1589 /*
  1590  * Get the joystick for this controller
  1591  */
  1592 SDL_Joystick *SDL_GameControllerGetJoystick(SDL_GameController * gamecontroller)
  1593 {
  1594     if (!gamecontroller)
  1595         return NULL;
  1596 
  1597     return gamecontroller->joystick;
  1598 }
  1599 
  1600 
  1601 /*
  1602  * Find the SDL_GameController that owns this instance id
  1603  */
  1604 SDL_GameController *
  1605 SDL_GameControllerFromInstanceID(SDL_JoystickID joyid)
  1606 {
  1607     SDL_GameController *gamecontroller;
  1608 
  1609     SDL_LockJoysticks();
  1610     gamecontroller = SDL_gamecontrollers;
  1611     while (gamecontroller) {
  1612         if (gamecontroller->joystick->instance_id == joyid) {
  1613             SDL_UnlockJoysticks();
  1614             return gamecontroller;
  1615         }
  1616         gamecontroller = gamecontroller->next;
  1617     }
  1618     SDL_UnlockJoysticks();
  1619     return NULL;
  1620 }
  1621 
  1622 
  1623 /*
  1624  * Get the SDL joystick layer binding for this controller axis mapping
  1625  */
  1626 SDL_GameControllerButtonBind SDL_GameControllerGetBindForAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis)
  1627 {
  1628     int i;
  1629     SDL_GameControllerButtonBind bind;
  1630     SDL_zero(bind);
  1631 
  1632     if (!gamecontroller || axis == SDL_CONTROLLER_AXIS_INVALID)
  1633         return bind;
  1634 
  1635     for (i = 0; i < gamecontroller->num_bindings; ++i) {
  1636         SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
  1637         if (binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS && binding->output.axis.axis == axis) {
  1638             bind.bindType = binding->inputType;
  1639             if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
  1640                 /* FIXME: There might be multiple axes bound now that we have axis ranges... */
  1641                 bind.value.axis = binding->input.axis.axis;
  1642             } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
  1643                 bind.value.button = binding->input.button;
  1644             } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
  1645                 bind.value.hat.hat = binding->input.hat.hat;
  1646                 bind.value.hat.hat_mask = binding->input.hat.hat_mask;
  1647             }
  1648             break;
  1649         }
  1650     }
  1651     return bind;
  1652 }
  1653 
  1654 
  1655 /*
  1656  * Get the SDL joystick layer binding for this controller button mapping
  1657  */
  1658 SDL_GameControllerButtonBind SDL_GameControllerGetBindForButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button)
  1659 {
  1660     int i;
  1661     SDL_GameControllerButtonBind bind;
  1662     SDL_zero(bind);
  1663 
  1664     if (!gamecontroller || button == SDL_CONTROLLER_BUTTON_INVALID)
  1665         return bind;
  1666 
  1667     for (i = 0; i < gamecontroller->num_bindings; ++i) {
  1668         SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
  1669         if (binding->outputType == SDL_CONTROLLER_BINDTYPE_BUTTON && binding->output.button == button) {
  1670             bind.bindType = binding->inputType;
  1671             if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
  1672                 bind.value.axis = binding->input.axis.axis;
  1673             } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
  1674                 bind.value.button = binding->input.button;
  1675             } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
  1676                 bind.value.hat.hat = binding->input.hat.hat;
  1677                 bind.value.hat.hat_mask = binding->input.hat.hat_mask;
  1678             }
  1679             break;
  1680         }
  1681     }
  1682     return bind;
  1683 }
  1684 
  1685 
  1686 void
  1687 SDL_GameControllerClose(SDL_GameController * gamecontroller)
  1688 {
  1689     SDL_GameController *gamecontrollerlist, *gamecontrollerlistprev;
  1690 
  1691     if (!gamecontroller)
  1692         return;
  1693 
  1694     SDL_LockJoysticks();
  1695 
  1696     /* First decrement ref count */
  1697     if (--gamecontroller->ref_count > 0) {
  1698         SDL_UnlockJoysticks();
  1699         return;
  1700     }
  1701 
  1702     SDL_JoystickClose(gamecontroller->joystick);
  1703 
  1704     gamecontrollerlist = SDL_gamecontrollers;
  1705     gamecontrollerlistprev = NULL;
  1706     while (gamecontrollerlist) {
  1707         if (gamecontroller == gamecontrollerlist) {
  1708             if (gamecontrollerlistprev) {
  1709                 /* unlink this entry */
  1710                 gamecontrollerlistprev->next = gamecontrollerlist->next;
  1711             } else {
  1712                 SDL_gamecontrollers = gamecontroller->next;
  1713             }
  1714             break;
  1715         }
  1716         gamecontrollerlistprev = gamecontrollerlist;
  1717         gamecontrollerlist = gamecontrollerlist->next;
  1718     }
  1719 
  1720     SDL_free(gamecontroller->bindings);
  1721     SDL_free(gamecontroller->last_match_axis);
  1722     SDL_free(gamecontroller->last_hat_mask);
  1723     SDL_free(gamecontroller);
  1724 
  1725     SDL_UnlockJoysticks();
  1726 }
  1727 
  1728 
  1729 /*
  1730  * Quit the controller subsystem
  1731  */
  1732 void
  1733 SDL_GameControllerQuit(void)
  1734 {
  1735     SDL_LockJoysticks();
  1736     while (SDL_gamecontrollers) {
  1737         SDL_gamecontrollers->ref_count = 1;
  1738         SDL_GameControllerClose(SDL_gamecontrollers);
  1739     }
  1740     SDL_UnlockJoysticks();
  1741 }
  1742 
  1743 void
  1744 SDL_GameControllerQuitMappings(void)
  1745 {
  1746     ControllerMapping_t *pControllerMap;
  1747 
  1748     while (s_pSupportedControllers) {
  1749         pControllerMap = s_pSupportedControllers;
  1750         s_pSupportedControllers = s_pSupportedControllers->next;
  1751         SDL_free(pControllerMap->name);
  1752         SDL_free(pControllerMap->mapping);
  1753         SDL_free(pControllerMap);
  1754     }
  1755 
  1756     SDL_DelEventWatch(SDL_GameControllerEventWatcher, NULL);
  1757 
  1758     SDL_DelHintCallback(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES,
  1759                         SDL_GameControllerIgnoreDevicesChanged, NULL);
  1760     SDL_DelHintCallback(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT,
  1761                         SDL_GameControllerIgnoreDevicesExceptChanged, NULL);
  1762 
  1763     if (SDL_allowed_controllers.entries) {
  1764         SDL_free(SDL_allowed_controllers.entries);
  1765         SDL_zero(SDL_allowed_controllers);
  1766     }
  1767     if (SDL_ignored_controllers.entries) {
  1768         SDL_free(SDL_ignored_controllers.entries);
  1769         SDL_zero(SDL_ignored_controllers);
  1770     }
  1771 }
  1772 
  1773 /*
  1774  * Event filter to transform joystick events into appropriate game controller ones
  1775  */
  1776 static int
  1777 SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis, Sint16 value)
  1778 {
  1779     int posted;
  1780 
  1781     /* translate the event, if desired */
  1782     posted = 0;
  1783 #if !SDL_EVENTS_DISABLED
  1784     if (SDL_GetEventState(SDL_CONTROLLERAXISMOTION) == SDL_ENABLE) {
  1785         SDL_Event event;
  1786         event.type = SDL_CONTROLLERAXISMOTION;
  1787         event.caxis.which = gamecontroller->joystick->instance_id;
  1788         event.caxis.axis = axis;
  1789         event.caxis.value = value;
  1790         posted = SDL_PushEvent(&event) == 1;
  1791     }
  1792 #endif /* !SDL_EVENTS_DISABLED */
  1793     return (posted);
  1794 }
  1795 
  1796 
  1797 /*
  1798  * Event filter to transform joystick events into appropriate game controller ones
  1799  */
  1800 static int
  1801 SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button, Uint8 state)
  1802 {
  1803     int posted;
  1804 #if !SDL_EVENTS_DISABLED
  1805     SDL_Event event;
  1806 
  1807     if (button == SDL_CONTROLLER_BUTTON_INVALID)
  1808         return (0);
  1809 
  1810     switch (state) {
  1811     case SDL_PRESSED:
  1812         event.type = SDL_CONTROLLERBUTTONDOWN;
  1813         break;
  1814     case SDL_RELEASED:
  1815         event.type = SDL_CONTROLLERBUTTONUP;
  1816         break;
  1817     default:
  1818         /* Invalid state -- bail */
  1819         return (0);
  1820     }
  1821 #endif /* !SDL_EVENTS_DISABLED */
  1822 
  1823     /* translate the event, if desired */
  1824     posted = 0;
  1825 #if !SDL_EVENTS_DISABLED
  1826     if (SDL_GetEventState(event.type) == SDL_ENABLE) {
  1827         event.cbutton.which = gamecontroller->joystick->instance_id;
  1828         event.cbutton.button = button;
  1829         event.cbutton.state = state;
  1830         posted = SDL_PushEvent(&event) == 1;
  1831     }
  1832 #endif /* !SDL_EVENTS_DISABLED */
  1833     return (posted);
  1834 }
  1835 
  1836 /*
  1837  * Turn off controller events
  1838  */
  1839 int
  1840 SDL_GameControllerEventState(int state)
  1841 {
  1842 #if SDL_EVENTS_DISABLED
  1843     return SDL_IGNORE;
  1844 #else
  1845     const Uint32 event_list[] = {
  1846         SDL_CONTROLLERAXISMOTION, SDL_CONTROLLERBUTTONDOWN, SDL_CONTROLLERBUTTONUP,
  1847         SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEREMOVED, SDL_CONTROLLERDEVICEREMAPPED,
  1848     };
  1849     unsigned int i;
  1850 
  1851     switch (state) {
  1852     case SDL_QUERY:
  1853         state = SDL_IGNORE;
  1854         for (i = 0; i < SDL_arraysize(event_list); ++i) {
  1855             state = SDL_EventState(event_list[i], SDL_QUERY);
  1856             if (state == SDL_ENABLE) {
  1857                 break;
  1858             }
  1859         }
  1860         break;
  1861     default:
  1862         for (i = 0; i < SDL_arraysize(event_list); ++i) {
  1863             SDL_EventState(event_list[i], state);
  1864         }
  1865         break;
  1866     }
  1867     return (state);
  1868 #endif /* SDL_EVENTS_DISABLED */
  1869 }
  1870 
  1871 /* vi: set ts=4 sw=4 expandtab: */