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