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