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