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