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