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 
37 static SDL_bool SDL_joystick_allows_background_events = SDL_FALSE;
38 static SDL_Joystick *SDL_joysticks = NULL;
39 static SDL_bool SDL_updating_joystick = SDL_FALSE;
40 static SDL_mutex *SDL_joystick_lock = NULL; /* This needs to support recursive locks */
41 
42 void
SDL_LockJoysticks(void)43 SDL_LockJoysticks(void)
44 {
45     if (SDL_joystick_lock) {
46         SDL_LockMutex(SDL_joystick_lock);
47     }
48 }
49 
50 void
SDL_UnlockJoysticks(void)51 SDL_UnlockJoysticks(void)
52 {
53     if (SDL_joystick_lock) {
54         SDL_UnlockMutex(SDL_joystick_lock);
55     }
56 }
57 
58 
59 static void SDLCALL
SDL_JoystickAllowBackgroundEventsChanged(void * userdata,const char * name,const char * oldValue,const char * hint)60 SDL_JoystickAllowBackgroundEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
61 {
62     if (hint && *hint == '1') {
63         SDL_joystick_allows_background_events = SDL_TRUE;
64     } else {
65         SDL_joystick_allows_background_events = SDL_FALSE;
66     }
67 }
68 
69 int
SDL_JoystickInit(void)70 SDL_JoystickInit(void)
71 {
72     int status;
73 
74     SDL_GameControllerInitMappings();
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 */
82     SDL_AddHintCallback(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS,
83                         SDL_JoystickAllowBackgroundEventsChanged, NULL);
84 
85 #if !SDL_EVENTS_DISABLED
86     if (SDL_InitSubSystem(SDL_INIT_EVENTS) < 0) {
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
SDL_NumJoysticks(void)102 SDL_NumJoysticks(void)
103 {
104     return SDL_SYS_NumJoysticks();
105 }
106 
107 /*
108  * Get the implementation dependent name of a joystick
109  */
110 const char *
SDL_JoystickNameForIndex(int device_index)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
SDL_JoystickAxesCenteredAtZero(SDL_Joystick * joystick)126 SDL_JoystickAxesCenteredAtZero(SDL_Joystick *joystick)
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;
134     Uint32 id = MAKE_VIDPID(SDL_JoystickGetVendor(joystick),
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 *
SDL_JoystickOpen(int device_index)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 
171     SDL_LockJoysticks();
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;
181                 SDL_UnlockJoysticks();
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();
191         SDL_UnlockJoysticks();
192         return NULL;
193     }
194 
195     if (SDL_SYS_JoystickOpen(joystick, device_index) < 0) {
196         SDL_free(joystick);
197         SDL_UnlockJoysticks();
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);
225         SDL_UnlockJoysticks();
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 
247     SDL_UnlockJoysticks();
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
SDL_PrivateJoystickValid(SDL_Joystick * joystick)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
SDL_JoystickNumAxes(SDL_Joystick * joystick)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
SDL_JoystickNumHats(SDL_Joystick * joystick)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
SDL_JoystickNumBalls(SDL_Joystick * joystick)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
SDL_JoystickNumButtons(SDL_Joystick * joystick)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
SDL_JoystickGetAxis(SDL_Joystick * joystick,int axis)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
SDL_JoystickGetAxisInitialState(SDL_Joystick * joystick,int axis,Sint16 * state)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
SDL_JoystickGetHat(SDL_Joystick * joystick,int hat)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
SDL_JoystickGetBall(SDL_Joystick * joystick,int ball,int * dx,int * dy)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
SDL_JoystickGetButton(SDL_Joystick * joystick,int button)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
SDL_JoystickGetAttached(SDL_Joystick * joystick)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  */
445 SDL_JoystickID
SDL_JoystickInstanceID(SDL_Joystick * joystick)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 *
SDL_JoystickFromInstanceID(SDL_JoystickID joyid)459 SDL_JoystickFromInstanceID(SDL_JoystickID joyid)
460 {
461     SDL_Joystick *joystick;
462 
463     SDL_LockJoysticks();
464     for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
465         if (joystick->instance_id == joyid) {
466             SDL_UnlockJoysticks();
467             return joystick;
468         }
469     }
470     SDL_UnlockJoysticks();
471     return NULL;
472 }
473 
474 /*
475  * Get the friendly name of this joystick
476  */
477 const char *
SDL_JoystickName(SDL_Joystick * joystick)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
SDL_JoystickClose(SDL_Joystick * joystick)491 SDL_JoystickClose(SDL_Joystick * joystick)
492 {
493     SDL_Joystick *joysticklist;
494     SDL_Joystick *joysticklistprev;
495 
496     if (!joystick) {
497         return;
498     }
499 
500     SDL_LockJoysticks();
501 
502     /* First decrement ref count */
503     if (--joystick->ref_count > 0) {
504         SDL_UnlockJoysticks();
505         return;
506     }
507 
508     if (SDL_updating_joystick) {
509         SDL_UnlockJoysticks();
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 
541     SDL_UnlockJoysticks();
542 }
543 
544 void
SDL_JoystickQuit(void)545 SDL_JoystickQuit(void)
546 {
547     /* Make sure we're not getting called in the middle of updating joysticks */
548     SDL_assert(!SDL_updating_joystick);
549 
550     SDL_LockJoysticks();
551 
552     /* Stop the event polling */
553     while (SDL_joysticks) {
554         SDL_joysticks->ref_count = 1;
555         SDL_JoystickClose(SDL_joysticks);
556     }
557 
558     /* Quit the joystick setup */
559     SDL_SYS_JoystickQuit();
560 
561     SDL_UnlockJoysticks();
562 
563 #if !SDL_EVENTS_DISABLED
564     SDL_QuitSubSystem(SDL_INIT_EVENTS);
565 #endif
566 
567     SDL_DelHintCallback(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS,
568                         SDL_JoystickAllowBackgroundEventsChanged, NULL);
569 
570     if (SDL_joystick_lock) {
571         SDL_DestroyMutex(SDL_joystick_lock);
572         SDL_joystick_lock = NULL;
573     }
574 
575     SDL_GameControllerQuitMappings();
576 }
577 
578 
579 static SDL_bool
SDL_PrivateJoystickShouldIgnoreEvent()580 SDL_PrivateJoystickShouldIgnoreEvent()
581 {
582     if (SDL_joystick_allows_background_events) {
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 
SDL_PrivateJoystickAdded(int device_index)595 void SDL_PrivateJoystickAdded(int device_index)
596 {
597 #if !SDL_EVENTS_DISABLED
598     SDL_Event event;
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  */
UpdateEventsForDeviceRemoval()614 static void UpdateEventsForDeviceRemoval()
615 {
616     int i, num_events;
617     SDL_Event *events;
618 
619     num_events = SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, SDL_JOYDEVICEADDED, SDL_JOYDEVICEADDED);
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 
SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance)638 void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance)
639 {
640 #if !SDL_EVENTS_DISABLED
641     SDL_Event event;
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 
650     UpdateEventsForDeviceRemoval();
651 #endif /* !SDL_EVENTS_DISABLED */
652 }
653 
654 int
SDL_PrivateJoystickAxis(SDL_Joystick * joystick,Uint8 axis,Sint16 value)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      */
686     if (SDL_PrivateJoystickShouldIgnoreEvent()) {
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
699     if (SDL_GetEventState(SDL_JOYAXISMOTION) == SDL_ENABLE) {
700         SDL_Event event;
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
SDL_PrivateJoystickHat(SDL_Joystick * joystick,Uint8 hat,Uint8 value)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      */
727     if (SDL_PrivateJoystickShouldIgnoreEvent()) {
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
739     if (SDL_GetEventState(SDL_JOYHATMOTION) == SDL_ENABLE) {
740         SDL_Event event;
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
SDL_PrivateJoystickBall(SDL_Joystick * joystick,Uint8 ball,Sint16 xrel,Sint16 yrel)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. */
763     if (SDL_PrivateJoystickShouldIgnoreEvent()) {
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
774     if (SDL_GetEventState(SDL_JOYBALLMOTION) == SDL_ENABLE) {
775         SDL_Event event;
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
SDL_PrivateJoystickButton(SDL_Joystick * joystick,Uint8 button,Uint8 state)788 SDL_PrivateJoystickButton(SDL_Joystick * joystick, Uint8 button, Uint8 state)
789 {
790     int posted;
791 #if !SDL_EVENTS_DISABLED
792     SDL_Event event;
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. */
817     if (SDL_PrivateJoystickShouldIgnoreEvent()) {
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
SDL_JoystickUpdate(void)840 SDL_JoystickUpdate(void)
841 {
842     SDL_Joystick *joystick;
843 
844     SDL_LockJoysticks();
845 
846     if (SDL_updating_joystick) {
847         /* The joysticks are already being updated */
848         SDL_UnlockJoysticks();
849         return;
850     }
851 
852     SDL_updating_joystick = SDL_TRUE;
853 
854     /* Make sure the list is unlocked while dispatching events to prevent application deadlocks */
855     SDL_UnlockJoysticks();
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++) {
875                 SDL_PrivateJoystickHat(joystick, i, SDL_HAT_CENTERED);
876             }
877 
878             joystick->force_recentering = SDL_FALSE;
879         }
880     }
881 
882     SDL_LockJoysticks();
883 
884     SDL_updating_joystick = SDL_FALSE;
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      */
896     SDL_SYS_JoystickDetect();
897 
898     SDL_UnlockJoysticks();
899 }
900 
901 int
SDL_JoystickEventState(int state)902 SDL_JoystickEventState(int state)
903 {
904 #if SDL_EVENTS_DISABLED
905     return SDL_DISABLE;
906 #else
907     const Uint32 event_list[] = {
908         SDL_JOYAXISMOTION, SDL_JOYBALLMOTION, SDL_JOYHATMOTION,
909         SDL_JOYBUTTONDOWN, SDL_JOYBUTTONUP, SDL_JOYDEVICEADDED, SDL_JOYDEVICEREMOVED
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 
SDL_GetJoystickGUIDInfo(SDL_JoystickGUID guid,Uint16 * vendor,Uint16 * product,Uint16 * version)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 
SDL_IsJoystickProductWheel(Uint32 vidpid)968 static SDL_bool SDL_IsJoystickProductWheel(Uint32 vidpid)
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 
SDL_IsJoystickProductFlightStick(Uint32 vidpid)995 static SDL_bool SDL_IsJoystickProductFlightStick(Uint32 vidpid)
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 
SDL_IsJoystickProductThrottle(Uint32 vidpid)1011 static SDL_bool SDL_IsJoystickProductThrottle(Uint32 vidpid)
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 
SDL_GetJoystickGUIDType(SDL_JoystickGUID guid)1027 static SDL_JoystickType SDL_GetJoystickGUIDType(SDL_JoystickGUID guid)
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 */
1037             return SDL_JOYSTICK_TYPE_GAMECONTROLLER;
1038         case 0x02:  /* XINPUT_DEVSUBTYPE_WHEEL */
1039             return SDL_JOYSTICK_TYPE_WHEEL;
1040         case 0x03:  /* XINPUT_DEVSUBTYPE_ARCADE_STICK */
1041             return SDL_JOYSTICK_TYPE_ARCADE_STICK;
1042         case 0x04:  /* XINPUT_DEVSUBTYPE_FLIGHT_STICK */
1043             return SDL_JOYSTICK_TYPE_FLIGHT_STICK;
1044         case 0x05:  /* XINPUT_DEVSUBTYPE_DANCE_PAD */
1045             return SDL_JOYSTICK_TYPE_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 */
1051             return SDL_JOYSTICK_TYPE_DRUM_KIT;
1052         case 0x13:  /* XINPUT_DEVSUBTYPE_ARCADE_PAD */
1053             return SDL_JOYSTICK_TYPE_ARCADE_PAD;
1054         default:
1055             return SDL_JOYSTICK_TYPE_UNKNOWN;
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)) {
1067         return SDL_JOYSTICK_TYPE_FLIGHT_STICK;
1068     }
1069 
1070     if (SDL_IsJoystickProductThrottle(vidpid)) {
1071         return SDL_JOYSTICK_TYPE_THROTTLE;
1072     }
1073 
1074     return SDL_JOYSTICK_TYPE_UNKNOWN;
1075 }
1076 
1077 /* return the guid for this index */
SDL_JoystickGetDeviceGUID(int device_index)1078 SDL_JoystickGUID SDL_JoystickGetDeviceGUID(int device_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 
SDL_JoystickGetDeviceVendor(int device_index)1089 Uint16 SDL_JoystickGetDeviceVendor(int device_index)
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 
SDL_JoystickGetDeviceProduct(int device_index)1098 Uint16 SDL_JoystickGetDeviceProduct(int device_index)
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 
SDL_JoystickGetDeviceProductVersion(int device_index)1107 Uint16 SDL_JoystickGetDeviceProductVersion(int device_index)
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 
SDL_JoystickGetDeviceType(int device_index)1116 SDL_JoystickType SDL_JoystickGetDeviceType(int device_index)
1117 {
1118     SDL_JoystickType type;
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)) {
1124             type = SDL_JOYSTICK_TYPE_GAMECONTROLLER;
1125         }
1126     }
1127     return type;
1128 }
1129 
SDL_JoystickGetDeviceInstanceID(int device_index)1130 SDL_JoystickID SDL_JoystickGetDeviceInstanceID(int device_index)
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 
SDL_JoystickGetGUID(SDL_Joystick * joystick)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 
SDL_JoystickGetVendor(SDL_Joystick * joystick)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 
SDL_JoystickGetProduct(SDL_Joystick * joystick)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 
SDL_JoystickGetProductVersion(SDL_Joystick * joystick)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 
SDL_JoystickGetType(SDL_Joystick * joystick)1176 SDL_JoystickType SDL_JoystickGetType(SDL_Joystick * joystick)
1177 {
1178     SDL_JoystickType type;
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) {
1184             type = SDL_JOYSTICK_TYPE_GAMECONTROLLER;
1185         }
1186     }
1187     return type;
1188 }
1189 
1190 /* convert the guid to a printable string */
SDL_JoystickGetGUIDString(SDL_JoystickGUID guid,char * pszGUID,int cbGUID)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  *-----------------------------------------------------------------------------*/
nibble(char c)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 */
SDL_JoystickGetGUIDFromString(const char * pchGUID)1238 SDL_JoystickGUID SDL_JoystickGetGUIDFromString(const char *pchGUID)
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 */
SDL_PrivateJoystickBatteryLevel(SDL_Joystick * joystick,SDL_JoystickPowerLevel ePowerLevel)1261 void SDL_PrivateJoystickBatteryLevel(SDL_Joystick * joystick, SDL_JoystickPowerLevel ePowerLevel)
1262 {
1263     joystick->epowerlevel = ePowerLevel;
1264 }
1265 
1266 
1267 /* return its power level */
SDL_JoystickCurrentPowerLevel(SDL_Joystick * joystick)1268 SDL_JoystickPowerLevel SDL_JoystickCurrentPowerLevel(SDL_Joystick * joystick)
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: */
1277