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