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