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