SDL 2.0
SDL_gamecontroller.c
Go to the documentation of this file.
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21#include "../SDL_internal.h"
22
23/* This is the game controller API for Simple DirectMedia Layer */
24
25#include "SDL_events.h"
26#include "SDL_assert.h"
27#include "SDL_hints.h"
28#include "SDL_timer.h"
29#include "SDL_sysjoystick.h"
30#include "SDL_joystick_c.h"
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
47/* a list of currently opened game controllers */
48static SDL_GameController *SDL_gamecontrollers = NULL;
49
50typedef struct
51{
53 union
54 {
55 int button;
56
57 struct {
58 int axis;
62
63 struct {
64 int hat;
66 } hat;
67
69
71 union
72 {
74
75 struct {
77 int axis_min;
78 int axis_max;
80
82
84
85/* our hard coded list of mapping support */
86typedef enum
87{
92
93typedef struct _ControllerMapping_t
94{
96 char *name;
97 char *mapping;
99 struct _ControllerMapping_t *next;
101
107
108/* The SDL game controller structure */
110{
111 SDL_Joystick *joystick; /* underlying joystick device */
113
114 const char *name;
120
121 struct _SDL_GameController *next; /* pointer to next game controller we have allocated */
122};
123
124
125typedef struct
126{
131
134
135static void
137{
138 Uint32 entry;
139 char *spot;
140 char *file = NULL;
141
142 list->num_entries = 0;
143
144 if (hint && *hint == '@') {
145 spot = file = (char *)SDL_LoadFile(hint+1, NULL);
146 } else {
147 spot = (char *)hint;
148 }
149
150 if (!spot) {
151 return;
152 }
153
154 while ((spot = SDL_strstr(spot, "0x")) != NULL) {
155 entry = (Uint16)SDL_strtol(spot, &spot, 0);
156 entry <<= 16;
157 spot = SDL_strstr(spot, "0x");
158 if (!spot) {
159 break;
160 }
161 entry |= (Uint16)SDL_strtol(spot, &spot, 0);
162
163 if (list->num_entries == list->max_entries) {
164 int max_entries = list->max_entries + 16;
165 Uint32 *entries = (Uint32 *)SDL_realloc(list->entries, max_entries*sizeof(*list->entries));
166 if (entries == NULL) {
167 /* Out of memory, go with what we have already */
168 break;
169 }
170 list->entries = entries;
171 list->max_entries = max_entries;
172 }
173 list->entries[list->num_entries++] = entry;
174 }
175
176 if (file) {
177 SDL_free(file);
178 }
179}
180
181static void SDLCALL
182SDL_GameControllerIgnoreDevicesChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
183{
185}
186
187static void SDLCALL
188SDL_GameControllerIgnoreDevicesExceptChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
189{
191}
192
193static int SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis, Sint16 value);
194static int SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button, Uint8 state);
195
196/*
197 * If there is an existing add event in the queue, it needs to be modified
198 * to have the right value for which, because the number of controllers in
199 * the system is now one less.
200 */
202{
203 int i, num_events;
205 SDL_bool isstack;
206
208 if (num_events <= 0) {
209 return;
210 }
211
212 events = SDL_small_alloc(SDL_Event, num_events, &isstack);
213 if (!events) {
214 return;
215 }
216
218 for (i = 0; i < num_events; ++i) {
220 }
221 SDL_PeepEvents(events, num_events, SDL_ADDEVENT, 0, 0);
222
223 SDL_small_free(events, isstack);
224}
225
227{
228 if (a->outputType != b->outputType) {
229 return SDL_FALSE;
230 }
231
232 if (a->outputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
233 return (a->output.axis.axis == b->output.axis.axis);
234 } else {
235 return (a->output.button == b->output.button);
236 }
237}
238
239static void ResetOutput(SDL_GameController *gamecontroller, SDL_ExtendedGameControllerBind *bind)
240{
242 SDL_PrivateGameControllerAxis(gamecontroller, bind->output.axis.axis, 0);
243 } else {
245 }
246}
247
248static void HandleJoystickAxis(SDL_GameController *gamecontroller, int axis, int value)
249{
250 int i;
251 SDL_ExtendedGameControllerBind *last_match = gamecontroller->last_match_axis[axis];
253
254 for (i = 0; i < gamecontroller->num_bindings; ++i) {
255 SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
256 if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS &&
257 axis == binding->input.axis.axis) {
258 if (binding->input.axis.axis_min < binding->input.axis.axis_max) {
259 if (value >= binding->input.axis.axis_min &&
260 value <= binding->input.axis.axis_max) {
261 match = binding;
262 break;
263 }
264 } else {
265 if (value >= binding->input.axis.axis_max &&
266 value <= binding->input.axis.axis_min) {
267 match = binding;
268 break;
269 }
270 }
271 }
272 }
273
274 if (last_match && (!match || !HasSameOutput(last_match, match))) {
275 /* Clear the last input that this axis generated */
276 ResetOutput(gamecontroller, last_match);
277 }
278
279 if (match) {
281 if (match->input.axis.axis_min != match->output.axis.axis_min || match->input.axis.axis_max != match->output.axis.axis_max) {
282 float normalized_value = (float)(value - match->input.axis.axis_min) / (match->input.axis.axis_max - match->input.axis.axis_min);
283 value = match->output.axis.axis_min + (int)(normalized_value * (match->output.axis.axis_max - match->output.axis.axis_min));
284 }
285 SDL_PrivateGameControllerAxis(gamecontroller, match->output.axis.axis, (Sint16)value);
286 } else {
287 Uint8 state;
288 int threshold = match->input.axis.axis_min + (match->input.axis.axis_max - match->input.axis.axis_min) / 2;
289 if (match->input.axis.axis_max < match->input.axis.axis_min) {
290 state = (value <= threshold) ? SDL_PRESSED : SDL_RELEASED;
291 } else {
292 state = (value >= threshold) ? SDL_PRESSED : SDL_RELEASED;
293 }
294 SDL_PrivateGameControllerButton(gamecontroller, match->output.button, state);
295 }
296 }
297 gamecontroller->last_match_axis[axis] = match;
298}
299
300static void HandleJoystickButton(SDL_GameController *gamecontroller, int button, Uint8 state)
301{
302 int i;
303
304 for (i = 0; i < gamecontroller->num_bindings; ++i) {
305 SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
307 button == binding->input.button) {
309 int value = state ? binding->output.axis.axis_max : binding->output.axis.axis_min;
310 SDL_PrivateGameControllerAxis(gamecontroller, binding->output.axis.axis, (Sint16)value);
311 } else {
312 SDL_PrivateGameControllerButton(gamecontroller, binding->output.button, state);
313 }
314 break;
315 }
316 }
317}
318
319static void HandleJoystickHat(SDL_GameController *gamecontroller, int hat, Uint8 value)
320{
321 int i;
322 Uint8 last_mask = gamecontroller->last_hat_mask[hat];
323 Uint8 changed_mask = (last_mask ^ value);
324
325 for (i = 0; i < gamecontroller->num_bindings; ++i) {
326 SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
327 if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT && hat == binding->input.hat.hat) {
328 if ((changed_mask & binding->input.hat.hat_mask) != 0) {
329 if (value & binding->input.hat.hat_mask) {
331 SDL_PrivateGameControllerAxis(gamecontroller, binding->output.axis.axis, (Sint16)binding->output.axis.axis_max);
332 } else {
333 SDL_PrivateGameControllerButton(gamecontroller, binding->output.button, SDL_PRESSED);
334 }
335 } else {
336 ResetOutput(gamecontroller, binding);
337 }
338 }
339 }
340 }
341 gamecontroller->last_hat_mask[hat] = value;
342}
343
344/*
345 * Event filter to fire controller events from joystick ones
346 */
348{
349 switch(event->type) {
351 {
352 SDL_GameController *controllerlist = SDL_gamecontrollers;
353 while (controllerlist) {
354 if (controllerlist->joystick->instance_id == event->jaxis.which) {
355 HandleJoystickAxis(controllerlist, event->jaxis.axis, event->jaxis.value);
356 break;
357 }
358 controllerlist = controllerlist->next;
359 }
360 }
361 break;
363 case SDL_JOYBUTTONUP:
364 {
365 SDL_GameController *controllerlist = SDL_gamecontrollers;
366 while (controllerlist) {
367 if (controllerlist->joystick->instance_id == event->jbutton.which) {
368 HandleJoystickButton(controllerlist, event->jbutton.button, event->jbutton.state);
369 break;
370 }
371 controllerlist = controllerlist->next;
372 }
373 }
374 break;
375 case SDL_JOYHATMOTION:
376 {
377 SDL_GameController *controllerlist = SDL_gamecontrollers;
378 while (controllerlist) {
379 if (controllerlist->joystick->instance_id == event->jhat.which) {
380 HandleJoystickHat(controllerlist, event->jhat.hat, event->jhat.value);
381 break;
382 }
383 controllerlist = controllerlist->next;
384 }
385 }
386 break;
388 {
389 if (SDL_IsGameController(event->jdevice.which)) {
390 SDL_Event deviceevent;
391 deviceevent.type = SDL_CONTROLLERDEVICEADDED;
392 deviceevent.cdevice.which = event->jdevice.which;
393 SDL_PushEvent(&deviceevent);
394 }
395 }
396 break;
398 {
399 SDL_GameController *controllerlist = SDL_gamecontrollers;
400 while (controllerlist) {
401 if (controllerlist->joystick->instance_id == event->jdevice.which) {
402 SDL_Event deviceevent;
403
404 deviceevent.type = SDL_CONTROLLERDEVICEREMOVED;
405 deviceevent.cdevice.which = event->jdevice.which;
406 SDL_PushEvent(&deviceevent);
407
409 break;
410 }
411 controllerlist = controllerlist->next;
412 }
413 }
414 break;
415 default:
416 break;
417 }
418
419 return 1;
420}
421
422/*
423 * Helper function to scan the mappings database for a controller with the specified GUID
424 */
426{
427 ControllerMapping_t *pSupportedController = s_pSupportedControllers;
428 while (pSupportedController) {
429 if (SDL_memcmp(guid, &pSupportedController->guid, sizeof(*guid)) == 0) {
430 return pSupportedController;
431 }
432 pSupportedController = pSupportedController->next;
433 }
434 if (!exact_match) {
435 if (SDL_IsJoystickHIDAPI(*guid)) {
436 /* This is a HIDAPI device */
437 return s_pHIDAPIMapping;
438 }
439#if SDL_JOYSTICK_XINPUT
440 if (SDL_IsJoystickXInput(*guid)) {
441 /* This is an XInput device */
442 return s_pXInputMapping;
443 }
444#endif
445 }
446 return NULL;
447}
448
449static const char* map_StringForControllerAxis[] = {
450 "leftx",
451 "lefty",
452 "rightx",
453 "righty",
454 "lefttrigger",
455 "righttrigger",
456 NULL
457};
458
459/*
460 * convert a string to its enum equivalent
461 */
463{
464 int entry;
465
466 if (pchString && (*pchString == '+' || *pchString == '-')) {
467 ++pchString;
468 }
469
470 if (!pchString || !pchString[0]) {
472 }
473
474 for (entry = 0; map_StringForControllerAxis[entry]; ++entry) {
475 if (!SDL_strcasecmp(pchString, map_StringForControllerAxis[entry]))
476 return (SDL_GameControllerAxis) entry;
477 }
479}
480
481/*
482 * convert an enum to its string equivalent
483 */
485{
488 }
489 return NULL;
490}
491
492static const char* map_StringForControllerButton[] = {
493 "a",
494 "b",
495 "x",
496 "y",
497 "back",
498 "guide",
499 "start",
500 "leftstick",
501 "rightstick",
502 "leftshoulder",
503 "rightshoulder",
504 "dpup",
505 "dpdown",
506 "dpleft",
507 "dpright",
508 NULL
509};
510
511/*
512 * convert a string to its enum equivalent
513 */
515{
516 int entry;
517 if (!pchString || !pchString[0])
519
520 for (entry = 0; map_StringForControllerButton[entry]; ++entry) {
521 if (SDL_strcasecmp(pchString, map_StringForControllerButton[entry]) == 0)
522 return (SDL_GameControllerButton) entry;
523 }
525}
526
527/*
528 * convert an enum to its string equivalent
529 */
531{
534 }
535 return NULL;
536}
537
538/*
539 * given a controller button name and a joystick name update our mapping structure with it
540 */
541static void SDL_PrivateGameControllerParseElement(SDL_GameController *gamecontroller, const char *szGameButton, const char *szJoystickButton)
542{
546 SDL_bool invert_input = SDL_FALSE;
547 char half_axis_input = 0;
548 char half_axis_output = 0;
549
550 if (*szGameButton == '+' || *szGameButton == '-') {
551 half_axis_output = *szGameButton++;
552 }
553
558 bind.output.axis.axis = axis;
560 bind.output.axis.axis_min = 0;
561 bind.output.axis.axis_max = SDL_JOYSTICK_AXIS_MAX;
562 } else {
563 if (half_axis_output == '+') {
564 bind.output.axis.axis_min = 0;
565 bind.output.axis.axis_max = SDL_JOYSTICK_AXIS_MAX;
566 } else if (half_axis_output == '-') {
567 bind.output.axis.axis_min = 0;
568 bind.output.axis.axis_max = SDL_JOYSTICK_AXIS_MIN;
569 } else {
570 bind.output.axis.axis_min = SDL_JOYSTICK_AXIS_MIN;
571 bind.output.axis.axis_max = SDL_JOYSTICK_AXIS_MAX;
572 }
573 }
576 bind.output.button = button;
577 } else {
578 SDL_SetError("Unexpected controller element %s", szGameButton);
579 return;
580 }
581
582 if (*szJoystickButton == '+' || *szJoystickButton == '-') {
583 half_axis_input = *szJoystickButton++;
584 }
585 if (szJoystickButton[SDL_strlen(szJoystickButton) - 1] == '~') {
586 invert_input = SDL_TRUE;
587 }
588
589 if (szJoystickButton[0] == 'a' && SDL_isdigit(szJoystickButton[1])) {
591 bind.input.axis.axis = SDL_atoi(&szJoystickButton[1]);
592 if (half_axis_input == '+') {
593 bind.input.axis.axis_min = 0;
594 bind.input.axis.axis_max = SDL_JOYSTICK_AXIS_MAX;
595 } else if (half_axis_input == '-') {
596 bind.input.axis.axis_min = 0;
597 bind.input.axis.axis_max = SDL_JOYSTICK_AXIS_MIN;
598 } else {
599 bind.input.axis.axis_min = SDL_JOYSTICK_AXIS_MIN;
600 bind.input.axis.axis_max = SDL_JOYSTICK_AXIS_MAX;
601 }
602 if (invert_input) {
603 int tmp = bind.input.axis.axis_min;
604 bind.input.axis.axis_min = bind.input.axis.axis_max;
605 bind.input.axis.axis_max = tmp;
606 }
607 } else if (szJoystickButton[0] == 'b' && SDL_isdigit(szJoystickButton[1])) {
609 bind.input.button = SDL_atoi(&szJoystickButton[1]);
610 } else if (szJoystickButton[0] == 'h' && SDL_isdigit(szJoystickButton[1]) &&
611 szJoystickButton[2] == '.' && SDL_isdigit(szJoystickButton[3])) {
612 int hat = SDL_atoi(&szJoystickButton[1]);
613 int mask = SDL_atoi(&szJoystickButton[3]);
615 bind.input.hat.hat = hat;
616 bind.input.hat.hat_mask = mask;
617 } else {
618 SDL_SetError("Unexpected joystick element: %s", szJoystickButton);
619 return;
620 }
621
622 ++gamecontroller->num_bindings;
623 gamecontroller->bindings = (SDL_ExtendedGameControllerBind *)SDL_realloc(gamecontroller->bindings, gamecontroller->num_bindings * sizeof(*gamecontroller->bindings));
624 if (!gamecontroller->bindings) {
625 gamecontroller->num_bindings = 0;
627 return;
628 }
629 gamecontroller->bindings[gamecontroller->num_bindings - 1] = bind;
630}
631
632
633/*
634 * given a controller mapping string update our mapping object
635 */
636static void
637SDL_PrivateGameControllerParseControllerConfigString(SDL_GameController *gamecontroller, const char *pchString)
638{
639 char szGameButton[20];
640 char szJoystickButton[20];
641 SDL_bool bGameButton = SDL_TRUE;
642 int i = 0;
643 const char *pchPos = pchString;
644
645 SDL_zero(szGameButton);
646 SDL_zero(szJoystickButton);
647
648 while (pchPos && *pchPos) {
649 if (*pchPos == ':') {
650 i = 0;
651 bGameButton = SDL_FALSE;
652 } else if (*pchPos == ' ') {
653
654 } else if (*pchPos == ',') {
655 i = 0;
656 bGameButton = SDL_TRUE;
657 SDL_PrivateGameControllerParseElement(gamecontroller, szGameButton, szJoystickButton);
658 SDL_zero(szGameButton);
659 SDL_zero(szJoystickButton);
660
661 } else if (bGameButton) {
662 if (i >= sizeof(szGameButton)) {
663 SDL_SetError("Button name too large: %s", szGameButton);
664 return;
665 }
666 szGameButton[i] = *pchPos;
667 i++;
668 } else {
669 if (i >= sizeof(szJoystickButton)) {
670 SDL_SetError("Joystick button name too large: %s", szJoystickButton);
671 return;
672 }
673 szJoystickButton[i] = *pchPos;
674 i++;
675 }
676 pchPos++;
677 }
678
679 /* No more values if the string was terminated by a comma. Don't report an error. */
680 if (szGameButton[0] != '\0' || szJoystickButton[0] != '\0') {
681 SDL_PrivateGameControllerParseElement(gamecontroller, szGameButton, szJoystickButton);
682 }
683}
684
685/*
686 * Make a new button mapping struct
687 */
688static void SDL_PrivateLoadButtonMapping(SDL_GameController *gamecontroller, const char *pchName, const char *pchMapping)
689{
690 int i;
691
692 gamecontroller->name = pchName;
693 gamecontroller->num_bindings = 0;
694 SDL_memset(gamecontroller->last_match_axis, 0, gamecontroller->joystick->naxes * sizeof(*gamecontroller->last_match_axis));
695
697
698 /* Set the zero point for triggers */
699 for (i = 0; i < gamecontroller->num_bindings; ++i) {
700 SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
701 if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS &&
703 (binding->output.axis.axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT ||
704 binding->output.axis.axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT)) {
705 if (binding->input.axis.axis < gamecontroller->joystick->naxes) {
706 gamecontroller->joystick->axes[binding->input.axis.axis].value =
707 gamecontroller->joystick->axes[binding->input.axis.axis].zero = (Sint16)binding->input.axis.axis_min;
708 }
709 }
710 }
711}
712
713
714/*
715 * grab the guid string from a mapping string
716 */
717static char *SDL_PrivateGetControllerGUIDFromMappingString(const char *pMapping)
718{
719 const char *pFirstComma = SDL_strchr(pMapping, ',');
720 if (pFirstComma) {
721 char *pchGUID = SDL_malloc(pFirstComma - pMapping + 1);
722 if (!pchGUID) {
724 return NULL;
725 }
726 SDL_memcpy(pchGUID, pMapping, pFirstComma - pMapping);
727 pchGUID[pFirstComma - pMapping] = '\0';
728
729 /* Convert old style GUIDs to the new style in 2.0.5 */
730#if __WIN32__
731 if (SDL_strlen(pchGUID) == 32 &&
732 SDL_memcmp(&pchGUID[20], "504944564944", 12) == 0) {
733 SDL_memcpy(&pchGUID[20], "000000000000", 12);
734 SDL_memcpy(&pchGUID[16], &pchGUID[4], 4);
735 SDL_memcpy(&pchGUID[8], &pchGUID[0], 4);
736 SDL_memcpy(&pchGUID[0], "03000000", 8);
737 }
738#elif __MACOSX__
739 if (SDL_strlen(pchGUID) == 32 &&
740 SDL_memcmp(&pchGUID[4], "000000000000", 12) == 0 &&
741 SDL_memcmp(&pchGUID[20], "000000000000", 12) == 0) {
742 SDL_memcpy(&pchGUID[20], "000000000000", 12);
743 SDL_memcpy(&pchGUID[8], &pchGUID[0], 4);
744 SDL_memcpy(&pchGUID[0], "03000000", 8);
745 }
746#endif
747 return pchGUID;
748 }
749 return NULL;
750}
751
752
753/*
754 * grab the name string from a mapping string
755 */
756static char *SDL_PrivateGetControllerNameFromMappingString(const char *pMapping)
757{
758 const char *pFirstComma, *pSecondComma;
759 char *pchName;
760
761 pFirstComma = SDL_strchr(pMapping, ',');
762 if (!pFirstComma)
763 return NULL;
764
765 pSecondComma = SDL_strchr(pFirstComma + 1, ',');
766 if (!pSecondComma)
767 return NULL;
768
769 pchName = SDL_malloc(pSecondComma - pFirstComma);
770 if (!pchName) {
772 return NULL;
773 }
774 SDL_memcpy(pchName, pFirstComma + 1, pSecondComma - pFirstComma);
775 pchName[pSecondComma - pFirstComma - 1] = 0;
776 return pchName;
777}
778
779
780/*
781 * grab the button mapping string from a mapping string
782 */
783static char *SDL_PrivateGetControllerMappingFromMappingString(const char *pMapping)
784{
785 const char *pFirstComma, *pSecondComma;
786
787 pFirstComma = SDL_strchr(pMapping, ',');
788 if (!pFirstComma)
789 return NULL;
790
791 pSecondComma = SDL_strchr(pFirstComma + 1, ',');
792 if (!pSecondComma)
793 return NULL;
794
795 return SDL_strdup(pSecondComma + 1); /* mapping is everything after the 3rd comma */
796}
797
798/*
799 * Helper function to refresh a mapping
800 */
802{
803 SDL_GameController *gamecontrollerlist = SDL_gamecontrollers;
804 while (gamecontrollerlist) {
805 if (!SDL_memcmp(&gamecontrollerlist->joystick->guid, &pControllerMapping->guid, sizeof(pControllerMapping->guid))) {
806 /* Not really threadsafe. Should this lock access within SDL_GameControllerEventWatcher? */
807 SDL_PrivateLoadButtonMapping(gamecontrollerlist, pControllerMapping->name, pControllerMapping->mapping);
808
809 {
811 event.type = SDL_CONTROLLERDEVICEREMAPPED;
812 event.cdevice.which = gamecontrollerlist->joystick->instance_id;
814 }
815 }
816
817 gamecontrollerlist = gamecontrollerlist->next;
818 }
819}
820
821/*
822 * Helper function to add a mapping for a guid
823 */
824static ControllerMapping_t *
825SDL_PrivateAddMappingForGUID(SDL_JoystickGUID jGUID, const char *mappingString, SDL_bool *existing, SDL_ControllerMappingPriority priority)
826{
827 char *pchName;
828 char *pchMapping;
829 ControllerMapping_t *pControllerMapping;
830
831 pchName = SDL_PrivateGetControllerNameFromMappingString(mappingString);
832 if (!pchName) {
833 SDL_SetError("Couldn't parse name from %s", mappingString);
834 return NULL;
835 }
836
837 pchMapping = SDL_PrivateGetControllerMappingFromMappingString(mappingString);
838 if (!pchMapping) {
839 SDL_free(pchName);
840 SDL_SetError("Couldn't parse %s", mappingString);
841 return NULL;
842 }
843
844 pControllerMapping = SDL_PrivateGetControllerMappingForGUID(&jGUID, SDL_TRUE);
845 if (pControllerMapping) {
846 /* Only overwrite the mapping if the priority is the same or higher. */
847 if (pControllerMapping->priority <= priority) {
848 /* Update existing mapping */
849 SDL_free(pControllerMapping->name);
850 pControllerMapping->name = pchName;
851 SDL_free(pControllerMapping->mapping);
852 pControllerMapping->mapping = pchMapping;
853 pControllerMapping->priority = priority;
854 /* refresh open controllers */
855 SDL_PrivateGameControllerRefreshMapping(pControllerMapping);
856 } else {
857 SDL_free(pchName);
858 SDL_free(pchMapping);
859 }
860 *existing = SDL_TRUE;
861 } else {
862 pControllerMapping = SDL_malloc(sizeof(*pControllerMapping));
863 if (!pControllerMapping) {
864 SDL_free(pchName);
865 SDL_free(pchMapping);
867 return NULL;
868 }
869 pControllerMapping->guid = jGUID;
870 pControllerMapping->name = pchName;
871 pControllerMapping->mapping = pchMapping;
872 pControllerMapping->next = NULL;
873 pControllerMapping->priority = priority;
874
876 /* Add the mapping to the end of the list */
877 ControllerMapping_t *pCurrMapping, *pPrevMapping;
878
879 for ( pPrevMapping = s_pSupportedControllers, pCurrMapping = pPrevMapping->next;
880 pCurrMapping;
881 pPrevMapping = pCurrMapping, pCurrMapping = pCurrMapping->next ) {
882 continue;
883 }
884 pPrevMapping->next = pControllerMapping;
885 } else {
886 s_pSupportedControllers = pControllerMapping;
887 }
888 *existing = SDL_FALSE;
889 }
890 return pControllerMapping;
891}
892
893#ifdef __ANDROID__
894/*
895 * Helper function to guess at a mapping based on the elements reported for this controller
896 */
897static ControllerMapping_t *SDL_CreateMappingForAndroidController(const char *name, SDL_JoystickGUID guid)
898{
899 SDL_bool existing;
900 char name_string[128];
901 char mapping_string[1024];
902 int button_mask;
903 int axis_mask;
904
905 button_mask = SDL_SwapLE16(*(Uint16*)(&guid.data[sizeof(guid.data)-4]));
906 axis_mask = SDL_SwapLE16(*(Uint16*)(&guid.data[sizeof(guid.data)-2]));
907 if (!button_mask && !axis_mask) {
908 /* Accelerometer, shouldn't have a game controller mapping */
909 return NULL;
910 }
911
912 /* Remove any commas in the name */
913 SDL_strlcpy(name_string, name, sizeof(name_string));
914 {
915 char *spot;
916 for (spot = name_string; *spot; ++spot) {
917 if (*spot == ',') {
918 *spot = ' ';
919 }
920 }
921 }
922 SDL_snprintf(mapping_string, sizeof(mapping_string), "none,%s,", name_string);
923 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_A)) {
924 SDL_strlcat(mapping_string, "a:b0,", sizeof(mapping_string));
925 }
926 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_B)) {
927 SDL_strlcat(mapping_string, "b:b1,", sizeof(mapping_string));
928 } else if (button_mask & (1 << SDL_CONTROLLER_BUTTON_BACK)) {
929 /* Use the back button as "B" for easy UI navigation with TV remotes */
930 SDL_strlcat(mapping_string, "b:b4,", sizeof(mapping_string));
931 button_mask &= ~(1 << SDL_CONTROLLER_BUTTON_BACK);
932 }
933 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_X)) {
934 SDL_strlcat(mapping_string, "x:b2,", sizeof(mapping_string));
935 }
936 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_Y)) {
937 SDL_strlcat(mapping_string, "y:b3,", sizeof(mapping_string));
938 }
939 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_BACK)) {
940 SDL_strlcat(mapping_string, "back:b4,", sizeof(mapping_string));
941 }
942#if 0 /* The guide button generally isn't functional (or acts as a home button) on most Android controllers */
943 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_GUIDE)) {
944 SDL_strlcat(mapping_string, "guide:b5,", sizeof(mapping_string));
945#if 0 /* Actually this will be done in Steam */
946 } else if (button_mask & (1 << SDL_CONTROLLER_BUTTON_START)) {
947 /* The guide button doesn't exist, use the start button instead,
948 so you can do Steam guide button chords and open the Steam overlay.
949 */
950 SDL_strlcat(mapping_string, "guide:b6,", sizeof(mapping_string));
951 button_mask &= ~(1 << SDL_CONTROLLER_BUTTON_START);
952#endif
953 }
954#endif
955 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_START)) {
956 SDL_strlcat(mapping_string, "start:b6,", sizeof(mapping_string));
957 }
958 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_LEFTSTICK)) {
959 SDL_strlcat(mapping_string, "leftstick:b7,", sizeof(mapping_string));
960 }
961 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_RIGHTSTICK)) {
962 SDL_strlcat(mapping_string, "rightstick:b8,", sizeof(mapping_string));
963 }
964 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_LEFTSHOULDER)) {
965 SDL_strlcat(mapping_string, "leftshoulder:b9,", sizeof(mapping_string));
966 }
967 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)) {
968 SDL_strlcat(mapping_string, "rightshoulder:b10,", sizeof(mapping_string));
969 }
970 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_DPAD_UP)) {
971 SDL_strlcat(mapping_string, "dpup:b11,", sizeof(mapping_string));
972 }
973 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_DPAD_DOWN)) {
974 SDL_strlcat(mapping_string, "dpdown:b12,", sizeof(mapping_string));
975 }
976 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_DPAD_LEFT)) {
977 SDL_strlcat(mapping_string, "dpleft:b13,", sizeof(mapping_string));
978 }
979 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_DPAD_RIGHT)) {
980 SDL_strlcat(mapping_string, "dpright:b14,", sizeof(mapping_string));
981 }
982 if (axis_mask & (1 << SDL_CONTROLLER_AXIS_LEFTX)) {
983 SDL_strlcat(mapping_string, "leftx:a0,", sizeof(mapping_string));
984 }
985 if (axis_mask & (1 << SDL_CONTROLLER_AXIS_LEFTY)) {
986 SDL_strlcat(mapping_string, "lefty:a1,", sizeof(mapping_string));
987 }
988 if (axis_mask & (1 << SDL_CONTROLLER_AXIS_RIGHTX)) {
989 SDL_strlcat(mapping_string, "rightx:a2,", sizeof(mapping_string));
990 }
991 if (axis_mask & (1 << SDL_CONTROLLER_AXIS_RIGHTY)) {
992 SDL_strlcat(mapping_string, "righty:a3,", sizeof(mapping_string));
993 }
994 if (axis_mask & (1 << SDL_CONTROLLER_AXIS_TRIGGERLEFT)) {
995 SDL_strlcat(mapping_string, "lefttrigger:a4,", sizeof(mapping_string));
996 }
997 if (axis_mask & (1 << SDL_CONTROLLER_AXIS_TRIGGERRIGHT)) {
998 SDL_strlcat(mapping_string, "righttrigger:a5,", sizeof(mapping_string));
999 }
1000
1001 /* Remove trailing comma */
1002 {
1003 int pos = (int)SDL_strlen(mapping_string) - 1;
1004 if (pos >= 0) {
1005 if (mapping_string[pos] == ',') {
1006 mapping_string[pos] = '\0';
1007 }
1008 }
1009 }
1010
1011 return SDL_PrivateAddMappingForGUID(guid, mapping_string,
1013}
1014#endif /* __ANDROID__ */
1015
1016
1017/*
1018 * Helper function to determine pre-calculated offset to certain joystick mappings
1019 */
1021{
1023
1025#ifdef __LINUX__
1026 if (!mapping && name) {
1027 if (SDL_strstr(name, "Xbox 360 Wireless Receiver")) {
1028 /* The Linux driver xpad.c maps the wireless dpad to buttons */
1029 SDL_bool existing;
1031"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",
1033 }
1034 }
1035#endif /* __LINUX__ */
1036
1037 if (!mapping && name) {
1038 if (SDL_strstr(name, "Xbox") || SDL_strstr(name, "X-Box") || SDL_strstr(name, "XBOX")) {
1040 }
1041 }
1042#ifdef __ANDROID__
1043 if (!mapping && name && !SDL_IsJoystickHIDAPI(guid)) {
1044 mapping = SDL_CreateMappingForAndroidController(name, guid);
1045 }
1046#endif
1047 if (!mapping) {
1049 }
1050 return mapping;
1051}
1052
1054{
1055 const char *name;
1056 SDL_JoystickGUID guid;
1058
1060
1061 if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
1062 SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
1064 return (NULL);
1065 }
1066
1067 name = SDL_JoystickNameForIndex(device_index);
1068 guid = SDL_JoystickGetDeviceGUID(device_index);
1071 return mapping;
1072}
1073
1074/*
1075 * Add or update an entry into the Mappings Database
1076 */
1077int
1079{
1080 const char *platform = SDL_GetPlatform();
1081 int controllers = 0;
1082 char *buf, *line, *line_end, *tmp, *comma, line_platform[64];
1083 size_t db_size, platform_len;
1084
1085 if (rw == NULL) {
1086 return SDL_SetError("Invalid RWops");
1087 }
1088 db_size = (size_t)SDL_RWsize(rw);
1089
1090 buf = (char *)SDL_malloc(db_size + 1);
1091 if (buf == NULL) {
1092 if (freerw) {
1093 SDL_RWclose(rw);
1094 }
1095 return SDL_SetError("Could not allocate space to read DB into memory");
1096 }
1097
1098 if (SDL_RWread(rw, buf, db_size, 1) != 1) {
1099 if (freerw) {
1100 SDL_RWclose(rw);
1101 }
1102 SDL_free(buf);
1103 return SDL_SetError("Could not read DB");
1104 }
1105
1106 if (freerw) {
1107 SDL_RWclose(rw);
1108 }
1109
1110 buf[db_size] = '\0';
1111 line = buf;
1112
1113 while (line < buf + db_size) {
1114 line_end = SDL_strchr(line, '\n');
1115 if (line_end != NULL) {
1116 *line_end = '\0';
1117 } else {
1118 line_end = buf + db_size;
1119 }
1120
1121 /* Extract and verify the platform */
1123 if (tmp != NULL) {
1125 comma = SDL_strchr(tmp, ',');
1126 if (comma != NULL) {
1127 platform_len = comma - tmp + 1;
1128 if (platform_len + 1 < SDL_arraysize(line_platform)) {
1129 SDL_strlcpy(line_platform, tmp, platform_len);
1130 if (SDL_strncasecmp(line_platform, platform, platform_len) == 0 &&
1131 SDL_GameControllerAddMapping(line) > 0) {
1132 controllers++;
1133 }
1134 }
1135 }
1136 }
1137
1138 line = line_end + 1;
1139 }
1140
1141 SDL_free(buf);
1142 return controllers;
1143}
1144
1145/*
1146 * Add or update an entry into the Mappings Database with a priority
1147 */
1148static int
1150{
1151 char *pchGUID;
1152 SDL_JoystickGUID jGUID;
1153 SDL_bool is_default_mapping = SDL_FALSE;
1154 SDL_bool is_hidapi_mapping = SDL_FALSE;
1155 SDL_bool is_xinput_mapping = SDL_FALSE;
1156 SDL_bool existing = SDL_FALSE;
1157 ControllerMapping_t *pControllerMapping;
1158
1159 if (!mappingString) {
1160 return SDL_InvalidParamError("mappingString");
1161 }
1162
1163 pchGUID = SDL_PrivateGetControllerGUIDFromMappingString(mappingString);
1164 if (!pchGUID) {
1165 return SDL_SetError("Couldn't parse GUID from %s", mappingString);
1166 }
1167 if (!SDL_strcasecmp(pchGUID, "default")) {
1168 is_default_mapping = SDL_TRUE;
1169 } else if (!SDL_strcasecmp(pchGUID, "hidapi")) {
1170 is_hidapi_mapping = SDL_TRUE;
1171 } else if (!SDL_strcasecmp(pchGUID, "xinput")) {
1172 is_xinput_mapping = SDL_TRUE;
1173 }
1174 jGUID = SDL_JoystickGetGUIDFromString(pchGUID);
1175 SDL_free(pchGUID);
1176
1177 pControllerMapping = SDL_PrivateAddMappingForGUID(jGUID, mappingString, &existing, priority);
1178 if (!pControllerMapping) {
1179 return -1;
1180 }
1181
1182 if (existing) {
1183 return 0;
1184 } else {
1185 if (is_default_mapping) {
1186 s_pDefaultMapping = pControllerMapping;
1187 } else if (is_hidapi_mapping) {
1188 s_pHIDAPIMapping = pControllerMapping;
1189 } else if (is_xinput_mapping) {
1190 s_pXInputMapping = pControllerMapping;
1191 }
1192 return 1;
1193 }
1194}
1195
1196/*
1197 * Add or update an entry into the Mappings Database
1198 */
1199int
1200SDL_GameControllerAddMapping(const char *mappingString)
1201{
1203}
1204
1205/*
1206 * Get the number of mappings installed
1207 */
1208int
1210{
1211 int num_mappings = 0;
1213
1215 if (SDL_memcmp(&mapping->guid, &s_zeroGUID, sizeof(mapping->guid)) == 0) {
1216 continue;
1217 }
1218 ++num_mappings;
1219 }
1220 return num_mappings;
1221}
1222
1223/*
1224 * Get the mapping at a particular index.
1225 */
1226char *
1228{
1230
1232 if (SDL_memcmp(&mapping->guid, &s_zeroGUID, sizeof(mapping->guid)) == 0) {
1233 continue;
1234 }
1235 if (mapping_index == 0) {
1236 char *pMappingString;
1237 char pchGUID[33];
1238 size_t needed;
1239
1240 SDL_JoystickGetGUIDString(mapping->guid, pchGUID, sizeof(pchGUID));
1241 /* allocate enough memory for GUID + ',' + name + ',' + mapping + \0 */
1242 needed = SDL_strlen(pchGUID) + 1 + SDL_strlen(mapping->name) + 1 + SDL_strlen(mapping->mapping) + 1;
1243 pMappingString = SDL_malloc(needed);
1244 if (!pMappingString) {
1246 return NULL;
1247 }
1248 SDL_snprintf(pMappingString, needed, "%s,%s,%s", pchGUID, mapping->name, mapping->mapping);
1249 return pMappingString;
1250 }
1251 --mapping_index;
1252 }
1253 return NULL;
1254}
1255
1256/*
1257 * Get the mapping string for this GUID
1258 */
1259char *
1261{
1262 char *pMappingString = NULL;
1264 if (mapping) {
1265 char pchGUID[33];
1266 size_t needed;
1267 SDL_JoystickGetGUIDString(guid, pchGUID, sizeof(pchGUID));
1268 /* allocate enough memory for GUID + ',' + name + ',' + mapping + \0 */
1269 needed = SDL_strlen(pchGUID) + 1 + SDL_strlen(mapping->name) + 1 + SDL_strlen(mapping->mapping) + 1;
1270 pMappingString = SDL_malloc(needed);
1271 if (!pMappingString) {
1273 return NULL;
1274 }
1275 SDL_snprintf(pMappingString, needed, "%s,%s,%s", pchGUID, mapping->name, mapping->mapping);
1276 }
1277 return pMappingString;
1278}
1279
1280/*
1281 * Get the mapping string for this device
1282 */
1283char *
1284SDL_GameControllerMapping(SDL_GameController * gamecontroller)
1285{
1286 if (!gamecontroller) {
1287 return NULL;
1288 }
1289
1290 return SDL_GameControllerMappingForGUID(gamecontroller->joystick->guid);
1291}
1292
1293static void
1295{
1296 const char *hint = SDL_GetHint(SDL_HINT_GAMECONTROLLERCONFIG);
1297 if (hint && hint[0]) {
1298 size_t nchHints = SDL_strlen(hint);
1299 char *pUserMappings = SDL_malloc(nchHints + 1);
1300 char *pTempMappings = pUserMappings;
1301 SDL_memcpy(pUserMappings, hint, nchHints);
1302 pUserMappings[nchHints] = '\0';
1303 while (pUserMappings) {
1304 char *pchNewLine = NULL;
1305
1306 pchNewLine = SDL_strchr(pUserMappings, '\n');
1307 if (pchNewLine)
1308 *pchNewLine = '\0';
1309
1311
1312 if (pchNewLine) {
1313 pUserMappings = pchNewLine + 1;
1314 } else {
1315 pUserMappings = NULL;
1316 }
1317 }
1318 SDL_free(pTempMappings);
1319 }
1320}
1321
1322/*
1323 * Fill the given buffer with the expected controller mapping filepath.
1324 * Usually this will just be SDL_HINT_GAMECONTROLLERCONFIG_FILE, but for
1325 * Android, we want to get the internal storage path.
1326 */
1328{
1330 if (hint && *hint) {
1331 return SDL_strlcpy(path, hint, size) < size;
1332 }
1333
1334#if defined(__ANDROID__)
1335 return SDL_snprintf(path, size, "%s/controller_map.txt", SDL_AndroidGetInternalStoragePath()) < size;
1336#else
1337 return SDL_FALSE;
1338#endif
1339}
1340
1341/*
1342 * Initialize the game controller system, mostly load our DB of controller config mappings
1343 */
1344int
1346{
1347 char szControllerMapPath[1024];
1348 int i = 0;
1349 const char *pMappingString = NULL;
1350 pMappingString = s_ControllerMappings[i];
1351 while (pMappingString) {
1353
1354 i++;
1355 pMappingString = s_ControllerMappings[i];
1356 }
1357
1358 if (SDL_GetControllerMappingFilePath(szControllerMapPath, sizeof(szControllerMapPath))) {
1359 SDL_GameControllerAddMappingsFromFile(szControllerMapPath);
1360 }
1361
1362 /* load in any user supplied config */
1364
1369
1370 return (0);
1371}
1372
1373int
1375{
1376 int i;
1377
1378 /* watch for joy events and fire controller ones if needed */
1380
1381 /* Send added events for controllers currently attached */
1382 for (i = 0; i < SDL_NumJoysticks(); ++i) {
1383 if (SDL_IsGameController(i)) {
1384 SDL_Event deviceevent;
1385 deviceevent.type = SDL_CONTROLLERDEVICEADDED;
1386 deviceevent.cdevice.which = i;
1387 SDL_PushEvent(&deviceevent);
1388 }
1389 }
1390
1391 return (0);
1392}
1393
1394
1395/*
1396 * Get the implementation dependent name of a controller
1397 */
1398const char *
1400{
1401 ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(device_index);
1402 if (pSupportedController) {
1403 if (SDL_strcmp(pSupportedController->name, "*") == 0) {
1404 return SDL_JoystickNameForIndex(device_index);
1405 } else {
1406 return pSupportedController->name;
1407 }
1408 }
1409 return NULL;
1410}
1411
1412
1413/**
1414 * Get the mapping of a game controller.
1415 * This can be called before any controllers are opened.
1416 * If no mapping can be found, this function returns NULL.
1417 */
1418char *
1420{
1421 char *pMappingString = NULL;
1423
1425 mapping = SDL_PrivateGetControllerMapping(joystick_index);
1426 if (mapping) {
1427 SDL_JoystickGUID guid;
1428 char pchGUID[33];
1429 size_t needed;
1430 guid = SDL_JoystickGetDeviceGUID(joystick_index);
1431 SDL_JoystickGetGUIDString(guid, pchGUID, sizeof(pchGUID));
1432 /* allocate enough memory for GUID + ',' + name + ',' + mapping + \0 */
1433 needed = SDL_strlen(pchGUID) + 1 + SDL_strlen(mapping->name) + 1 + SDL_strlen(mapping->mapping) + 1;
1434 pMappingString = SDL_malloc(needed);
1435 if (!pMappingString) {
1438 return NULL;
1439 }
1440 SDL_snprintf(pMappingString, needed, "%s,%s,%s", pchGUID, mapping->name, mapping->mapping);
1441 }
1443 return pMappingString;
1444}
1445
1446
1447/*
1448 * Return 1 if the joystick with this name and GUID is a supported controller
1449 */
1452{
1454 if (pSupportedController) {
1455 return SDL_TRUE;
1456 }
1457 return SDL_FALSE;
1458}
1459
1460/*
1461 * Return 1 if the joystick at this device index is a supported controller
1462 */
1464SDL_IsGameController(int device_index)
1465{
1466 ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(device_index);
1467 if (pSupportedController) {
1468 return SDL_TRUE;
1469 }
1470 return SDL_FALSE;
1471}
1472
1473/*
1474 * Return 1 if the game controller should be ignored by SDL
1475 */
1477{
1478 int i;
1479 Uint16 vendor;
1480 Uint16 product;
1481 Uint16 version;
1482 Uint32 vidpid;
1483
1484#if defined(__LINUX__)
1485 if (name && SDL_strstr(name, "Wireless Controller Motion Sensors")) {
1486 /* Don't treat the PS4 motion controls as a separate game controller */
1487 return SDL_TRUE;
1488 }
1489#endif
1490
1493 return SDL_FALSE;
1494 }
1495
1496 SDL_GetJoystickGUIDInfo(guid, &vendor, &product, &version);
1497
1498 if (SDL_GetHintBoolean("SDL_GAMECONTROLLER_ALLOW_STEAM_VIRTUAL_GAMEPAD", SDL_FALSE)) {
1499 /* 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 */
1500 SDL_bool bSteamVirtualGamepad = SDL_FALSE;
1501#if defined(__LINUX__)
1502 bSteamVirtualGamepad = (vendor == 0x28DE && product == 0x11FF);
1503#elif defined(__MACOSX__)
1504 bSteamVirtualGamepad = (vendor == 0x045E && product == 0x028E && version == 1);
1505#elif defined(__WIN32__)
1506 /* We can't tell on Windows, but Steam will block others in input hooks */
1507 bSteamVirtualGamepad = SDL_TRUE;
1508#endif
1509 if (bSteamVirtualGamepad) {
1510 return SDL_FALSE;
1511 }
1512 }
1513
1514 vidpid = MAKE_VIDPID(vendor, product);
1515
1517 for (i = 0; i < SDL_allowed_controllers.num_entries; ++i) {
1518 if (vidpid == SDL_allowed_controllers.entries[i]) {
1519 return SDL_FALSE;
1520 }
1521 }
1522 return SDL_TRUE;
1523 } else {
1524 for (i = 0; i < SDL_ignored_controllers.num_entries; ++i) {
1525 if (vidpid == SDL_ignored_controllers.entries[i]) {
1526 return SDL_TRUE;
1527 }
1528 }
1529 return SDL_FALSE;
1530 }
1531}
1532
1533/*
1534 * Open a controller for use - the index passed as an argument refers to
1535 * the N'th controller on the system. This index is the value which will
1536 * identify this controller in future controller events.
1537 *
1538 * This function returns a controller identifier, or NULL if an error occurred.
1539 */
1540SDL_GameController *
1541SDL_GameControllerOpen(int device_index)
1542{
1543 SDL_JoystickID instance_id;
1544 SDL_GameController *gamecontroller;
1545 SDL_GameController *gamecontrollerlist;
1546 ControllerMapping_t *pSupportedController = NULL;
1547
1549
1550 gamecontrollerlist = SDL_gamecontrollers;
1551 /* If the controller is already open, return it */
1552 instance_id = SDL_JoystickGetDeviceInstanceID(device_index);
1553 while (gamecontrollerlist) {
1554 if (instance_id == gamecontrollerlist->joystick->instance_id) {
1555 gamecontroller = gamecontrollerlist;
1556 ++gamecontroller->ref_count;
1558 return (gamecontroller);
1559 }
1560 gamecontrollerlist = gamecontrollerlist->next;
1561 }
1562
1563 /* Find a controller mapping */
1564 pSupportedController = SDL_PrivateGetControllerMapping(device_index);
1565 if (!pSupportedController) {
1566 SDL_SetError("Couldn't find mapping for device (%d)", device_index);
1568 return NULL;
1569 }
1570
1571 /* Create and initialize the controller */
1572 gamecontroller = (SDL_GameController *) SDL_calloc(1, sizeof(*gamecontroller));
1573 if (gamecontroller == NULL) {
1576 return NULL;
1577 }
1578
1579 gamecontroller->joystick = SDL_JoystickOpen(device_index);
1580 if (!gamecontroller->joystick) {
1581 SDL_free(gamecontroller);
1583 return NULL;
1584 }
1585
1586 if (gamecontroller->joystick->naxes) {
1587 gamecontroller->last_match_axis = (SDL_ExtendedGameControllerBind **)SDL_calloc(gamecontroller->joystick->naxes, sizeof(*gamecontroller->last_match_axis));
1588 if (!gamecontroller->last_match_axis) {
1590 SDL_JoystickClose(gamecontroller->joystick);
1591 SDL_free(gamecontroller);
1593 return NULL;
1594 }
1595 }
1596 if (gamecontroller->joystick->nhats) {
1597 gamecontroller->last_hat_mask = (Uint8 *)SDL_calloc(gamecontroller->joystick->nhats, sizeof(*gamecontroller->last_hat_mask));
1598 if (!gamecontroller->last_hat_mask) {
1600 SDL_JoystickClose(gamecontroller->joystick);
1601 SDL_free(gamecontroller->last_match_axis);
1602 SDL_free(gamecontroller);
1604 return NULL;
1605 }
1606 }
1607
1608 SDL_PrivateLoadButtonMapping(gamecontroller, pSupportedController->name, pSupportedController->mapping);
1609
1610 /* Add the controller to list */
1611 ++gamecontroller->ref_count;
1612 /* Link the controller in the list */
1613 gamecontroller->next = SDL_gamecontrollers;
1614 SDL_gamecontrollers = gamecontroller;
1615
1617
1618 return (gamecontroller);
1619}
1620
1621/*
1622 * Manually pump for controller updates.
1623 */
1624void
1626{
1627 /* Just for API completeness; the joystick API does all the work. */
1629}
1630
1631/*
1632 * Get the current state of an axis control on a controller
1633 */
1634Sint16
1635SDL_GameControllerGetAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis)
1636{
1637 int i;
1638
1639 if (!gamecontroller)
1640 return 0;
1641
1642 for (i = 0; i < gamecontroller->num_bindings; ++i) {
1643 SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
1644 if (binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS && binding->output.axis.axis == axis) {
1645 int value = 0;
1646 SDL_bool valid_input_range;
1647 SDL_bool valid_output_range;
1648
1649 if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
1650 value = SDL_JoystickGetAxis(gamecontroller->joystick, binding->input.axis.axis);
1651 if (binding->input.axis.axis_min < binding->input.axis.axis_max) {
1652 valid_input_range = (value >= binding->input.axis.axis_min && value <= binding->input.axis.axis_max);
1653 } else {
1654 valid_input_range = (value >= binding->input.axis.axis_max && value <= binding->input.axis.axis_min);
1655 }
1656 if (valid_input_range) {
1657 if (binding->input.axis.axis_min != binding->output.axis.axis_min || binding->input.axis.axis_max != binding->output.axis.axis_max) {
1658 float normalized_value = (float)(value - binding->input.axis.axis_min) / (binding->input.axis.axis_max - binding->input.axis.axis_min);
1659 value = binding->output.axis.axis_min + (int)(normalized_value * (binding->output.axis.axis_max - binding->output.axis.axis_min));
1660 }
1661 } else {
1662 value = 0;
1663 }
1664 } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
1665 value = SDL_JoystickGetButton(gamecontroller->joystick, binding->input.button);
1666 if (value == SDL_PRESSED) {
1667 value = binding->output.axis.axis_max;
1668 }
1669 } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
1670 int hat_mask = SDL_JoystickGetHat(gamecontroller->joystick, binding->input.hat.hat);
1671 if (hat_mask & binding->input.hat.hat_mask) {
1672 value = binding->output.axis.axis_max;
1673 }
1674 }
1675
1676 if (binding->output.axis.axis_min < binding->output.axis.axis_max) {
1677 valid_output_range = (value >= binding->output.axis.axis_min && value <= binding->output.axis.axis_max);
1678 } else {
1679 valid_output_range = (value >= binding->output.axis.axis_max && value <= binding->output.axis.axis_min);
1680 }
1681 /* If the value is zero, there might be another binding that makes it non-zero */
1682 if (value != 0 && valid_output_range) {
1683 return (Sint16)value;
1684 }
1685 }
1686 }
1687 return 0;
1688}
1689
1690/*
1691 * Get the current state of a button on a controller
1692 */
1693Uint8
1695{
1696 int i;
1697
1698 if (!gamecontroller)
1699 return 0;
1700
1701 for (i = 0; i < gamecontroller->num_bindings; ++i) {
1702 SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
1703 if (binding->outputType == SDL_CONTROLLER_BINDTYPE_BUTTON && binding->output.button == button) {
1704 if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
1705 SDL_bool valid_input_range;
1706
1707 int value = SDL_JoystickGetAxis(gamecontroller->joystick, binding->input.axis.axis);
1708 int threshold = binding->input.axis.axis_min + (binding->input.axis.axis_max - binding->input.axis.axis_min) / 2;
1709 if (binding->input.axis.axis_min < binding->input.axis.axis_max) {
1710 valid_input_range = (value >= binding->input.axis.axis_min && value <= binding->input.axis.axis_max);
1711 if (valid_input_range) {
1712 return (value >= threshold) ? SDL_PRESSED : SDL_RELEASED;
1713 }
1714 } else {
1715 valid_input_range = (value >= binding->input.axis.axis_max && value <= binding->input.axis.axis_min);
1716 if (valid_input_range) {
1717 return (value <= threshold) ? SDL_PRESSED : SDL_RELEASED;
1718 }
1719 }
1720 } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
1721 return SDL_JoystickGetButton(gamecontroller->joystick, binding->input.button);
1722 } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
1723 int hat_mask = SDL_JoystickGetHat(gamecontroller->joystick, binding->input.hat.hat);
1724 return (hat_mask & binding->input.hat.hat_mask) ? SDL_PRESSED : SDL_RELEASED;
1725 }
1726 }
1727 }
1728 return SDL_RELEASED;
1729}
1730
1731const char *
1732SDL_GameControllerName(SDL_GameController * gamecontroller)
1733{
1734 if (!gamecontroller)
1735 return NULL;
1736
1737 if (SDL_strcmp(gamecontroller->name, "*") == 0) {
1738 return SDL_JoystickName(SDL_GameControllerGetJoystick(gamecontroller));
1739 } else {
1740 return gamecontroller->name;
1741 }
1742}
1743
1744int
1745SDL_GameControllerGetPlayerIndex(SDL_GameController *gamecontroller)
1746{
1748}
1749
1750Uint16
1751SDL_GameControllerGetVendor(SDL_GameController * gamecontroller)
1752{
1754}
1755
1756Uint16
1757SDL_GameControllerGetProduct(SDL_GameController * gamecontroller)
1758{
1760}
1761
1762Uint16
1763SDL_GameControllerGetProductVersion(SDL_GameController * gamecontroller)
1764{
1766}
1767
1768/*
1769 * Return if the controller in question is currently attached to the system,
1770 * \return 0 if not plugged in, 1 if still present.
1771 */
1773SDL_GameControllerGetAttached(SDL_GameController * gamecontroller)
1774{
1775 if (!gamecontroller)
1776 return SDL_FALSE;
1777
1778 return SDL_JoystickGetAttached(gamecontroller->joystick);
1779}
1780
1781/*
1782 * Get the joystick for this controller
1783 */
1784SDL_Joystick *SDL_GameControllerGetJoystick(SDL_GameController * gamecontroller)
1785{
1786 if (!gamecontroller)
1787 return NULL;
1788
1789 return gamecontroller->joystick;
1790}
1791
1792
1793/*
1794 * Find the SDL_GameController that owns this instance id
1795 */
1796SDL_GameController *
1798{
1799 SDL_GameController *gamecontroller;
1800
1802 gamecontroller = SDL_gamecontrollers;
1803 while (gamecontroller) {
1804 if (gamecontroller->joystick->instance_id == joyid) {
1806 return gamecontroller;
1807 }
1808 gamecontroller = gamecontroller->next;
1809 }
1811 return NULL;
1812}
1813
1814
1815/*
1816 * Get the SDL joystick layer binding for this controller axis mapping
1817 */
1819{
1820 int i;
1822 SDL_zero(bind);
1823
1824 if (!gamecontroller || axis == SDL_CONTROLLER_AXIS_INVALID)
1825 return bind;
1826
1827 for (i = 0; i < gamecontroller->num_bindings; ++i) {
1828 SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
1829 if (binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS && binding->output.axis.axis == axis) {
1830 bind.bindType = binding->inputType;
1831 if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
1832 /* FIXME: There might be multiple axes bound now that we have axis ranges... */
1833 bind.value.axis = binding->input.axis.axis;
1834 } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
1835 bind.value.button = binding->input.button;
1836 } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
1837 bind.value.hat.hat = binding->input.hat.hat;
1838 bind.value.hat.hat_mask = binding->input.hat.hat_mask;
1839 }
1840 break;
1841 }
1842 }
1843 return bind;
1844}
1845
1846
1847/*
1848 * Get the SDL joystick layer binding for this controller button mapping
1849 */
1851{
1852 int i;
1854 SDL_zero(bind);
1855
1856 if (!gamecontroller || button == SDL_CONTROLLER_BUTTON_INVALID)
1857 return bind;
1858
1859 for (i = 0; i < gamecontroller->num_bindings; ++i) {
1860 SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
1861 if (binding->outputType == SDL_CONTROLLER_BINDTYPE_BUTTON && binding->output.button == button) {
1862 bind.bindType = binding->inputType;
1863 if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
1864 bind.value.axis = binding->input.axis.axis;
1865 } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
1866 bind.value.button = binding->input.button;
1867 } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
1868 bind.value.hat.hat = binding->input.hat.hat;
1869 bind.value.hat.hat_mask = binding->input.hat.hat_mask;
1870 }
1871 break;
1872 }
1873 }
1874 return bind;
1875}
1876
1877
1878int
1879SDL_GameControllerRumble(SDL_GameController *gamecontroller, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
1880{
1881 return SDL_JoystickRumble(SDL_GameControllerGetJoystick(gamecontroller), low_frequency_rumble, high_frequency_rumble, duration_ms);
1882}
1883
1884void
1885SDL_GameControllerClose(SDL_GameController * gamecontroller)
1886{
1887 SDL_GameController *gamecontrollerlist, *gamecontrollerlistprev;
1888
1889 if (!gamecontroller)
1890 return;
1891
1893
1894 /* First decrement ref count */
1895 if (--gamecontroller->ref_count > 0) {
1897 return;
1898 }
1899
1900 SDL_JoystickClose(gamecontroller->joystick);
1901
1902 gamecontrollerlist = SDL_gamecontrollers;
1903 gamecontrollerlistprev = NULL;
1904 while (gamecontrollerlist) {
1905 if (gamecontroller == gamecontrollerlist) {
1906 if (gamecontrollerlistprev) {
1907 /* unlink this entry */
1908 gamecontrollerlistprev->next = gamecontrollerlist->next;
1909 } else {
1910 SDL_gamecontrollers = gamecontroller->next;
1911 }
1912 break;
1913 }
1914 gamecontrollerlistprev = gamecontrollerlist;
1915 gamecontrollerlist = gamecontrollerlist->next;
1916 }
1917
1918 SDL_free(gamecontroller->bindings);
1919 SDL_free(gamecontroller->last_match_axis);
1920 SDL_free(gamecontroller->last_hat_mask);
1921 SDL_free(gamecontroller);
1922
1924}
1925
1926
1927/*
1928 * Quit the controller subsystem
1929 */
1930void
1932{
1934 while (SDL_gamecontrollers) {
1935 SDL_gamecontrollers->ref_count = 1;
1937 }
1939}
1940
1941void
1943{
1944 ControllerMapping_t *pControllerMap;
1945
1946 while (s_pSupportedControllers) {
1947 pControllerMap = s_pSupportedControllers;
1949 SDL_free(pControllerMap->name);
1950 SDL_free(pControllerMap->mapping);
1951 SDL_free(pControllerMap);
1952 }
1953
1955
1960
1964 }
1968 }
1969}
1970
1971/*
1972 * Event filter to transform joystick events into appropriate game controller ones
1973 */
1974static int
1976{
1977 int posted;
1978
1979 /* translate the event, if desired */
1980 posted = 0;
1981#if !SDL_EVENTS_DISABLED
1984 event.type = SDL_CONTROLLERAXISMOTION;
1985 event.caxis.which = gamecontroller->joystick->instance_id;
1986 event.caxis.axis = axis;
1987 event.caxis.value = value;
1988 posted = SDL_PushEvent(&event) == 1;
1989 }
1990#endif /* !SDL_EVENTS_DISABLED */
1991 return (posted);
1992}
1993
1994
1995/*
1996 * Event filter to transform joystick events into appropriate game controller ones
1997 */
1998static int
2000{
2001 int posted;
2002#if !SDL_EVENTS_DISABLED
2004
2006 return (0);
2007
2008 switch (state) {
2009 case SDL_PRESSED:
2010 event.type = SDL_CONTROLLERBUTTONDOWN;
2011 break;
2012 case SDL_RELEASED:
2013 event.type = SDL_CONTROLLERBUTTONUP;
2014 break;
2015 default:
2016 /* Invalid state -- bail */
2017 return (0);
2018 }
2019#endif /* !SDL_EVENTS_DISABLED */
2020
2022 Uint32 now = SDL_GetTicks();
2023 if (state == SDL_PRESSED) {
2024 gamecontroller->guide_button_down = now;
2025
2026 if (gamecontroller->joystick->delayed_guide_button) {
2027 /* Skip duplicate press */
2028 return (0);
2029 }
2030 } else {
2031 if (!SDL_TICKS_PASSED(now, gamecontroller->guide_button_down+SDL_MINIMUM_GUIDE_BUTTON_DELAY_MS) && !gamecontroller->joystick->force_recentering) {
2032 gamecontroller->joystick->delayed_guide_button = SDL_TRUE;
2033 return (0);
2034 }
2035 gamecontroller->joystick->delayed_guide_button = SDL_FALSE;
2036 }
2037 }
2038
2039 /* translate the event, if desired */
2040 posted = 0;
2041#if !SDL_EVENTS_DISABLED
2042 if (SDL_GetEventState(event.type) == SDL_ENABLE) {
2043 event.cbutton.which = gamecontroller->joystick->instance_id;
2044 event.cbutton.button = button;
2045 event.cbutton.state = state;
2046 posted = SDL_PushEvent(&event) == 1;
2047 }
2048#endif /* !SDL_EVENTS_DISABLED */
2049 return (posted);
2050}
2051
2052/*
2053 * Turn off controller events
2054 */
2055int
2057{
2058#if SDL_EVENTS_DISABLED
2059 return SDL_IGNORE;
2060#else
2061 const Uint32 event_list[] = {
2064 };
2065 unsigned int i;
2066
2067 switch (state) {
2068 case SDL_QUERY:
2069 state = SDL_IGNORE;
2070 for (i = 0; i < SDL_arraysize(event_list); ++i) {
2071 state = SDL_EventState(event_list[i], SDL_QUERY);
2072 if (state == SDL_ENABLE) {
2073 break;
2074 }
2075 }
2076 break;
2077 default:
2078 for (i = 0; i < SDL_arraysize(event_list); ++i) {
2079 SDL_EventState(event_list[i], state);
2080 }
2081 break;
2082 }
2083 return (state);
2084#endif /* SDL_EVENTS_DISABLED */
2085}
2086
2087void
2089{
2090 SDL_GameController *controllerlist = SDL_gamecontrollers;
2091 while (controllerlist) {
2092 if (controllerlist->joystick == joystick) {
2094 break;
2095 }
2096 controllerlist = controllerlist->next;
2097 }
2098}
2099
2100/* vi: set ts=4 sw=4 expandtab: */
unsigned int size_t
#define SDL_SetError
#define SDL_memset
#define SDL_strchr
#define SDL_JoystickGetDeviceInstanceID
#define SDL_JoystickName
#define SDL_JoystickUpdate
#define SDL_LockJoysticks
#define SDL_DelHintCallback
#define SDL_PushEvent
#define SDL_JoystickGetPlayerIndex
#define SDL_isdigit
#define SDL_JoystickNameForIndex
#define SDL_JoystickGetAxis
#define SDL_strlcat
#define SDL_JoystickClose
#define SDL_DelEventWatch
#define SDL_JoystickRumble
#define SDL_JoystickGetHat
#define SDL_JoystickGetGUIDString
#define SDL_JoystickOpen
#define SDL_NumJoysticks
#define SDL_AndroidGetInternalStoragePath
#define SDL_AddEventWatch
#define SDL_RWread
#define SDL_malloc
#define SDL_strlen
#define SDL_realloc
#define SDL_strcasecmp
#define SDL_JoystickGetDeviceGUID
#define SDL_EventState
#define SDL_strlcpy
#define SDL_GetPlatform
#define SDL_JoystickGetVendor
#define SDL_JoystickGetAttached
#define SDL_strtol
#define SDL_free
#define SDL_JoystickGetButton
#define SDL_strdup
#define SDL_strcmp
#define SDL_memcmp
#define SDL_JoystickGetProductVersion
#define SDL_strstr
#define SDL_UnlockJoysticks
#define SDL_PeepEvents
#define SDL_GetHintBoolean
#define SDL_RWsize
#define SDL_memcpy
#define SDL_LoadFile
#define SDL_JoystickGetGUIDFromString
#define SDL_atoi
#define SDL_AddHintCallback
#define SDL_snprintf
#define SDL_calloc
#define SDL_GetHint
#define SDL_RWclose
#define SDL_strncasecmp
#define SDL_JoystickGetProduct
#define SDL_SwapLE16(X)
Definition: SDL_endian.h:232
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
#define SDL_InvalidParamError(param)
Definition: SDL_error.h:54
@ SDL_JOYDEVICEADDED
Definition: SDL_events.h:116
@ SDL_JOYBUTTONDOWN
Definition: SDL_events.h:114
@ SDL_JOYDEVICEREMOVED
Definition: SDL_events.h:117
@ SDL_JOYBUTTONUP
Definition: SDL_events.h:115
@ SDL_CONTROLLERBUTTONUP
Definition: SDL_events.h:122
@ SDL_CONTROLLERDEVICEADDED
Definition: SDL_events.h:123
@ SDL_CONTROLLERBUTTONDOWN
Definition: SDL_events.h:121
@ SDL_CONTROLLERAXISMOTION
Definition: SDL_events.h:120
@ SDL_CONTROLLERDEVICEREMOVED
Definition: SDL_events.h:124
@ SDL_CONTROLLERDEVICEREMAPPED
Definition: SDL_events.h:125
@ SDL_JOYAXISMOTION
Definition: SDL_events.h:111
@ SDL_JOYHATMOTION
Definition: SDL_events.h:113
#define SDL_QUERY
Definition: SDL_events.h:756
#define SDL_GetEventState(type)
Definition: SDL_events.h:772
@ SDL_ADDEVENT
Definition: SDL_events.h:615
@ SDL_PEEKEVENT
Definition: SDL_events.h:616
@ SDL_GETEVENT
Definition: SDL_events.h:617
#define SDL_RELEASED
Definition: SDL_events.h:49
#define SDL_ENABLE
Definition: SDL_events.h:759
#define SDL_PRESSED
Definition: SDL_events.h:50
#define SDL_IGNORE
Definition: SDL_events.h:757
static char * SDL_PrivateGetControllerGUIDFromMappingString(const char *pMapping)
char * SDL_GameControllerMappingForDeviceIndex(int joystick_index)
SDL_bool SDL_IsGameController(int device_index)
static ControllerMapping_t * s_pDefaultMapping
void SDL_GameControllerQuit(void)
void SDL_GameControllerUpdate(void)
int SDL_GameControllerInit(void)
static ControllerMapping_t * SDL_PrivateGetControllerMappingForNameAndGUID(const char *name, SDL_JoystickGUID guid)
int SDL_GameControllerAddMappingsFromRW(SDL_RWops *rw, int freerw)
void SDL_GameControllerHandleDelayedGuideButton(SDL_Joystick *joystick)
static int SDL_PrivateGameControllerButton(SDL_GameController *gamecontroller, SDL_GameControllerButton button, Uint8 state)
void SDL_GameControllerQuitMappings(void)
const char * SDL_GameControllerGetStringForAxis(SDL_GameControllerAxis axis)
SDL_GameController * SDL_GameControllerFromInstanceID(SDL_JoystickID joyid)
static void SDL_PrivateGameControllerParseElement(SDL_GameController *gamecontroller, const char *szGameButton, const char *szJoystickButton)
static int SDL_PrivateGameControllerAxis(SDL_GameController *gamecontroller, SDL_GameControllerAxis axis, Sint16 value)
static ControllerMapping_t * s_pHIDAPIMapping
static void SDL_PrivateLoadButtonMapping(SDL_GameController *gamecontroller, const char *pchName, const char *pchMapping)
int SDL_GameControllerNumMappings(void)
void SDL_GameControllerClose(SDL_GameController *gamecontroller)
int SDL_GameControllerEventState(int state)
int SDL_GameControllerRumble(SDL_GameController *gamecontroller, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
static void SDL_PrivateGameControllerRefreshMapping(ControllerMapping_t *pControllerMapping)
static SDL_vidpid_list SDL_allowed_controllers
static void SDL_LoadVIDPIDListFromHint(const char *hint, SDL_vidpid_list *list)
static void SDL_PrivateGameControllerParseControllerConfigString(SDL_GameController *gamecontroller, const char *pchString)
static void SDL_GameControllerLoadHints()
SDL_bool SDL_IsGameControllerNameAndGUID(const char *name, SDL_JoystickGUID guid)
SDL_GameControllerButtonBind SDL_GameControllerGetBindForAxis(SDL_GameController *gamecontroller, SDL_GameControllerAxis axis)
static int SDL_GameControllerEventWatcher(void *userdata, SDL_Event *event)
const char * SDL_GameControllerName(SDL_GameController *gamecontroller)
char * SDL_GameControllerMappingForGUID(SDL_JoystickGUID guid)
static SDL_vidpid_list SDL_ignored_controllers
static ControllerMapping_t * s_pSupportedControllers
static SDL_bool HasSameOutput(SDL_ExtendedGameControllerBind *a, SDL_ExtendedGameControllerBind *b)
SDL_GameControllerButton SDL_GameControllerGetButtonFromString(const char *pchString)
static const char * map_StringForControllerAxis[]
const char * SDL_GameControllerGetStringForButton(SDL_GameControllerButton axis)
static void ResetOutput(SDL_GameController *gamecontroller, SDL_ExtendedGameControllerBind *bind)
int SDL_GameControllerAddMapping(const char *mappingString)
SDL_GameControllerAxis SDL_GameControllerGetAxisFromString(const char *pchString)
static SDL_JoystickGUID s_zeroGUID
static void HandleJoystickButton(SDL_GameController *gamecontroller, int button, Uint8 state)
static const char * map_StringForControllerButton[]
static SDL_bool SDL_GetControllerMappingFilePath(char *path, size_t size)
#define SDL_MINIMUM_GUIDE_BUTTON_DELAY_MS
Uint16 SDL_GameControllerGetVendor(SDL_GameController *gamecontroller)
const char * SDL_GameControllerNameForIndex(int device_index)
static void UpdateEventsForDeviceRemoval()
#define SDL_CONTROLLER_PLATFORM_FIELD
static void HandleJoystickHat(SDL_GameController *gamecontroller, int hat, Uint8 value)
static char * SDL_PrivateGetControllerMappingFromMappingString(const char *pMapping)
SDL_bool SDL_ShouldIgnoreGameController(const char *name, SDL_JoystickGUID guid)
Uint16 SDL_GameControllerGetProductVersion(SDL_GameController *gamecontroller)
static ControllerMapping_t * s_pXInputMapping
SDL_Joystick * SDL_GameControllerGetJoystick(SDL_GameController *gamecontroller)
static void HandleJoystickAxis(SDL_GameController *gamecontroller, int axis, int value)
SDL_GameController * SDL_GameControllerOpen(int device_index)
static ControllerMapping_t * SDL_PrivateGetControllerMappingForGUID(SDL_JoystickGUID *guid, SDL_bool exact_match)
char * SDL_GameControllerMapping(SDL_GameController *gamecontroller)
static SDL_GameController * SDL_gamecontrollers
SDL_ControllerMappingPriority
@ SDL_CONTROLLER_MAPPING_PRIORITY_USER
@ SDL_CONTROLLER_MAPPING_PRIORITY_API
@ SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT
static ControllerMapping_t * SDL_PrivateAddMappingForGUID(SDL_JoystickGUID jGUID, const char *mappingString, SDL_bool *existing, SDL_ControllerMappingPriority priority)
Uint8 SDL_GameControllerGetButton(SDL_GameController *gamecontroller, SDL_GameControllerButton button)
Uint16 SDL_GameControllerGetProduct(SDL_GameController *gamecontroller)
static void SDL_GameControllerIgnoreDevicesChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
Sint16 SDL_GameControllerGetAxis(SDL_GameController *gamecontroller, SDL_GameControllerAxis axis)
SDL_GameControllerButtonBind SDL_GameControllerGetBindForButton(SDL_GameController *gamecontroller, SDL_GameControllerButton button)
int SDL_GameControllerGetPlayerIndex(SDL_GameController *gamecontroller)
static void SDL_GameControllerIgnoreDevicesExceptChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
static char * SDL_PrivateGetControllerNameFromMappingString(const char *pMapping)
SDL_bool SDL_GameControllerGetAttached(SDL_GameController *gamecontroller)
int SDL_GameControllerInitMappings(void)
char * SDL_GameControllerMappingForIndex(int mapping_index)
static ControllerMapping_t * SDL_PrivateGetControllerMapping(int device_index)
static int SDL_PrivateGameControllerAddMapping(const char *mappingString, SDL_ControllerMappingPriority priority)
#define SDL_GameControllerAddMappingsFromFile(file)
SDL_GameControllerAxis
@ SDL_CONTROLLER_AXIS_LEFTX
@ SDL_CONTROLLER_AXIS_TRIGGERRIGHT
@ SDL_CONTROLLER_AXIS_INVALID
@ SDL_CONTROLLER_AXIS_RIGHTY
@ SDL_CONTROLLER_AXIS_RIGHTX
@ SDL_CONTROLLER_AXIS_MAX
@ SDL_CONTROLLER_AXIS_TRIGGERLEFT
@ SDL_CONTROLLER_AXIS_LEFTY
SDL_GameControllerButton
@ SDL_CONTROLLER_BUTTON_B
@ SDL_CONTROLLER_BUTTON_BACK
@ SDL_CONTROLLER_BUTTON_LEFTSTICK
@ SDL_CONTROLLER_BUTTON_START
@ SDL_CONTROLLER_BUTTON_DPAD_LEFT
@ SDL_CONTROLLER_BUTTON_RIGHTSHOULDER
@ SDL_CONTROLLER_BUTTON_INVALID
@ SDL_CONTROLLER_BUTTON_DPAD_DOWN
@ SDL_CONTROLLER_BUTTON_DPAD_UP
@ SDL_CONTROLLER_BUTTON_MAX
@ SDL_CONTROLLER_BUTTON_LEFTSHOULDER
@ SDL_CONTROLLER_BUTTON_GUIDE
@ SDL_CONTROLLER_BUTTON_DPAD_RIGHT
@ SDL_CONTROLLER_BUTTON_X
@ SDL_CONTROLLER_BUTTON_RIGHTSTICK
@ SDL_CONTROLLER_BUTTON_Y
@ SDL_CONTROLLER_BUTTON_A
SDL_GameControllerBindType
@ SDL_CONTROLLER_BINDTYPE_AXIS
@ SDL_CONTROLLER_BINDTYPE_HAT
@ SDL_CONTROLLER_BINDTYPE_BUTTON
static const char * s_ControllerMappings[]
#define SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT
Definition: SDL_hints.h:483
#define SDL_HINT_GAMECONTROLLERCONFIG_FILE
A variable that lets you provide a file with extra gamecontroller db entries.
Definition: SDL_hints.h:457
#define SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES
Definition: SDL_hints.h:470
#define SDL_HINT_GAMECONTROLLERCONFIG
A variable that lets you manually hint extra gamecontroller db entries.
Definition: SDL_hints.h:447
#define SDLCALL
Definition: SDL_internal.h:49
#define SDL_small_alloc(type, count, pisstack)
Definition: SDL_internal.h:39
#define SDL_small_free(ptr, isstack)
Definition: SDL_internal.h:40
SDL_bool SDL_IsJoystickHIDAPI(SDL_JoystickGUID guid)
void SDL_GetJoystickGUIDInfo(SDL_JoystickGUID guid, Uint16 *vendor, Uint16 *product, Uint16 *version)
SDL_bool SDL_IsJoystickXInput(SDL_JoystickGUID guid)
#define SDL_JOYSTICK_AXIS_MIN
Definition: SDL_joystick.h:302
Sint32 SDL_JoystickID
Definition: SDL_joystick.h:81
#define SDL_JOYSTICK_AXIS_MAX
Definition: SDL_joystick.h:301
GLboolean GLboolean GLboolean b
struct _cl_event * event
GLboolean GLboolean GLboolean GLboolean a
GLuint const GLchar * name
GLsizeiptr size
GLenum GLuint GLenum GLsizei const GLchar * buf
GLenum GLenum GLenum GLenum mapping
GLsizei const GLchar *const * path
GLsizei const GLfloat * value
GLenum GLenum GLenum input
GLenum GLint GLuint mask
#define SDL_zero(x)
Definition: SDL_stdinc.h:416
SDL_bool
Definition: SDL_stdinc.h:162
@ SDL_TRUE
Definition: SDL_stdinc.h:164
@ SDL_FALSE
Definition: SDL_stdinc.h:163
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:115
uint32_t Uint32
Definition: SDL_stdinc.h:203
int16_t Sint16
Definition: SDL_stdinc.h:185
uint16_t Uint16
Definition: SDL_stdinc.h:191
uint8_t Uint8
Definition: SDL_stdinc.h:179
#define MAKE_VIDPID(VID, PID)
Uint32 SDL_GetTicks(void)
Get the number of milliseconds since the SDL library initialization.
#define SDL_TICKS_PASSED(A, B)
Compare SDL ticks values, and return true if A has passed B.
Definition: SDL_timer.h:56
struct xkb_state * state
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:167
SDL_ExtendedGameControllerBind ** last_match_axis
SDL_ExtendedGameControllerBind * bindings
struct _SDL_GameController * next
SDL_ControllerMappingPriority priority
SDL_JoystickGUID guid
struct _ControllerMapping_t * next
SDL_GameControllerBindType outputType
union SDL_ExtendedGameControllerBind::@24 input
union SDL_ExtendedGameControllerBind::@25 output
SDL_GameControllerBindType inputType
SDL_GameControllerButton button
SDL_GameControllerBindType bindType
union SDL_GameControllerButtonBind::@0 value
Uint8 data[16]
Definition: SDL_joystick.h:71
SDL_Texture * button
SDL_Texture * axis
static SDL_Event events[EVENT_BUF_SIZE]
Definition: testgesture.c:39
General event structure.
Definition: SDL_events.h:558
Uint32 type
Definition: SDL_events.h:559
SDL_ControllerDeviceEvent cdevice
Definition: SDL_events.h:576