SDL  2.0
SDL_joystick.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
4 
5  This software is provided 'as-is', without any express or implied
6  warranty. In no event will the authors be held liable for any damages
7  arising from the use of this software.
8 
9  Permission is granted to anyone to use this software for any purpose,
10  including commercial applications, and to alter it and redistribute it
11  freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not
14  claim that you wrote the original software. If you use this software
15  in a product, an acknowledgment in the product documentation would be
16  appreciated but is not required.
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19  3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../SDL_internal.h"
22 
23 /* This is the 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  SDL_PushEvent(&event);
605  }
606 #endif /* !SDL_EVENTS_DISABLED */
607 }
608 
609 /*
610  * If there is an existing add event in the queue, it needs to be modified
611  * to have the right value for which, because the number of controllers in
612  * the system is now one less.
613  */
615 {
616  int i, num_events;
617  SDL_Event *events;
618 
620  if (num_events <= 0) {
621  return;
622  }
623 
624  events = SDL_stack_alloc(SDL_Event, num_events);
625  if (!events) {
626  return;
627  }
628 
629  num_events = SDL_PeepEvents(events, num_events, SDL_GETEVENT, SDL_JOYDEVICEADDED, SDL_JOYDEVICEADDED);
630  for (i = 0; i < num_events; ++i) {
631  --events[i].jdevice.which;
632  }
633  SDL_PeepEvents(events, num_events, SDL_ADDEVENT, 0, 0);
634 
635  SDL_stack_free(events);
636 }
637 
639 {
640 #if !SDL_EVENTS_DISABLED
642 
643  event.type = SDL_JOYDEVICEREMOVED;
644 
645  if (SDL_GetEventState(event.type) == SDL_ENABLE) {
646  event.jdevice.which = device_instance;
647  SDL_PushEvent(&event);
648  }
649 
651 #endif /* !SDL_EVENTS_DISABLED */
652 }
653 
654 int
655 SDL_PrivateJoystickAxis(SDL_Joystick * joystick, Uint8 axis, Sint16 value)
656 {
657  int posted;
658 
659  /* Make sure we're not getting garbage or duplicate events */
660  if (axis >= joystick->naxes) {
661  return 0;
662  }
663  if (!joystick->axes[axis].has_initial_value) {
664  joystick->axes[axis].initial_value = value;
665  joystick->axes[axis].value = value;
666  joystick->axes[axis].zero = value;
667  joystick->axes[axis].has_initial_value = SDL_TRUE;
668  }
669  if (value == joystick->axes[axis].value) {
670  return 0;
671  }
672  if (!joystick->axes[axis].sent_initial_value) {
673  /* Make sure we don't send motion until there's real activity on this axis */
674  const int MAX_ALLOWED_JITTER = SDL_JOYSTICK_AXIS_MAX / 80; /* ShanWan PS3 controller needed 96 */
675  if (SDL_abs(value - joystick->axes[axis].value) <= MAX_ALLOWED_JITTER) {
676  return 0;
677  }
678  joystick->axes[axis].sent_initial_value = SDL_TRUE;
679  joystick->axes[axis].value = value; /* Just so we pass the check above */
680  SDL_PrivateJoystickAxis(joystick, axis, joystick->axes[axis].initial_value);
681  }
682 
683  /* We ignore events if we don't have keyboard focus, except for centering
684  * events.
685  */
687  if ((value > joystick->axes[axis].zero && value >= joystick->axes[axis].value) ||
688  (value < joystick->axes[axis].zero && value <= joystick->axes[axis].value)) {
689  return 0;
690  }
691  }
692 
693  /* Update internal joystick state */
694  joystick->axes[axis].value = value;
695 
696  /* Post the event, if desired */
697  posted = 0;
698 #if !SDL_EVENTS_DISABLED
701  event.type = SDL_JOYAXISMOTION;
702  event.jaxis.which = joystick->instance_id;
703  event.jaxis.axis = axis;
704  event.jaxis.value = value;
705  posted = SDL_PushEvent(&event) == 1;
706  }
707 #endif /* !SDL_EVENTS_DISABLED */
708  return (posted);
709 }
710 
711 int
712 SDL_PrivateJoystickHat(SDL_Joystick * joystick, Uint8 hat, Uint8 value)
713 {
714  int posted;
715 
716  /* Make sure we're not getting garbage or duplicate events */
717  if (hat >= joystick->nhats) {
718  return 0;
719  }
720  if (value == joystick->hats[hat]) {
721  return 0;
722  }
723 
724  /* We ignore events if we don't have keyboard focus, except for centering
725  * events.
726  */
728  if (value != SDL_HAT_CENTERED) {
729  return 0;
730  }
731  }
732 
733  /* Update internal joystick state */
734  joystick->hats[hat] = value;
735 
736  /* Post the event, if desired */
737  posted = 0;
738 #if !SDL_EVENTS_DISABLED
741  event.jhat.type = SDL_JOYHATMOTION;
742  event.jhat.which = joystick->instance_id;
743  event.jhat.hat = hat;
744  event.jhat.value = value;
745  posted = SDL_PushEvent(&event) == 1;
746  }
747 #endif /* !SDL_EVENTS_DISABLED */
748  return (posted);
749 }
750 
751 int
752 SDL_PrivateJoystickBall(SDL_Joystick * joystick, Uint8 ball,
753  Sint16 xrel, Sint16 yrel)
754 {
755  int posted;
756 
757  /* Make sure we're not getting garbage events */
758  if (ball >= joystick->nballs) {
759  return 0;
760  }
761 
762  /* We ignore events if we don't have keyboard focus. */
764  return 0;
765  }
766 
767  /* Update internal mouse state */
768  joystick->balls[ball].dx += xrel;
769  joystick->balls[ball].dy += yrel;
770 
771  /* Post the event, if desired */
772  posted = 0;
773 #if !SDL_EVENTS_DISABLED
776  event.jball.type = SDL_JOYBALLMOTION;
777  event.jball.which = joystick->instance_id;
778  event.jball.ball = ball;
779  event.jball.xrel = xrel;
780  event.jball.yrel = yrel;
781  posted = SDL_PushEvent(&event) == 1;
782  }
783 #endif /* !SDL_EVENTS_DISABLED */
784  return (posted);
785 }
786 
787 int
789 {
790  int posted;
791 #if !SDL_EVENTS_DISABLED
793 
794  switch (state) {
795  case SDL_PRESSED:
796  event.type = SDL_JOYBUTTONDOWN;
797  break;
798  case SDL_RELEASED:
799  event.type = SDL_JOYBUTTONUP;
800  break;
801  default:
802  /* Invalid state -- bail */
803  return (0);
804  }
805 #endif /* !SDL_EVENTS_DISABLED */
806 
807  /* Make sure we're not getting garbage or duplicate events */
808  if (button >= joystick->nbuttons) {
809  return 0;
810  }
811  if (state == joystick->buttons[button]) {
812  return 0;
813  }
814 
815  /* We ignore events if we don't have keyboard focus, except for button
816  * release. */
818  if (state == SDL_PRESSED) {
819  return 0;
820  }
821  }
822 
823  /* Update internal joystick state */
824  joystick->buttons[button] = state;
825 
826  /* Post the event, if desired */
827  posted = 0;
828 #if !SDL_EVENTS_DISABLED
829  if (SDL_GetEventState(event.type) == SDL_ENABLE) {
830  event.jbutton.which = joystick->instance_id;
831  event.jbutton.button = button;
832  event.jbutton.state = state;
833  posted = SDL_PushEvent(&event) == 1;
834  }
835 #endif /* !SDL_EVENTS_DISABLED */
836  return (posted);
837 }
838 
839 void
841 {
842  SDL_Joystick *joystick;
843 
845 
846  if (SDL_updating_joystick) {
847  /* The joysticks are already being updated */
849  return;
850  }
851 
853 
854  /* Make sure the list is unlocked while dispatching events to prevent application deadlocks */
856 
857  for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
858  SDL_SYS_JoystickUpdate(joystick);
859 
860  if (joystick->force_recentering) {
861  int i;
862 
863  /* Tell the app that everything is centered/unpressed... */
864  for (i = 0; i < joystick->naxes; i++) {
865  if (joystick->axes[i].has_initial_value) {
866  SDL_PrivateJoystickAxis(joystick, i, joystick->axes[i].zero);
867  }
868  }
869 
870  for (i = 0; i < joystick->nbuttons; i++) {
871  SDL_PrivateJoystickButton(joystick, i, 0);
872  }
873 
874  for (i = 0; i < joystick->nhats; i++) {
876  }
877 
878  joystick->force_recentering = SDL_FALSE;
879  }
880  }
881 
883 
885 
886  /* If any joysticks were closed while updating, free them here */
887  for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
888  if (joystick->ref_count <= 0) {
889  SDL_JoystickClose(joystick);
890  }
891  }
892 
893  /* this needs to happen AFTER walking the joystick list above, so that any
894  dangling hardware data from removed devices can be free'd
895  */
897 
899 }
900 
901 int
903 {
904 #if SDL_EVENTS_DISABLED
905  return SDL_DISABLE;
906 #else
907  const Uint32 event_list[] = {
910  };
911  unsigned int i;
912 
913  switch (state) {
914  case SDL_QUERY:
915  state = SDL_DISABLE;
916  for (i = 0; i < SDL_arraysize(event_list); ++i) {
917  state = SDL_EventState(event_list[i], SDL_QUERY);
918  if (state == SDL_ENABLE) {
919  break;
920  }
921  }
922  break;
923  default:
924  for (i = 0; i < SDL_arraysize(event_list); ++i) {
925  SDL_EventState(event_list[i], state);
926  }
927  break;
928  }
929  return (state);
930 #endif /* SDL_EVENTS_DISABLED */
931 }
932 
933 void SDL_GetJoystickGUIDInfo(SDL_JoystickGUID guid, Uint16 *vendor, Uint16 *product, Uint16 *version)
934 {
935  Uint16 *guid16 = (Uint16 *)guid.data;
936 
937  /* If the GUID fits the form of BUS 0000 VENDOR 0000 PRODUCT 0000, return the data */
938  if (/* guid16[0] is device bus type */
939  guid16[1] == 0x0000 &&
940  /* guid16[2] is vendor ID */
941  guid16[3] == 0x0000 &&
942  /* guid16[4] is product ID */
943  guid16[5] == 0x0000
944  /* guid16[6] is product version */
945  ) {
946  if (vendor) {
947  *vendor = guid16[2];
948  }
949  if (product) {
950  *product = guid16[4];
951  }
952  if (version) {
953  *version = guid16[6];
954  }
955  } else {
956  if (vendor) {
957  *vendor = 0;
958  }
959  if (product) {
960  *product = 0;
961  }
962  if (version) {
963  *version = 0;
964  }
965  }
966 }
967 
969 {
970  static Uint32 wheel_joysticks[] = {
971  MAKE_VIDPID(0x046d, 0xc294), /* Logitech generic wheel */
972  MAKE_VIDPID(0x046d, 0xc295), /* Logitech Momo Force */
973  MAKE_VIDPID(0x046d, 0xc298), /* Logitech Driving Force Pro */
974  MAKE_VIDPID(0x046d, 0xc299), /* Logitech G25 */
975  MAKE_VIDPID(0x046d, 0xc29a), /* Logitech Driving Force GT */
976  MAKE_VIDPID(0x046d, 0xc29b), /* Logitech G27 */
977  MAKE_VIDPID(0x046d, 0xc261), /* Logitech G920 (initial mode) */
978  MAKE_VIDPID(0x046d, 0xc262), /* Logitech G920 (active mode) */
979  MAKE_VIDPID(0x044f, 0xb65d), /* Thrustmaster Wheel FFB */
980  MAKE_VIDPID(0x044f, 0xb66d), /* Thrustmaster Wheel FFB */
981  MAKE_VIDPID(0x044f, 0xb677), /* Thrustmaster T150 */
982  MAKE_VIDPID(0x044f, 0xb664), /* Thrustmaster TX (initial mode) */
983  MAKE_VIDPID(0x044f, 0xb669), /* Thrustmaster TX (active mode) */
984  };
985  int i;
986 
987  for (i = 0; i < SDL_arraysize(wheel_joysticks); ++i) {
988  if (vidpid == wheel_joysticks[i]) {
989  return SDL_TRUE;
990  }
991  }
992  return SDL_FALSE;
993 }
994 
996 {
997  static Uint32 flightstick_joysticks[] = {
998  MAKE_VIDPID(0x044f, 0x0402), /* HOTAS Warthog Joystick */
999  MAKE_VIDPID(0x0738, 0x2221), /* Saitek Pro Flight X-56 Rhino Stick */
1000  };
1001  int i;
1002 
1003  for (i = 0; i < SDL_arraysize(flightstick_joysticks); ++i) {
1004  if (vidpid == flightstick_joysticks[i]) {
1005  return SDL_TRUE;
1006  }
1007  }
1008  return SDL_FALSE;
1009 }
1010 
1012 {
1013  static Uint32 throttle_joysticks[] = {
1014  MAKE_VIDPID(0x044f, 0x0404), /* HOTAS Warthog Throttle */
1015  MAKE_VIDPID(0x0738, 0xa221), /* Saitek Pro Flight X-56 Rhino Throttle */
1016  };
1017  int i;
1018 
1019  for (i = 0; i < SDL_arraysize(throttle_joysticks); ++i) {
1020  if (vidpid == throttle_joysticks[i]) {
1021  return SDL_TRUE;
1022  }
1023  }
1024  return SDL_FALSE;
1025 }
1026 
1028 {
1029  Uint16 vendor;
1030  Uint16 product;
1031  Uint32 vidpid;
1032 
1033  if (guid.data[14] == 'x') {
1034  /* XInput GUID, get the type based on the XInput device subtype */
1035  switch (guid.data[15]) {
1036  case 0x01: /* XINPUT_DEVSUBTYPE_GAMEPAD */
1038  case 0x02: /* XINPUT_DEVSUBTYPE_WHEEL */
1039  return SDL_JOYSTICK_TYPE_WHEEL;
1040  case 0x03: /* XINPUT_DEVSUBTYPE_ARCADE_STICK */
1042  case 0x04: /* XINPUT_DEVSUBTYPE_FLIGHT_STICK */
1044  case 0x05: /* XINPUT_DEVSUBTYPE_DANCE_PAD */
1046  case 0x06: /* XINPUT_DEVSUBTYPE_GUITAR */
1047  case 0x07: /* XINPUT_DEVSUBTYPE_GUITAR_ALTERNATE */
1048  case 0x0B: /* XINPUT_DEVSUBTYPE_GUITAR_BASS */
1049  return SDL_JOYSTICK_TYPE_GUITAR;
1050  case 0x08: /* XINPUT_DEVSUBTYPE_DRUM_KIT */
1052  case 0x13: /* XINPUT_DEVSUBTYPE_ARCADE_PAD */
1054  default:
1056  }
1057  }
1058 
1059  SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL);
1060  vidpid = MAKE_VIDPID(vendor, product);
1061 
1062  if (SDL_IsJoystickProductWheel(vidpid)) {
1063  return SDL_JOYSTICK_TYPE_WHEEL;
1064  }
1065 
1066  if (SDL_IsJoystickProductFlightStick(vidpid)) {
1068  }
1069 
1070  if (SDL_IsJoystickProductThrottle(vidpid)) {
1072  }
1073 
1075 }
1076 
1077 /* return the guid for this index */
1079 {
1080  if (device_index < 0 || device_index >= SDL_NumJoysticks()) {
1081  SDL_JoystickGUID emptyGUID;
1082  SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
1083  SDL_zero(emptyGUID);
1084  return emptyGUID;
1085  }
1086  return SDL_SYS_JoystickGetDeviceGUID(device_index);
1087 }
1088 
1090 {
1091  Uint16 vendor;
1092  SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
1093 
1094  SDL_GetJoystickGUIDInfo(guid, &vendor, NULL, NULL);
1095  return vendor;
1096 }
1097 
1099 {
1100  Uint16 product;
1101  SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
1102 
1103  SDL_GetJoystickGUIDInfo(guid, NULL, &product, NULL);
1104  return product;
1105 }
1106 
1108 {
1109  Uint16 version;
1110  SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
1111 
1112  SDL_GetJoystickGUIDInfo(guid, NULL, NULL, &version);
1113  return version;
1114 }
1115 
1117 {
1119  SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
1120 
1121  type = SDL_GetJoystickGUIDType(guid);
1122  if (type == SDL_JOYSTICK_TYPE_UNKNOWN) {
1123  if (SDL_IsGameController(device_index)) {
1125  }
1126  }
1127  return type;
1128 }
1129 
1131 {
1132  if (device_index < 0 || device_index >= SDL_NumJoysticks()) {
1133  SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
1134  return -1;
1135  }
1136  return SDL_SYS_GetInstanceIdOfDeviceIndex(device_index);
1137 }
1138 
1139 SDL_JoystickGUID SDL_JoystickGetGUID(SDL_Joystick * joystick)
1140 {
1141  if (!SDL_PrivateJoystickValid(joystick)) {
1142  SDL_JoystickGUID emptyGUID;
1143  SDL_zero(emptyGUID);
1144  return emptyGUID;
1145  }
1146  return SDL_SYS_JoystickGetGUID(joystick);
1147 }
1148 
1149 Uint16 SDL_JoystickGetVendor(SDL_Joystick * joystick)
1150 {
1151  Uint16 vendor;
1152  SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
1153 
1154  SDL_GetJoystickGUIDInfo(guid, &vendor, NULL, NULL);
1155  return vendor;
1156 }
1157 
1158 Uint16 SDL_JoystickGetProduct(SDL_Joystick * joystick)
1159 {
1160  Uint16 product;
1161  SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
1162 
1163  SDL_GetJoystickGUIDInfo(guid, NULL, &product, NULL);
1164  return product;
1165 }
1166 
1167 Uint16 SDL_JoystickGetProductVersion(SDL_Joystick * joystick)
1168 {
1169  Uint16 version;
1170  SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
1171 
1172  SDL_GetJoystickGUIDInfo(guid, NULL, NULL, &version);
1173  return version;
1174 }
1175 
1176 SDL_JoystickType SDL_JoystickGetType(SDL_Joystick * joystick)
1177 {
1179  SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
1180 
1181  type = SDL_GetJoystickGUIDType(guid);
1182  if (type == SDL_JOYSTICK_TYPE_UNKNOWN) {
1183  if (joystick && joystick->is_game_controller) {
1185  }
1186  }
1187  return type;
1188 }
1189 
1190 /* convert the guid to a printable string */
1191 void SDL_JoystickGetGUIDString(SDL_JoystickGUID guid, char *pszGUID, int cbGUID)
1192 {
1193  static const char k_rgchHexToASCII[] = "0123456789abcdef";
1194  int i;
1195 
1196  if ((pszGUID == NULL) || (cbGUID <= 0)) {
1197  return;
1198  }
1199 
1200  for (i = 0; i < sizeof(guid.data) && i < (cbGUID-1)/2; i++) {
1201  /* each input byte writes 2 ascii chars, and might write a null byte. */
1202  /* If we don't have room for next input byte, stop */
1203  unsigned char c = guid.data[i];
1204 
1205  *pszGUID++ = k_rgchHexToASCII[c >> 4];
1206  *pszGUID++ = k_rgchHexToASCII[c & 0x0F];
1207  }
1208  *pszGUID = '\0';
1209 }
1210 
1211 
1212 /*-----------------------------------------------------------------------------
1213  * Purpose: Returns the 4 bit nibble for a hex character
1214  * Input : c -
1215  * Output : unsigned char
1216  *-----------------------------------------------------------------------------*/
1217 static unsigned char nibble(char c)
1218 {
1219  if ((c >= '0') && (c <= '9')) {
1220  return (unsigned char)(c - '0');
1221  }
1222 
1223  if ((c >= 'A') && (c <= 'F')) {
1224  return (unsigned char)(c - 'A' + 0x0a);
1225  }
1226 
1227  if ((c >= 'a') && (c <= 'f')) {
1228  return (unsigned char)(c - 'a' + 0x0a);
1229  }
1230 
1231  /* received an invalid character, and no real way to return an error */
1232  /* AssertMsg1(false, "Q_nibble invalid hex character '%c' ", c); */
1233  return 0;
1234 }
1235 
1236 
1237 /* convert the string version of a joystick guid to the struct */
1239 {
1240  SDL_JoystickGUID guid;
1241  int maxoutputbytes= sizeof(guid);
1242  size_t len = SDL_strlen(pchGUID);
1243  Uint8 *p;
1244  size_t i;
1245 
1246  /* Make sure it's even */
1247  len = (len) & ~0x1;
1248 
1249  SDL_memset(&guid, 0x00, sizeof(guid));
1250 
1251  p = (Uint8 *)&guid;
1252  for (i = 0; (i < len) && ((p - (Uint8 *)&guid) < maxoutputbytes); i+=2, p++) {
1253  *p = (nibble(pchGUID[i]) << 4) | nibble(pchGUID[i+1]);
1254  }
1255 
1256  return guid;
1257 }
1258 
1259 
1260 /* update the power level for this joystick */
1261 void SDL_PrivateJoystickBatteryLevel(SDL_Joystick * joystick, SDL_JoystickPowerLevel ePowerLevel)
1262 {
1263  joystick->epowerlevel = ePowerLevel;
1264 }
1265 
1266 
1267 /* return its power level */
1269 {
1270  if (!SDL_PrivateJoystickValid(joystick)) {
1271  return (SDL_JOYSTICK_POWER_UNKNOWN);
1272  }
1273  return joystick->epowerlevel;
1274 }
1275 
1276 /* vi: set ts=4 sw=4 expandtab: */
static SDL_bool SDL_IsJoystickProductWheel(Uint32 vidpid)
Definition: SDL_joystick.c:968
Uint16 SDL_JoystickGetVendor(SDL_Joystick *joystick)
void SDL_JoystickUpdate(void)
Definition: SDL_joystick.c:840
#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:466
#define SDL_abs
#define SDL_INIT_EVENTS
Definition: SDL.h:82
#define SDL_LockMutex
void SDL_LockJoysticks(void)
Definition: SDL_joystick.c:43
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:638
Uint16 SDL_JoystickGetProduct(SDL_Joystick *joystick)
void SDL_GameControllerQuitMappings(void)
int SDL_PrivateJoystickHat(SDL_Joystick *joystick, Uint8 hat, Uint8 value)
Definition: SDL_joystick.c:712
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:788
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
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:655
GLuint const GLchar * name
SDL_JoystickPowerLevel SDL_JoystickCurrentPowerLevel(SDL_Joystick *joystick)
static SDL_bool SDL_IsJoystickProductFlightStick(Uint32 vidpid)
Definition: SDL_joystick.c:995
SDL_bool retval
static void UpdateEventsForDeviceRemoval()
Definition: SDL_joystick.c:614
const char * SDL_JoystickName(SDL_Joystick *joystick)
Definition: SDL_joystick.c:478
int SDL_JoystickEventState(int state)
Definition: SDL_joystick.c:902
#define SDL_JOYSTICK_AXIS_MAX
Definition: SDL_joystick.h:288
int SDL_PrivateJoystickBall(SDL_Joystick *joystick, Uint8 ball, Sint16 xrel, Sint16 yrel)
Definition: SDL_joystick.c:752
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_free
#define SDL_stack_alloc(type, count)
Definition: SDL_stdinc.h:354
struct _cl_event * event
SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
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:416
const char * SDL_SYS_JoystickNameForDeviceIndex(int device_index)
SDL_Joystick * SDL_JoystickOpen(int device_index)
Definition: SDL_joystick.c:160
void SDL_UnlockJoysticks(void)
Definition: SDL_joystick.c:51
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
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 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)
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
#define SDL_calloc
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:933
#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:316
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