sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_gamecontroller.c (88892B)


      1 /*
      2   Simple DirectMedia Layer
      3   Copyright (C) 1997-2020 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_hints.h"
     27 #include "SDL_timer.h"
     28 #include "SDL_sysjoystick.h"
     29 #include "SDL_joystick_c.h"
     30 #include "SDL_gamecontrollerdb.h"
     31 #include "usb_ids.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 #define SDL_CONTROLLER_HINT_FIELD       "hint:"
     47 #define SDL_CONTROLLER_SDKGE_FIELD      "sdk>=:"
     48 #define SDL_CONTROLLER_SDKLE_FIELD      "sdk<=:"
     49 
     50 /* a list of currently opened game controllers */
     51 static SDL_GameController *SDL_gamecontrollers = NULL;
     52 
     53 typedef struct
     54 {
     55     SDL_GameControllerBindType inputType;
     56     union
     57     {
     58         int button;
     59 
     60         struct {
     61             int axis;
     62             int axis_min;
     63             int axis_max;
     64         } axis;
     65 
     66         struct {
     67             int hat;
     68             int hat_mask;
     69         } hat;
     70 
     71     } input;
     72 
     73     SDL_GameControllerBindType outputType;
     74     union
     75     {
     76         SDL_GameControllerButton button;
     77 
     78         struct {
     79             SDL_GameControllerAxis axis;
     80             int axis_min;
     81             int axis_max;
     82         } axis;
     83 
     84     } output;
     85 
     86 } SDL_ExtendedGameControllerBind;
     87 
     88 /* our hard coded list of mapping support */
     89 typedef enum
     90 {
     91     SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT,
     92     SDL_CONTROLLER_MAPPING_PRIORITY_API,
     93     SDL_CONTROLLER_MAPPING_PRIORITY_USER,
     94 } SDL_ControllerMappingPriority;
     95 
     96 typedef struct _ControllerMapping_t
     97 {
     98     SDL_JoystickGUID guid;
     99     char *name;
    100     char *mapping;
    101     SDL_ControllerMappingPriority priority;
    102     struct _ControllerMapping_t *next;
    103 } ControllerMapping_t;
    104 
    105 static SDL_JoystickGUID s_zeroGUID;
    106 static ControllerMapping_t *s_pSupportedControllers = NULL;
    107 static ControllerMapping_t *s_pDefaultMapping = NULL;
    108 static ControllerMapping_t *s_pXInputMapping = NULL;
    109 
    110 /* The SDL game controller structure */
    111 struct _SDL_GameController
    112 {
    113     SDL_Joystick *joystick; /* underlying joystick device */
    114     int ref_count;
    115 
    116     const char *name;
    117     int num_bindings;
    118     SDL_ExtendedGameControllerBind *bindings;
    119     SDL_ExtendedGameControllerBind **last_match_axis;
    120     Uint8 *last_hat_mask;
    121     Uint32 guide_button_down;
    122 
    123     struct _SDL_GameController *next; /* pointer to next game controller we have allocated */
    124 };
    125 
    126 
    127 typedef struct
    128 {
    129     int num_entries;
    130     int max_entries;
    131     Uint32 *entries;
    132 } SDL_vidpid_list;
    133 
    134 static SDL_vidpid_list SDL_allowed_controllers;
    135 static SDL_vidpid_list SDL_ignored_controllers;
    136 
    137 static void
    138 SDL_LoadVIDPIDListFromHint(const char *hint, SDL_vidpid_list *list)
    139 {
    140     Uint32 entry;
    141     char *spot;
    142     char *file = NULL;
    143 
    144     list->num_entries = 0;
    145 
    146     if (hint && *hint == '@') {
    147         spot = file = (char *)SDL_LoadFile(hint+1, NULL);
    148     } else {
    149         spot = (char *)hint;
    150     }
    151 
    152     if (!spot) {
    153         return;
    154     }
    155 
    156     while ((spot = SDL_strstr(spot, "0x")) != NULL) {
    157         entry = (Uint16)SDL_strtol(spot, &spot, 0);
    158         entry <<= 16;
    159         spot = SDL_strstr(spot, "0x");
    160         if (!spot) {
    161             break;
    162         }
    163         entry |= (Uint16)SDL_strtol(spot, &spot, 0);
    164 
    165         if (list->num_entries == list->max_entries) {
    166             int max_entries = list->max_entries + 16;
    167             Uint32 *entries = (Uint32 *)SDL_realloc(list->entries, max_entries*sizeof(*list->entries));
    168             if (entries == NULL) {
    169                 /* Out of memory, go with what we have already */
    170                 break;
    171             }
    172             list->entries = entries;
    173             list->max_entries = max_entries;
    174         }
    175         list->entries[list->num_entries++] = entry;
    176     }
    177 
    178     if (file) {
    179         SDL_free(file);
    180     }
    181 }
    182 
    183 static void SDLCALL
    184 SDL_GameControllerIgnoreDevicesChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
    185 {
    186     SDL_LoadVIDPIDListFromHint(hint, &SDL_ignored_controllers);
    187 }
    188 
    189 static void SDLCALL
    190 SDL_GameControllerIgnoreDevicesExceptChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
    191 {
    192     SDL_LoadVIDPIDListFromHint(hint, &SDL_allowed_controllers);
    193 }
    194 
    195 static ControllerMapping_t *SDL_PrivateAddMappingForGUID(SDL_JoystickGUID jGUID, const char *mappingString, SDL_bool *existing, SDL_ControllerMappingPriority priority);
    196 static int SDL_PrivateGameControllerAxis(SDL_GameController *gamecontroller, SDL_GameControllerAxis axis, Sint16 value);
    197 static int SDL_PrivateGameControllerButton(SDL_GameController *gamecontroller, SDL_GameControllerButton button, Uint8 state);
    198 
    199 /*
    200  * If there is an existing add event in the queue, it needs to be modified
    201  * to have the right value for which, because the number of controllers in
    202  * the system is now one less.
    203  */
    204 static void UpdateEventsForDeviceRemoval(int device_index)
    205 {
    206     int i, num_events;
    207     SDL_Event *events;
    208     SDL_bool isstack;
    209 
    210     num_events = SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEADDED);
    211     if (num_events <= 0) {
    212         return;
    213     }
    214 
    215     events = SDL_small_alloc(SDL_Event, num_events, &isstack);
    216     if (!events) {
    217         return;
    218     }
    219 
    220     num_events = SDL_PeepEvents(events, num_events, SDL_GETEVENT, SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEADDED);
    221     for (i = 0; i < num_events; ++i) {
    222         if (events[i].cdevice.which < device_index) {
    223             /* No change for index values lower than the removed device */
    224         }
    225         else if (events[i].cdevice.which == device_index) {
    226             /* Drop this event entirely */
    227             SDL_memmove(&events[i], &events[i + 1], sizeof(*events) * (num_events - (i + 1)));
    228             --i;
    229             --num_events;
    230         }
    231         else {
    232             /* Fix up the device index if greater than the removed device */
    233             --events[i].cdevice.which;
    234         }
    235     }
    236     SDL_PeepEvents(events, num_events, SDL_ADDEVENT, 0, 0);
    237 
    238     SDL_small_free(events, isstack);
    239 }
    240 
    241 static SDL_bool HasSameOutput(SDL_ExtendedGameControllerBind *a, SDL_ExtendedGameControllerBind *b)
    242 {
    243     if (a->outputType != b->outputType) {
    244         return SDL_FALSE;
    245     }
    246 
    247     if (a->outputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
    248         return (a->output.axis.axis == b->output.axis.axis);
    249     } else {
    250         return (a->output.button == b->output.button);
    251     }
    252 }
    253 
    254 static void ResetOutput(SDL_GameController *gamecontroller, SDL_ExtendedGameControllerBind *bind)
    255 {
    256     if (bind->outputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
    257         SDL_PrivateGameControllerAxis(gamecontroller, bind->output.axis.axis, 0);
    258     } else {
    259         SDL_PrivateGameControllerButton(gamecontroller, bind->output.button, SDL_RELEASED);
    260     }
    261 }
    262 
    263 static void HandleJoystickAxis(SDL_GameController *gamecontroller, int axis, int value)
    264 {
    265     int i;
    266     SDL_ExtendedGameControllerBind *last_match = gamecontroller->last_match_axis[axis];
    267     SDL_ExtendedGameControllerBind *match = NULL;
    268 
    269     for (i = 0; i < gamecontroller->num_bindings; ++i) {
    270         SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
    271         if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS &&
    272             axis == binding->input.axis.axis) {
    273             if (binding->input.axis.axis_min < binding->input.axis.axis_max) {
    274                 if (value >= binding->input.axis.axis_min &&
    275                     value <= binding->input.axis.axis_max) {
    276                     match = binding;
    277                     break;
    278                 }
    279             } else {
    280                 if (value >= binding->input.axis.axis_max &&
    281                     value <= binding->input.axis.axis_min) {
    282                     match = binding;
    283                     break;
    284                 }
    285             }
    286         }
    287     }
    288 
    289     if (last_match && (!match || !HasSameOutput(last_match, match))) {
    290         /* Clear the last input that this axis generated */
    291         ResetOutput(gamecontroller, last_match);
    292     }
    293 
    294     if (match) {
    295         if (match->outputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
    296             if (match->input.axis.axis_min != match->output.axis.axis_min || match->input.axis.axis_max != match->output.axis.axis_max) {
    297                 float normalized_value = (float)(value - match->input.axis.axis_min) / (match->input.axis.axis_max - match->input.axis.axis_min);
    298                 value = match->output.axis.axis_min + (int)(normalized_value * (match->output.axis.axis_max - match->output.axis.axis_min));
    299             }
    300             SDL_PrivateGameControllerAxis(gamecontroller, match->output.axis.axis, (Sint16)value);
    301         } else {
    302             Uint8 state;
    303             int threshold = match->input.axis.axis_min + (match->input.axis.axis_max - match->input.axis.axis_min) / 2;
    304             if (match->input.axis.axis_max < match->input.axis.axis_min) {
    305                 state = (value <= threshold) ? SDL_PRESSED : SDL_RELEASED;
    306             } else {
    307                 state = (value >= threshold) ? SDL_PRESSED : SDL_RELEASED;
    308             }
    309             SDL_PrivateGameControllerButton(gamecontroller, match->output.button, state);
    310         }
    311     }
    312     gamecontroller->last_match_axis[axis] = match;
    313 }
    314 
    315 static void HandleJoystickButton(SDL_GameController *gamecontroller, int button, Uint8 state)
    316 {
    317     int i;
    318 
    319     for (i = 0; i < gamecontroller->num_bindings; ++i) {
    320         SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
    321         if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON &&
    322             button == binding->input.button) {
    323             if (binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
    324                 int value = state ? binding->output.axis.axis_max : binding->output.axis.axis_min;
    325                 SDL_PrivateGameControllerAxis(gamecontroller, binding->output.axis.axis, (Sint16)value);
    326             } else {
    327                 SDL_PrivateGameControllerButton(gamecontroller, binding->output.button, state);
    328             }
    329             break;
    330         }
    331     }
    332 }
    333 
    334 static void HandleJoystickHat(SDL_GameController *gamecontroller, int hat, Uint8 value)
    335 {
    336     int i;
    337     Uint8 last_mask = gamecontroller->last_hat_mask[hat];
    338     Uint8 changed_mask = (last_mask ^ value);
    339 
    340     for (i = 0; i < gamecontroller->num_bindings; ++i) {
    341         SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
    342         if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT && hat == binding->input.hat.hat) {
    343             if ((changed_mask & binding->input.hat.hat_mask) != 0) {
    344                 if (value & binding->input.hat.hat_mask) {
    345                     if (binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
    346                         SDL_PrivateGameControllerAxis(gamecontroller, binding->output.axis.axis, (Sint16)binding->output.axis.axis_max);
    347                     } else {
    348                         SDL_PrivateGameControllerButton(gamecontroller, binding->output.button, SDL_PRESSED);
    349                     }
    350                 } else {
    351                     ResetOutput(gamecontroller, binding);
    352                 }
    353             }
    354         }
    355     }
    356     gamecontroller->last_hat_mask[hat] = value;
    357 }
    358 
    359 
    360 /* The joystick layer will _also_ send events to recenter before disconnect,
    361     but it has to make (sometimes incorrect) guesses at what being "centered"
    362     is. The game controller layer, however, can set a definite logical idle
    363     position, so set them all here. If we happened to already be at the
    364     center thanks to the joystick layer or idle hands, this won't generate
    365     duplicate events. */
    366 static void RecenterGameController(SDL_GameController *gamecontroller)
    367 {
    368     SDL_GameControllerButton button;
    369     SDL_GameControllerAxis axis;
    370 
    371     for (button = (SDL_GameControllerButton) 0; button < SDL_CONTROLLER_BUTTON_MAX; button++) {
    372         if (SDL_GameControllerGetButton(gamecontroller, button)) {
    373             SDL_PrivateGameControllerButton(gamecontroller, button, SDL_RELEASED);
    374         }
    375     }
    376 
    377     for (axis = (SDL_GameControllerAxis) 0; axis < SDL_CONTROLLER_AXIS_MAX; axis++) {
    378         if (SDL_GameControllerGetAxis(gamecontroller, axis) != 0) {
    379             SDL_PrivateGameControllerAxis(gamecontroller, axis, 0);
    380         }
    381     }
    382 }
    383 
    384 
    385 /*
    386  * Event filter to fire controller events from joystick ones
    387  */
    388 static int SDLCALL SDL_GameControllerEventWatcher(void *userdata, SDL_Event * event)
    389 {
    390     switch(event->type) {
    391     case SDL_JOYAXISMOTION:
    392         {
    393             SDL_GameController *controllerlist = SDL_gamecontrollers;
    394             while (controllerlist) {
    395                 if (controllerlist->joystick->instance_id == event->jaxis.which) {
    396                     HandleJoystickAxis(controllerlist, event->jaxis.axis, event->jaxis.value);
    397                     break;
    398                 }
    399                 controllerlist = controllerlist->next;
    400             }
    401         }
    402         break;
    403     case SDL_JOYBUTTONDOWN:
    404     case SDL_JOYBUTTONUP:
    405         {
    406             SDL_GameController *controllerlist = SDL_gamecontrollers;
    407             while (controllerlist) {
    408                 if (controllerlist->joystick->instance_id == event->jbutton.which) {
    409                     HandleJoystickButton(controllerlist, event->jbutton.button, event->jbutton.state);
    410                     break;
    411                 }
    412                 controllerlist = controllerlist->next;
    413             }
    414         }
    415         break;
    416     case SDL_JOYHATMOTION:
    417         {
    418             SDL_GameController *controllerlist = SDL_gamecontrollers;
    419             while (controllerlist) {
    420                 if (controllerlist->joystick->instance_id == event->jhat.which) {
    421                     HandleJoystickHat(controllerlist, event->jhat.hat, event->jhat.value);
    422                     break;
    423                 }
    424                 controllerlist = controllerlist->next;
    425             }
    426         }
    427         break;
    428     case SDL_JOYDEVICEADDED:
    429         {
    430             if (SDL_IsGameController(event->jdevice.which)) {
    431                 SDL_Event deviceevent;
    432                 deviceevent.type = SDL_CONTROLLERDEVICEADDED;
    433                 deviceevent.cdevice.which = event->jdevice.which;
    434                 SDL_PushEvent(&deviceevent);
    435             }
    436         }
    437         break;
    438     case SDL_JOYDEVICEREMOVED:
    439         {
    440             SDL_GameController *controllerlist = SDL_gamecontrollers;
    441             int device_index = 0;
    442             while (controllerlist) {
    443                 if (controllerlist->joystick->instance_id == event->jdevice.which) {
    444                     SDL_Event deviceevent;
    445 
    446                     RecenterGameController(controllerlist);
    447 
    448                     deviceevent.type = SDL_CONTROLLERDEVICEREMOVED;
    449                     deviceevent.cdevice.which = event->jdevice.which;
    450                     SDL_PushEvent(&deviceevent);
    451 
    452                     UpdateEventsForDeviceRemoval(device_index);
    453                     break;
    454                 }
    455                 controllerlist = controllerlist->next;
    456                 ++device_index;
    457             }
    458         }
    459         break;
    460     default:
    461         break;
    462     }
    463 
    464     return 1;
    465 }
    466 
    467 #ifdef __ANDROID__
    468 /*
    469  * Helper function to guess at a mapping based on the elements reported for this controller
    470  */
    471 static ControllerMapping_t *SDL_CreateMappingForAndroidController(SDL_JoystickGUID guid)
    472 {
    473     SDL_bool existing;
    474     char mapping_string[1024];
    475     int button_mask;
    476     int axis_mask;
    477 
    478     button_mask = SDL_SwapLE16(*(Uint16*)(&guid.data[sizeof(guid.data)-4]));
    479     axis_mask = SDL_SwapLE16(*(Uint16*)(&guid.data[sizeof(guid.data)-2]));
    480     if (!button_mask && !axis_mask) {
    481         /* Accelerometer, shouldn't have a game controller mapping */
    482         return NULL;
    483     }
    484 
    485     SDL_strlcpy(mapping_string, "none,*,", sizeof(mapping_string));
    486 
    487     if (button_mask & (1 << SDL_CONTROLLER_BUTTON_A)) {
    488         SDL_strlcat(mapping_string, "a:b0,", sizeof(mapping_string));
    489     }
    490     if (button_mask & (1 << SDL_CONTROLLER_BUTTON_B)) {
    491         SDL_strlcat(mapping_string, "b:b1,", sizeof(mapping_string));
    492     } else if (button_mask & (1 << SDL_CONTROLLER_BUTTON_BACK)) {
    493         /* Use the back button as "B" for easy UI navigation with TV remotes */
    494         SDL_strlcat(mapping_string, "b:b4,", sizeof(mapping_string));
    495         button_mask &= ~(1 << SDL_CONTROLLER_BUTTON_BACK);
    496     }
    497     if (button_mask & (1 << SDL_CONTROLLER_BUTTON_X)) {
    498         SDL_strlcat(mapping_string, "x:b2,", sizeof(mapping_string));
    499     }
    500     if (button_mask & (1 << SDL_CONTROLLER_BUTTON_Y)) {
    501         SDL_strlcat(mapping_string, "y:b3,", sizeof(mapping_string));
    502     }
    503     if (button_mask & (1 << SDL_CONTROLLER_BUTTON_BACK)) {
    504         SDL_strlcat(mapping_string, "back:b4,", sizeof(mapping_string));
    505     }
    506     if (button_mask & (1 << SDL_CONTROLLER_BUTTON_GUIDE)) {
    507         /* The guide button generally isn't functional (or acts as a home button) on most Android controllers before Android 11 */
    508         if (SDL_GetAndroidSDKVersion() >= 30 /* Android 11 */) {
    509             SDL_strlcat(mapping_string, "guide:b5,", sizeof(mapping_string));
    510         }
    511     }
    512     if (button_mask & (1 << SDL_CONTROLLER_BUTTON_START)) {
    513         SDL_strlcat(mapping_string, "start:b6,", sizeof(mapping_string));
    514     }
    515     if (button_mask & (1 << SDL_CONTROLLER_BUTTON_LEFTSTICK)) {
    516         SDL_strlcat(mapping_string, "leftstick:b7,", sizeof(mapping_string));
    517     }
    518     if (button_mask & (1 << SDL_CONTROLLER_BUTTON_RIGHTSTICK)) {
    519         SDL_strlcat(mapping_string, "rightstick:b8,", sizeof(mapping_string));
    520     }
    521     if (button_mask & (1 << SDL_CONTROLLER_BUTTON_LEFTSHOULDER)) {
    522         SDL_strlcat(mapping_string, "leftshoulder:b9,", sizeof(mapping_string));
    523     }
    524     if (button_mask & (1 << SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)) {
    525         SDL_strlcat(mapping_string, "rightshoulder:b10,", sizeof(mapping_string));
    526     }
    527     if (button_mask & (1 << SDL_CONTROLLER_BUTTON_DPAD_UP)) {
    528         SDL_strlcat(mapping_string, "dpup:b11,", sizeof(mapping_string));
    529     }
    530     if (button_mask & (1 << SDL_CONTROLLER_BUTTON_DPAD_DOWN)) {
    531         SDL_strlcat(mapping_string, "dpdown:b12,", sizeof(mapping_string));
    532     }
    533     if (button_mask & (1 << SDL_CONTROLLER_BUTTON_DPAD_LEFT)) {
    534         SDL_strlcat(mapping_string, "dpleft:b13,", sizeof(mapping_string));
    535     }
    536     if (button_mask & (1 << SDL_CONTROLLER_BUTTON_DPAD_RIGHT)) {
    537         SDL_strlcat(mapping_string, "dpright:b14,", sizeof(mapping_string));
    538     }
    539     if (axis_mask & (1 << SDL_CONTROLLER_AXIS_LEFTX)) {
    540         SDL_strlcat(mapping_string, "leftx:a0,", sizeof(mapping_string));
    541     }
    542     if (axis_mask & (1 << SDL_CONTROLLER_AXIS_LEFTY)) {
    543         SDL_strlcat(mapping_string, "lefty:a1,", sizeof(mapping_string));
    544     }
    545     if (axis_mask & (1 << SDL_CONTROLLER_AXIS_RIGHTX)) {
    546         SDL_strlcat(mapping_string, "rightx:a2,", sizeof(mapping_string));
    547     }
    548     if (axis_mask & (1 << SDL_CONTROLLER_AXIS_RIGHTY)) {
    549         SDL_strlcat(mapping_string, "righty:a3,", sizeof(mapping_string));
    550     }
    551     if (axis_mask & (1 << SDL_CONTROLLER_AXIS_TRIGGERLEFT)) {
    552         SDL_strlcat(mapping_string, "lefttrigger:a4,", sizeof(mapping_string));
    553     }
    554     if (axis_mask & (1 << SDL_CONTROLLER_AXIS_TRIGGERRIGHT)) {
    555         SDL_strlcat(mapping_string, "righttrigger:a5,", sizeof(mapping_string));
    556     }
    557 
    558     return SDL_PrivateAddMappingForGUID(guid, mapping_string,
    559                       &existing, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT);
    560 }
    561 #endif /* __ANDROID__ */
    562 
    563 /*
    564  * Helper function to guess at a mapping for HIDAPI controllers
    565  */
    566 static ControllerMapping_t *SDL_CreateMappingForHIDAPIController(SDL_JoystickGUID guid)
    567 {
    568     SDL_bool existing;
    569     char mapping_string[1024];
    570     Uint16 vendor;
    571     Uint16 product;
    572 
    573     SDL_strlcpy(mapping_string, "none,*,", sizeof(mapping_string));
    574 
    575     SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL);
    576 
    577     if (vendor == USB_VENDOR_NINTENDO && product == USB_PRODUCT_NINTENDO_GAMECUBE_ADAPTER) {
    578         /* GameCube driver has 12 buttons and 6 axes */
    579         SDL_strlcat(mapping_string, "a:b0,b:b1,dpdown:b6,dpleft:b4,dpright:b5,dpup:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:a5,rightx:a2,righty:a3,start:b8,x:b2,y:b3,", sizeof(mapping_string));
    580     } else {
    581         /* All other controllers have the standard set of 19 buttons and 6 axes */
    582         if (!SDL_IsJoystickNintendoSwitchPro(vendor, product) ||
    583             SDL_GetHintBoolean(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS, SDL_TRUE)) {
    584             SDL_strlcat(mapping_string, "a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,", sizeof(mapping_string));
    585         } else {
    586             /* Nintendo Switch Pro Controller with swapped face buttons to match Xbox Controller physical layout */
    587             SDL_strlcat(mapping_string, "a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,", sizeof(mapping_string));
    588         }
    589 
    590         if (SDL_IsJoystickXboxOneSeriesX(vendor, product)) {
    591             /* XBox One Series X Controllers have a share button under the guide button */
    592             SDL_strlcat(mapping_string, "misc1:b15,", sizeof(mapping_string));
    593         } else if (SDL_IsJoystickXboxOneElite(vendor, product)) {
    594             /* XBox One Elite Controllers have 4 back paddle buttons */
    595             SDL_strlcat(mapping_string, "paddle1:b15,paddle2:b17,paddle3:b16,paddle4:b18,", sizeof(mapping_string));
    596         } else if (SDL_IsJoystickSteamController(vendor, product)) {
    597             /* Steam controllers have 2 back paddle buttons */
    598             SDL_strlcat(mapping_string, "paddle1:b16,paddle2:b15,", sizeof(mapping_string));
    599         } else {
    600             switch (SDL_GetJoystickGameControllerTypeFromGUID(guid, NULL)) {
    601             case SDL_CONTROLLER_TYPE_PS4:
    602                 /* PS4 controllers have an additional touchpad button */
    603                 SDL_strlcat(mapping_string, "touchpad:b15,", sizeof(mapping_string));
    604                 break;
    605             case SDL_CONTROLLER_TYPE_PS5:
    606                 /* PS5 controllers have a microphone button and an additional touchpad button */
    607                 SDL_strlcat(mapping_string, "misc1:b15,touchpad:b16", sizeof(mapping_string));
    608                 break;
    609             case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO:
    610                 /* Nintendo Switch Pro controllers have a screenshot button */
    611                 SDL_strlcat(mapping_string, "misc1:b15,", sizeof(mapping_string));
    612                 break;
    613             default:
    614                 break;
    615             }
    616         }
    617     }
    618 
    619     return SDL_PrivateAddMappingForGUID(guid, mapping_string,
    620                       &existing, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT);
    621 }
    622 
    623 /*
    624  * Helper function to guess at a mapping for RAWINPUT controllers
    625  */
    626 static ControllerMapping_t *SDL_CreateMappingForRAWINPUTController(SDL_JoystickGUID guid)
    627 {
    628     SDL_bool existing;
    629     char mapping_string[1024];
    630 
    631     SDL_strlcpy(mapping_string, "none,*,", sizeof(mapping_string));
    632     SDL_strlcat(mapping_string, "a:b0,b:b1,x:b2,y:b3,back:b6,guide:b10,start:b7,leftstick:b8,rightstick:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,", sizeof(mapping_string));
    633 
    634     return SDL_PrivateAddMappingForGUID(guid, mapping_string,
    635                       &existing, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT);
    636 }
    637 
    638 /*
    639  * Helper function to scan the mappings database for a controller with the specified GUID
    640  */
    641 static ControllerMapping_t *SDL_PrivateGetControllerMappingForGUID(SDL_JoystickGUID guid, SDL_bool exact_match)
    642 {
    643     ControllerMapping_t *mapping = s_pSupportedControllers;
    644 
    645     while (mapping) {
    646         if (SDL_memcmp(&guid, &mapping->guid, sizeof(guid)) == 0) {
    647             return mapping;
    648         }
    649         mapping = mapping->next;
    650     }
    651 
    652     if (!exact_match) {
    653 #if SDL_JOYSTICK_XINPUT
    654         if (SDL_IsJoystickXInput(guid)) {
    655             /* This is an XInput device */
    656             return s_pXInputMapping;
    657         }
    658 #endif
    659 #ifdef __ANDROID__
    660         if (!mapping && !SDL_IsJoystickHIDAPI(guid)) {
    661             mapping = SDL_CreateMappingForAndroidController(guid);
    662         }
    663 #endif
    664         if (!mapping && SDL_IsJoystickHIDAPI(guid)) {
    665             mapping = SDL_CreateMappingForHIDAPIController(guid);
    666         }
    667         if (!mapping && SDL_IsJoystickRAWINPUT(guid)) {
    668             mapping = SDL_CreateMappingForRAWINPUTController(guid);
    669         }
    670     }
    671     return mapping;
    672 }
    673 
    674 static const char* map_StringForControllerAxis[] = {
    675     "leftx",
    676     "lefty",
    677     "rightx",
    678     "righty",
    679     "lefttrigger",
    680     "righttrigger",
    681     NULL
    682 };
    683 
    684 /*
    685  * convert a string to its enum equivalent
    686  */
    687 SDL_GameControllerAxis SDL_GameControllerGetAxisFromString(const char *pchString)
    688 {
    689     int entry;
    690 
    691     if (pchString && (*pchString == '+' || *pchString == '-')) {
    692         ++pchString;
    693     }
    694 
    695     if (!pchString || !pchString[0]) {
    696         return SDL_CONTROLLER_AXIS_INVALID;
    697     }
    698 
    699     for (entry = 0; map_StringForControllerAxis[entry]; ++entry) {
    700         if (!SDL_strcasecmp(pchString, map_StringForControllerAxis[entry]))
    701             return (SDL_GameControllerAxis) entry;
    702     }
    703     return SDL_CONTROLLER_AXIS_INVALID;
    704 }
    705 
    706 /*
    707  * convert an enum to its string equivalent
    708  */
    709 const char* SDL_GameControllerGetStringForAxis(SDL_GameControllerAxis axis)
    710 {
    711     if (axis > SDL_CONTROLLER_AXIS_INVALID && axis < SDL_CONTROLLER_AXIS_MAX) {
    712         return map_StringForControllerAxis[axis];
    713     }
    714     return NULL;
    715 }
    716 
    717 static const char* map_StringForControllerButton[] = {
    718     "a",
    719     "b",
    720     "x",
    721     "y",
    722     "back",
    723     "guide",
    724     "start",
    725     "leftstick",
    726     "rightstick",
    727     "leftshoulder",
    728     "rightshoulder",
    729     "dpup",
    730     "dpdown",
    731     "dpleft",
    732     "dpright",
    733     "misc1",
    734     "paddle1",
    735     "paddle2",
    736     "paddle3",
    737     "paddle4",
    738     "touchpad",
    739     NULL
    740 };
    741 
    742 /*
    743  * convert a string to its enum equivalent
    744  */
    745 SDL_GameControllerButton SDL_GameControllerGetButtonFromString(const char *pchString)
    746 {
    747     int entry;
    748     if (!pchString || !pchString[0])
    749         return SDL_CONTROLLER_BUTTON_INVALID;
    750 
    751     for (entry = 0; map_StringForControllerButton[entry]; ++entry) {
    752         if (SDL_strcasecmp(pchString, map_StringForControllerButton[entry]) == 0)
    753             return (SDL_GameControllerButton) entry;
    754     }
    755     return SDL_CONTROLLER_BUTTON_INVALID;
    756 }
    757 
    758 /*
    759  * convert an enum to its string equivalent
    760  */
    761 const char* SDL_GameControllerGetStringForButton(SDL_GameControllerButton axis)
    762 {
    763     if (axis > SDL_CONTROLLER_BUTTON_INVALID && axis < SDL_CONTROLLER_BUTTON_MAX) {
    764         return map_StringForControllerButton[axis];
    765     }
    766     return NULL;
    767 }
    768 
    769 /*
    770  * given a controller button name and a joystick name update our mapping structure with it
    771  */
    772 static void SDL_PrivateGameControllerParseElement(SDL_GameController *gamecontroller, const char *szGameButton, const char *szJoystickButton)
    773 {
    774     SDL_ExtendedGameControllerBind bind;
    775     SDL_GameControllerButton button;
    776     SDL_GameControllerAxis axis;
    777     SDL_bool invert_input = SDL_FALSE;
    778     char half_axis_input = 0;
    779     char half_axis_output = 0;
    780 
    781     if (*szGameButton == '+' || *szGameButton == '-') {
    782         half_axis_output = *szGameButton++;
    783     }
    784 
    785     axis = SDL_GameControllerGetAxisFromString(szGameButton);
    786     button = SDL_GameControllerGetButtonFromString(szGameButton);
    787     if (axis != SDL_CONTROLLER_AXIS_INVALID) {
    788         bind.outputType = SDL_CONTROLLER_BINDTYPE_AXIS;
    789         bind.output.axis.axis = axis;
    790         if (axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT || axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT) {
    791             bind.output.axis.axis_min = 0;
    792             bind.output.axis.axis_max = SDL_JOYSTICK_AXIS_MAX;
    793         } else {
    794             if (half_axis_output == '+') {
    795                 bind.output.axis.axis_min = 0;
    796                 bind.output.axis.axis_max = SDL_JOYSTICK_AXIS_MAX;
    797             } else if (half_axis_output == '-') {
    798                 bind.output.axis.axis_min = 0;
    799                 bind.output.axis.axis_max = SDL_JOYSTICK_AXIS_MIN;
    800             } else {
    801                 bind.output.axis.axis_min = SDL_JOYSTICK_AXIS_MIN;
    802                 bind.output.axis.axis_max = SDL_JOYSTICK_AXIS_MAX;
    803             }
    804         }
    805     } else if (button != SDL_CONTROLLER_BUTTON_INVALID) {
    806         bind.outputType = SDL_CONTROLLER_BINDTYPE_BUTTON;
    807         bind.output.button = button;
    808     } else {
    809         SDL_SetError("Unexpected controller element %s", szGameButton);
    810         return;
    811     }
    812 
    813     if (*szJoystickButton == '+' || *szJoystickButton == '-') {
    814         half_axis_input = *szJoystickButton++;
    815     }
    816     if (szJoystickButton[SDL_strlen(szJoystickButton) - 1] == '~') {
    817         invert_input = SDL_TRUE;
    818     }
    819 
    820     if (szJoystickButton[0] == 'a' && SDL_isdigit(szJoystickButton[1])) {
    821         bind.inputType = SDL_CONTROLLER_BINDTYPE_AXIS;
    822         bind.input.axis.axis = SDL_atoi(&szJoystickButton[1]);
    823         if (half_axis_input == '+') {
    824             bind.input.axis.axis_min = 0;
    825             bind.input.axis.axis_max = SDL_JOYSTICK_AXIS_MAX;
    826         } else if (half_axis_input == '-') {
    827             bind.input.axis.axis_min = 0;
    828             bind.input.axis.axis_max = SDL_JOYSTICK_AXIS_MIN;
    829         } else {
    830             bind.input.axis.axis_min = SDL_JOYSTICK_AXIS_MIN;
    831             bind.input.axis.axis_max = SDL_JOYSTICK_AXIS_MAX;
    832         }
    833         if (invert_input) {
    834             int tmp = bind.input.axis.axis_min;
    835             bind.input.axis.axis_min = bind.input.axis.axis_max;
    836             bind.input.axis.axis_max = tmp;
    837         }
    838     } else if (szJoystickButton[0] == 'b' && SDL_isdigit(szJoystickButton[1])) {
    839         bind.inputType = SDL_CONTROLLER_BINDTYPE_BUTTON;
    840         bind.input.button = SDL_atoi(&szJoystickButton[1]);
    841     } else if (szJoystickButton[0] == 'h' && SDL_isdigit(szJoystickButton[1]) &&
    842                szJoystickButton[2] == '.' && SDL_isdigit(szJoystickButton[3])) {
    843         int hat = SDL_atoi(&szJoystickButton[1]);
    844         int mask = SDL_atoi(&szJoystickButton[3]);
    845         bind.inputType = SDL_CONTROLLER_BINDTYPE_HAT;
    846         bind.input.hat.hat = hat;
    847         bind.input.hat.hat_mask = mask;
    848     } else {
    849         SDL_SetError("Unexpected joystick element: %s", szJoystickButton);
    850         return;
    851     }
    852 
    853     ++gamecontroller->num_bindings;
    854     gamecontroller->bindings = (SDL_ExtendedGameControllerBind *)SDL_realloc(gamecontroller->bindings, gamecontroller->num_bindings * sizeof(*gamecontroller->bindings));
    855     if (!gamecontroller->bindings) {
    856         gamecontroller->num_bindings = 0;
    857         SDL_OutOfMemory();
    858         return;
    859     }
    860     gamecontroller->bindings[gamecontroller->num_bindings - 1] = bind;
    861 }
    862 
    863 
    864 /*
    865  * given a controller mapping string update our mapping object
    866  */
    867 static void
    868 SDL_PrivateGameControllerParseControllerConfigString(SDL_GameController *gamecontroller, const char *pchString)
    869 {
    870     char szGameButton[20];
    871     char szJoystickButton[20];
    872     SDL_bool bGameButton = SDL_TRUE;
    873     int i = 0;
    874     const char *pchPos = pchString;
    875 
    876     SDL_zeroa(szGameButton);
    877     SDL_zeroa(szJoystickButton);
    878 
    879     while (pchPos && *pchPos) {
    880         if (*pchPos == ':') {
    881             i = 0;
    882             bGameButton = SDL_FALSE;
    883         } else if (*pchPos == ' ') {
    884 
    885         } else if (*pchPos == ',') {
    886             i = 0;
    887             bGameButton = SDL_TRUE;
    888             SDL_PrivateGameControllerParseElement(gamecontroller, szGameButton, szJoystickButton);
    889             SDL_zeroa(szGameButton);
    890             SDL_zeroa(szJoystickButton);
    891 
    892         } else if (bGameButton) {
    893             if (i >= sizeof(szGameButton)) {
    894                 SDL_SetError("Button name too large: %s", szGameButton);
    895                 return;
    896             }
    897             szGameButton[i] = *pchPos;
    898             i++;
    899         } else {
    900             if (i >= sizeof(szJoystickButton)) {
    901                 SDL_SetError("Joystick button name too large: %s", szJoystickButton);
    902                 return;
    903             }
    904             szJoystickButton[i] = *pchPos;
    905             i++;
    906         }
    907         pchPos++;
    908     }
    909 
    910     /* No more values if the string was terminated by a comma. Don't report an error. */
    911     if (szGameButton[0] != '\0' || szJoystickButton[0] != '\0') {
    912         SDL_PrivateGameControllerParseElement(gamecontroller, szGameButton, szJoystickButton);
    913     }
    914 }
    915 
    916 /*
    917  * Make a new button mapping struct
    918  */
    919 static void SDL_PrivateLoadButtonMapping(SDL_GameController *gamecontroller, const char *pchName, const char *pchMapping)
    920 {
    921     int i;
    922 
    923     gamecontroller->name = pchName;
    924     gamecontroller->num_bindings = 0;
    925     if (gamecontroller->joystick->naxes) {
    926         SDL_memset(gamecontroller->last_match_axis, 0, gamecontroller->joystick->naxes * sizeof(*gamecontroller->last_match_axis));
    927     }
    928 
    929     SDL_PrivateGameControllerParseControllerConfigString(gamecontroller, pchMapping);
    930 
    931     /* Set the zero point for triggers */
    932     for (i = 0; i < gamecontroller->num_bindings; ++i) {
    933         SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
    934         if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS &&
    935             binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS &&
    936             (binding->output.axis.axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT ||
    937              binding->output.axis.axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT)) {
    938             if (binding->input.axis.axis < gamecontroller->joystick->naxes) {
    939                 gamecontroller->joystick->axes[binding->input.axis.axis].value =
    940                 gamecontroller->joystick->axes[binding->input.axis.axis].zero = (Sint16)binding->input.axis.axis_min;
    941             }
    942         }
    943     }
    944 }
    945 
    946 
    947 /*
    948  * grab the guid string from a mapping string
    949  */
    950 static char *SDL_PrivateGetControllerGUIDFromMappingString(const char *pMapping)
    951 {
    952     const char *pFirstComma = SDL_strchr(pMapping, ',');
    953     if (pFirstComma) {
    954         char *pchGUID = SDL_malloc(pFirstComma - pMapping + 1);
    955         if (!pchGUID) {
    956             SDL_OutOfMemory();
    957             return NULL;
    958         }
    959         SDL_memcpy(pchGUID, pMapping, pFirstComma - pMapping);
    960         pchGUID[pFirstComma - pMapping] = '\0';
    961 
    962         /* Convert old style GUIDs to the new style in 2.0.5 */
    963 #if __WIN32__
    964         if (SDL_strlen(pchGUID) == 32 &&
    965             SDL_memcmp(&pchGUID[20], "504944564944", 12) == 0) {
    966             SDL_memcpy(&pchGUID[20], "000000000000", 12);
    967             SDL_memcpy(&pchGUID[16], &pchGUID[4], 4);
    968             SDL_memcpy(&pchGUID[8], &pchGUID[0], 4);
    969             SDL_memcpy(&pchGUID[0], "03000000", 8);
    970         }
    971 #elif __MACOSX__
    972         if (SDL_strlen(pchGUID) == 32 &&
    973             SDL_memcmp(&pchGUID[4], "000000000000", 12) == 0 &&
    974             SDL_memcmp(&pchGUID[20], "000000000000", 12) == 0) {
    975             SDL_memcpy(&pchGUID[20], "000000000000", 12);
    976             SDL_memcpy(&pchGUID[8], &pchGUID[0], 4);
    977             SDL_memcpy(&pchGUID[0], "03000000", 8);
    978         }
    979 #endif
    980         return pchGUID;
    981     }
    982     return NULL;
    983 }
    984 
    985 
    986 /*
    987  * grab the name string from a mapping string
    988  */
    989 static char *SDL_PrivateGetControllerNameFromMappingString(const char *pMapping)
    990 {
    991     const char *pFirstComma, *pSecondComma;
    992     char *pchName;
    993 
    994     pFirstComma = SDL_strchr(pMapping, ',');
    995     if (!pFirstComma)
    996         return NULL;
    997 
    998     pSecondComma = SDL_strchr(pFirstComma + 1, ',');
    999     if (!pSecondComma)
   1000         return NULL;
   1001 
   1002     pchName = SDL_malloc(pSecondComma - pFirstComma);
   1003     if (!pchName) {
   1004         SDL_OutOfMemory();
   1005         return NULL;
   1006     }
   1007     SDL_memcpy(pchName, pFirstComma + 1, pSecondComma - pFirstComma);
   1008     pchName[pSecondComma - pFirstComma - 1] = 0;
   1009     return pchName;
   1010 }
   1011 
   1012 
   1013 /*
   1014  * grab the button mapping string from a mapping string
   1015  */
   1016 static char *SDL_PrivateGetControllerMappingFromMappingString(const char *pMapping)
   1017 {
   1018     const char *pFirstComma, *pSecondComma;
   1019 
   1020     pFirstComma = SDL_strchr(pMapping, ',');
   1021     if (!pFirstComma)
   1022         return NULL;
   1023 
   1024     pSecondComma = SDL_strchr(pFirstComma + 1, ',');
   1025     if (!pSecondComma)
   1026         return NULL;
   1027 
   1028     return SDL_strdup(pSecondComma + 1); /* mapping is everything after the 3rd comma */
   1029 }
   1030 
   1031 /*
   1032  * Helper function to refresh a mapping
   1033  */
   1034 static void SDL_PrivateGameControllerRefreshMapping(ControllerMapping_t *pControllerMapping)
   1035 {
   1036     SDL_GameController *gamecontrollerlist = SDL_gamecontrollers;
   1037     while (gamecontrollerlist) {
   1038         if (!SDL_memcmp(&gamecontrollerlist->joystick->guid, &pControllerMapping->guid, sizeof(pControllerMapping->guid))) {
   1039             /* Not really threadsafe.  Should this lock access within SDL_GameControllerEventWatcher? */
   1040             SDL_PrivateLoadButtonMapping(gamecontrollerlist, pControllerMapping->name, pControllerMapping->mapping);
   1041 
   1042             {
   1043                 SDL_Event event;
   1044                 event.type = SDL_CONTROLLERDEVICEREMAPPED;
   1045                 event.cdevice.which = gamecontrollerlist->joystick->instance_id;
   1046                 SDL_PushEvent(&event);
   1047             }
   1048         }
   1049 
   1050         gamecontrollerlist = gamecontrollerlist->next;
   1051     }
   1052 }
   1053 
   1054 /*
   1055  * Helper function to add a mapping for a guid
   1056  */
   1057 static ControllerMapping_t *
   1058 SDL_PrivateAddMappingForGUID(SDL_JoystickGUID jGUID, const char *mappingString, SDL_bool *existing, SDL_ControllerMappingPriority priority)
   1059 {
   1060     char *pchName;
   1061     char *pchMapping;
   1062     ControllerMapping_t *pControllerMapping;
   1063 
   1064     pchName = SDL_PrivateGetControllerNameFromMappingString(mappingString);
   1065     if (!pchName) {
   1066         SDL_SetError("Couldn't parse name from %s", mappingString);
   1067         return NULL;
   1068     }
   1069 
   1070     pchMapping = SDL_PrivateGetControllerMappingFromMappingString(mappingString);
   1071     if (!pchMapping) {
   1072         SDL_free(pchName);
   1073         SDL_SetError("Couldn't parse %s", mappingString);
   1074         return NULL;
   1075     }
   1076 
   1077     pControllerMapping = SDL_PrivateGetControllerMappingForGUID(jGUID, SDL_TRUE);
   1078     if (pControllerMapping) {
   1079         /* Only overwrite the mapping if the priority is the same or higher. */
   1080         if (pControllerMapping->priority <= priority) {
   1081             /* Update existing mapping */
   1082             SDL_free(pControllerMapping->name);
   1083             pControllerMapping->name = pchName;
   1084             SDL_free(pControllerMapping->mapping);
   1085             pControllerMapping->mapping = pchMapping;
   1086             pControllerMapping->priority = priority;
   1087             /* refresh open controllers */
   1088             SDL_PrivateGameControllerRefreshMapping(pControllerMapping);
   1089         } else {
   1090             SDL_free(pchName);
   1091             SDL_free(pchMapping);
   1092         }
   1093         *existing = SDL_TRUE;
   1094     } else {
   1095         pControllerMapping = SDL_malloc(sizeof(*pControllerMapping));
   1096         if (!pControllerMapping) {
   1097             SDL_free(pchName);
   1098             SDL_free(pchMapping);
   1099             SDL_OutOfMemory();
   1100             return NULL;
   1101         }
   1102         pControllerMapping->guid = jGUID;
   1103         pControllerMapping->name = pchName;
   1104         pControllerMapping->mapping = pchMapping;
   1105         pControllerMapping->next = NULL;
   1106         pControllerMapping->priority = priority;
   1107 
   1108         if (s_pSupportedControllers) {
   1109             /* Add the mapping to the end of the list */
   1110             ControllerMapping_t *pCurrMapping, *pPrevMapping;
   1111 
   1112             for ( pPrevMapping = s_pSupportedControllers, pCurrMapping = pPrevMapping->next;
   1113                   pCurrMapping; 
   1114                   pPrevMapping = pCurrMapping, pCurrMapping = pCurrMapping->next ) {
   1115                 /* continue; */
   1116             }
   1117             pPrevMapping->next = pControllerMapping;
   1118         } else {
   1119             s_pSupportedControllers = pControllerMapping;
   1120         }
   1121         *existing = SDL_FALSE;
   1122     }
   1123     return pControllerMapping;
   1124 }
   1125 
   1126 /*
   1127  * Helper function to determine pre-calculated offset to certain joystick mappings
   1128  */
   1129 static ControllerMapping_t *SDL_PrivateGetControllerMappingForNameAndGUID(const char *name, SDL_JoystickGUID guid)
   1130 {
   1131     ControllerMapping_t *mapping;
   1132 
   1133     mapping = SDL_PrivateGetControllerMappingForGUID(guid, SDL_FALSE);
   1134 #ifdef __LINUX__
   1135     if (!mapping && name) {
   1136         if (SDL_strstr(name, "Xbox 360 Wireless Receiver")) {
   1137             /* The Linux driver xpad.c maps the wireless dpad to buttons */
   1138             SDL_bool existing;
   1139             mapping = SDL_PrivateAddMappingForGUID(guid,
   1140 "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",
   1141                           &existing, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT);
   1142         }
   1143     }
   1144 #endif /* __LINUX__ */
   1145 
   1146     if (!mapping && name && !SDL_IsJoystickWGI(guid)) {
   1147         if (SDL_strstr(name, "Xbox") || SDL_strstr(name, "X-Box") || SDL_strstr(name, "XBOX")) {
   1148             mapping = s_pXInputMapping;
   1149         }
   1150     }
   1151     if (!mapping) {
   1152         mapping = s_pDefaultMapping;
   1153     }
   1154     return mapping;
   1155 }
   1156 
   1157 static void SDL_PrivateAppendToMappingString(char *mapping_string,
   1158                                              size_t mapping_string_len,
   1159                                              const char *input_name,
   1160                                              SDL_InputMapping *mapping)
   1161 {
   1162     char buffer[16];
   1163     if (mapping->kind == EMappingKind_None) {
   1164         return;
   1165     }
   1166 
   1167     SDL_strlcat(mapping_string, input_name, mapping_string_len);
   1168     SDL_strlcat(mapping_string, ":", mapping_string_len);
   1169     switch (mapping->kind) {
   1170         case EMappingKind_Button:
   1171             SDL_snprintf(buffer, sizeof(buffer), "b%i", mapping->target);
   1172             break;
   1173         case EMappingKind_Axis:
   1174             SDL_snprintf(buffer, sizeof(buffer), "a%i", mapping->target);
   1175             break;
   1176         case EMappingKind_Hat:
   1177             SDL_snprintf(buffer, sizeof(buffer), "h%i.%i", mapping->target >> 4, mapping->target & 0x0F);
   1178             break;
   1179         default:
   1180             SDL_assert(SDL_FALSE);
   1181     }
   1182 
   1183     SDL_strlcat(mapping_string, buffer, mapping_string_len);
   1184     SDL_strlcat(mapping_string, ",", mapping_string_len);
   1185 }
   1186 
   1187 static ControllerMapping_t *SDL_PrivateGenerateAutomaticControllerMapping(const char *name,
   1188                                                                           SDL_JoystickGUID guid,
   1189                                                                           SDL_GamepadMapping *raw_map)
   1190 {
   1191     SDL_bool existing;
   1192     char name_string[128];
   1193     char mapping[1024];
   1194 
   1195     /* Remove any commas in the name */
   1196     SDL_strlcpy(name_string, name, sizeof(name_string));
   1197     {
   1198         char *spot;
   1199         for (spot = name_string; *spot; ++spot) {
   1200             if (*spot == ',') {
   1201                 *spot = ' ';
   1202             }
   1203         }
   1204     }
   1205     SDL_snprintf(mapping, sizeof(mapping), "none,%s,", name_string);
   1206     SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "a", &raw_map->a);
   1207     SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "b", &raw_map->b);
   1208     SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "x", &raw_map->x);
   1209     SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "y", &raw_map->y);
   1210     SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "back", &raw_map->back);
   1211     SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "guide", &raw_map->guide);
   1212     SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "start", &raw_map->start);
   1213     SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "leftstick", &raw_map->leftstick);
   1214     SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "rightstick", &raw_map->rightstick);
   1215     SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "leftshoulder", &raw_map->leftshoulder);
   1216     SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "rightshoulder", &raw_map->rightshoulder);
   1217     SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "dpup", &raw_map->dpup);
   1218     SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "dpdown", &raw_map->dpdown);
   1219     SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "dpleft", &raw_map->dpleft);
   1220     SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "dpright", &raw_map->dpright);
   1221     SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "leftx", &raw_map->leftx);
   1222     SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "lefty", &raw_map->lefty);
   1223     SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "rightx", &raw_map->rightx);
   1224     SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "righty", &raw_map->righty);
   1225     SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "lefttrigger", &raw_map->lefttrigger);
   1226     SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "righttrigger", &raw_map->righttrigger);
   1227 
   1228     /* Remove trailing comma */
   1229     {
   1230         int pos = (int)SDL_strlen(mapping) - 1;
   1231         if (pos >= 0) {
   1232             if (mapping[pos] == ',') {
   1233                 mapping[pos] = '\0';
   1234             }
   1235         }
   1236     }
   1237 
   1238     return SDL_PrivateAddMappingForGUID(guid, mapping,
   1239                       &existing, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT);
   1240 }
   1241 
   1242 static ControllerMapping_t *SDL_PrivateGetControllerMapping(int device_index)
   1243 {
   1244     const char *name;
   1245     SDL_JoystickGUID guid;
   1246     ControllerMapping_t *mapping;
   1247 
   1248     SDL_LockJoysticks();
   1249 
   1250     if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
   1251         SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
   1252         SDL_UnlockJoysticks();
   1253         return (NULL);
   1254     }
   1255 
   1256     name = SDL_JoystickNameForIndex(device_index);
   1257     guid = SDL_JoystickGetDeviceGUID(device_index);
   1258     mapping = SDL_PrivateGetControllerMappingForNameAndGUID(name, guid);
   1259     if (!mapping) {
   1260         SDL_GamepadMapping raw_map;
   1261 
   1262         SDL_zero(raw_map);
   1263         if (SDL_PrivateJoystickGetAutoGamepadMapping(device_index, &raw_map)) {
   1264             mapping = SDL_PrivateGenerateAutomaticControllerMapping(name, guid, &raw_map);
   1265         }
   1266     }
   1267 
   1268     SDL_UnlockJoysticks();
   1269     return mapping;
   1270 }
   1271 
   1272 /*
   1273  * Add or update an entry into the Mappings Database
   1274  */
   1275 int
   1276 SDL_GameControllerAddMappingsFromRW(SDL_RWops * rw, int freerw)
   1277 {
   1278     const char *platform = SDL_GetPlatform();
   1279     int controllers = 0;
   1280     char *buf, *line, *line_end, *tmp, *comma, line_platform[64];
   1281     size_t db_size, platform_len;
   1282     
   1283     if (rw == NULL) {
   1284         return SDL_SetError("Invalid RWops");
   1285     }
   1286     db_size = (size_t)SDL_RWsize(rw);
   1287     
   1288     buf = (char *)SDL_malloc(db_size + 1);
   1289     if (buf == NULL) {
   1290         if (freerw) {
   1291             SDL_RWclose(rw);
   1292         }
   1293         return SDL_SetError("Could not allocate space to read DB into memory");
   1294     }
   1295     
   1296     if (SDL_RWread(rw, buf, db_size, 1) != 1) {
   1297         if (freerw) {
   1298             SDL_RWclose(rw);
   1299         }
   1300         SDL_free(buf);
   1301         return SDL_SetError("Could not read DB");
   1302     }
   1303     
   1304     if (freerw) {
   1305         SDL_RWclose(rw);
   1306     }
   1307     
   1308     buf[db_size] = '\0';
   1309     line = buf;
   1310     
   1311     while (line < buf + db_size) {
   1312         line_end = SDL_strchr(line, '\n');
   1313         if (line_end != NULL) {
   1314             *line_end = '\0';
   1315         } else {
   1316             line_end = buf + db_size;
   1317         }
   1318         
   1319         /* Extract and verify the platform */
   1320         tmp = SDL_strstr(line, SDL_CONTROLLER_PLATFORM_FIELD);
   1321         if (tmp != NULL) {
   1322             tmp += SDL_strlen(SDL_CONTROLLER_PLATFORM_FIELD);
   1323             comma = SDL_strchr(tmp, ',');
   1324             if (comma != NULL) {
   1325                 platform_len = comma - tmp + 1;
   1326                 if (platform_len + 1 < SDL_arraysize(line_platform)) {
   1327                     SDL_strlcpy(line_platform, tmp, platform_len);
   1328                     if (SDL_strncasecmp(line_platform, platform, platform_len) == 0 &&
   1329                         SDL_GameControllerAddMapping(line) > 0) {
   1330                         controllers++;
   1331                     }
   1332                 }
   1333             }
   1334         }
   1335 
   1336         line = line_end + 1;
   1337     }
   1338 
   1339     SDL_free(buf);
   1340     return controllers;
   1341 }
   1342 
   1343 /*
   1344  * Add or update an entry into the Mappings Database with a priority
   1345  */
   1346 static int
   1347 SDL_PrivateGameControllerAddMapping(const char *mappingString, SDL_ControllerMappingPriority priority)
   1348 {
   1349     char *pchGUID;
   1350     SDL_JoystickGUID jGUID;
   1351     SDL_bool is_default_mapping = SDL_FALSE;
   1352     SDL_bool is_xinput_mapping = SDL_FALSE;
   1353     SDL_bool existing = SDL_FALSE;
   1354     ControllerMapping_t *pControllerMapping;
   1355 
   1356     if (!mappingString) {
   1357         return SDL_InvalidParamError("mappingString");
   1358     }
   1359 
   1360     { /* Extract and verify the hint field */
   1361         const char *tmp;
   1362 
   1363         tmp = SDL_strstr(mappingString, SDL_CONTROLLER_HINT_FIELD);
   1364         if (tmp != NULL) {
   1365             SDL_bool default_value, value, negate;
   1366             int len;
   1367             char hint[128];
   1368 
   1369             tmp += SDL_strlen(SDL_CONTROLLER_HINT_FIELD);
   1370 
   1371             if (*tmp == '!') {
   1372                 negate = SDL_TRUE;
   1373                 ++tmp;
   1374             } else {
   1375                 negate = SDL_FALSE;
   1376             }
   1377 
   1378             len = 0;
   1379             while (*tmp && *tmp != ',' && *tmp != ':' && len < (sizeof(hint) - 1)) {
   1380                 hint[len++] = *tmp++;
   1381             }
   1382             hint[len] = '\0';
   1383 
   1384             if (tmp[0] == ':' && tmp[1] == '=') {
   1385                 tmp += 2;
   1386                 default_value = SDL_atoi(tmp);
   1387             } else {
   1388                 default_value = SDL_FALSE;
   1389             }
   1390 
   1391             value = SDL_GetHintBoolean(hint, default_value);
   1392             if (negate) {
   1393                 value = !value;
   1394             }
   1395             if (!value) {
   1396                 return 0;
   1397             }
   1398         }
   1399     }
   1400 
   1401 #ifdef ANDROID
   1402     { /* Extract and verify the SDK version */
   1403         const char *tmp;
   1404 
   1405         tmp = SDL_strstr(mappingString, SDL_CONTROLLER_SDKGE_FIELD);
   1406         if (tmp != NULL) {
   1407             tmp += SDL_strlen(SDL_CONTROLLER_SDKGE_FIELD);
   1408             if (!(SDL_GetAndroidSDKVersion() >= SDL_atoi(tmp))) {
   1409                 return SDL_SetError("SDK version %d < minimum version %d", SDL_GetAndroidSDKVersion(), SDL_atoi(tmp));
   1410             }
   1411         }
   1412         tmp = SDL_strstr(mappingString, SDL_CONTROLLER_SDKLE_FIELD);
   1413         if (tmp != NULL) {
   1414             tmp += SDL_strlen(SDL_CONTROLLER_SDKLE_FIELD);
   1415             if (!(SDL_GetAndroidSDKVersion() <= SDL_atoi(tmp))) {
   1416                 return SDL_SetError("SDK version %d > maximum version %d", SDL_GetAndroidSDKVersion(), SDL_atoi(tmp));
   1417             }
   1418         }
   1419     }
   1420 #endif
   1421 
   1422     pchGUID = SDL_PrivateGetControllerGUIDFromMappingString(mappingString);
   1423     if (!pchGUID) {
   1424         return SDL_SetError("Couldn't parse GUID from %s", mappingString);
   1425     }
   1426     if (!SDL_strcasecmp(pchGUID, "default")) {
   1427         is_default_mapping = SDL_TRUE;
   1428     } else if (!SDL_strcasecmp(pchGUID, "xinput")) {
   1429         is_xinput_mapping = SDL_TRUE;
   1430     }
   1431     jGUID = SDL_JoystickGetGUIDFromString(pchGUID);
   1432     SDL_free(pchGUID);
   1433 
   1434     pControllerMapping = SDL_PrivateAddMappingForGUID(jGUID, mappingString, &existing, priority);
   1435     if (!pControllerMapping) {
   1436         return -1;
   1437     }
   1438 
   1439     if (existing) {
   1440         return 0;
   1441     } else {
   1442         if (is_default_mapping) {
   1443             s_pDefaultMapping = pControllerMapping;
   1444         } else if (is_xinput_mapping) {
   1445             s_pXInputMapping = pControllerMapping;
   1446         }
   1447         return 1;
   1448     }
   1449 }
   1450 
   1451 /*
   1452  * Add or update an entry into the Mappings Database
   1453  */
   1454 int
   1455 SDL_GameControllerAddMapping(const char *mappingString)
   1456 {
   1457     return SDL_PrivateGameControllerAddMapping(mappingString, SDL_CONTROLLER_MAPPING_PRIORITY_API);
   1458 }
   1459 
   1460 /*
   1461  *  Get the number of mappings installed
   1462  */
   1463 int
   1464 SDL_GameControllerNumMappings(void)
   1465 {
   1466     int num_mappings = 0;
   1467     ControllerMapping_t *mapping;
   1468 
   1469     for (mapping = s_pSupportedControllers; mapping; mapping = mapping->next) {
   1470         if (SDL_memcmp(&mapping->guid, &s_zeroGUID, sizeof(mapping->guid)) == 0) {
   1471             continue;
   1472         }
   1473         ++num_mappings;
   1474     }
   1475     return num_mappings;
   1476 }
   1477 
   1478 /*
   1479  *  Get the mapping at a particular index.
   1480  */
   1481 char *
   1482 SDL_GameControllerMappingForIndex(int mapping_index)
   1483 {
   1484     ControllerMapping_t *mapping;
   1485 
   1486     for (mapping = s_pSupportedControllers; mapping; mapping = mapping->next) {
   1487         if (SDL_memcmp(&mapping->guid, &s_zeroGUID, sizeof(mapping->guid)) == 0) {
   1488             continue;
   1489         }
   1490         if (mapping_index == 0) {
   1491             char *pMappingString;
   1492             char pchGUID[33];
   1493             size_t needed;
   1494 
   1495             SDL_JoystickGetGUIDString(mapping->guid, pchGUID, sizeof(pchGUID));
   1496             /* allocate enough memory for GUID + ',' + name + ',' + mapping + \0 */
   1497             needed = SDL_strlen(pchGUID) + 1 + SDL_strlen(mapping->name) + 1 + SDL_strlen(mapping->mapping) + 1;
   1498             pMappingString = SDL_malloc(needed);
   1499             if (!pMappingString) {
   1500                 SDL_OutOfMemory();
   1501                 return NULL;
   1502             }
   1503             SDL_snprintf(pMappingString, needed, "%s,%s,%s", pchGUID, mapping->name, mapping->mapping);
   1504             return pMappingString;
   1505         }
   1506         --mapping_index;
   1507     }
   1508     return NULL;
   1509 }
   1510 
   1511 /*
   1512  * Get the mapping string for this GUID
   1513  */
   1514 char *
   1515 SDL_GameControllerMappingForGUID(SDL_JoystickGUID guid)
   1516 {
   1517     char *pMappingString = NULL;
   1518     ControllerMapping_t *mapping = SDL_PrivateGetControllerMappingForGUID(guid, SDL_FALSE);
   1519     if (mapping) {
   1520         char pchGUID[33];
   1521         size_t needed;
   1522         SDL_JoystickGetGUIDString(guid, pchGUID, sizeof(pchGUID));
   1523         /* allocate enough memory for GUID + ',' + name + ',' + mapping + \0 */
   1524         needed = SDL_strlen(pchGUID) + 1 + SDL_strlen(mapping->name) + 1 + SDL_strlen(mapping->mapping) + 1;
   1525         pMappingString = SDL_malloc(needed);
   1526         if (!pMappingString) {
   1527             SDL_OutOfMemory();
   1528             return NULL;
   1529         }
   1530         SDL_snprintf(pMappingString, needed, "%s,%s,%s", pchGUID, mapping->name, mapping->mapping);
   1531     }
   1532     return pMappingString;
   1533 }
   1534 
   1535 /*
   1536  * Get the mapping string for this device
   1537  */
   1538 char *
   1539 SDL_GameControllerMapping(SDL_GameController *gamecontroller)
   1540 {
   1541     if (!gamecontroller) {
   1542         return NULL;
   1543     }
   1544 
   1545     return SDL_GameControllerMappingForGUID(gamecontroller->joystick->guid);
   1546 }
   1547 
   1548 static void
   1549 SDL_GameControllerLoadHints()
   1550 {
   1551     const char *hint = SDL_GetHint(SDL_HINT_GAMECONTROLLERCONFIG);
   1552     if (hint && hint[0]) {
   1553         size_t nchHints = SDL_strlen(hint);
   1554         char *pUserMappings = SDL_malloc(nchHints + 1);
   1555         char *pTempMappings = pUserMappings;
   1556         SDL_memcpy(pUserMappings, hint, nchHints);
   1557         pUserMappings[nchHints] = '\0';
   1558         while (pUserMappings) {
   1559             char *pchNewLine = NULL;
   1560 
   1561             pchNewLine = SDL_strchr(pUserMappings, '\n');
   1562             if (pchNewLine)
   1563                 *pchNewLine = '\0';
   1564 
   1565             SDL_PrivateGameControllerAddMapping(pUserMappings, SDL_CONTROLLER_MAPPING_PRIORITY_USER);
   1566 
   1567             if (pchNewLine) {
   1568                 pUserMappings = pchNewLine + 1;
   1569             } else {
   1570                 pUserMappings = NULL;
   1571             }
   1572         }
   1573         SDL_free(pTempMappings);
   1574     }
   1575 }
   1576 
   1577 /*
   1578  * Fill the given buffer with the expected controller mapping filepath. 
   1579  * Usually this will just be SDL_HINT_GAMECONTROLLERCONFIG_FILE, but for
   1580  * Android, we want to get the internal storage path.
   1581  */
   1582 static SDL_bool SDL_GetControllerMappingFilePath(char *path, size_t size)
   1583 {
   1584     const char *hint = SDL_GetHint(SDL_HINT_GAMECONTROLLERCONFIG_FILE);
   1585     if (hint && *hint) {
   1586         return SDL_strlcpy(path, hint, size) < size;
   1587     }
   1588 
   1589 #if defined(__ANDROID__)
   1590     return SDL_snprintf(path, size, "%s/controller_map.txt", SDL_AndroidGetInternalStoragePath()) < size;
   1591 #else
   1592     return SDL_FALSE;
   1593 #endif
   1594 }
   1595 
   1596 /*
   1597  * Initialize the game controller system, mostly load our DB of controller config mappings
   1598  */
   1599 int
   1600 SDL_GameControllerInitMappings(void)
   1601 {
   1602     char szControllerMapPath[1024];
   1603     int i = 0;
   1604     const char *pMappingString = NULL;
   1605     pMappingString = s_ControllerMappings[i];
   1606     while (pMappingString) {
   1607         SDL_PrivateGameControllerAddMapping(pMappingString, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT);
   1608 
   1609         i++;
   1610         pMappingString = s_ControllerMappings[i];
   1611     }
   1612 
   1613     if (SDL_GetControllerMappingFilePath(szControllerMapPath, sizeof(szControllerMapPath))) {
   1614         SDL_GameControllerAddMappingsFromFile(szControllerMapPath);        
   1615     }
   1616 
   1617     /* load in any user supplied config */
   1618     SDL_GameControllerLoadHints();
   1619 
   1620     SDL_AddHintCallback(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES,
   1621                         SDL_GameControllerIgnoreDevicesChanged, NULL);
   1622     SDL_AddHintCallback(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT,
   1623                         SDL_GameControllerIgnoreDevicesExceptChanged, NULL);
   1624 
   1625     return (0);
   1626 }
   1627 
   1628 int
   1629 SDL_GameControllerInit(void)
   1630 {
   1631     int i;
   1632 
   1633     /* watch for joy events and fire controller ones if needed */
   1634     SDL_AddEventWatch(SDL_GameControllerEventWatcher, NULL);
   1635 
   1636     /* Send added events for controllers currently attached */
   1637     for (i = 0; i < SDL_NumJoysticks(); ++i) {
   1638         if (SDL_IsGameController(i)) {
   1639             SDL_Event deviceevent;
   1640             deviceevent.type = SDL_CONTROLLERDEVICEADDED;
   1641             deviceevent.cdevice.which = i;
   1642             SDL_PushEvent(&deviceevent);
   1643         }
   1644     }
   1645 
   1646     return (0);
   1647 }
   1648 
   1649 
   1650 /*
   1651  * Get the implementation dependent name of a controller
   1652  */
   1653 const char *
   1654 SDL_GameControllerNameForIndex(int device_index)
   1655 {
   1656     ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(device_index);
   1657     if (pSupportedController) {
   1658         if (SDL_strcmp(pSupportedController->name, "*") == 0) {
   1659             return SDL_JoystickNameForIndex(device_index);
   1660         } else {
   1661             return pSupportedController->name;
   1662         }
   1663     }
   1664     return NULL;
   1665 }
   1666 
   1667 
   1668 /**
   1669  *  Get the type of a game controller.
   1670  */
   1671 SDL_GameControllerType
   1672 SDL_GameControllerTypeForIndex(int joystick_index)
   1673 {
   1674     return SDL_GetJoystickGameControllerTypeFromGUID(SDL_JoystickGetDeviceGUID(joystick_index), SDL_JoystickNameForIndex(joystick_index));
   1675 }
   1676 
   1677 
   1678 /**
   1679  *  Get the mapping of a game controller.
   1680  *  This can be called before any controllers are opened.
   1681  *  If no mapping can be found, this function returns NULL.
   1682  */
   1683 char *
   1684 SDL_GameControllerMappingForDeviceIndex(int joystick_index)
   1685 {
   1686     char *pMappingString = NULL;
   1687     ControllerMapping_t *mapping;
   1688 
   1689     SDL_LockJoysticks();
   1690     mapping = SDL_PrivateGetControllerMapping(joystick_index);
   1691     if (mapping) {
   1692         SDL_JoystickGUID guid;
   1693         char pchGUID[33];
   1694         size_t needed;
   1695         guid = SDL_JoystickGetDeviceGUID(joystick_index);
   1696         SDL_JoystickGetGUIDString(guid, pchGUID, sizeof(pchGUID));
   1697         /* allocate enough memory for GUID + ',' + name + ',' + mapping + \0 */
   1698         needed = SDL_strlen(pchGUID) + 1 + SDL_strlen(mapping->name) + 1 + SDL_strlen(mapping->mapping) + 1;
   1699         pMappingString = SDL_malloc(needed);
   1700         if (!pMappingString) {
   1701             SDL_OutOfMemory();
   1702             SDL_UnlockJoysticks();
   1703             return NULL;
   1704         }
   1705         SDL_snprintf(pMappingString, needed, "%s,%s,%s", pchGUID, mapping->name, mapping->mapping);
   1706     }
   1707     SDL_UnlockJoysticks();
   1708     return pMappingString;
   1709 }
   1710 
   1711 
   1712 /*
   1713  * Return 1 if the joystick with this name and GUID is a supported controller
   1714  */
   1715 SDL_bool
   1716 SDL_IsGameControllerNameAndGUID(const char *name, SDL_JoystickGUID guid)
   1717 {
   1718     ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMappingForNameAndGUID(name, guid);
   1719     if (pSupportedController) {
   1720         return SDL_TRUE;
   1721     }
   1722     return SDL_FALSE;
   1723 }
   1724 
   1725 /*
   1726  * Return 1 if the joystick at this device index is a supported controller
   1727  */
   1728 SDL_bool
   1729 SDL_IsGameController(int device_index)
   1730 {
   1731     ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(device_index);
   1732     if (pSupportedController) {
   1733         return SDL_TRUE;
   1734     }
   1735     return SDL_FALSE;
   1736 }
   1737 
   1738 /*
   1739  * Return 1 if the game controller should be ignored by SDL
   1740  */
   1741 SDL_bool SDL_ShouldIgnoreGameController(const char *name, SDL_JoystickGUID guid)
   1742 {
   1743     int i;
   1744     Uint16 vendor;
   1745     Uint16 product;
   1746     Uint16 version;
   1747     Uint32 vidpid;
   1748 
   1749 #if defined(__LINUX__)
   1750     if (name && SDL_strstr(name, "Motion Sensors")) {
   1751         /* Don't treat the PS3 and PS4 motion controls as a separate game controller */
   1752         return SDL_TRUE;
   1753     }
   1754 #endif
   1755 
   1756     if (SDL_allowed_controllers.num_entries == 0 &&
   1757         SDL_ignored_controllers.num_entries == 0) {
   1758         return SDL_FALSE;
   1759     }
   1760 
   1761     SDL_GetJoystickGUIDInfo(guid, &vendor, &product, &version);
   1762 
   1763     if (SDL_GetHintBoolean("SDL_GAMECONTROLLER_ALLOW_STEAM_VIRTUAL_GAMEPAD", SDL_FALSE)) {
   1764         /* 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 */
   1765         SDL_bool bSteamVirtualGamepad = SDL_FALSE;
   1766 #if defined(__LINUX__)
   1767         bSteamVirtualGamepad = (vendor == 0x28DE && product == 0x11FF);
   1768 #elif defined(__MACOSX__)
   1769         bSteamVirtualGamepad = (vendor == 0x045E && product == 0x028E && version == 1);
   1770 #elif defined(__WIN32__)
   1771         /* We can't tell on Windows, but Steam will block others in input hooks */
   1772         bSteamVirtualGamepad = SDL_TRUE;
   1773 #endif
   1774         if (bSteamVirtualGamepad) {
   1775             return SDL_FALSE;
   1776         }
   1777     }
   1778 
   1779     vidpid = MAKE_VIDPID(vendor, product);
   1780 
   1781     if (SDL_allowed_controllers.num_entries > 0) {
   1782         for (i = 0; i < SDL_allowed_controllers.num_entries; ++i) {
   1783             if (vidpid == SDL_allowed_controllers.entries[i]) {
   1784                 return SDL_FALSE;
   1785             }
   1786         }
   1787         return SDL_TRUE;
   1788     } else {
   1789         for (i = 0; i < SDL_ignored_controllers.num_entries; ++i) {
   1790             if (vidpid == SDL_ignored_controllers.entries[i]) {
   1791                 return SDL_TRUE;
   1792             }
   1793         }
   1794         return SDL_FALSE;
   1795     }
   1796 }
   1797 
   1798 /*
   1799  * Open a controller for use - the index passed as an argument refers to
   1800  * the N'th controller on the system.  This index is the value which will
   1801  * identify this controller in future controller events.
   1802  *
   1803  * This function returns a controller identifier, or NULL if an error occurred.
   1804  */
   1805 SDL_GameController *
   1806 SDL_GameControllerOpen(int device_index)
   1807 {
   1808     SDL_JoystickID instance_id;
   1809     SDL_GameController *gamecontroller;
   1810     SDL_GameController *gamecontrollerlist;
   1811     ControllerMapping_t *pSupportedController = NULL;
   1812 
   1813     SDL_LockJoysticks();
   1814 
   1815     gamecontrollerlist = SDL_gamecontrollers;
   1816     /* If the controller is already open, return it */
   1817     instance_id = SDL_JoystickGetDeviceInstanceID(device_index);
   1818     while (gamecontrollerlist) {
   1819         if (instance_id == gamecontrollerlist->joystick->instance_id) {
   1820                 gamecontroller = gamecontrollerlist;
   1821                 ++gamecontroller->ref_count;
   1822                 SDL_UnlockJoysticks();
   1823                 return (gamecontroller);
   1824         }
   1825         gamecontrollerlist = gamecontrollerlist->next;
   1826     }
   1827 
   1828     /* Find a controller mapping */
   1829     pSupportedController =  SDL_PrivateGetControllerMapping(device_index);
   1830     if (!pSupportedController) {
   1831         SDL_SetError("Couldn't find mapping for device (%d)", device_index);
   1832         SDL_UnlockJoysticks();
   1833         return NULL;
   1834     }
   1835 
   1836     /* Create and initialize the controller */
   1837     gamecontroller = (SDL_GameController *) SDL_calloc(1, sizeof(*gamecontroller));
   1838     if (gamecontroller == NULL) {
   1839         SDL_OutOfMemory();
   1840         SDL_UnlockJoysticks();
   1841         return NULL;
   1842     }
   1843 
   1844     gamecontroller->joystick = SDL_JoystickOpen(device_index);
   1845     if (!gamecontroller->joystick) {
   1846         SDL_free(gamecontroller);
   1847         SDL_UnlockJoysticks();
   1848         return NULL;
   1849     }
   1850 
   1851     if (gamecontroller->joystick->naxes) {
   1852         gamecontroller->last_match_axis = (SDL_ExtendedGameControllerBind **)SDL_calloc(gamecontroller->joystick->naxes, sizeof(*gamecontroller->last_match_axis));
   1853         if (!gamecontroller->last_match_axis) {
   1854             SDL_OutOfMemory();
   1855             SDL_JoystickClose(gamecontroller->joystick);
   1856             SDL_free(gamecontroller);
   1857             SDL_UnlockJoysticks();
   1858             return NULL;
   1859         }
   1860     }
   1861     if (gamecontroller->joystick->nhats) {
   1862         gamecontroller->last_hat_mask = (Uint8 *)SDL_calloc(gamecontroller->joystick->nhats, sizeof(*gamecontroller->last_hat_mask));
   1863         if (!gamecontroller->last_hat_mask) {
   1864             SDL_OutOfMemory();
   1865             SDL_JoystickClose(gamecontroller->joystick);
   1866             SDL_free(gamecontroller->last_match_axis);
   1867             SDL_free(gamecontroller);
   1868             SDL_UnlockJoysticks();
   1869             return NULL;
   1870         }
   1871     }
   1872 
   1873     SDL_PrivateLoadButtonMapping(gamecontroller, pSupportedController->name, pSupportedController->mapping);
   1874 
   1875     /* Add the controller to list */
   1876     ++gamecontroller->ref_count;
   1877     /* Link the controller in the list */
   1878     gamecontroller->next = SDL_gamecontrollers;
   1879     SDL_gamecontrollers = gamecontroller;
   1880 
   1881     SDL_UnlockJoysticks();
   1882 
   1883     return (gamecontroller);
   1884 }
   1885 
   1886 /*
   1887  * Manually pump for controller updates.
   1888  */
   1889 void
   1890 SDL_GameControllerUpdate(void)
   1891 {
   1892     /* Just for API completeness; the joystick API does all the work. */
   1893     SDL_JoystickUpdate();
   1894 }
   1895 
   1896 /**
   1897  *  Return whether a game controller has a given axis
   1898  */
   1899 SDL_bool
   1900 SDL_GameControllerHasAxis(SDL_GameController *gamecontroller, SDL_GameControllerAxis axis)
   1901 {
   1902     SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForAxis(gamecontroller, axis);
   1903     return (bind.bindType != SDL_CONTROLLER_BINDTYPE_NONE) ? SDL_TRUE : SDL_FALSE;
   1904 }
   1905 
   1906 /*
   1907  * Get the current state of an axis control on a controller
   1908  */
   1909 Sint16
   1910 SDL_GameControllerGetAxis(SDL_GameController *gamecontroller, SDL_GameControllerAxis axis)
   1911 {
   1912     int i;
   1913 
   1914     if (!gamecontroller)
   1915         return 0;
   1916 
   1917     for (i = 0; i < gamecontroller->num_bindings; ++i) {
   1918         SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
   1919         if (binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS && binding->output.axis.axis == axis) {
   1920             int value = 0;
   1921             SDL_bool valid_input_range;
   1922             SDL_bool valid_output_range;
   1923 
   1924             if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
   1925                 value = SDL_JoystickGetAxis(gamecontroller->joystick, binding->input.axis.axis);
   1926                 if (binding->input.axis.axis_min < binding->input.axis.axis_max) {
   1927                     valid_input_range = (value >= binding->input.axis.axis_min && value <= binding->input.axis.axis_max);
   1928                 } else {
   1929                     valid_input_range = (value >= binding->input.axis.axis_max && value <= binding->input.axis.axis_min);
   1930                 }
   1931                 if (valid_input_range) {
   1932                     if (binding->input.axis.axis_min != binding->output.axis.axis_min || binding->input.axis.axis_max != binding->output.axis.axis_max) {
   1933                         float normalized_value = (float)(value - binding->input.axis.axis_min) / (binding->input.axis.axis_max - binding->input.axis.axis_min);
   1934                         value = binding->output.axis.axis_min + (int)(normalized_value * (binding->output.axis.axis_max - binding->output.axis.axis_min));
   1935                     }
   1936                 } else {
   1937                     value = 0;
   1938                 }
   1939             } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
   1940                 value = SDL_JoystickGetButton(gamecontroller->joystick, binding->input.button);
   1941                 if (value == SDL_PRESSED) {
   1942                     value = binding->output.axis.axis_max;
   1943                 }
   1944             } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
   1945                 int hat_mask = SDL_JoystickGetHat(gamecontroller->joystick, binding->input.hat.hat);
   1946                 if (hat_mask & binding->input.hat.hat_mask) {
   1947                     value = binding->output.axis.axis_max;
   1948                 }
   1949             }
   1950 
   1951             if (binding->output.axis.axis_min < binding->output.axis.axis_max) {
   1952                 valid_output_range = (value >= binding->output.axis.axis_min && value <= binding->output.axis.axis_max);
   1953             } else {
   1954                 valid_output_range = (value >= binding->output.axis.axis_max && value <= binding->output.axis.axis_min);
   1955             }
   1956             /* If the value is zero, there might be another binding that makes it non-zero */
   1957             if (value != 0 && valid_output_range) {
   1958                 return (Sint16)value;
   1959             }
   1960         }
   1961     }
   1962     return 0;
   1963 }
   1964 
   1965 /**
   1966  *  Return whether a game controller has a given button
   1967  */
   1968 SDL_bool
   1969 SDL_GameControllerHasButton(SDL_GameController *gamecontroller, SDL_GameControllerButton button)
   1970 {
   1971     SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForButton(gamecontroller, button);
   1972     return (bind.bindType != SDL_CONTROLLER_BINDTYPE_NONE) ? SDL_TRUE : SDL_FALSE;
   1973 }
   1974 
   1975 /*
   1976  * Get the current state of a button on a controller
   1977  */
   1978 Uint8
   1979 SDL_GameControllerGetButton(SDL_GameController *gamecontroller, SDL_GameControllerButton button)
   1980 {
   1981     int i;
   1982 
   1983     if (!gamecontroller)
   1984         return 0;
   1985 
   1986     for (i = 0; i < gamecontroller->num_bindings; ++i) {
   1987         SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
   1988         if (binding->outputType == SDL_CONTROLLER_BINDTYPE_BUTTON && binding->output.button == button) {
   1989             if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
   1990                 SDL_bool valid_input_range;
   1991 
   1992                 int value = SDL_JoystickGetAxis(gamecontroller->joystick, binding->input.axis.axis);
   1993                 int threshold = binding->input.axis.axis_min + (binding->input.axis.axis_max - binding->input.axis.axis_min) / 2;
   1994                 if (binding->input.axis.axis_min < binding->input.axis.axis_max) {
   1995                     valid_input_range = (value >= binding->input.axis.axis_min && value <= binding->input.axis.axis_max);
   1996                     if (valid_input_range) {
   1997                         return (value >= threshold) ? SDL_PRESSED : SDL_RELEASED;
   1998                     }
   1999                 } else {
   2000                     valid_input_range = (value >= binding->input.axis.axis_max && value <= binding->input.axis.axis_min);
   2001                     if (valid_input_range) {
   2002                         return (value <= threshold) ? SDL_PRESSED : SDL_RELEASED;
   2003                     }
   2004                 }
   2005             } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
   2006                 return SDL_JoystickGetButton(gamecontroller->joystick, binding->input.button);
   2007             } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
   2008                 int hat_mask = SDL_JoystickGetHat(gamecontroller->joystick, binding->input.hat.hat);
   2009                 return (hat_mask & binding->input.hat.hat_mask) ? SDL_PRESSED : SDL_RELEASED;
   2010             }
   2011         }
   2012     }
   2013     return SDL_RELEASED;
   2014 }
   2015 
   2016 /**
   2017  *  Get the number of touchpads on a game controller.
   2018  */
   2019 int
   2020 SDL_GameControllerGetNumTouchpads(SDL_GameController *gamecontroller)
   2021 {
   2022     SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
   2023 
   2024     if (joystick) {
   2025         return joystick->ntouchpads;
   2026     }
   2027     return 0;
   2028 }
   2029 
   2030 /**
   2031  *  Get the number of supported simultaneous fingers on a touchpad on a game controller.
   2032  */
   2033 int SDL_GameControllerGetNumTouchpadFingers(SDL_GameController *gamecontroller, int touchpad)
   2034 {
   2035     SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
   2036 
   2037     if (joystick && touchpad >= 0 && touchpad < joystick->ntouchpads) {
   2038         return joystick->touchpads[touchpad].nfingers;
   2039     }
   2040     return 0;
   2041 }
   2042 
   2043 /**
   2044  *  Get the current state of a finger on a touchpad on a game controller.
   2045  */
   2046 int
   2047 SDL_GameControllerGetTouchpadFinger(SDL_GameController *gamecontroller, int touchpad, int finger, Uint8 *state, float *x, float *y, float *pressure)
   2048 {
   2049     SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
   2050 
   2051     if (joystick ) {
   2052         if (touchpad >= 0 && touchpad < joystick->ntouchpads) {
   2053             SDL_JoystickTouchpadInfo *touchpad_info = &joystick->touchpads[touchpad];
   2054             if (finger >= 0 && finger < touchpad_info->nfingers) {
   2055                 SDL_JoystickTouchpadFingerInfo *info = &touchpad_info->fingers[finger];
   2056 
   2057                 if (state) {
   2058                     *state = info->state;
   2059                 }
   2060                 if (x) {
   2061                     *x = info->x;
   2062                 }
   2063                 if (y) {
   2064                     *y = info->y;
   2065                 }
   2066                 if (pressure) {
   2067                     *pressure = info->pressure;
   2068                 }
   2069                 return 0;
   2070             } else {
   2071                 return SDL_InvalidParamError("finger");
   2072             }
   2073         } else {
   2074             return SDL_InvalidParamError("touchpad");
   2075         }
   2076     } else {
   2077         return SDL_InvalidParamError("gamecontroller");
   2078     }
   2079 }
   2080 
   2081 /**
   2082  *  Return whether a game controller has a particular sensor.
   2083  */
   2084 SDL_bool
   2085 SDL_GameControllerHasSensor(SDL_GameController *gamecontroller, SDL_SensorType type)
   2086 {
   2087     SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
   2088     int i;
   2089 
   2090     if (joystick) {
   2091         for (i = 0; i < joystick->nsensors; ++i) {
   2092             if (joystick->sensors[i].type == type) {
   2093                 return SDL_TRUE;
   2094             }
   2095         }
   2096     }
   2097     return SDL_FALSE;
   2098 }
   2099 
   2100 /*
   2101  *  Set whether data reporting for a game controller sensor is enabled
   2102  */
   2103 int SDL_GameControllerSetSensorEnabled(SDL_GameController *gamecontroller, SDL_SensorType type, SDL_bool enabled)
   2104 {
   2105     SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
   2106     int i;
   2107 
   2108     if (!joystick) {
   2109         return SDL_InvalidParamError("gamecontroller");
   2110     }
   2111 
   2112     for (i = 0; i < joystick->nsensors; ++i) {
   2113         SDL_JoystickSensorInfo *sensor = &joystick->sensors[i];
   2114 
   2115         if (sensor->type == type) {
   2116             if (sensor->enabled == enabled) {
   2117                 return 0;
   2118             }
   2119 
   2120             if (enabled) {
   2121                 if (joystick->nsensors_enabled == 0) {
   2122                     if (joystick->driver->SetSensorsEnabled(joystick, SDL_TRUE) < 0) {
   2123                         return -1;
   2124                     }
   2125                 }
   2126                 ++joystick->nsensors_enabled;
   2127             } else {
   2128                 if (joystick->nsensors_enabled == 1) {
   2129                     if (joystick->driver->SetSensorsEnabled(joystick, SDL_FALSE) < 0) {
   2130                         return -1;
   2131                     }
   2132                 }
   2133                 --joystick->nsensors_enabled;
   2134             }
   2135 
   2136             sensor->enabled = enabled;
   2137             return 0;
   2138         }
   2139     }
   2140     return SDL_Unsupported();
   2141 }
   2142 
   2143 /*
   2144  *  Query whether sensor data reporting is enabled for a game controller
   2145  */
   2146 SDL_bool SDL_GameControllerIsSensorEnabled(SDL_GameController *gamecontroller, SDL_SensorType type)
   2147 {
   2148     SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
   2149     int i;
   2150 
   2151     if (joystick) {
   2152         for (i = 0; i < joystick->nsensors; ++i) {
   2153             if (joystick->sensors[i].type == type) {
   2154                 return joystick->sensors[i].enabled;
   2155             }
   2156         }
   2157     }
   2158     return SDL_FALSE;
   2159 }
   2160 
   2161 /*
   2162  *  Get the current state of a game controller sensor.
   2163  */
   2164 int
   2165 SDL_GameControllerGetSensorData(SDL_GameController *gamecontroller, SDL_SensorType type, float *data, int num_values)
   2166 {
   2167     SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
   2168     int i;
   2169 
   2170     if (!joystick) {
   2171         return SDL_InvalidParamError("gamecontroller");
   2172     }
   2173 
   2174     for (i = 0; i < joystick->nsensors; ++i) {
   2175         SDL_JoystickSensorInfo *sensor = &joystick->sensors[i];
   2176 
   2177         if (sensor->type == type) {
   2178             num_values = SDL_min(num_values, SDL_arraysize(sensor->data));
   2179             SDL_memcpy(data, sensor->data, num_values*sizeof(*data));
   2180             return 0;
   2181         }
   2182     }
   2183     return SDL_Unsupported();
   2184 }
   2185 
   2186 const char *
   2187 SDL_GameControllerName(SDL_GameController *gamecontroller)
   2188 {
   2189     if (!gamecontroller)
   2190         return NULL;
   2191 
   2192     if (SDL_strcmp(gamecontroller->name, "*") == 0) {
   2193         return SDL_JoystickName(SDL_GameControllerGetJoystick(gamecontroller));
   2194     } else {
   2195         return gamecontroller->name;
   2196     }
   2197 }
   2198 
   2199 SDL_GameControllerType
   2200 SDL_GameControllerGetType(SDL_GameController *gamecontroller)
   2201 {
   2202     return SDL_GetJoystickGameControllerTypeFromGUID(SDL_JoystickGetGUID(SDL_GameControllerGetJoystick(gamecontroller)), SDL_JoystickName(SDL_GameControllerGetJoystick(gamecontroller)));
   2203 }
   2204 
   2205 int
   2206 SDL_GameControllerGetPlayerIndex(SDL_GameController *gamecontroller)
   2207 {
   2208     return SDL_JoystickGetPlayerIndex(SDL_GameControllerGetJoystick(gamecontroller));
   2209 }
   2210 
   2211 /**
   2212  *  Set the player index of an opened game controller
   2213  */
   2214 void
   2215 SDL_GameControllerSetPlayerIndex(SDL_GameController *gamecontroller, int player_index)
   2216 {
   2217     SDL_JoystickSetPlayerIndex(SDL_GameControllerGetJoystick(gamecontroller), player_index);
   2218 }
   2219 
   2220 Uint16
   2221 SDL_GameControllerGetVendor(SDL_GameController *gamecontroller)
   2222 {
   2223     return SDL_JoystickGetVendor(SDL_GameControllerGetJoystick(gamecontroller));
   2224 }
   2225 
   2226 Uint16
   2227 SDL_GameControllerGetProduct(SDL_GameController *gamecontroller)
   2228 {
   2229     return SDL_JoystickGetProduct(SDL_GameControllerGetJoystick(gamecontroller));
   2230 }
   2231 
   2232 Uint16
   2233 SDL_GameControllerGetProductVersion(SDL_GameController *gamecontroller)
   2234 {
   2235     return SDL_JoystickGetProductVersion(SDL_GameControllerGetJoystick(gamecontroller));
   2236 }
   2237 
   2238 const char *
   2239 SDL_GameControllerGetSerial(SDL_GameController *gamecontroller)
   2240 {
   2241     return SDL_JoystickGetSerial(SDL_GameControllerGetJoystick(gamecontroller));
   2242 }
   2243 
   2244 /*
   2245  * Return if the controller in question is currently attached to the system,
   2246  *  \return 0 if not plugged in, 1 if still present.
   2247  */
   2248 SDL_bool
   2249 SDL_GameControllerGetAttached(SDL_GameController *gamecontroller)
   2250 {
   2251     if (!gamecontroller)
   2252         return SDL_FALSE;
   2253 
   2254     return SDL_JoystickGetAttached(gamecontroller->joystick);
   2255 }
   2256 
   2257 /*
   2258  * Get the joystick for this controller
   2259  */
   2260 SDL_Joystick *
   2261 SDL_GameControllerGetJoystick(SDL_GameController *gamecontroller)
   2262 {
   2263     if (!gamecontroller)
   2264         return NULL;
   2265 
   2266     return gamecontroller->joystick;
   2267 }
   2268 
   2269 
   2270 /*
   2271  * Return the SDL_GameController associated with an instance id.
   2272  */
   2273 SDL_GameController *
   2274 SDL_GameControllerFromInstanceID(SDL_JoystickID joyid)
   2275 {
   2276     SDL_GameController *gamecontroller;
   2277 
   2278     SDL_LockJoysticks();
   2279     gamecontroller = SDL_gamecontrollers;
   2280     while (gamecontroller) {
   2281         if (gamecontroller->joystick->instance_id == joyid) {
   2282             SDL_UnlockJoysticks();
   2283             return gamecontroller;
   2284         }
   2285         gamecontroller = gamecontroller->next;
   2286     }
   2287     SDL_UnlockJoysticks();
   2288     return NULL;
   2289 }
   2290 
   2291 
   2292 /**
   2293  * Return the SDL_GameController associated with a player index.
   2294  */
   2295 SDL_GameController *SDL_GameControllerFromPlayerIndex(int player_index)
   2296 {
   2297     SDL_Joystick *joystick = SDL_JoystickFromPlayerIndex(player_index);
   2298     if (joystick) {
   2299         return SDL_GameControllerFromInstanceID(joystick->instance_id);
   2300     }
   2301     return NULL;
   2302 }
   2303 
   2304 
   2305 /*
   2306  * Get the SDL joystick layer binding for this controller axis mapping
   2307  */
   2308 SDL_GameControllerButtonBind SDL_GameControllerGetBindForAxis(SDL_GameController *gamecontroller, SDL_GameControllerAxis axis)
   2309 {
   2310     int i;
   2311     SDL_GameControllerButtonBind bind;
   2312     SDL_zero(bind);
   2313 
   2314     if (!gamecontroller || axis == SDL_CONTROLLER_AXIS_INVALID)
   2315         return bind;
   2316 
   2317     for (i = 0; i < gamecontroller->num_bindings; ++i) {
   2318         SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
   2319         if (binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS && binding->output.axis.axis == axis) {
   2320             bind.bindType = binding->inputType;
   2321             if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
   2322                 /* FIXME: There might be multiple axes bound now that we have axis ranges... */
   2323                 bind.value.axis = binding->input.axis.axis;
   2324             } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
   2325                 bind.value.button = binding->input.button;
   2326             } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
   2327                 bind.value.hat.hat = binding->input.hat.hat;
   2328                 bind.value.hat.hat_mask = binding->input.hat.hat_mask;
   2329             }
   2330             break;
   2331         }
   2332     }
   2333     return bind;
   2334 }
   2335 
   2336 
   2337 /*
   2338  * Get the SDL joystick layer binding for this controller button mapping
   2339  */
   2340 SDL_GameControllerButtonBind SDL_GameControllerGetBindForButton(SDL_GameController *gamecontroller, SDL_GameControllerButton button)
   2341 {
   2342     int i;
   2343     SDL_GameControllerButtonBind bind;
   2344     SDL_zero(bind);
   2345 
   2346     if (!gamecontroller || button == SDL_CONTROLLER_BUTTON_INVALID)
   2347         return bind;
   2348 
   2349     for (i = 0; i < gamecontroller->num_bindings; ++i) {
   2350         SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
   2351         if (binding->outputType == SDL_CONTROLLER_BINDTYPE_BUTTON && binding->output.button == button) {
   2352             bind.bindType = binding->inputType;
   2353             if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
   2354                 bind.value.axis = binding->input.axis.axis;
   2355             } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
   2356                 bind.value.button = binding->input.button;
   2357             } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
   2358                 bind.value.hat.hat = binding->input.hat.hat;
   2359                 bind.value.hat.hat_mask = binding->input.hat.hat_mask;
   2360             }
   2361             break;
   2362         }
   2363     }
   2364     return bind;
   2365 }
   2366 
   2367 
   2368 int
   2369 SDL_GameControllerRumble(SDL_GameController *gamecontroller, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
   2370 {
   2371     return SDL_JoystickRumble(SDL_GameControllerGetJoystick(gamecontroller), low_frequency_rumble, high_frequency_rumble, duration_ms);
   2372 }
   2373 
   2374 int
   2375 SDL_GameControllerRumbleTriggers(SDL_GameController *gamecontroller, Uint16 left_rumble, Uint16 right_rumble, Uint32 duration_ms)
   2376 {
   2377     return SDL_JoystickRumbleTriggers(SDL_GameControllerGetJoystick(gamecontroller), left_rumble, right_rumble, duration_ms);
   2378 }
   2379 
   2380 SDL_bool
   2381 SDL_GameControllerHasLED(SDL_GameController *gamecontroller)
   2382 {
   2383     return SDL_JoystickHasLED(SDL_GameControllerGetJoystick(gamecontroller));
   2384 }
   2385 
   2386 int
   2387 SDL_GameControllerSetLED(SDL_GameController *gamecontroller, Uint8 red, Uint8 green, Uint8 blue)
   2388 {
   2389     return SDL_JoystickSetLED(SDL_GameControllerGetJoystick(gamecontroller), red, green, blue);
   2390 }
   2391 
   2392 void
   2393 SDL_GameControllerClose(SDL_GameController *gamecontroller)
   2394 {
   2395     SDL_GameController *gamecontrollerlist, *gamecontrollerlistprev;
   2396 
   2397     if (!gamecontroller)
   2398         return;
   2399 
   2400     SDL_LockJoysticks();
   2401 
   2402     /* First decrement ref count */
   2403     if (--gamecontroller->ref_count > 0) {
   2404         SDL_UnlockJoysticks();
   2405         return;
   2406     }
   2407 
   2408     SDL_JoystickClose(gamecontroller->joystick);
   2409 
   2410     gamecontrollerlist = SDL_gamecontrollers;
   2411     gamecontrollerlistprev = NULL;
   2412     while (gamecontrollerlist) {
   2413         if (gamecontroller == gamecontrollerlist) {
   2414             if (gamecontrollerlistprev) {
   2415                 /* unlink this entry */
   2416                 gamecontrollerlistprev->next = gamecontrollerlist->next;
   2417             } else {
   2418                 SDL_gamecontrollers = gamecontroller->next;
   2419             }
   2420             break;
   2421         }
   2422         gamecontrollerlistprev = gamecontrollerlist;
   2423         gamecontrollerlist = gamecontrollerlist->next;
   2424     }
   2425 
   2426     SDL_free(gamecontroller->bindings);
   2427     SDL_free(gamecontroller->last_match_axis);
   2428     SDL_free(gamecontroller->last_hat_mask);
   2429     SDL_free(gamecontroller);
   2430 
   2431     SDL_UnlockJoysticks();
   2432 }
   2433 
   2434 
   2435 /*
   2436  * Quit the controller subsystem
   2437  */
   2438 void
   2439 SDL_GameControllerQuit(void)
   2440 {
   2441     SDL_LockJoysticks();
   2442     while (SDL_gamecontrollers) {
   2443         SDL_gamecontrollers->ref_count = 1;
   2444         SDL_GameControllerClose(SDL_gamecontrollers);
   2445     }
   2446     SDL_UnlockJoysticks();
   2447 }
   2448 
   2449 void
   2450 SDL_GameControllerQuitMappings(void)
   2451 {
   2452     ControllerMapping_t *pControllerMap;
   2453 
   2454     while (s_pSupportedControllers) {
   2455         pControllerMap = s_pSupportedControllers;
   2456         s_pSupportedControllers = s_pSupportedControllers->next;
   2457         SDL_free(pControllerMap->name);
   2458         SDL_free(pControllerMap->mapping);
   2459         SDL_free(pControllerMap);
   2460     }
   2461 
   2462     SDL_DelEventWatch(SDL_GameControllerEventWatcher, NULL);
   2463 
   2464     SDL_DelHintCallback(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES,
   2465                         SDL_GameControllerIgnoreDevicesChanged, NULL);
   2466     SDL_DelHintCallback(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT,
   2467                         SDL_GameControllerIgnoreDevicesExceptChanged, NULL);
   2468 
   2469     if (SDL_allowed_controllers.entries) {
   2470         SDL_free(SDL_allowed_controllers.entries);
   2471         SDL_zero(SDL_allowed_controllers);
   2472     }
   2473     if (SDL_ignored_controllers.entries) {
   2474         SDL_free(SDL_ignored_controllers.entries);
   2475         SDL_zero(SDL_ignored_controllers);
   2476     }
   2477 }
   2478 
   2479 /*
   2480  * Event filter to transform joystick events into appropriate game controller ones
   2481  */
   2482 static int
   2483 SDL_PrivateGameControllerAxis(SDL_GameController *gamecontroller, SDL_GameControllerAxis axis, Sint16 value)
   2484 {
   2485     int posted;
   2486 
   2487     /* translate the event, if desired */
   2488     posted = 0;
   2489 #if !SDL_EVENTS_DISABLED
   2490     if (SDL_GetEventState(SDL_CONTROLLERAXISMOTION) == SDL_ENABLE) {
   2491         SDL_Event event;
   2492         event.type = SDL_CONTROLLERAXISMOTION;
   2493         event.caxis.which = gamecontroller->joystick->instance_id;
   2494         event.caxis.axis = axis;
   2495         event.caxis.value = value;
   2496         posted = SDL_PushEvent(&event) == 1;
   2497     }
   2498 #endif /* !SDL_EVENTS_DISABLED */
   2499     return (posted);
   2500 }
   2501 
   2502 
   2503 /*
   2504  * Event filter to transform joystick events into appropriate game controller ones
   2505  */
   2506 static int
   2507 SDL_PrivateGameControllerButton(SDL_GameController *gamecontroller, SDL_GameControllerButton button, Uint8 state)
   2508 {
   2509     int posted;
   2510 #if !SDL_EVENTS_DISABLED
   2511     SDL_Event event;
   2512 
   2513     if (button == SDL_CONTROLLER_BUTTON_INVALID)
   2514         return (0);
   2515 
   2516     switch (state) {
   2517     case SDL_PRESSED:
   2518         event.type = SDL_CONTROLLERBUTTONDOWN;
   2519         break;
   2520     case SDL_RELEASED:
   2521         event.type = SDL_CONTROLLERBUTTONUP;
   2522         break;
   2523     default:
   2524         /* Invalid state -- bail */
   2525         return (0);
   2526     }
   2527 #endif /* !SDL_EVENTS_DISABLED */
   2528 
   2529     if (button == SDL_CONTROLLER_BUTTON_GUIDE) {
   2530         Uint32 now = SDL_GetTicks();
   2531         if (state == SDL_PRESSED) {
   2532             gamecontroller->guide_button_down = now;
   2533 
   2534             if (gamecontroller->joystick->delayed_guide_button) {
   2535                 /* Skip duplicate press */
   2536                 return (0);
   2537             }
   2538         } else {
   2539             if (!SDL_TICKS_PASSED(now, gamecontroller->guide_button_down+SDL_MINIMUM_GUIDE_BUTTON_DELAY_MS)) {
   2540                 gamecontroller->joystick->delayed_guide_button = SDL_TRUE;
   2541                 return (0);
   2542             }
   2543             gamecontroller->joystick->delayed_guide_button = SDL_FALSE;
   2544         }
   2545     }
   2546 
   2547     /* translate the event, if desired */
   2548     posted = 0;
   2549 #if !SDL_EVENTS_DISABLED
   2550     if (SDL_GetEventState(event.type) == SDL_ENABLE) {
   2551         event.cbutton.which = gamecontroller->joystick->instance_id;
   2552         event.cbutton.button = button;
   2553         event.cbutton.state = state;
   2554         posted = SDL_PushEvent(&event) == 1;
   2555     }
   2556 #endif /* !SDL_EVENTS_DISABLED */
   2557     return (posted);
   2558 }
   2559 
   2560 /*
   2561  * Turn off controller events
   2562  */
   2563 int
   2564 SDL_GameControllerEventState(int state)
   2565 {
   2566 #if SDL_EVENTS_DISABLED
   2567     return SDL_IGNORE;
   2568 #else
   2569     const Uint32 event_list[] = {
   2570         SDL_CONTROLLERAXISMOTION, SDL_CONTROLLERBUTTONDOWN, SDL_CONTROLLERBUTTONUP,
   2571         SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEREMOVED, SDL_CONTROLLERDEVICEREMAPPED,
   2572     };
   2573     unsigned int i;
   2574 
   2575     switch (state) {
   2576     case SDL_QUERY:
   2577         state = SDL_IGNORE;
   2578         for (i = 0; i < SDL_arraysize(event_list); ++i) {
   2579             state = SDL_EventState(event_list[i], SDL_QUERY);
   2580             if (state == SDL_ENABLE) {
   2581                 break;
   2582             }
   2583         }
   2584         break;
   2585     default:
   2586         for (i = 0; i < SDL_arraysize(event_list); ++i) {
   2587             SDL_EventState(event_list[i], state);
   2588         }
   2589         break;
   2590     }
   2591     return (state);
   2592 #endif /* SDL_EVENTS_DISABLED */
   2593 }
   2594 
   2595 void
   2596 SDL_GameControllerHandleDelayedGuideButton(SDL_Joystick *joystick)
   2597 {
   2598     SDL_GameController *controllerlist = SDL_gamecontrollers;
   2599     while (controllerlist) {
   2600         if (controllerlist->joystick == joystick) {
   2601             SDL_PrivateGameControllerButton(controllerlist, SDL_CONTROLLER_BUTTON_GUIDE, SDL_RELEASED);
   2602             break;
   2603         }
   2604         controllerlist = controllerlist->next;
   2605     }
   2606 }
   2607 
   2608 /* vi: set ts=4 sw=4 expandtab: */