SDL  2.0
SDL_joystick.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 joystick API for Simple DirectMedia Layer */
24 
25 #include "SDL.h"
26 #include "SDL_events.h"
27 #include "SDL_sysjoystick.h"
28 #include "SDL_assert.h"
29 #include "SDL_hints.h"
30 
31 #if !SDL_EVENTS_DISABLED
32 #include "../events/SDL_events_c.h"
33 #endif
34 #include "../video/SDL_sysvideo.h"
35 
36 
38 static SDL_Joystick *SDL_joysticks = NULL;
40 static SDL_mutex *SDL_joystick_lock = NULL; /* This needs to support recursive locks */
41 
42 void
44 {
45  if (SDL_joystick_lock) {
46  SDL_LockMutex(SDL_joystick_lock);
47  }
48 }
49 
50 void
52 {
53  if (SDL_joystick_lock) {
54  SDL_UnlockMutex(SDL_joystick_lock);
55  }
56 }
57 
58 
59 static void SDLCALL
60 SDL_JoystickAllowBackgroundEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
61 {
62  if (hint && *hint == '1') {
64  } else {
66  }
67 }
68 
69 int
71 {
72  int status;
73 
75 
76  /* Create the joystick list lock */
77  if (!SDL_joystick_lock) {
78  SDL_joystick_lock = SDL_CreateMutex();
79  }
80 
81  /* See if we should allow joystick events while in the background */
84 
85 #if !SDL_EVENTS_DISABLED
87  return -1;
88  }
89 #endif /* !SDL_EVENTS_DISABLED */
90 
91  status = SDL_SYS_JoystickInit();
92  if (status >= 0) {
93  status = 0;
94  }
95  return (status);
96 }
97 
98 /*
99  * Count the number of joysticks attached to the system
100  */
101 int
103 {
104  return SDL_SYS_NumJoysticks();
105 }
106 
107 /*
108  * Get the implementation dependent name of a joystick
109  */
110 const char *
111 SDL_JoystickNameForIndex(int device_index)
112 {
113  if (device_index < 0 || device_index >= SDL_NumJoysticks()) {
114  SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
115  return (NULL);
116  }
117  return (SDL_SYS_JoystickNameForDeviceIndex(device_index));
118 }
119 
120 /*
121  * Return true if this joystick is known to have all axes centered at zero
122  * This isn't generally needed unless the joystick never generates an initial axis value near zero,
123  * e.g. it's emulating axes with digital buttons
124  */
125 static SDL_bool
127 {
128  static Uint32 zero_centered_joysticks[] = {
129  MAKE_VIDPID(0x0e8f, 0x3013), /* HuiJia SNES USB adapter */
130  MAKE_VIDPID(0x05a0, 0x3232), /* 8Bitdo Zero Gamepad */
131  };
132 
133  int i;
135  SDL_JoystickGetProduct(joystick));
136 
137 /*printf("JOYSTICK '%s' VID/PID 0x%.4x/0x%.4x AXES: %d\n", joystick->name, vendor, product, joystick->naxes);*/
138 
139  if (joystick->naxes == 2) {
140  /* Assume D-pad or thumbstick style axes are centered at 0 */
141  return SDL_TRUE;
142  }
143 
144  for (i = 0; i < SDL_arraysize(zero_centered_joysticks); ++i) {
145  if (id == zero_centered_joysticks[i]) {
146  return SDL_TRUE;
147  }
148  }
149  return SDL_FALSE;
150 }
151 
152 /*
153  * Open a joystick for use - the index passed as an argument refers to
154  * the N'th joystick on the system. This index is the value which will
155  * identify this joystick in future joystick events.
156  *
157  * This function returns a joystick identifier, or NULL if an error occurred.
158  */
159 SDL_Joystick *
160 SDL_JoystickOpen(int device_index)
161 {
162  SDL_Joystick *joystick;
163  SDL_Joystick *joysticklist;
164  const char *joystickname = NULL;
165 
166  if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
167  SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
168  return (NULL);
169  }
170 
172 
173  joysticklist = SDL_joysticks;
174  /* If the joystick is already open, return it
175  * it is important that we have a single joystick * for each instance id
176  */
177  while (joysticklist) {
178  if (SDL_JoystickGetDeviceInstanceID(device_index) == joysticklist->instance_id) {
179  joystick = joysticklist;
180  ++joystick->ref_count;
182  return (joystick);
183  }
184  joysticklist = joysticklist->next;
185  }
186 
187  /* Create and initialize the joystick */
188  joystick = (SDL_Joystick *) SDL_calloc(sizeof(*joystick), 1);
189  if (joystick == NULL) {
190  SDL_OutOfMemory();
192  return NULL;
193  }
194 
195  if (SDL_SYS_JoystickOpen(joystick, device_index) < 0) {
196  SDL_free(joystick);
198  return NULL;
199  }
200 
201  joystickname = SDL_SYS_JoystickNameForDeviceIndex(device_index);
202  if (joystickname)
203  joystick->name = SDL_strdup(joystickname);
204  else
205  joystick->name = NULL;
206 
207  if (joystick->naxes > 0) {
208  joystick->axes = (SDL_JoystickAxisInfo *) SDL_calloc(joystick->naxes, sizeof(SDL_JoystickAxisInfo));
209  }
210  if (joystick->nhats > 0) {
211  joystick->hats = (Uint8 *) SDL_calloc(joystick->nhats, sizeof(Uint8));
212  }
213  if (joystick->nballs > 0) {
214  joystick->balls = (struct balldelta *) SDL_calloc(joystick->nballs, sizeof(*joystick->balls));
215  }
216  if (joystick->nbuttons > 0) {
217  joystick->buttons = (Uint8 *) SDL_calloc(joystick->nbuttons, sizeof(Uint8));
218  }
219  if (((joystick->naxes > 0) && !joystick->axes)
220  || ((joystick->nhats > 0) && !joystick->hats)
221  || ((joystick->nballs > 0) && !joystick->balls)
222  || ((joystick->nbuttons > 0) && !joystick->buttons)) {
223  SDL_OutOfMemory();
224  SDL_JoystickClose(joystick);
226  return NULL;
227  }
228  joystick->epowerlevel = SDL_JOYSTICK_POWER_UNKNOWN;
229 
230  /* If this joystick is known to have all zero centered axes, skip the auto-centering code */
231  if (SDL_JoystickAxesCenteredAtZero(joystick)) {
232  int i;
233 
234  for (i = 0; i < joystick->naxes; ++i) {
235  joystick->axes[i].has_initial_value = SDL_TRUE;
236  }
237  }
238 
239  joystick->is_game_controller = SDL_IsGameController(device_index);
240 
241  /* Add joystick to list */
242  ++joystick->ref_count;
243  /* Link the joystick in the list */
244  joystick->next = SDL_joysticks;
245  SDL_joysticks = joystick;
246 
248 
249  SDL_SYS_JoystickUpdate(joystick);
250 
251  return (joystick);
252 }
253 
254 
255 /*
256  * Checks to make sure the joystick is valid.
257  */
258 int
259 SDL_PrivateJoystickValid(SDL_Joystick * joystick)
260 {
261  int valid;
262 
263  if (joystick == NULL) {
264  SDL_SetError("Joystick hasn't been opened yet");
265  valid = 0;
266  } else {
267  valid = 1;
268  }
269 
270  return valid;
271 }
272 
273 /*
274  * Get the number of multi-dimensional axis controls on a joystick
275  */
276 int
277 SDL_JoystickNumAxes(SDL_Joystick * joystick)
278 {
279  if (!SDL_PrivateJoystickValid(joystick)) {
280  return (-1);
281  }
282  return (joystick->naxes);
283 }
284 
285 /*
286  * Get the number of hats on a joystick
287  */
288 int
289 SDL_JoystickNumHats(SDL_Joystick * joystick)
290 {
291  if (!SDL_PrivateJoystickValid(joystick)) {
292  return (-1);
293  }
294  return (joystick->nhats);
295 }
296 
297 /*
298  * Get the number of trackballs on a joystick
299  */
300 int
301 SDL_JoystickNumBalls(SDL_Joystick * joystick)
302 {
303  if (!SDL_PrivateJoystickValid(joystick)) {
304  return (-1);
305  }
306  return (joystick->nballs);
307 }
308 
309 /*
310  * Get the number of buttons on a joystick
311  */
312 int
313 SDL_JoystickNumButtons(SDL_Joystick * joystick)
314 {
315  if (!SDL_PrivateJoystickValid(joystick)) {
316  return (-1);
317  }
318  return (joystick->nbuttons);
319 }
320 
321 /*
322  * Get the current state of an axis control on a joystick
323  */
324 Sint16
325 SDL_JoystickGetAxis(SDL_Joystick * joystick, int axis)
326 {
327  Sint16 state;
328 
329  if (!SDL_PrivateJoystickValid(joystick)) {
330  return (0);
331  }
332  if (axis < joystick->naxes) {
333  state = joystick->axes[axis].value;
334  } else {
335  SDL_SetError("Joystick only has %d axes", joystick->naxes);
336  state = 0;
337  }
338  return (state);
339 }
340 
341 /*
342  * Get the initial state of an axis control on a joystick
343  */
344 SDL_bool
345 SDL_JoystickGetAxisInitialState(SDL_Joystick * joystick, int axis, Sint16 *state)
346 {
347  if (!SDL_PrivateJoystickValid(joystick)) {
348  return SDL_FALSE;
349  }
350  if (axis >= joystick->naxes) {
351  SDL_SetError("Joystick only has %d axes", joystick->naxes);
352  return SDL_FALSE;
353  }
354  if (state) {
355  *state = joystick->axes[axis].initial_value;
356  }
357  return joystick->axes[axis].has_initial_value;
358 }
359 
360 /*
361  * Get the current state of a hat on a joystick
362  */
363 Uint8
364 SDL_JoystickGetHat(SDL_Joystick * joystick, int hat)
365 {
366  Uint8 state;
367 
368  if (!SDL_PrivateJoystickValid(joystick)) {
369  return (0);
370  }
371  if (hat < joystick->nhats) {
372  state = joystick->hats[hat];
373  } else {
374  SDL_SetError("Joystick only has %d hats", joystick->nhats);
375  state = 0;
376  }
377  return (state);
378 }
379 
380 /*
381  * Get the ball axis change since the last poll
382  */
383 int
384 SDL_JoystickGetBall(SDL_Joystick * joystick, int ball, int *dx, int *dy)
385 {
386  int retval;
387 
388  if (!SDL_PrivateJoystickValid(joystick)) {
389  return (-1);
390  }
391 
392  retval = 0;
393  if (ball < joystick->nballs) {
394  if (dx) {
395  *dx = joystick->balls[ball].dx;
396  }
397  if (dy) {
398  *dy = joystick->balls[ball].dy;
399  }
400  joystick->balls[ball].dx = 0;
401  joystick->balls[ball].dy = 0;
402  } else {
403  return SDL_SetError("Joystick only has %d balls", joystick->nballs);
404  }
405  return (retval);
406 }
407 
408 /*
409  * Get the current state of a button on a joystick
410  */
411 Uint8
412 SDL_JoystickGetButton(SDL_Joystick * joystick, int button)
413 {
414  Uint8 state;
415 
416  if (!SDL_PrivateJoystickValid(joystick)) {
417  return (0);
418  }
419  if (button < joystick->nbuttons) {
420  state = joystick->buttons[button];
421  } else {
422  SDL_SetError("Joystick only has %d buttons", joystick->nbuttons);
423  state = 0;
424  }
425  return (state);
426 }
427 
428 /*
429  * Return if the joystick in question is currently attached to the system,
430  * \return SDL_FALSE if not plugged in, SDL_TRUE if still present.
431  */
432 SDL_bool
433 SDL_JoystickGetAttached(SDL_Joystick * joystick)
434 {
435  if (!SDL_PrivateJoystickValid(joystick)) {
436  return SDL_FALSE;
437  }
438 
439  return SDL_SYS_JoystickAttached(joystick);
440 }
441 
442 /*
443  * Get the instance id for this opened joystick
444  */
446 SDL_JoystickInstanceID(SDL_Joystick * joystick)
447 {
448  if (!SDL_PrivateJoystickValid(joystick)) {
449  return (-1);
450  }
451 
452  return (joystick->instance_id);
453 }
454 
455 /*
456  * Find the SDL_Joystick that owns this instance id
457  */
458 SDL_Joystick *
460 {
461  SDL_Joystick *joystick;
462 
464  for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
465  if (joystick->instance_id == joyid) {
467  return joystick;
468  }
469  }
471  return NULL;
472 }
473 
474 /*
475  * Get the friendly name of this joystick
476  */
477 const char *
478 SDL_JoystickName(SDL_Joystick * joystick)
479 {
480  if (!SDL_PrivateJoystickValid(joystick)) {
481  return (NULL);
482  }
483 
484  return (joystick->name);
485 }
486 
487 /*
488  * Close a joystick previously opened with SDL_JoystickOpen()
489  */
490 void
491 SDL_JoystickClose(SDL_Joystick * joystick)
492 {
493  SDL_Joystick *joysticklist;
494  SDL_Joystick *joysticklistprev;
495 
496  if (!joystick) {
497  return;
498  }
499 
501 
502  /* First decrement ref count */
503  if (--joystick->ref_count > 0) {
505  return;
506  }
507 
508  if (SDL_updating_joystick) {
510  return;
511  }
512 
513  SDL_SYS_JoystickClose(joystick);
514  joystick->hwdata = NULL;
515 
516  joysticklist = SDL_joysticks;
517  joysticklistprev = NULL;
518  while (joysticklist) {
519  if (joystick == joysticklist) {
520  if (joysticklistprev) {
521  /* unlink this entry */
522  joysticklistprev->next = joysticklist->next;
523  } else {
524  SDL_joysticks = joystick->next;
525  }
526  break;
527  }
528  joysticklistprev = joysticklist;
529  joysticklist = joysticklist->next;
530  }
531 
532  SDL_free(joystick->name);
533 
534  /* Free the data associated with this joystick */
535  SDL_free(joystick->axes);
536  SDL_free(joystick->hats);
537  SDL_free(joystick->balls);
538  SDL_free(joystick->buttons);
539  SDL_free(joystick);
540 
542 }
543 
544 void
546 {
547  /* Make sure we're not getting called in the middle of updating joysticks */
549 
551 
552  /* Stop the event polling */
553  while (SDL_joysticks) {
554  SDL_joysticks->ref_count = 1;
556  }
557 
558  /* Quit the joystick setup */
560 
562 
563 #if !SDL_EVENTS_DISABLED
565 #endif
566 
569 
570  if (SDL_joystick_lock) {
571  SDL_DestroyMutex(SDL_joystick_lock);
572  SDL_joystick_lock = NULL;
573  }
574 
576 }
577 
578 
579 static SDL_bool
581 {
583  return SDL_FALSE;
584  }
585 
586  if (SDL_HasWindows() && SDL_GetKeyboardFocus() == NULL) {
587  /* We have windows but we don't have focus, ignore the event. */
588  return SDL_TRUE;
589  }
590  return SDL_FALSE;
591 }
592 
593 /* These are global for SDL_sysjoystick.c and SDL_events.c */
594 
595 void SDL_PrivateJoystickAdded(int device_index)
596 {
597 #if !SDL_EVENTS_DISABLED
599 
600  event.type = SDL_JOYDEVICEADDED;
601 
602  if (SDL_GetEventState(event.type) == SDL_ENABLE) {
603  event.jdevice.which = device_index;
604  if ((SDL_EventOK == NULL) ||
605  (*SDL_EventOK) (SDL_EventOKParam, &event)) {
606  SDL_PushEvent(&event);
607  }
608  }
609 #endif /* !SDL_EVENTS_DISABLED */
610 }
611 
612 /*
613  * If there is an existing add event in the queue, it needs to be modified
614  * to have the right value for which, because the number of controllers in
615  * the system is now one less.
616  */
618 {
619  int i, num_events;
620  SDL_Event *events;
621 
623  if (num_events <= 0) {
624  return;
625  }
626 
627  events = SDL_stack_alloc(SDL_Event, num_events);
628  if (!events) {
629  return;
630  }
631 
632  num_events = SDL_PeepEvents(events, num_events, SDL_GETEVENT, SDL_JOYDEVICEADDED, SDL_JOYDEVICEADDED);
633  for (i = 0; i < num_events; ++i) {
634  --events[i].jdevice.which;
635  }
636  SDL_PeepEvents(events, num_events, SDL_ADDEVENT, 0, 0);
637 
638  SDL_stack_free(events);
639 }
640 
642 {
643 #if !SDL_EVENTS_DISABLED
645 
646  event.type = SDL_JOYDEVICEREMOVED;
647 
648  if (SDL_GetEventState(event.type) == SDL_ENABLE) {
649  event.jdevice.which = device_instance;
650  if ((SDL_EventOK == NULL) ||
651  (*SDL_EventOK) (SDL_EventOKParam, &event)) {
652  SDL_PushEvent(&event);
653  }
654  }
655 
657 #endif /* !SDL_EVENTS_DISABLED */
658 }
659 
660 int
661 SDL_PrivateJoystickAxis(SDL_Joystick * joystick, Uint8 axis, Sint16 value)
662 {
663  int posted;
664 
665  /* Make sure we're not getting garbage or duplicate events */
666  if (axis >= joystick->naxes) {
667  return 0;
668  }
669  if (!joystick->axes[axis].has_initial_value) {
670  joystick->axes[axis].initial_value = value;
671  joystick->axes[axis].value = value;
672  joystick->axes[axis].zero = value;
673  joystick->axes[axis].has_initial_value = SDL_TRUE;
674  }
675  if (value == joystick->axes[axis].value) {
676  return 0;
677  }
678  if (!joystick->axes[axis].sent_initial_value) {
679  /* Make sure we don't send motion until there's real activity on this axis */
680  const int MAX_ALLOWED_JITTER = SDL_JOYSTICK_AXIS_MAX / 80; /* ShanWan PS3 controller needed 96 */
681  if (SDL_abs(value - joystick->axes[axis].value) <= MAX_ALLOWED_JITTER) {
682  return 0;
683  }
684  joystick->axes[axis].sent_initial_value = SDL_TRUE;
685  joystick->axes[axis].value = value; /* Just so we pass the check above */
686  SDL_PrivateJoystickAxis(joystick, axis, joystick->axes[axis].initial_value);
687  }
688 
689  /* We ignore events if we don't have keyboard focus, except for centering
690  * events.
691  */
693  if ((value > joystick->axes[axis].zero && value >= joystick->axes[axis].value) ||
694  (value < joystick->axes[axis].zero && value <= joystick->axes[axis].value)) {
695  return 0;
696  }
697  }
698 
699  /* Update internal joystick state */
700  joystick->axes[axis].value = value;
701 
702  /* Post the event, if desired */
703  posted = 0;
704 #if !SDL_EVENTS_DISABLED
707  event.type = SDL_JOYAXISMOTION;
708  event.jaxis.which = joystick->instance_id;
709  event.jaxis.axis = axis;
710  event.jaxis.value = value;
711  posted = SDL_PushEvent(&event) == 1;
712  }
713 #endif /* !SDL_EVENTS_DISABLED */
714  return (posted);
715 }
716 
717 int
718 SDL_PrivateJoystickHat(SDL_Joystick * joystick, Uint8 hat, Uint8 value)
719 {
720  int posted;
721 
722  /* Make sure we're not getting garbage or duplicate events */
723  if (hat >= joystick->nhats) {
724  return 0;
725  }
726  if (value == joystick->hats[hat]) {
727  return 0;
728  }
729 
730  /* We ignore events if we don't have keyboard focus, except for centering
731  * events.
732  */
734  if (value != SDL_HAT_CENTERED) {
735  return 0;
736  }
737  }
738 
739  /* Update internal joystick state */
740  joystick->hats[hat] = value;
741 
742  /* Post the event, if desired */
743  posted = 0;
744 #if !SDL_EVENTS_DISABLED
747  event.jhat.type = SDL_JOYHATMOTION;
748  event.jhat.which = joystick->instance_id;
749  event.jhat.hat = hat;
750  event.jhat.value = value;
751  posted = SDL_PushEvent(&event) == 1;
752  }
753 #endif /* !SDL_EVENTS_DISABLED */
754  return (posted);
755 }
756 
757 int
758 SDL_PrivateJoystickBall(SDL_Joystick * joystick, Uint8 ball,
759  Sint16 xrel, Sint16 yrel)
760 {
761  int posted;
762 
763  /* Make sure we're not getting garbage events */
764  if (ball >= joystick->nballs) {
765  return 0;
766  }
767 
768  /* We ignore events if we don't have keyboard focus. */
770  return 0;
771  }
772 
773  /* Update internal mouse state */
774  joystick->balls[ball].dx += xrel;
775  joystick->balls[ball].dy += yrel;
776 
777  /* Post the event, if desired */
778  posted = 0;
779 #if !SDL_EVENTS_DISABLED
782  event.jball.type = SDL_JOYBALLMOTION;
783  event.jball.which = joystick->instance_id;
784  event.jball.ball = ball;
785  event.jball.xrel = xrel;
786  event.jball.yrel = yrel;
787  posted = SDL_PushEvent(&event) == 1;
788  }
789 #endif /* !SDL_EVENTS_DISABLED */
790  return (posted);
791 }
792 
793 int
795 {
796  int posted;
797 #if !SDL_EVENTS_DISABLED
799 
800  switch (state) {
801  case SDL_PRESSED:
802  event.type = SDL_JOYBUTTONDOWN;
803  break;
804  case SDL_RELEASED:
805  event.type = SDL_JOYBUTTONUP;
806  break;
807  default:
808  /* Invalid state -- bail */
809  return (0);
810  }
811 #endif /* !SDL_EVENTS_DISABLED */
812 
813  /* Make sure we're not getting garbage or duplicate events */
814  if (button >= joystick->nbuttons) {
815  return 0;
816  }
817  if (state == joystick->buttons[button]) {
818  return 0;
819  }
820 
821  /* We ignore events if we don't have keyboard focus, except for button
822  * release. */
824  if (state == SDL_PRESSED) {
825  return 0;
826  }
827  }
828 
829  /* Update internal joystick state */
830  joystick->buttons[button] = state;
831 
832  /* Post the event, if desired */
833  posted = 0;
834 #if !SDL_EVENTS_DISABLED
835  if (SDL_GetEventState(event.type) == SDL_ENABLE) {
836  event.jbutton.which = joystick->instance_id;
837  event.jbutton.button = button;
838  event.jbutton.state = state;
839  posted = SDL_PushEvent(&event) == 1;
840  }
841 #endif /* !SDL_EVENTS_DISABLED */
842  return (posted);
843 }
844 
845 void
847 {
848  SDL_Joystick *joystick;
849 
851 
852  if (SDL_updating_joystick) {
853  /* The joysticks are already being updated */
855  return;
856  }
857 
859 
860  /* Make sure the list is unlocked while dispatching events to prevent application deadlocks */
862 
863  for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
864  SDL_SYS_JoystickUpdate(joystick);
865 
866  if (joystick->force_recentering) {
867  int i;
868 
869  /* Tell the app that everything is centered/unpressed... */
870  for (i = 0; i < joystick->naxes; i++) {
871  if (joystick->axes[i].has_initial_value) {
872  SDL_PrivateJoystickAxis(joystick, i, joystick->axes[i].zero);
873  }
874  }
875 
876  for (i = 0; i < joystick->nbuttons; i++) {
877  SDL_PrivateJoystickButton(joystick, i, 0);
878  }
879 
880  for (i = 0; i < joystick->nhats; i++) {
882  }
883 
884  joystick->force_recentering = SDL_FALSE;
885  }
886  }
887 
889 
891 
892  /* If any joysticks were closed while updating, free them here */
893  for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
894  if (joystick->ref_count <= 0) {
895  SDL_JoystickClose(joystick);
896  }
897  }
898 
899  /* this needs to happen AFTER walking the joystick list above, so that any
900  dangling hardware data from removed devices can be free'd
901  */
903 
905 }
906 
907 int
909 {
910 #if SDL_EVENTS_DISABLED
911  return SDL_DISABLE;
912 #else
913  const Uint32 event_list[] = {
916  };
917  unsigned int i;
918 
919  switch (state) {
920  case SDL_QUERY:
921  state = SDL_DISABLE;
922  for (i = 0; i < SDL_arraysize(event_list); ++i) {
923  state = SDL_EventState(event_list[i], SDL_QUERY);
924  if (state == SDL_ENABLE) {
925  break;
926  }
927  }
928  break;
929  default:
930  for (i = 0; i < SDL_arraysize(event_list); ++i) {
931  SDL_EventState(event_list[i], state);
932  }
933  break;
934  }
935  return (state);
936 #endif /* SDL_EVENTS_DISABLED */
937 }
938 
939 void SDL_GetJoystickGUIDInfo(SDL_JoystickGUID guid, Uint16 *vendor, Uint16 *product, Uint16 *version)
940 {
941  Uint16 *guid16 = (Uint16 *)guid.data;
942 
943  /* If the GUID fits the form of BUS 0000 VENDOR 0000 PRODUCT 0000, return the data */
944  if (/* guid16[0] is device bus type */
945  guid16[1] == 0x0000 &&
946  /* guid16[2] is vendor ID */
947  guid16[3] == 0x0000 &&
948  /* guid16[4] is product ID */
949  guid16[5] == 0x0000
950  /* guid16[6] is product version */
951  ) {
952  if (vendor) {
953  *vendor = guid16[2];
954  }
955  if (product) {
956  *product = guid16[4];
957  }
958  if (version) {
959  *version = guid16[6];
960  }
961  } else {
962  if (vendor) {
963  *vendor = 0;
964  }
965  if (product) {
966  *product = 0;
967  }
968  if (version) {
969  *version = 0;
970  }
971  }
972 }
973 
975 {
976  static Uint32 wheel_joysticks[] = {
977  MAKE_VIDPID(0x046d, 0xc294), /* Logitech generic wheel */
978  MAKE_VIDPID(0x046d, 0xc295), /* Logitech Momo Force */
979  MAKE_VIDPID(0x046d, 0xc298), /* Logitech Driving Force Pro */
980  MAKE_VIDPID(0x046d, 0xc299), /* Logitech G25 */
981  MAKE_VIDPID(0x046d, 0xc29a), /* Logitech Driving Force GT */
982  MAKE_VIDPID(0x046d, 0xc29b), /* Logitech G27 */
983  MAKE_VIDPID(0x046d, 0xc261), /* Logitech G920 (initial mode) */
984  MAKE_VIDPID(0x046d, 0xc262), /* Logitech G920 (active mode) */
985  MAKE_VIDPID(0x044f, 0xb65d), /* Thrustmaster Wheel FFB */
986  MAKE_VIDPID(0x044f, 0xb66d), /* Thrustmaster Wheel FFB */
987  MAKE_VIDPID(0x044f, 0xb677), /* Thrustmaster T150 */
988  MAKE_VIDPID(0x044f, 0xb664), /* Thrustmaster TX (initial mode) */
989  MAKE_VIDPID(0x044f, 0xb669), /* Thrustmaster TX (active mode) */
990  };
991  int i;
992 
993  for (i = 0; i < SDL_arraysize(wheel_joysticks); ++i) {
994  if (vidpid == wheel_joysticks[i]) {
995  return SDL_TRUE;
996  }
997  }
998  return SDL_FALSE;
999 }
1000 
1002 {
1003  static Uint32 flightstick_joysticks[] = {
1004  MAKE_VIDPID(0x044f, 0x0402), /* HOTAS Warthog Joystick */
1005  MAKE_VIDPID(0x0738, 0x2221), /* Saitek Pro Flight X-56 Rhino Stick */
1006  };
1007  int i;
1008 
1009  for (i = 0; i < SDL_arraysize(flightstick_joysticks); ++i) {
1010  if (vidpid == flightstick_joysticks[i]) {
1011  return SDL_TRUE;
1012  }
1013  }
1014  return SDL_FALSE;
1015 }
1016 
1018 {
1019  static Uint32 throttle_joysticks[] = {
1020  MAKE_VIDPID(0x044f, 0x0404), /* HOTAS Warthog Throttle */
1021  MAKE_VIDPID(0x0738, 0xa221), /* Saitek Pro Flight X-56 Rhino Throttle */
1022  };
1023  int i;
1024 
1025  for (i = 0; i < SDL_arraysize(throttle_joysticks); ++i) {
1026  if (vidpid == throttle_joysticks[i]) {
1027  return SDL_TRUE;
1028  }
1029  }
1030  return SDL_FALSE;
1031 }
1032 
1034 {
1035  Uint16 vendor;
1036  Uint16 product;
1037  Uint32 vidpid;
1038 
1039  if (guid.data[14] == 'x') {
1040  /* XInput GUID, get the type based on the XInput device subtype */
1041  switch (guid.data[15]) {
1042  case 0x01: /* XINPUT_DEVSUBTYPE_GAMEPAD */
1044  case 0x02: /* XINPUT_DEVSUBTYPE_WHEEL */
1045  return SDL_JOYSTICK_TYPE_WHEEL;
1046  case 0x03: /* XINPUT_DEVSUBTYPE_ARCADE_STICK */
1048  case 0x04: /* XINPUT_DEVSUBTYPE_FLIGHT_STICK */
1050  case 0x05: /* XINPUT_DEVSUBTYPE_DANCE_PAD */
1052  case 0x06: /* XINPUT_DEVSUBTYPE_GUITAR */
1053  case 0x07: /* XINPUT_DEVSUBTYPE_GUITAR_ALTERNATE */
1054  case 0x0B: /* XINPUT_DEVSUBTYPE_GUITAR_BASS */
1055  return SDL_JOYSTICK_TYPE_GUITAR;
1056  case 0x08: /* XINPUT_DEVSUBTYPE_DRUM_KIT */
1058  case 0x13: /* XINPUT_DEVSUBTYPE_ARCADE_PAD */
1060  default:
1062  }
1063  }
1064 
1065  SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL);
1066  vidpid = MAKE_VIDPID(vendor, product);
1067 
1068  if (SDL_IsJoystickProductWheel(vidpid)) {
1069  return SDL_JOYSTICK_TYPE_WHEEL;
1070  }
1071 
1072  if (SDL_IsJoystickProductFlightStick(vidpid)) {
1074  }
1075 
1076  if (SDL_IsJoystickProductThrottle(vidpid)) {
1078  }
1079 
1081 }
1082 
1083 /* return the guid for this index */
1085 {
1086  if (device_index < 0 || device_index >= SDL_NumJoysticks()) {
1087  SDL_JoystickGUID emptyGUID;
1088  SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
1089  SDL_zero(emptyGUID);
1090  return emptyGUID;
1091  }
1092  return SDL_SYS_JoystickGetDeviceGUID(device_index);
1093 }
1094 
1096 {
1097  Uint16 vendor;
1098  SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
1099 
1100  SDL_GetJoystickGUIDInfo(guid, &vendor, NULL, NULL);
1101  return vendor;
1102 }
1103 
1105 {
1106  Uint16 product;
1107  SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
1108 
1109  SDL_GetJoystickGUIDInfo(guid, NULL, &product, NULL);
1110  return product;
1111 }
1112 
1114 {
1115  Uint16 version;
1116  SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
1117 
1118  SDL_GetJoystickGUIDInfo(guid, NULL, NULL, &version);
1119  return version;
1120 }
1121 
1123 {
1125  SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
1126 
1127  type = SDL_GetJoystickGUIDType(guid);
1128  if (type == SDL_JOYSTICK_TYPE_UNKNOWN) {
1129  if (SDL_IsGameController(device_index)) {
1131  }
1132  }
1133  return type;
1134 }
1135 
1137 {
1138  if (device_index < 0 || device_index >= SDL_NumJoysticks()) {
1139  SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
1140  return -1;
1141  }
1142  return SDL_SYS_GetInstanceIdOfDeviceIndex(device_index);
1143 }
1144 
1145 SDL_JoystickGUID SDL_JoystickGetGUID(SDL_Joystick * joystick)
1146 {
1147  if (!SDL_PrivateJoystickValid(joystick)) {
1148  SDL_JoystickGUID emptyGUID;
1149  SDL_zero(emptyGUID);
1150  return emptyGUID;
1151  }
1152  return SDL_SYS_JoystickGetGUID(joystick);
1153 }
1154 
1155 Uint16 SDL_JoystickGetVendor(SDL_Joystick * joystick)
1156 {
1157  Uint16 vendor;
1158  SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
1159 
1160  SDL_GetJoystickGUIDInfo(guid, &vendor, NULL, NULL);
1161  return vendor;
1162 }
1163 
1164 Uint16 SDL_JoystickGetProduct(SDL_Joystick * joystick)
1165 {
1166  Uint16 product;
1167  SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
1168 
1169  SDL_GetJoystickGUIDInfo(guid, NULL, &product, NULL);
1170  return product;
1171 }
1172 
1173 Uint16 SDL_JoystickGetProductVersion(SDL_Joystick * joystick)
1174 {
1175  Uint16 version;
1176  SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
1177 
1178  SDL_GetJoystickGUIDInfo(guid, NULL, NULL, &version);
1179  return version;
1180 }
1181 
1182 SDL_JoystickType SDL_JoystickGetType(SDL_Joystick * joystick)
1183 {
1185  SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
1186 
1187  type = SDL_GetJoystickGUIDType(guid);
1188  if (type == SDL_JOYSTICK_TYPE_UNKNOWN) {
1189  if (joystick && joystick->is_game_controller) {
1191  }
1192  }
1193  return type;
1194 }
1195 
1196 /* convert the guid to a printable string */
1197 void SDL_JoystickGetGUIDString(SDL_JoystickGUID guid, char *pszGUID, int cbGUID)
1198 {
1199  static const char k_rgchHexToASCII[] = "0123456789abcdef";
1200  int i;
1201 
1202  if ((pszGUID == NULL) || (cbGUID <= 0)) {
1203  return;
1204  }
1205 
1206  for (i = 0; i < sizeof(guid.data) && i < (cbGUID-1)/2; i++) {
1207  /* each input byte writes 2 ascii chars, and might write a null byte. */
1208  /* If we don't have room for next input byte, stop */
1209  unsigned char c = guid.data[i];
1210 
1211  *pszGUID++ = k_rgchHexToASCII[c >> 4];
1212  *pszGUID++ = k_rgchHexToASCII[c & 0x0F];
1213  }
1214  *pszGUID = '\0';
1215 }
1216 
1217 
1218 /*-----------------------------------------------------------------------------
1219  * Purpose: Returns the 4 bit nibble for a hex character
1220  * Input : c -
1221  * Output : unsigned char
1222  *-----------------------------------------------------------------------------*/
1223 static unsigned char nibble(char c)
1224 {
1225  if ((c >= '0') && (c <= '9')) {
1226  return (unsigned char)(c - '0');
1227  }
1228 
1229  if ((c >= 'A') && (c <= 'F')) {
1230  return (unsigned char)(c - 'A' + 0x0a);
1231  }
1232 
1233  if ((c >= 'a') && (c <= 'f')) {
1234  return (unsigned char)(c - 'a' + 0x0a);
1235  }
1236 
1237  /* received an invalid character, and no real way to return an error */
1238  /* AssertMsg1(false, "Q_nibble invalid hex character '%c' ", c); */
1239  return 0;
1240 }
1241 
1242 
1243 /* convert the string version of a joystick guid to the struct */
1245 {
1246  SDL_JoystickGUID guid;
1247  int maxoutputbytes= sizeof(guid);
1248  size_t len = SDL_strlen(pchGUID);
1249  Uint8 *p;
1250  size_t i;
1251 
1252  /* Make sure it's even */
1253  len = (len) & ~0x1;
1254 
1255  SDL_memset(&guid, 0x00, sizeof(guid));
1256 
1257  p = (Uint8 *)&guid;
1258  for (i = 0; (i < len) && ((p - (Uint8 *)&guid) < maxoutputbytes); i+=2, p++) {
1259  *p = (nibble(pchGUID[i]) << 4) | nibble(pchGUID[i+1]);
1260  }
1261 
1262  return guid;
1263 }
1264 
1265 
1266 /* update the power level for this joystick */
1267 void SDL_PrivateJoystickBatteryLevel(SDL_Joystick * joystick, SDL_JoystickPowerLevel ePowerLevel)
1268 {
1269  joystick->epowerlevel = ePowerLevel;
1270 }
1271 
1272 
1273 /* return its power level */
1275 {
1276  if (!SDL_PrivateJoystickValid(joystick)) {
1277  return (SDL_JOYSTICK_POWER_UNKNOWN);
1278  }
1279  return joystick->epowerlevel;
1280 }
1281 
1282 /* vi: set ts=4 sw=4 expandtab: */
static SDL_bool SDL_IsJoystickProductWheel(Uint32 vidpid)
Definition: SDL_joystick.c:974
Uint16 SDL_JoystickGetVendor(SDL_Joystick *joystick)
void SDL_UnlockJoystickList(void)
Definition: SDL_joystick.c:51
void SDL_JoystickUpdate(void)
Definition: SDL_joystick.c:846
#define SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS
A variable that lets you enable joystick (and gamecontroller) events even when your app is in the bac...
Definition: SDL_hints.h:433
#define SDL_abs
#define SDL_INIT_EVENTS
Definition: SDL.h:82
#define SDL_LockMutex
int SDL_JoystickGetBall(SDL_Joystick *joystick, int ball, int *dx, int *dy)
Definition: SDL_joystick.c:384
int SDL_PrivateJoystickValid(SDL_Joystick *joystick)
Definition: SDL_joystick.c:259
SDL_JoyDeviceEvent jdevice
Definition: SDL_events.h:540
GLuint GLfloat GLfloat GLfloat x1
SDL_bool SDL_JoystickGetAxisInitialState(SDL_Joystick *joystick, int axis, Sint16 *state)
Definition: SDL_joystick.c:345
#define MAKE_VIDPID(VID, PID)
SDL_Texture * button
void SDL_JoystickClose(SDL_Joystick *joystick)
Definition: SDL_joystick.c:491
void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance)
Definition: SDL_joystick.c:641
Uint16 SDL_JoystickGetProduct(SDL_Joystick *joystick)
void SDL_GameControllerQuitMappings(void)
int SDL_PrivateJoystickHat(SDL_Joystick *joystick, Uint8 hat, Uint8 value)
Definition: SDL_joystick.c:718
int SDL_GameControllerInitMappings(void)
#define SDL_IsGameController
static SDL_mutex * SDL_joystick_lock
Definition: SDL_joystick.c:40
#define SDL_CreateMutex
#define SDL_QuitSubSystem
int SDL_JoystickInit(void)
Definition: SDL_joystick.c:70
struct xkb_state * state
GLfloat GLfloat p
static SDL_Event events[EVENT_BUF_SIZE]
Definition: testgesture.c:35
int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
Definition: SDL_joystick.c:794
int SDL_JoystickNumHats(SDL_Joystick *joystick)
Definition: SDL_joystick.c:289
#define SDL_ENABLE
Definition: SDL_events.h:722
#define SDL_InitSubSystem
Uint16 SDL_JoystickGetDeviceProduct(int device_index)
SDL_Texture * axis
void SDL_LockJoystickList(void)
Definition: SDL_joystick.c:43
Uint16 SDL_JoystickGetProductVersion(SDL_Joystick *joystick)
void SDL_SYS_JoystickQuit(void)
#define SDL_GetKeyboardFocus
uint32_t Uint32
Definition: SDL_stdinc.h:181
Uint8 data[16]
Definition: SDL_joystick.h:71
Uint16 SDL_JoystickGetDeviceProductVersion(int device_index)
GLenum GLsizei len
int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
Definition: SDL_joystick.c:661
GLuint const GLchar * name
SDL_JoystickPowerLevel SDL_JoystickCurrentPowerLevel(SDL_Joystick *joystick)
static SDL_bool SDL_IsJoystickProductFlightStick(Uint32 vidpid)
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 retval
static void UpdateEventsForDeviceRemoval()
Definition: SDL_joystick.c:617
void * SDL_calloc(size_t nmemb, size_t size)
const char * SDL_JoystickName(SDL_Joystick *joystick)
Definition: SDL_joystick.c:478
int SDL_JoystickEventState(int state)
Definition: SDL_joystick.c:908
#define SDL_JOYSTICK_AXIS_MAX
Definition: SDL_joystick.h:274
int SDL_PrivateJoystickBall(SDL_Joystick *joystick, Uint8 ball, Sint16 xrel, Sint16 yrel)
Definition: SDL_joystick.c:758
int SDL_NumJoysticks(void)
Definition: SDL_joystick.c:102
static SDL_bool SDL_joystick_allows_background_events
Definition: SDL_joystick.c:37
#define SDL_GetEventState(type)
Definition: SDL_events.h:735
Sint32 SDL_JoystickID
Definition: SDL_joystick.h:81
#define SDL_PeepEvents
uint8_t Uint8
Definition: SDL_stdinc.h:157
#define SDL_stack_alloc(type, count)
Definition: SDL_stdinc.h:354
struct _cl_event * event
void SDL_free(void *mem)
SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
SDL_EventFilter SDL_EventOK
Definition: SDL_events.c:42
SDL_JoystickGUID SDL_JoystickGetGUID(SDL_Joystick *joystick)
#define SDL_PushEvent
const GLubyte * c
GLsizei const GLfloat * value
void SDL_PrivateJoystickAdded(int device_index)
Definition: SDL_joystick.c:595
#define SDL_zero(x)
Definition: SDL_stdinc.h:385
const char * SDL_SYS_JoystickNameForDeviceIndex(int device_index)
SDL_Joystick * SDL_JoystickOpen(int device_index)
Definition: SDL_joystick.c:160
int SDL_JoystickNumAxes(SDL_Joystick *joystick)
Definition: SDL_joystick.c:277
void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick)
SDL_JoystickPowerLevel
Definition: SDL_joystick.h:97
SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick *joystick)
SDL_JoystickType
Definition: SDL_joystick.h:83
SDL_Joystick * SDL_JoystickFromInstanceID(SDL_JoystickID joyid)
Definition: SDL_joystick.c:459
#define SDL_assert(condition)
Definition: SDL_assert.h:169
int SDL_SYS_JoystickInit(void)
SDL_JoystickGUID SDL_JoystickGetDeviceGUID(int device_index)
SDL_JoystickGUID SDL_JoystickGetGUIDFromString(const char *pchGUID)
void * SDL_EventOKParam
Definition: SDL_events.c:43
SDL_JoystickID SDL_JoystickGetDeviceInstanceID(int device_index)
#define SDL_DISABLE
Definition: SDL_events.h:721
#define NULL
Definition: begin_code.h:164
int SDL_JoystickNumBalls(SDL_Joystick *joystick)
Definition: SDL_joystick.c:301
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_bool
Definition: SDL_stdinc.h:139
int SDL_SYS_NumJoysticks(void)
#define SDL_SetError
static unsigned char nibble(char c)
#define SDL_DestroyMutex
SDL_JoystickID SDL_JoystickInstanceID(SDL_Joystick *joystick)
Definition: SDL_joystick.c:446
SDL_bool SDL_HasWindows(void)
Definition: SDL_video.c:1630
void SDL_GetJoystickGUIDInfo(SDL_JoystickGUID guid, Uint16 *vendor, Uint16 *product, Uint16 *version)
Definition: SDL_joystick.c:939
#define SDL_strlen
#define SDL_strdup
void SDL_PrivateJoystickBatteryLevel(SDL_Joystick *joystick, SDL_JoystickPowerLevel ePowerLevel)
#define SDL_EventState
#define SDL_AddHintCallback
int SDL_JoystickNumButtons(SDL_Joystick *joystick)
Definition: SDL_joystick.c:313
#define SDL_DelHintCallback
void SDL_JoystickGetGUIDString(SDL_JoystickGUID guid, char *pszGUID, int cbGUID)
SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
uint16_t Uint16
Definition: SDL_stdinc.h:169
GLuint GLuint GLsizei GLenum type
Definition: SDL_opengl.h:1571
static SDL_bool SDL_JoystickAxesCenteredAtZero(SDL_Joystick *joystick)
Definition: SDL_joystick.c:126
#define SDL_UnlockMutex
static SDL_bool SDL_PrivateJoystickShouldIgnoreEvent()
Definition: SDL_joystick.c:580
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:93
int SDL_SYS_JoystickOpen(SDL_Joystick *joystick, int device_index)
General event structure.
Definition: SDL_events.h:525
Uint8 SDL_JoystickGetButton(SDL_Joystick *joystick, int button)
Definition: SDL_joystick.c:412
Uint8 SDL_JoystickGetHat(SDL_Joystick *joystick, int hat)
Definition: SDL_joystick.c:364
void SDL_JoystickQuit(void)
Definition: SDL_joystick.c:545
static void SDL_JoystickAllowBackgroundEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
Definition: SDL_joystick.c:60
#define SDL_PRESSED
Definition: SDL_events.h:50
#define SDL_QUERY
Definition: SDL_events.h:719
#define SDL_stack_free(data)
Definition: SDL_stdinc.h:355
#define SDL_HAT_CENTERED
Definition: SDL_joystick.h:302
SDL_bool SDL_JoystickGetAttached(SDL_Joystick *joystick)
Definition: SDL_joystick.c:433
void SDL_SYS_JoystickClose(SDL_Joystick *joystick)
static SDL_JoystickType SDL_GetJoystickGUIDType(SDL_JoystickGUID guid)
#define SDL_RELEASED
Definition: SDL_events.h:49
Uint16 SDL_JoystickGetDeviceVendor(int device_index)
#define SDLCALL
Definition: SDL_internal.h:45
SDL_JoystickType SDL_JoystickGetDeviceType(int device_index)
static SDL_bool SDL_updating_joystick
Definition: SDL_joystick.c:39
SDL_JoystickType SDL_JoystickGetType(SDL_Joystick *joystick)
SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID(int device_index)
const char * SDL_JoystickNameForIndex(int device_index)
Definition: SDL_joystick.c:111
#define SDL_memset
static SDL_bool SDL_IsJoystickProductThrottle(Uint32 vidpid)
int16_t Sint16
Definition: SDL_stdinc.h:163
Uint32 type
Definition: SDL_events.h:527
static SDL_Joystick * SDL_joysticks
Definition: SDL_joystick.c:38
void SDL_SYS_JoystickDetect(void)
Sint16 SDL_JoystickGetAxis(SDL_Joystick *joystick, int axis)
Definition: SDL_joystick.c:325