SDL  2.0
SDL_gamecontroller.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2017 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_sysjoystick.h"
29 #include "SDL_joystick_c.h"
30 #include "SDL_gamecontrollerdb.h"
31 
32 #if !SDL_EVENTS_DISABLED
33 #include "../events/SDL_events_c.h"
34 #endif
35 
36 #if defined(__ANDROID__)
37 #include "SDL_system.h"
38 #endif
39 
40 
41 #define SDL_CONTROLLER_PLATFORM_FIELD "platform:"
42 
43 /* a list of currently opened game controllers */
44 static SDL_GameController *SDL_gamecontrollers = NULL;
45 
46 typedef struct
47 {
49  union
50  {
51  int button;
52 
53  struct {
54  int axis;
55  int axis_min;
56  int axis_max;
57  } axis;
58 
59  struct {
60  int hat;
61  int hat_mask;
62  } hat;
63 
64  } input;
65 
67  union
68  {
70 
71  struct {
73  int axis_min;
74  int axis_max;
75  } axis;
76 
77  } output;
78 
80 
81 /* our hard coded list of mapping support */
82 typedef enum
83 {
88 
89 typedef struct _ControllerMapping_t
90 {
92  char *name;
93  char *mapping;
95  struct _ControllerMapping_t *next;
97 
102 
103 /* The SDL game controller structure */
105 {
106  SDL_Joystick *joystick; /* underlying joystick device */
108 
110  const char *name;
115 
116  struct _SDL_GameController *next; /* pointer to next game controller we have allocated */
117 };
118 
119 
120 typedef struct
121 {
126 
129 
130 static void
132 {
133  Uint32 entry;
134  char *spot;
135  char *file = NULL;
136 
137  list->num_entries = 0;
138 
139  if (hint && *hint == '@') {
140  spot = file = (char *)SDL_LoadFile(hint+1, NULL);
141  } else {
142  spot = (char *)hint;
143  }
144 
145  if (!spot) {
146  return;
147  }
148 
149  while ((spot = SDL_strstr(spot, "0x")) != NULL) {
150  entry = (Uint16)SDL_strtol(spot, &spot, 0);
151  entry <<= 16;
152  spot = SDL_strstr(spot, "0x");
153  if (!spot) {
154  break;
155  }
156  entry |= (Uint16)SDL_strtol(spot, &spot, 0);
157 
158  if (list->num_entries == list->max_entries) {
159  int max_entries = list->max_entries + 16;
160  Uint32 *entries = (Uint32 *)SDL_realloc(list->entries, max_entries*sizeof(*list->entries));
161  if (entries == NULL) {
162  /* Out of memory, go with what we have already */
163  break;
164  }
165  list->entries = entries;
166  list->max_entries = max_entries;
167  }
168  list->entries[list->num_entries++] = entry;
169  }
170 
171  if (file) {
172  SDL_free(file);
173  }
174 }
175 
176 static void SDLCALL
177 SDL_GameControllerIgnoreDevicesChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
178 {
179  SDL_LoadVIDPIDListFromHint(hint, &SDL_ignored_controllers);
180 }
181 
182 static void SDLCALL
183 SDL_GameControllerIgnoreDevicesExceptChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
184 {
185  SDL_LoadVIDPIDListFromHint(hint, &SDL_allowed_controllers);
186 }
187 
188 static int SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis, Sint16 value);
189 static int SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button, Uint8 state);
190 
191 /*
192  * If there is an existing add event in the queue, it needs to be modified
193  * to have the right value for which, because the number of controllers in
194  * the system is now one less.
195  */
197 {
198  int i, num_events;
199  SDL_Event *events;
200 
202  if (num_events <= 0) {
203  return;
204  }
205 
206  events = SDL_stack_alloc(SDL_Event, num_events);
207  if (!events) {
208  return;
209  }
210 
212  for (i = 0; i < num_events; ++i) {
213  --events[i].cdevice.which;
214  }
215  SDL_PeepEvents(events, num_events, SDL_ADDEVENT, 0, 0);
216 
217  SDL_stack_free(events);
218 }
219 
221 {
222  if (a->outputType != b->outputType) {
223  return SDL_FALSE;
224  }
225 
227  return (a->output.axis.axis == b->output.axis.axis);
228  } else {
229  return (a->output.button == b->output.button);
230  }
231 }
232 
233 static void ResetOutput(SDL_GameController *gamecontroller, SDL_ExtendedGameControllerBind *bind)
234 {
236  SDL_PrivateGameControllerAxis(gamecontroller, bind->output.axis.axis, 0);
237  } else {
239  }
240 }
241 
242 static void HandleJoystickAxis(SDL_GameController *gamecontroller, int axis, int value)
243 {
244  int i;
245  SDL_ExtendedGameControllerBind *last_match = gamecontroller->last_match_axis[axis];
247 
248  for (i = 0; i < gamecontroller->num_bindings; ++i) {
249  SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
250  if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS &&
251  axis == binding->input.axis.axis) {
252  if (binding->input.axis.axis_min < binding->input.axis.axis_max) {
253  if (value >= binding->input.axis.axis_min &&
254  value <= binding->input.axis.axis_max) {
255  match = binding;
256  break;
257  }
258  } else {
259  if (value >= binding->input.axis.axis_max &&
260  value <= binding->input.axis.axis_min) {
261  match = binding;
262  break;
263  }
264  }
265  }
266  }
267 
268  if (last_match && (!match || !HasSameOutput(last_match, match))) {
269  /* Clear the last input that this axis generated */
270  ResetOutput(gamecontroller, last_match);
271  }
272 
273  if (match) {
275  if (match->input.axis.axis_min != match->output.axis.axis_min || match->input.axis.axis_max != match->output.axis.axis_max) {
276  float normalized_value = (float)(value - match->input.axis.axis_min) / (match->input.axis.axis_max - match->input.axis.axis_min);
277  value = match->output.axis.axis_min + (int)(normalized_value * (match->output.axis.axis_max - match->output.axis.axis_min));
278  }
279  SDL_PrivateGameControllerAxis(gamecontroller, match->output.axis.axis, (Sint16)value);
280  } else {
281  Uint8 state;
282  int threshold = match->input.axis.axis_min + (match->input.axis.axis_max - match->input.axis.axis_min) / 2;
283  if (match->input.axis.axis_max < match->input.axis.axis_min) {
284  state = (value <= threshold) ? SDL_PRESSED : SDL_RELEASED;
285  } else {
286  state = (value >= threshold) ? SDL_PRESSED : SDL_RELEASED;
287  }
288  SDL_PrivateGameControllerButton(gamecontroller, match->output.button, state);
289  }
290  }
291  gamecontroller->last_match_axis[axis] = match;
292 }
293 
294 static void HandleJoystickButton(SDL_GameController *gamecontroller, int button, Uint8 state)
295 {
296  int i;
297 
298  for (i = 0; i < gamecontroller->num_bindings; ++i) {
299  SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
300  if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON &&
301  button == binding->input.button) {
302  if (binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
303  int value = state ? binding->output.axis.axis_max : binding->output.axis.axis_min;
304  SDL_PrivateGameControllerAxis(gamecontroller, binding->output.axis.axis, (Sint16)value);
305  } else {
306  SDL_PrivateGameControllerButton(gamecontroller, binding->output.button, state);
307  }
308  break;
309  }
310  }
311 }
312 
313 static void HandleJoystickHat(SDL_GameController *gamecontroller, int hat, Uint8 value)
314 {
315  int i;
316  Uint8 last_mask = gamecontroller->last_hat_mask[hat];
317  Uint8 changed_mask = (last_mask ^ value);
318 
319  for (i = 0; i < gamecontroller->num_bindings; ++i) {
320  SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
321  if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT && hat == binding->input.hat.hat) {
322  if ((changed_mask & binding->input.hat.hat_mask) != 0) {
323  if (value & binding->input.hat.hat_mask) {
324  if (binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
325  SDL_PrivateGameControllerAxis(gamecontroller, binding->output.axis.axis, (Sint16)binding->output.axis.axis_max);
326  } else {
327  SDL_PrivateGameControllerButton(gamecontroller, binding->output.button, SDL_PRESSED);
328  }
329  } else {
330  ResetOutput(gamecontroller, binding);
331  }
332  }
333  }
334  }
335  gamecontroller->last_hat_mask[hat] = value;
336 }
337 
338 /*
339  * Event filter to fire controller events from joystick ones
340  */
342 {
343  switch(event->type) {
344  case SDL_JOYAXISMOTION:
345  {
346  SDL_GameController *controllerlist = SDL_gamecontrollers;
347  while (controllerlist) {
348  if (controllerlist->joystick->instance_id == event->jaxis.which) {
349  HandleJoystickAxis(controllerlist, event->jaxis.axis, event->jaxis.value);
350  break;
351  }
352  controllerlist = controllerlist->next;
353  }
354  }
355  break;
356  case SDL_JOYBUTTONDOWN:
357  case SDL_JOYBUTTONUP:
358  {
359  SDL_GameController *controllerlist = SDL_gamecontrollers;
360  while (controllerlist) {
361  if (controllerlist->joystick->instance_id == event->jbutton.which) {
362  HandleJoystickButton(controllerlist, event->jbutton.button, event->jbutton.state);
363  break;
364  }
365  controllerlist = controllerlist->next;
366  }
367  }
368  break;
369  case SDL_JOYHATMOTION:
370  {
371  SDL_GameController *controllerlist = SDL_gamecontrollers;
372  while (controllerlist) {
373  if (controllerlist->joystick->instance_id == event->jhat.which) {
374  HandleJoystickHat(controllerlist, event->jhat.hat, event->jhat.value);
375  break;
376  }
377  controllerlist = controllerlist->next;
378  }
379  }
380  break;
381  case SDL_JOYDEVICEADDED:
382  {
383  if (SDL_IsGameController(event->jdevice.which)) {
384  SDL_Event deviceevent;
385  deviceevent.type = SDL_CONTROLLERDEVICEADDED;
386  deviceevent.cdevice.which = event->jdevice.which;
387  SDL_PushEvent(&deviceevent);
388  }
389  }
390  break;
392  {
393  SDL_GameController *controllerlist = SDL_gamecontrollers;
394  while (controllerlist) {
395  if (controllerlist->joystick->instance_id == event->jdevice.which) {
396  SDL_Event deviceevent;
397 
398  deviceevent.type = SDL_CONTROLLERDEVICEREMOVED;
399  deviceevent.cdevice.which = event->jdevice.which;
400  SDL_PushEvent(&deviceevent);
401 
403  break;
404  }
405  controllerlist = controllerlist->next;
406  }
407  }
408  break;
409  default:
410  break;
411  }
412 
413  return 1;
414 }
415 
416 /*
417  * Helper function to scan the mappings database for a controller with the specified GUID
418  */
420 {
421  ControllerMapping_t *pSupportedController = s_pSupportedControllers;
422  while (pSupportedController) {
423  if (SDL_memcmp(guid, &pSupportedController->guid, sizeof(*guid)) == 0) {
424  return pSupportedController;
425  }
426  pSupportedController = pSupportedController->next;
427  }
428  return NULL;
429 }
430 
431 static const char* map_StringForControllerAxis[] = {
432  "leftx",
433  "lefty",
434  "rightx",
435  "righty",
436  "lefttrigger",
437  "righttrigger",
438  NULL
439 };
440 
441 /*
442  * convert a string to its enum equivalent
443  */
445 {
446  int entry;
447 
448  if (pchString && (*pchString == '+' || *pchString == '-')) {
449  ++pchString;
450  }
451 
452  if (!pchString || !pchString[0]) {
454  }
455 
456  for (entry = 0; map_StringForControllerAxis[entry]; ++entry) {
457  if (!SDL_strcasecmp(pchString, map_StringForControllerAxis[entry]))
458  return (SDL_GameControllerAxis) entry;
459  }
461 }
462 
463 /*
464  * convert an enum to its string equivalent
465  */
467 {
470  }
471  return NULL;
472 }
473 
474 static const char* map_StringForControllerButton[] = {
475  "a",
476  "b",
477  "x",
478  "y",
479  "back",
480  "guide",
481  "start",
482  "leftstick",
483  "rightstick",
484  "leftshoulder",
485  "rightshoulder",
486  "dpup",
487  "dpdown",
488  "dpleft",
489  "dpright",
490  NULL
491 };
492 
493 /*
494  * convert a string to its enum equivalent
495  */
497 {
498  int entry;
499  if (!pchString || !pchString[0])
501 
502  for (entry = 0; map_StringForControllerButton[entry]; ++entry) {
503  if (SDL_strcasecmp(pchString, map_StringForControllerButton[entry]) == 0)
504  return (SDL_GameControllerButton) entry;
505  }
507 }
508 
509 /*
510  * convert an enum to its string equivalent
511  */
513 {
516  }
517  return NULL;
518 }
519 
520 /*
521  * given a controller button name and a joystick name update our mapping structure with it
522  */
523 static void SDL_PrivateGameControllerParseElement(SDL_GameController *gamecontroller, const char *szGameButton, const char *szJoystickButton)
524 {
528  SDL_bool invert_input = SDL_FALSE;
529  char half_axis_input = 0;
530  char half_axis_output = 0;
531 
532  if (*szGameButton == '+' || *szGameButton == '-') {
533  half_axis_output = *szGameButton++;
534  }
535 
536  axis = SDL_GameControllerGetAxisFromString(szGameButton);
537  button = SDL_GameControllerGetButtonFromString(szGameButton);
538  if (axis != SDL_CONTROLLER_AXIS_INVALID) {
540  bind.output.axis.axis = axis;
542  bind.output.axis.axis_min = 0;
543  bind.output.axis.axis_max = SDL_JOYSTICK_AXIS_MAX;
544  } else {
545  if (half_axis_output == '+') {
546  bind.output.axis.axis_min = 0;
547  bind.output.axis.axis_max = SDL_JOYSTICK_AXIS_MAX;
548  } else if (half_axis_output == '-') {
549  bind.output.axis.axis_min = 0;
550  bind.output.axis.axis_max = SDL_JOYSTICK_AXIS_MIN;
551  } else {
552  bind.output.axis.axis_min = SDL_JOYSTICK_AXIS_MIN;
553  bind.output.axis.axis_max = SDL_JOYSTICK_AXIS_MAX;
554  }
555  }
556  } else if (button != SDL_CONTROLLER_BUTTON_INVALID) {
558  bind.output.button = button;
559  } else {
560  SDL_SetError("Unexpected controller element %s", szGameButton);
561  return;
562  }
563 
564  if (*szJoystickButton == '+' || *szJoystickButton == '-') {
565  half_axis_input = *szJoystickButton++;
566  }
567  if (szJoystickButton[SDL_strlen(szJoystickButton) - 1] == '~') {
568  invert_input = SDL_TRUE;
569  }
570 
571  if (szJoystickButton[0] == 'a' && SDL_isdigit(szJoystickButton[1])) {
573  bind.input.axis.axis = SDL_atoi(&szJoystickButton[1]);
574  if (half_axis_input == '+') {
575  bind.input.axis.axis_min = 0;
576  bind.input.axis.axis_max = SDL_JOYSTICK_AXIS_MAX;
577  } else if (half_axis_input == '-') {
578  bind.input.axis.axis_min = 0;
579  bind.input.axis.axis_max = SDL_JOYSTICK_AXIS_MIN;
580  } else {
581  bind.input.axis.axis_min = SDL_JOYSTICK_AXIS_MIN;
582  bind.input.axis.axis_max = SDL_JOYSTICK_AXIS_MAX;
583  }
584  if (invert_input) {
585  int tmp = bind.input.axis.axis_min;
586  bind.input.axis.axis_min = bind.input.axis.axis_max;
587  bind.input.axis.axis_max = tmp;
588  }
589  } else if (szJoystickButton[0] == 'b' && SDL_isdigit(szJoystickButton[1])) {
591  bind.input.button = SDL_atoi(&szJoystickButton[1]);
592  } else if (szJoystickButton[0] == 'h' && SDL_isdigit(szJoystickButton[1]) &&
593  szJoystickButton[2] == '.' && SDL_isdigit(szJoystickButton[3])) {
594  int hat = SDL_atoi(&szJoystickButton[1]);
595  int mask = SDL_atoi(&szJoystickButton[3]);
597  bind.input.hat.hat = hat;
598  bind.input.hat.hat_mask = mask;
599  } else {
600  SDL_SetError("Unexpected joystick element: %s", szJoystickButton);
601  return;
602  }
603 
604  ++gamecontroller->num_bindings;
605  gamecontroller->bindings = (SDL_ExtendedGameControllerBind *)SDL_realloc(gamecontroller->bindings, gamecontroller->num_bindings * sizeof(*gamecontroller->bindings));
606  if (!gamecontroller->bindings) {
607  gamecontroller->num_bindings = 0;
608  SDL_OutOfMemory();
609  return;
610  }
611  gamecontroller->bindings[gamecontroller->num_bindings - 1] = bind;
612 }
613 
614 
615 /*
616  * given a controller mapping string update our mapping object
617  */
618 static void
619 SDL_PrivateGameControllerParseControllerConfigString(SDL_GameController *gamecontroller, const char *pchString)
620 {
621  char szGameButton[20];
622  char szJoystickButton[20];
623  SDL_bool bGameButton = SDL_TRUE;
624  int i = 0;
625  const char *pchPos = pchString;
626 
627  SDL_zero(szGameButton);
628  SDL_zero(szJoystickButton);
629 
630  while (pchPos && *pchPos) {
631  if (*pchPos == ':') {
632  i = 0;
633  bGameButton = SDL_FALSE;
634  } else if (*pchPos == ' ') {
635 
636  } else if (*pchPos == ',') {
637  i = 0;
638  bGameButton = SDL_TRUE;
639  SDL_PrivateGameControllerParseElement(gamecontroller, szGameButton, szJoystickButton);
640  SDL_zero(szGameButton);
641  SDL_zero(szJoystickButton);
642 
643  } else if (bGameButton) {
644  if (i >= sizeof(szGameButton)) {
645  SDL_SetError("Button name too large: %s", szGameButton);
646  return;
647  }
648  szGameButton[i] = *pchPos;
649  i++;
650  } else {
651  if (i >= sizeof(szJoystickButton)) {
652  SDL_SetError("Joystick button name too large: %s", szJoystickButton);
653  return;
654  }
655  szJoystickButton[i] = *pchPos;
656  i++;
657  }
658  pchPos++;
659  }
660 
661  SDL_PrivateGameControllerParseElement(gamecontroller, szGameButton, szJoystickButton);
662 
663 }
664 
665 /*
666  * Make a new button mapping struct
667  */
668 static void SDL_PrivateLoadButtonMapping(SDL_GameController *gamecontroller, SDL_JoystickGUID guid, const char *pchName, const char *pchMapping)
669 {
670  int i;
671 
672  gamecontroller->guid = guid;
673  gamecontroller->name = pchName;
674  gamecontroller->num_bindings = 0;
675  SDL_memset(gamecontroller->last_match_axis, 0, gamecontroller->joystick->naxes * sizeof(*gamecontroller->last_match_axis));
676 
677  SDL_PrivateGameControllerParseControllerConfigString(gamecontroller, pchMapping);
678 
679  /* Set the zero point for triggers */
680  for (i = 0; i < gamecontroller->num_bindings; ++i) {
681  SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
682  if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS &&
684  (binding->output.axis.axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT ||
685  binding->output.axis.axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT)) {
686  if (binding->input.axis.axis < gamecontroller->joystick->naxes) {
687  gamecontroller->joystick->axes[binding->input.axis.axis].value =
688  gamecontroller->joystick->axes[binding->input.axis.axis].zero = (Sint16)binding->input.axis.axis_min;
689  }
690  }
691  }
692 }
693 
694 
695 /*
696  * grab the guid string from a mapping string
697  */
698 static char *SDL_PrivateGetControllerGUIDFromMappingString(const char *pMapping)
699 {
700  const char *pFirstComma = SDL_strchr(pMapping, ',');
701  if (pFirstComma) {
702  char *pchGUID = SDL_malloc(pFirstComma - pMapping + 1);
703  if (!pchGUID) {
704  SDL_OutOfMemory();
705  return NULL;
706  }
707  SDL_memcpy(pchGUID, pMapping, pFirstComma - pMapping);
708  pchGUID[pFirstComma - pMapping] = '\0';
709 
710  /* Convert old style GUIDs to the new style in 2.0.5 */
711 #if __WIN32__
712  if (SDL_strlen(pchGUID) == 32 &&
713  SDL_memcmp(&pchGUID[20], "504944564944", 12) == 0) {
714  SDL_memcpy(&pchGUID[20], "000000000000", 12);
715  SDL_memcpy(&pchGUID[16], &pchGUID[4], 4);
716  SDL_memcpy(&pchGUID[8], &pchGUID[0], 4);
717  SDL_memcpy(&pchGUID[0], "03000000", 8);
718  }
719 #elif __MACOSX__
720  if (SDL_strlen(pchGUID) == 32 &&
721  SDL_memcmp(&pchGUID[4], "000000000000", 12) == 0 &&
722  SDL_memcmp(&pchGUID[20], "000000000000", 12) == 0) {
723  SDL_memcpy(&pchGUID[20], "000000000000", 12);
724  SDL_memcpy(&pchGUID[8], &pchGUID[0], 4);
725  SDL_memcpy(&pchGUID[0], "03000000", 8);
726  }
727 #endif
728  return pchGUID;
729  }
730  return NULL;
731 }
732 
733 
734 /*
735  * grab the name string from a mapping string
736  */
737 static char *SDL_PrivateGetControllerNameFromMappingString(const char *pMapping)
738 {
739  const char *pFirstComma, *pSecondComma;
740  char *pchName;
741 
742  pFirstComma = SDL_strchr(pMapping, ',');
743  if (!pFirstComma)
744  return NULL;
745 
746  pSecondComma = SDL_strchr(pFirstComma + 1, ',');
747  if (!pSecondComma)
748  return NULL;
749 
750  pchName = SDL_malloc(pSecondComma - pFirstComma);
751  if (!pchName) {
752  SDL_OutOfMemory();
753  return NULL;
754  }
755  SDL_memcpy(pchName, pFirstComma + 1, pSecondComma - pFirstComma);
756  pchName[pSecondComma - pFirstComma - 1] = 0;
757  return pchName;
758 }
759 
760 
761 /*
762  * grab the button mapping string from a mapping string
763  */
764 static char *SDL_PrivateGetControllerMappingFromMappingString(const char *pMapping)
765 {
766  const char *pFirstComma, *pSecondComma;
767 
768  pFirstComma = SDL_strchr(pMapping, ',');
769  if (!pFirstComma)
770  return NULL;
771 
772  pSecondComma = SDL_strchr(pFirstComma + 1, ',');
773  if (!pSecondComma)
774  return NULL;
775 
776  return SDL_strdup(pSecondComma + 1); /* mapping is everything after the 3rd comma */
777 }
778 
779 /*
780  * Helper function to refresh a mapping
781  */
783 {
784  SDL_GameController *gamecontrollerlist = SDL_gamecontrollers;
785  while (gamecontrollerlist) {
786  if (!SDL_memcmp(&gamecontrollerlist->guid, &pControllerMapping->guid, sizeof(pControllerMapping->guid))) {
788  event.type = SDL_CONTROLLERDEVICEREMAPPED;
789  event.cdevice.which = gamecontrollerlist->joystick->instance_id;
790  SDL_PushEvent(&event);
791 
792  /* Not really threadsafe. Should this lock access within SDL_GameControllerEventWatcher? */
793  SDL_PrivateLoadButtonMapping(gamecontrollerlist, pControllerMapping->guid, pControllerMapping->name, pControllerMapping->mapping);
794  }
795 
796  gamecontrollerlist = gamecontrollerlist->next;
797  }
798 }
799 
800 /*
801  * Helper function to add a mapping for a guid
802  */
803 static ControllerMapping_t *
804 SDL_PrivateAddMappingForGUID(SDL_JoystickGUID jGUID, const char *mappingString, SDL_bool *existing, SDL_ControllerMappingPriority priority)
805 {
806  char *pchName;
807  char *pchMapping;
808  ControllerMapping_t *pControllerMapping;
809 
810  pchName = SDL_PrivateGetControllerNameFromMappingString(mappingString);
811  if (!pchName) {
812  SDL_SetError("Couldn't parse name from %s", mappingString);
813  return NULL;
814  }
815 
816  pchMapping = SDL_PrivateGetControllerMappingFromMappingString(mappingString);
817  if (!pchMapping) {
818  SDL_free(pchName);
819  SDL_SetError("Couldn't parse %s", mappingString);
820  return NULL;
821  }
822 
823  pControllerMapping = SDL_PrivateGetControllerMappingForGUID(&jGUID);
824  if (pControllerMapping) {
825  /* Only overwrite the mapping if the priority is the same or higher. */
826  if (pControllerMapping->priority <= priority) {
827  /* Update existing mapping */
828  SDL_free(pControllerMapping->name);
829  pControllerMapping->name = pchName;
830  SDL_free(pControllerMapping->mapping);
831  pControllerMapping->mapping = pchMapping;
832  pControllerMapping->priority = priority;
833  /* refresh open controllers */
834  SDL_PrivateGameControllerRefreshMapping(pControllerMapping);
835  } else {
836  SDL_free(pchName);
837  SDL_free(pchMapping);
838  }
839  *existing = SDL_TRUE;
840  } else {
841  pControllerMapping = SDL_malloc(sizeof(*pControllerMapping));
842  if (!pControllerMapping) {
843  SDL_free(pchName);
844  SDL_free(pchMapping);
845  SDL_OutOfMemory();
846  return NULL;
847  }
848  pControllerMapping->guid = jGUID;
849  pControllerMapping->name = pchName;
850  pControllerMapping->mapping = pchMapping;
851  pControllerMapping->next = NULL;
852  pControllerMapping->priority = priority;
853 
854  if (s_pSupportedControllers) {
855  /* Add the mapping to the end of the list */
856  ControllerMapping_t *pCurrMapping, *pPrevMapping;
857 
858  for ( pPrevMapping = s_pSupportedControllers, pCurrMapping = pPrevMapping->next;
859  pCurrMapping;
860  pPrevMapping = pCurrMapping, pCurrMapping = pCurrMapping->next ) {
861  continue;
862  }
863  pPrevMapping->next = pControllerMapping;
864  } else {
865  s_pSupportedControllers = pControllerMapping;
866  }
867  *existing = SDL_FALSE;
868  }
869  return pControllerMapping;
870 }
871 
872 /*
873  * Helper function to determine pre-calculated offset to certain joystick mappings
874  */
876 {
878 
880 #if defined(SDL_JOYSTICK_EMSCRIPTEN)
881  if (!mapping && s_pEmscriptenMapping) {
882  mapping = s_pEmscriptenMapping;
883  }
884 #else
885  (void) s_pEmscriptenMapping; /* pacify ARMCC */
886 #endif
887 #ifdef __LINUX__
888  if (!mapping && name) {
889  if (SDL_strstr(name, "Xbox 360 Wireless Receiver")) {
890  /* The Linux driver xpad.c maps the wireless dpad to buttons */
891  SDL_bool existing;
892  mapping = SDL_PrivateAddMappingForGUID(guid,
893 "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,",
895  }
896  }
897 #endif /* __LINUX__ */
898 
899  if (!mapping && name) {
900  if (SDL_strstr(name, "Xbox") || SDL_strstr(name, "X-Box") || SDL_strstr(name, "XBOX")) {
901  mapping = s_pXInputMapping;
902  }
903  }
904  return mapping;
905 }
906 
908 {
909  const char *name;
912 
914  name = SDL_JoystickNameForIndex(device_index);
915  guid = SDL_JoystickGetDeviceGUID(device_index);
916  mapping = SDL_PrivateGetControllerMappingForNameAndGUID(name, guid);
917 #if SDL_JOYSTICK_XINPUT
918  if (!mapping && SDL_SYS_IsXInputGamepad_DeviceIndex(device_index)) {
919  mapping = s_pXInputMapping;
920  }
921 #endif
923  return mapping;
924 }
925 
926 /*
927  * Add or update an entry into the Mappings Database
928  */
929 int
931 {
932  const char *platform = SDL_GetPlatform();
933  int controllers = 0;
934  char *buf, *line, *line_end, *tmp, *comma, line_platform[64];
935  size_t db_size, platform_len;
936 
937  if (rw == NULL) {
938  return SDL_SetError("Invalid RWops");
939  }
940  db_size = (size_t)SDL_RWsize(rw);
941 
942  buf = (char *)SDL_malloc(db_size + 1);
943  if (buf == NULL) {
944  if (freerw) {
945  SDL_RWclose(rw);
946  }
947  return SDL_SetError("Could not allocate space to read DB into memory");
948  }
949 
950  if (SDL_RWread(rw, buf, db_size, 1) != 1) {
951  if (freerw) {
952  SDL_RWclose(rw);
953  }
954  SDL_free(buf);
955  return SDL_SetError("Could not read DB");
956  }
957 
958  if (freerw) {
959  SDL_RWclose(rw);
960  }
961 
962  buf[db_size] = '\0';
963  line = buf;
964 
965  while (line < buf + db_size) {
966  line_end = SDL_strchr(line, '\n');
967  if (line_end != NULL) {
968  *line_end = '\0';
969  } else {
970  line_end = buf + db_size;
971  }
972 
973  /* Extract and verify the platform */
975  if (tmp != NULL) {
977  comma = SDL_strchr(tmp, ',');
978  if (comma != NULL) {
979  platform_len = comma - tmp + 1;
980  if (platform_len + 1 < SDL_arraysize(line_platform)) {
981  SDL_strlcpy(line_platform, tmp, platform_len);
982  if (SDL_strncasecmp(line_platform, platform, platform_len) == 0 &&
983  SDL_GameControllerAddMapping(line) > 0) {
984  controllers++;
985  }
986  }
987  }
988  }
989 
990  line = line_end + 1;
991  }
992 
993  SDL_free(buf);
994  return controllers;
995 }
996 
997 /*
998  * Add or update an entry into the Mappings Database with a priority
999  */
1000 static int
1002 {
1003  char *pchGUID;
1004  SDL_JoystickGUID jGUID;
1005  SDL_bool is_xinput_mapping = SDL_FALSE;
1006  SDL_bool is_emscripten_mapping = SDL_FALSE;
1007  SDL_bool existing = SDL_FALSE;
1008  ControllerMapping_t *pControllerMapping;
1009 
1010  if (!mappingString) {
1011  return SDL_InvalidParamError("mappingString");
1012  }
1013 
1014  pchGUID = SDL_PrivateGetControllerGUIDFromMappingString(mappingString);
1015  if (!pchGUID) {
1016  return SDL_SetError("Couldn't parse GUID from %s", mappingString);
1017  }
1018  if (!SDL_strcasecmp(pchGUID, "xinput")) {
1019  is_xinput_mapping = SDL_TRUE;
1020  }
1021  if (!SDL_strcasecmp(pchGUID, "emscripten")) {
1022  is_emscripten_mapping = SDL_TRUE;
1023  }
1024  jGUID = SDL_JoystickGetGUIDFromString(pchGUID);
1025  SDL_free(pchGUID);
1026 
1027  pControllerMapping = SDL_PrivateAddMappingForGUID(jGUID, mappingString, &existing, priority);
1028  if (!pControllerMapping) {
1029  return -1;
1030  }
1031 
1032  if (existing) {
1033  return 0;
1034  } else {
1035  if (is_xinput_mapping) {
1036  s_pXInputMapping = pControllerMapping;
1037  }
1038  if (is_emscripten_mapping) {
1039  s_pEmscriptenMapping = pControllerMapping;
1040  }
1041  return 1;
1042  }
1043 }
1044 
1045 /*
1046  * Add or update an entry into the Mappings Database
1047  */
1048 int
1049 SDL_GameControllerAddMapping(const char *mappingString)
1050 {
1052 }
1053 
1054 /*
1055  * Get the number of mappings installed
1056  */
1057 int
1059 {
1060  int num_mappings = 0;
1062 
1063  for (mapping = s_pSupportedControllers; mapping; mapping = mapping->next) {
1064  if (SDL_memcmp(&mapping->guid, &s_zeroGUID, sizeof(mapping->guid)) == 0) {
1065  continue;
1066  }
1067  ++num_mappings;
1068  }
1069  return num_mappings;
1070 }
1071 
1072 /*
1073  * Get the mapping at a particular index.
1074  */
1075 char *
1077 {
1079 
1080  for (mapping = s_pSupportedControllers; mapping; mapping = mapping->next) {
1081  if (SDL_memcmp(&mapping->guid, &s_zeroGUID, sizeof(mapping->guid)) == 0) {
1082  continue;
1083  }
1084  if (mapping_index == 0) {
1085  char *pMappingString;
1086  char pchGUID[33];
1087  size_t needed;
1088 
1089  SDL_JoystickGetGUIDString(mapping->guid, pchGUID, sizeof(pchGUID));
1090  /* allocate enough memory for GUID + ',' + name + ',' + mapping + \0 */
1091  needed = SDL_strlen(pchGUID) + 1 + SDL_strlen(mapping->name) + 1 + SDL_strlen(mapping->mapping) + 1;
1092  pMappingString = SDL_malloc(needed);
1093  if (!pMappingString) {
1094  SDL_OutOfMemory();
1095  return NULL;
1096  }
1097  SDL_snprintf(pMappingString, needed, "%s,%s,%s", pchGUID, mapping->name, mapping->mapping);
1098  return pMappingString;
1099  }
1100  --mapping_index;
1101  }
1102  return NULL;
1103 }
1104 
1105 /*
1106  * Get the mapping string for this GUID
1107  */
1108 char *
1110 {
1111  char *pMappingString = NULL;
1113  if (mapping) {
1114  char pchGUID[33];
1115  size_t needed;
1116  SDL_JoystickGetGUIDString(guid, pchGUID, sizeof(pchGUID));
1117  /* allocate enough memory for GUID + ',' + name + ',' + mapping + \0 */
1118  needed = SDL_strlen(pchGUID) + 1 + SDL_strlen(mapping->name) + 1 + SDL_strlen(mapping->mapping) + 1;
1119  pMappingString = SDL_malloc(needed);
1120  if (!pMappingString) {
1121  SDL_OutOfMemory();
1122  return NULL;
1123  }
1124  SDL_snprintf(pMappingString, needed, "%s,%s,%s", pchGUID, mapping->name, mapping->mapping);
1125  }
1126  return pMappingString;
1127 }
1128 
1129 /*
1130  * Get the mapping string for this device
1131  */
1132 char *
1133 SDL_GameControllerMapping(SDL_GameController * gamecontroller)
1134 {
1135  if (!gamecontroller) {
1136  return NULL;
1137  }
1138 
1139  return SDL_GameControllerMappingForGUID(gamecontroller->guid);
1140 }
1141 
1142 static void
1144 {
1145  const char *hint = SDL_GetHint(SDL_HINT_GAMECONTROLLERCONFIG);
1146  if (hint && hint[0]) {
1147  size_t nchHints = SDL_strlen(hint);
1148  char *pUserMappings = SDL_malloc(nchHints + 1);
1149  char *pTempMappings = pUserMappings;
1150  SDL_memcpy(pUserMappings, hint, nchHints);
1151  pUserMappings[nchHints] = '\0';
1152  while (pUserMappings) {
1153  char *pchNewLine = NULL;
1154 
1155  pchNewLine = SDL_strchr(pUserMappings, '\n');
1156  if (pchNewLine)
1157  *pchNewLine = '\0';
1158 
1160 
1161  if (pchNewLine) {
1162  pUserMappings = pchNewLine + 1;
1163  } else {
1164  pUserMappings = NULL;
1165  }
1166  }
1167  SDL_free(pTempMappings);
1168  }
1169 }
1170 
1171 /*
1172  * Fill the given buffer with the expected controller mapping filepath.
1173  * Usually this will just be CONTROLLER_MAPPING_FILE, but for Android,
1174  * we want to get the internal storage path.
1175  */
1177 {
1178 #ifdef CONTROLLER_MAPPING_FILE
1179 #define STRING(X) SDL_STRINGIFY_ARG(X)
1180  return SDL_strlcpy(path, STRING(CONTROLLER_MAPPING_FILE), size) < size;
1181 #elif defined(__ANDROID__)
1182  return SDL_snprintf(path, size, "%s/controller_map.txt", SDL_AndroidGetInternalStoragePath()) < size;
1183 #else
1184  return SDL_FALSE;
1185 #endif
1186 }
1187 
1188 /*
1189  * Initialize the game controller system, mostly load our DB of controller config mappings
1190  */
1191 int
1193 {
1194  char szControllerMapPath[1024];
1195  int i = 0;
1196  const char *pMappingString = NULL;
1197  pMappingString = s_ControllerMappings[i];
1198  while (pMappingString) {
1200 
1201  i++;
1202  pMappingString = s_ControllerMappings[i];
1203  }
1204 
1205  if (SDL_GetControllerMappingFilePath(szControllerMapPath, sizeof(szControllerMapPath))) {
1206  SDL_GameControllerAddMappingsFromFile(szControllerMapPath);
1207  }
1208 
1209  /* load in any user supplied config */
1211 
1216 
1217  return (0);
1218 }
1219 
1220 int
1222 {
1223  int i;
1224 
1225  /* watch for joy events and fire controller ones if needed */
1227 
1228  /* Send added events for controllers currently attached */
1229  for (i = 0; i < SDL_NumJoysticks(); ++i) {
1230  if (SDL_IsGameController(i)) {
1231  SDL_Event deviceevent;
1232  deviceevent.type = SDL_CONTROLLERDEVICEADDED;
1233  deviceevent.cdevice.which = i;
1234  SDL_PushEvent(&deviceevent);
1235  }
1236  }
1237 
1238  return (0);
1239 }
1240 
1241 
1242 /*
1243  * Get the implementation dependent name of a controller
1244  */
1245 const char *
1247 {
1248  ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(device_index);
1249  if (pSupportedController) {
1250  return pSupportedController->name;
1251  }
1252  return NULL;
1253 }
1254 
1255 
1256 /*
1257  * Return 1 if the joystick with this name and GUID is a supported controller
1258  */
1259 SDL_bool
1261 {
1262  ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMappingForNameAndGUID(name, guid);
1263  if (pSupportedController) {
1264  return SDL_TRUE;
1265  }
1266  return SDL_FALSE;
1267 }
1268 
1269 /*
1270  * Return 1 if the joystick at this device index is a supported controller
1271  */
1272 SDL_bool
1273 SDL_IsGameController(int device_index)
1274 {
1275  ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(device_index);
1276  if (pSupportedController) {
1277  return SDL_TRUE;
1278  }
1279  return SDL_FALSE;
1280 }
1281 
1282 /*
1283  * Return 1 if the game controller should be ignored by SDL
1284  */
1286 {
1287  int i;
1288  Uint16 vendor;
1289  Uint16 product;
1290  Uint32 vidpid;
1291 
1292  if (SDL_allowed_controllers.num_entries == 0 &&
1293  SDL_ignored_controllers.num_entries == 0) {
1294  return SDL_FALSE;
1295  }
1296 
1297  SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL);
1298  vidpid = MAKE_VIDPID(vendor, product);
1299 
1300  if (SDL_GetHintBoolean("SDL_GAMECONTROLLER_ALLOW_STEAM_VIRTUAL_GAMEPAD", SDL_FALSE)) {
1301  /* 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 */
1302  SDL_bool bSteamVirtualGamepad = SDL_FALSE;
1303 #if defined(__LINUX__)
1304  bSteamVirtualGamepad = (vendor == 0x28DE && product == 0x11FF);
1305 #elif defined(__MACOSX__)
1306  bSteamVirtualGamepad = (SDL_strncmp(name, "GamePad-", 8) == 0);
1307 #elif defined(__WIN32__)
1308  /* We can't tell on Windows, but Steam will block others in input hooks */
1309  bSteamVirtualGamepad = SDL_TRUE;
1310 #endif
1311  if (bSteamVirtualGamepad) {
1312  return SDL_FALSE;
1313  }
1314  }
1315 
1316  if (SDL_allowed_controllers.num_entries > 0) {
1317  for (i = 0; i < SDL_allowed_controllers.num_entries; ++i) {
1318  if (vidpid == SDL_allowed_controllers.entries[i]) {
1319  return SDL_FALSE;
1320  }
1321  }
1322  return SDL_TRUE;
1323  } else {
1324  for (i = 0; i < SDL_ignored_controllers.num_entries; ++i) {
1325  if (vidpid == SDL_ignored_controllers.entries[i]) {
1326  return SDL_TRUE;
1327  }
1328  }
1329  return SDL_FALSE;
1330  }
1331 }
1332 
1333 /*
1334  * Open a controller for use - the index passed as an argument refers to
1335  * the N'th controller on the system. This index is the value which will
1336  * identify this controller in future controller events.
1337  *
1338  * This function returns a controller identifier, or NULL if an error occurred.
1339  */
1340 SDL_GameController *
1341 SDL_GameControllerOpen(int device_index)
1342 {
1343  SDL_GameController *gamecontroller;
1344  SDL_GameController *gamecontrollerlist;
1345  ControllerMapping_t *pSupportedController = NULL;
1346 
1347  if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
1348  SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
1349  return (NULL);
1350  }
1351 
1353 
1354  gamecontrollerlist = SDL_gamecontrollers;
1355  /* If the controller is already open, return it */
1356  while (gamecontrollerlist) {
1357  if (SDL_SYS_GetInstanceIdOfDeviceIndex(device_index) == gamecontrollerlist->joystick->instance_id) {
1358  gamecontroller = gamecontrollerlist;
1359  ++gamecontroller->ref_count;
1361  return (gamecontroller);
1362  }
1363  gamecontrollerlist = gamecontrollerlist->next;
1364  }
1365 
1366  /* Find a controller mapping */
1367  pSupportedController = SDL_PrivateGetControllerMapping(device_index);
1368  if (!pSupportedController) {
1369  SDL_SetError("Couldn't find mapping for device (%d)", device_index);
1371  return NULL;
1372  }
1373 
1374  /* Create and initialize the controller */
1375  gamecontroller = (SDL_GameController *) SDL_calloc(1, sizeof(*gamecontroller));
1376  if (gamecontroller == NULL) {
1377  SDL_OutOfMemory();
1379  return NULL;
1380  }
1381 
1382  gamecontroller->joystick = SDL_JoystickOpen(device_index);
1383  if (!gamecontroller->joystick) {
1384  SDL_free(gamecontroller);
1386  return NULL;
1387  }
1388 
1389  if (gamecontroller->joystick->naxes) {
1390  gamecontroller->last_match_axis = (SDL_ExtendedGameControllerBind **)SDL_calloc(gamecontroller->joystick->naxes, sizeof(*gamecontroller->last_match_axis));
1391  if (!gamecontroller->last_match_axis) {
1392  SDL_OutOfMemory();
1393  SDL_JoystickClose(gamecontroller->joystick);
1394  SDL_free(gamecontroller);
1396  return NULL;
1397  }
1398  }
1399  if (gamecontroller->joystick->nhats) {
1400  gamecontroller->last_hat_mask = (Uint8 *)SDL_calloc(gamecontroller->joystick->nhats, sizeof(*gamecontroller->last_hat_mask));
1401  if (!gamecontroller->last_hat_mask) {
1402  SDL_OutOfMemory();
1403  SDL_JoystickClose(gamecontroller->joystick);
1404  SDL_free(gamecontroller->last_match_axis);
1405  SDL_free(gamecontroller);
1407  return NULL;
1408  }
1409  }
1410 
1411  SDL_PrivateLoadButtonMapping(gamecontroller, pSupportedController->guid, pSupportedController->name, pSupportedController->mapping);
1412 
1413  /* Add the controller to list */
1414  ++gamecontroller->ref_count;
1415  /* Link the controller in the list */
1416  gamecontroller->next = SDL_gamecontrollers;
1417  SDL_gamecontrollers = gamecontroller;
1418 
1420 
1421  return (gamecontroller);
1422 }
1423 
1424 /*
1425  * Manually pump for controller updates.
1426  */
1427 void
1429 {
1430  /* Just for API completeness; the joystick API does all the work. */
1432 }
1433 
1434 /*
1435  * Get the current state of an axis control on a controller
1436  */
1437 Sint16
1438 SDL_GameControllerGetAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis)
1439 {
1440  int i;
1441 
1442  if (!gamecontroller)
1443  return 0;
1444 
1445  for (i = 0; i < gamecontroller->num_bindings; ++i) {
1446  SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
1447  if (binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS && binding->output.axis.axis == axis) {
1448  int value = 0;
1449  SDL_bool valid_input_range;
1450  SDL_bool valid_output_range;
1451 
1452  if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
1453  value = SDL_JoystickGetAxis(gamecontroller->joystick, binding->input.axis.axis);
1454  if (binding->input.axis.axis_min < binding->input.axis.axis_max) {
1455  valid_input_range = (value >= binding->input.axis.axis_min && value <= binding->input.axis.axis_max);
1456  } else {
1457  valid_input_range = (value >= binding->input.axis.axis_max && value <= binding->input.axis.axis_min);
1458  }
1459  if (valid_input_range) {
1460  if (binding->input.axis.axis_min != binding->output.axis.axis_min || binding->input.axis.axis_max != binding->output.axis.axis_max) {
1461  float normalized_value = (float)(value - binding->input.axis.axis_min) / (binding->input.axis.axis_max - binding->input.axis.axis_min);
1462  value = binding->output.axis.axis_min + (int)(normalized_value * (binding->output.axis.axis_max - binding->output.axis.axis_min));
1463  }
1464  }
1465  } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
1466  value = SDL_JoystickGetButton(gamecontroller->joystick, binding->input.button);
1467  if (value == SDL_PRESSED) {
1468  value = binding->output.axis.axis_max;
1469  }
1470  } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
1471  int hat_mask = SDL_JoystickGetHat(gamecontroller->joystick, binding->input.hat.hat);
1472  if (hat_mask & binding->input.hat.hat_mask) {
1473  value = binding->output.axis.axis_max;
1474  }
1475  }
1476 
1477  if (binding->output.axis.axis_min < binding->output.axis.axis_max) {
1478  valid_output_range = (value >= binding->output.axis.axis_min && value <= binding->output.axis.axis_max);
1479  } else {
1480  valid_output_range = (value >= binding->output.axis.axis_max && value <= binding->output.axis.axis_min);
1481  }
1482  /* If the value is zero, there might be another binding that makes it non-zero */
1483  if (value != 0 && valid_output_range) {
1484  return (Sint16)value;
1485  }
1486  }
1487  }
1488  return 0;
1489 }
1490 
1491 /*
1492  * Get the current state of a button on a controller
1493  */
1494 Uint8
1495 SDL_GameControllerGetButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button)
1496 {
1497  int i;
1498 
1499  if (!gamecontroller)
1500  return 0;
1501 
1502  for (i = 0; i < gamecontroller->num_bindings; ++i) {
1503  SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
1504  if (binding->outputType == SDL_CONTROLLER_BINDTYPE_BUTTON && binding->output.button == button) {
1505  if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
1506  SDL_bool valid_input_range;
1507 
1508  int value = SDL_JoystickGetAxis(gamecontroller->joystick, binding->input.axis.axis);
1509  int threshold = binding->input.axis.axis_min + (binding->input.axis.axis_max - binding->input.axis.axis_min) / 2;
1510  if (binding->input.axis.axis_min < binding->input.axis.axis_max) {
1511  valid_input_range = (value >= binding->input.axis.axis_min && value <= binding->input.axis.axis_max);
1512  if (valid_input_range) {
1513  return (value >= threshold) ? SDL_PRESSED : SDL_RELEASED;
1514  }
1515  } else {
1516  valid_input_range = (value >= binding->input.axis.axis_max && value <= binding->input.axis.axis_min);
1517  if (valid_input_range) {
1518  return (value <= threshold) ? SDL_PRESSED : SDL_RELEASED;
1519  }
1520  }
1521  } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
1522  return SDL_JoystickGetButton(gamecontroller->joystick, binding->input.button);
1523  } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
1524  int hat_mask = SDL_JoystickGetHat(gamecontroller->joystick, binding->input.hat.hat);
1525  return (hat_mask & binding->input.hat.hat_mask) ? SDL_PRESSED : SDL_RELEASED;
1526  }
1527  }
1528  }
1529  return SDL_RELEASED;
1530 }
1531 
1532 const char *
1533 SDL_GameControllerName(SDL_GameController * gamecontroller)
1534 {
1535  if (!gamecontroller)
1536  return NULL;
1537 
1538  return gamecontroller->name;
1539 }
1540 
1541 Uint16
1542 SDL_GameControllerGetVendor(SDL_GameController * gamecontroller)
1543 {
1544  return SDL_JoystickGetVendor(SDL_GameControllerGetJoystick(gamecontroller));
1545 }
1546 
1547 Uint16
1548 SDL_GameControllerGetProduct(SDL_GameController * gamecontroller)
1549 {
1550  return SDL_JoystickGetProduct(SDL_GameControllerGetJoystick(gamecontroller));
1551 }
1552 
1553 Uint16
1554 SDL_GameControllerGetProductVersion(SDL_GameController * gamecontroller)
1555 {
1557 }
1558 
1559 /*
1560  * Return if the controller in question is currently attached to the system,
1561  * \return 0 if not plugged in, 1 if still present.
1562  */
1563 SDL_bool
1564 SDL_GameControllerGetAttached(SDL_GameController * gamecontroller)
1565 {
1566  if (!gamecontroller)
1567  return SDL_FALSE;
1568 
1569  return SDL_JoystickGetAttached(gamecontroller->joystick);
1570 }
1571 
1572 /*
1573  * Get the joystick for this controller
1574  */
1575 SDL_Joystick *SDL_GameControllerGetJoystick(SDL_GameController * gamecontroller)
1576 {
1577  if (!gamecontroller)
1578  return NULL;
1579 
1580  return gamecontroller->joystick;
1581 }
1582 
1583 
1584 /*
1585  * Find the SDL_GameController that owns this instance id
1586  */
1587 SDL_GameController *
1589 {
1590  SDL_GameController *gamecontroller;
1591 
1593  gamecontroller = SDL_gamecontrollers;
1594  while (gamecontroller) {
1595  if (gamecontroller->joystick->instance_id == joyid) {
1597  return gamecontroller;
1598  }
1599  gamecontroller = gamecontroller->next;
1600  }
1602  return NULL;
1603 }
1604 
1605 
1606 /*
1607  * Get the SDL joystick layer binding for this controller axis mapping
1608  */
1610 {
1611  int i;
1613  SDL_zero(bind);
1614 
1615  if (!gamecontroller || axis == SDL_CONTROLLER_AXIS_INVALID)
1616  return bind;
1617 
1618  for (i = 0; i < gamecontroller->num_bindings; ++i) {
1619  SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
1620  if (binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS && binding->output.axis.axis == axis) {
1621  bind.bindType = binding->inputType;
1622  if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
1623  /* FIXME: There might be multiple axes bound now that we have axis ranges... */
1624  bind.value.axis = binding->input.axis.axis;
1625  } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
1626  bind.value.button = binding->input.button;
1627  } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
1628  bind.value.hat.hat = binding->input.hat.hat;
1629  bind.value.hat.hat_mask = binding->input.hat.hat_mask;
1630  }
1631  break;
1632  }
1633  }
1634  return bind;
1635 }
1636 
1637 
1638 /*
1639  * Get the SDL joystick layer binding for this controller button mapping
1640  */
1642 {
1643  int i;
1645  SDL_zero(bind);
1646 
1647  if (!gamecontroller || button == SDL_CONTROLLER_BUTTON_INVALID)
1648  return bind;
1649 
1650  for (i = 0; i < gamecontroller->num_bindings; ++i) {
1651  SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
1652  if (binding->outputType == SDL_CONTROLLER_BINDTYPE_BUTTON && binding->output.button == button) {
1653  bind.bindType = binding->inputType;
1654  if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
1655  bind.value.axis = binding->input.axis.axis;
1656  } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
1657  bind.value.button = binding->input.button;
1658  } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
1659  bind.value.hat.hat = binding->input.hat.hat;
1660  bind.value.hat.hat_mask = binding->input.hat.hat_mask;
1661  }
1662  break;
1663  }
1664  }
1665  return bind;
1666 }
1667 
1668 
1669 void
1670 SDL_GameControllerClose(SDL_GameController * gamecontroller)
1671 {
1672  SDL_GameController *gamecontrollerlist, *gamecontrollerlistprev;
1673 
1674  if (!gamecontroller)
1675  return;
1676 
1678 
1679  /* First decrement ref count */
1680  if (--gamecontroller->ref_count > 0) {
1682  return;
1683  }
1684 
1685  SDL_JoystickClose(gamecontroller->joystick);
1686 
1687  gamecontrollerlist = SDL_gamecontrollers;
1688  gamecontrollerlistprev = NULL;
1689  while (gamecontrollerlist) {
1690  if (gamecontroller == gamecontrollerlist) {
1691  if (gamecontrollerlistprev) {
1692  /* unlink this entry */
1693  gamecontrollerlistprev->next = gamecontrollerlist->next;
1694  } else {
1695  SDL_gamecontrollers = gamecontroller->next;
1696  }
1697  break;
1698  }
1699  gamecontrollerlistprev = gamecontrollerlist;
1700  gamecontrollerlist = gamecontrollerlist->next;
1701  }
1702 
1703  SDL_free(gamecontroller->bindings);
1704  SDL_free(gamecontroller->last_match_axis);
1705  SDL_free(gamecontroller->last_hat_mask);
1706  SDL_free(gamecontroller);
1707 
1709 }
1710 
1711 
1712 /*
1713  * Quit the controller subsystem
1714  */
1715 void
1717 {
1719  while (SDL_gamecontrollers) {
1720  SDL_gamecontrollers->ref_count = 1;
1722  }
1724 }
1725 
1726 void
1728 {
1729  ControllerMapping_t *pControllerMap;
1730 
1731  while (s_pSupportedControllers) {
1732  pControllerMap = s_pSupportedControllers;
1733  s_pSupportedControllers = s_pSupportedControllers->next;
1734  SDL_free(pControllerMap->name);
1735  SDL_free(pControllerMap->mapping);
1736  SDL_free(pControllerMap);
1737  }
1738 
1740 
1745 
1746  if (SDL_allowed_controllers.entries) {
1747  SDL_free(SDL_allowed_controllers.entries);
1748  SDL_zero(SDL_allowed_controllers);
1749  }
1750  if (SDL_ignored_controllers.entries) {
1751  SDL_free(SDL_ignored_controllers.entries);
1752  SDL_zero(SDL_ignored_controllers);
1753  }
1754 }
1755 
1756 /*
1757  * Event filter to transform joystick events into appropriate game controller ones
1758  */
1759 static int
1761 {
1762  int posted;
1763 
1764  /* translate the event, if desired */
1765  posted = 0;
1766 #if !SDL_EVENTS_DISABLED
1768  SDL_Event event;
1769  event.type = SDL_CONTROLLERAXISMOTION;
1770  event.caxis.which = gamecontroller->joystick->instance_id;
1771  event.caxis.axis = axis;
1772  event.caxis.value = value;
1773  posted = SDL_PushEvent(&event) == 1;
1774  }
1775 #endif /* !SDL_EVENTS_DISABLED */
1776  return (posted);
1777 }
1778 
1779 
1780 /*
1781  * Event filter to transform joystick events into appropriate game controller ones
1782  */
1783 static int
1785 {
1786  int posted;
1787 #if !SDL_EVENTS_DISABLED
1788  SDL_Event event;
1789 
1790  if (button == SDL_CONTROLLER_BUTTON_INVALID)
1791  return (0);
1792 
1793  switch (state) {
1794  case SDL_PRESSED:
1795  event.type = SDL_CONTROLLERBUTTONDOWN;
1796  break;
1797  case SDL_RELEASED:
1798  event.type = SDL_CONTROLLERBUTTONUP;
1799  break;
1800  default:
1801  /* Invalid state -- bail */
1802  return (0);
1803  }
1804 #endif /* !SDL_EVENTS_DISABLED */
1805 
1806  /* translate the event, if desired */
1807  posted = 0;
1808 #if !SDL_EVENTS_DISABLED
1809  if (SDL_GetEventState(event.type) == SDL_ENABLE) {
1810  event.cbutton.which = gamecontroller->joystick->instance_id;
1811  event.cbutton.button = button;
1812  event.cbutton.state = state;
1813  posted = SDL_PushEvent(&event) == 1;
1814  }
1815 #endif /* !SDL_EVENTS_DISABLED */
1816  return (posted);
1817 }
1818 
1819 /*
1820  * Turn off controller events
1821  */
1822 int
1824 {
1825 #if SDL_EVENTS_DISABLED
1826  return SDL_IGNORE;
1827 #else
1828  const Uint32 event_list[] = {
1831  };
1832  unsigned int i;
1833 
1834  switch (state) {
1835  case SDL_QUERY:
1836  state = SDL_IGNORE;
1837  for (i = 0; i < SDL_arraysize(event_list); ++i) {
1838  state = SDL_EventState(event_list[i], SDL_QUERY);
1839  if (state == SDL_ENABLE) {
1840  break;
1841  }
1842  }
1843  break;
1844  default:
1845  for (i = 0; i < SDL_arraysize(event_list); ++i) {
1846  SDL_EventState(event_list[i], state);
1847  }
1848  break;
1849  }
1850  return (state);
1851 #endif /* SDL_EVENTS_DISABLED */
1852 }
1853 
1854 /* vi: set ts=4 sw=4 expandtab: */
static const char * map_StringForControllerAxis[]
#define SDL_strlcpy
char * SDL_GameControllerMapping(SDL_GameController *gamecontroller)
SDL_JoystickID which
Definition: SDL_events.h:335
#define SDL_DelEventWatch
union SDL_ExtendedGameControllerBind::@22 input
Uint16 SDL_GameControllerGetProduct(SDL_GameController *gamecontroller)
SDL_GameControllerBindType
#define SDL_CONTROLLER_PLATFORM_FIELD
#define SDL_JoystickGetButton
SDL_GameControllerButton SDL_GameControllerGetButtonFromString(const char *pchString)
SDL_JoyDeviceEvent jdevice
Definition: SDL_events.h:540
#define SDL_UnlockJoysticks
#define SDL_JoystickClose
#define MAKE_VIDPID(VID, PID)
SDL_Texture * button
static int SDL_GameControllerEventWatcher(void *userdata, SDL_Event *event)
static void HandleJoystickHat(SDL_GameController *gamecontroller, int hat, Uint8 value)
SDL_JoystickGUID guid
#define SDL_JoystickGetVendor
void SDL_GameControllerQuitMappings(void)
SDL_ControllerDeviceEvent cdevice
Definition: SDL_events.h:543
int SDL_GameControllerInitMappings(void)
SDL_GameControllerButtonBind SDL_GameControllerGetBindForButton(SDL_GameController *gamecontroller, SDL_GameControllerButton button)
#define SDL_RWsize(ctx)
Definition: SDL_rwops.h:184
SDL_ControllerMappingPriority priority
SDL_JoyButtonEvent jbutton
Definition: SDL_events.h:539
struct _ControllerMapping_t * next
static void ResetOutput(SDL_GameController *gamecontroller, SDL_ExtendedGameControllerBind *bind)
static SDL_bool SDL_GetControllerMappingFilePath(char *path, size_t size)
static void UpdateEventsForDeviceRemoval()
char * SDL_GameControllerMappingForIndex(int mapping_index)
Uint16 SDL_GameControllerGetVendor(SDL_GameController *gamecontroller)
Sint16 SDL_GameControllerGetAxis(SDL_GameController *gamecontroller, SDL_GameControllerAxis axis)
SDL_GameControllerAxis SDL_GameControllerGetAxisFromString(const char *pchString)
#define SDL_JoystickNameForIndex
struct xkb_state * state
static SDL_vidpid_list SDL_ignored_controllers
static SDL_Event events[EVENT_BUF_SIZE]
Definition: testgesture.c:35
SDL_JoystickID which
Definition: SDL_events.h:283
SDL_GameControllerBindType inputType
#define SDL_GetHint
SDL_JoystickGUID guid
static ControllerMapping_t * SDL_PrivateGetControllerMappingForNameAndGUID(const char *name, SDL_JoystickGUID guid)
#define SDL_ENABLE
Definition: SDL_events.h:722
#define SDL_JoystickOpen
#define SDL_RWread(ctx, ptr, size, n)
Definition: SDL_rwops.h:187
#define SDL_NumJoysticks
SDL_Texture * axis
uint32_t Uint32
Definition: SDL_stdinc.h:181
#define SDL_InvalidParamError(param)
Definition: SDL_error.h:54
SDL_GameControllerButton
#define SDL_realloc
#define SDL_strcasecmp
static void SDL_GameControllerLoadHints()
static ControllerMapping_t * s_pEmscriptenMapping
SDL_ExtendedGameControllerBind * bindings
#define SDL_strncasecmp
#define SDL_JoystickGetGUIDString
#define SDL_strncmp
#define SDL_JoystickGetProduct
#define SDL_JoystickGetHat
GLuint const GLchar * name
struct _SDL_GameController * next
#define SDL_JoystickGetDeviceGUID
SDL_GameController * SDL_GameControllerFromInstanceID(SDL_JoystickID joyid)
#define SDL_strchr
#define SDL_GetHintBoolean
static ControllerMapping_t * SDL_PrivateGetControllerMappingForGUID(SDL_JoystickGUID *guid)
static int SDL_PrivateGameControllerAddMapping(const char *mappingString, SDL_ControllerMappingPriority priority)
#define SDL_JOYSTICK_AXIS_MIN
Definition: SDL_joystick.h:289
unsigned int size_t
void SDL_GameControllerClose(SDL_GameController *gamecontroller)
#define SDL_memcpy
#define SDL_JOYSTICK_AXIS_MAX
Definition: SDL_joystick.h:288
GLenum GLenum GLenum input
#define SDL_GetEventState(type)
Definition: SDL_events.h:735
Sint32 SDL_JoystickID
Definition: SDL_joystick.h:81
SDL_JoystickGUID guid
#define SDL_isdigit
#define SDL_PeepEvents
static SDL_GameController * SDL_gamecontrollers
static ControllerMapping_t * s_pSupportedControllers
int SDL_GameControllerEventState(int state)
SDL_JoyAxisEvent jaxis
Definition: SDL_events.h:536
void SDL_GameControllerQuit(void)
uint8_t Uint8
Definition: SDL_stdinc.h:157
#define SDL_free
int SDL_GameControllerAddMapping(const char *mappingString)
#define SDL_stack_alloc(type, count)
Definition: SDL_stdinc.h:354
struct _cl_event * event
const char * SDL_GameControllerGetStringForAxis(SDL_GameControllerAxis axis)
SDL_GameControllerBindType bindType
const char * SDL_GameControllerName(SDL_GameController *gamecontroller)
static void SDL_PrivateGameControllerParseControllerConfigString(SDL_GameController *gamecontroller, const char *pchString)
#define SDL_PushEvent
GLenum GLint GLuint mask
#define SDL_memcmp
SDL_GameControllerBindType outputType
SDL_ExtendedGameControllerBind ** last_match_axis
static SDL_bool HasSameOutput(SDL_ExtendedGameControllerBind *a, SDL_ExtendedGameControllerBind *b)
Uint16 SDL_GameControllerGetProductVersion(SDL_GameController *gamecontroller)
SDL_bool SDL_ShouldIgnoreGameController(const char *name, SDL_JoystickGUID guid)
GLsizei const GLfloat * value
#define SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT
Definition: SDL_hints.h:420
SDL_ControllerMappingPriority
static int SDL_PrivateGameControllerButton(SDL_GameController *gamecontroller, SDL_GameControllerButton button, Uint8 state)
#define SDL_JoystickGetAttached
#define SDL_strtol
#define SDL_zero(x)
Definition: SDL_stdinc.h:416
#define SDL_GetPlatform
static const char * map_StringForControllerButton[]
void SDL_GameControllerUpdate(void)
GLenum GLuint GLenum GLsizei const GLchar * buf
static ControllerMapping_t * SDL_PrivateGetControllerMapping(int device_index)
#define SDL_atoi
GLsizeiptr size
static char * SDL_PrivateGetControllerMappingFromMappingString(const char *pMapping)
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
SDL_bool SDL_IsGameControllerNameAndGUID(const char *name, SDL_JoystickGUID guid)
static void SDL_PrivateGameControllerParseElement(SDL_GameController *gamecontroller, const char *szGameButton, const char *szJoystickButton)
SDL_GameController * SDL_GameControllerOpen(int device_index)
static char * SDL_PrivateGetControllerGUIDFromMappingString(const char *pMapping)
static void HandleJoystickButton(SDL_GameController *gamecontroller, int button, Uint8 state)
static void SDL_PrivateGameControllerRefreshMapping(ControllerMapping_t *pControllerMapping)
SDL_bool SDL_IsGameController(int device_index)
#define NULL
Definition: begin_code.h:164
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_bool
Definition: SDL_stdinc.h:139
static char * SDL_PrivateGetControllerNameFromMappingString(const char *pMapping)
static void SDL_GameControllerIgnoreDevicesExceptChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
static const char * s_ControllerMappings[]
#define SDL_RWclose(ctx)
Definition: SDL_rwops.h:189
#define SDL_JoystickUpdate
static SDL_JoystickGUID s_zeroGUID
#define SDL_SetError
SDL_GameControllerButtonBind SDL_GameControllerGetBindForAxis(SDL_GameController *gamecontroller, SDL_GameControllerAxis axis)
static SDL_vidpid_list SDL_allowed_controllers
#define SDL_JoystickGetAxis
#define SDL_calloc
void SDL_GetJoystickGUIDInfo(SDL_JoystickGUID guid, Uint16 *vendor, Uint16 *product, Uint16 *version)
Definition: SDL_joystick.c:933
union SDL_GameControllerButtonBind::@0 value
#define SDL_AddEventWatch
#define SDL_strlen
#define SDL_strdup
SDL_Joystick * SDL_GameControllerGetJoystick(SDL_GameController *gamecontroller)
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 void
#define SDL_EventState
#define SDL_AddHintCallback
static ControllerMapping_t * s_pXInputMapping
#define SDL_DelHintCallback
SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
uint16_t Uint16
Definition: SDL_stdinc.h:169
int SDL_GameControllerNumMappings(void)
#define SDL_snprintf
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:93
GLenum GLenum GLenum GLenum mapping
#define SDL_HINT_GAMECONTROLLERCONFIG
A variable that lets you manually hint extra gamecontroller db entries.
Definition: SDL_hints.h:394
General event structure.
Definition: SDL_events.h:525
#define SDL_malloc
GLsizei const GLchar *const * path
SDL_GameControllerButton button
#define SDL_GameControllerAddMappingsFromFile(file)
static void SDL_PrivateLoadButtonMapping(SDL_GameController *gamecontroller, SDL_JoystickGUID guid, const char *pchName, const char *pchMapping)
#define SDL_PRESSED
Definition: SDL_events.h:50
#define SDL_QUERY
Definition: SDL_events.h:719
SDL_JoyHatEvent jhat
Definition: SDL_events.h:538
#define SDL_JoystickGetProductVersion
#define SDL_stack_free(data)
Definition: SDL_stdinc.h:355
union SDL_ExtendedGameControllerBind::@23 output
GLboolean GLboolean GLboolean GLboolean a
static void SDL_LoadVIDPIDListFromHint(const char *hint, SDL_vidpid_list *list)
int SDL_GameControllerAddMappingsFromRW(SDL_RWops *rw, int freerw)
int SDL_GameControllerInit(void)
#define SDL_RELEASED
Definition: SDL_events.h:49
const char * SDL_GameControllerGetStringForButton(SDL_GameControllerButton axis)
char * SDL_GameControllerMappingForGUID(SDL_JoystickGUID guid)
#define SDL_LockJoysticks
static ControllerMapping_t * SDL_PrivateAddMappingForGUID(SDL_JoystickGUID jGUID, const char *mappingString, SDL_bool *existing, SDL_ControllerMappingPriority priority)
#define SDLCALL
Definition: SDL_internal.h:45
Uint8 SDL_GameControllerGetButton(SDL_GameController *gamecontroller, SDL_GameControllerButton button)
GLboolean GLboolean GLboolean b
#define SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES
Definition: SDL_hints.h:407
#define SDL_AndroidGetInternalStoragePath
SDL_JoystickID which
Definition: SDL_events.h:315
SDL_GameControllerAxis
static int SDL_PrivateGameControllerAxis(SDL_GameController *gamecontroller, SDL_GameControllerAxis axis, Sint16 value)
#define SDL_LoadFile(file, datasize)
Definition: SDL_rwops.h:214
static void HandleJoystickAxis(SDL_GameController *gamecontroller, int axis, int value)
#define SDL_memset
SDL_bool SDL_GameControllerGetAttached(SDL_GameController *gamecontroller)
#define SDL_JoystickGetGUIDFromString
static void SDL_GameControllerIgnoreDevicesChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
int16_t Sint16
Definition: SDL_stdinc.h:163
#define SDL_strstr
Uint32 type
Definition: SDL_events.h:527
#define SDL_IGNORE
Definition: SDL_events.h:720
const char * SDL_GameControllerNameForIndex(int device_index)