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