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