1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2016 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 
35 static SDL_bool SDL_joystick_allows_background_events = SDL_FALSE;
36 static SDL_Joystick *SDL_joysticks = NULL;
37 static SDL_Joystick *SDL_updating_joystick = NULL;
38 
39 static void
SDL_JoystickAllowBackgroundEventsChanged(void * userdata,const char * name,const char * oldValue,const char * hint)40 SDL_JoystickAllowBackgroundEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
41 {
42     if (hint && *hint == '1') {
43         SDL_joystick_allows_background_events = SDL_TRUE;
44     } else {
45         SDL_joystick_allows_background_events = SDL_FALSE;
46     }
47 }
48 
49 int
SDL_JoystickInit(void)50 SDL_JoystickInit(void)
51 {
52     int status;
53 
54     /* See if we should allow joystick events while in the background */
55     SDL_AddHintCallback(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS,
56                         SDL_JoystickAllowBackgroundEventsChanged, NULL);
57 
58 #if !SDL_EVENTS_DISABLED
59     if (SDL_InitSubSystem(SDL_INIT_EVENTS) < 0) {
60         return -1;
61     }
62 #endif /* !SDL_EVENTS_DISABLED */
63 
64     status = SDL_SYS_JoystickInit();
65     if (status >= 0) {
66         status = 0;
67     }
68     return (status);
69 }
70 
71 /*
72  * Count the number of joysticks attached to the system
73  */
74 int
SDL_NumJoysticks(void)75 SDL_NumJoysticks(void)
76 {
77     return SDL_SYS_NumJoysticks();
78 }
79 
80 /*
81  * Get the implementation dependent name of a joystick
82  */
83 const char *
SDL_JoystickNameForIndex(int device_index)84 SDL_JoystickNameForIndex(int device_index)
85 {
86     if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
87         SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
88         return (NULL);
89     }
90     return (SDL_SYS_JoystickNameForDeviceIndex(device_index));
91 }
92 
93 /*
94  * Open a joystick for use - the index passed as an argument refers to
95  * the N'th joystick on the system.  This index is the value which will
96  * identify this joystick in future joystick events.
97  *
98  * This function returns a joystick identifier, or NULL if an error occurred.
99  */
100 SDL_Joystick *
SDL_JoystickOpen(int device_index)101 SDL_JoystickOpen(int device_index)
102 {
103     SDL_Joystick *joystick;
104     SDL_Joystick *joysticklist;
105     const char *joystickname = NULL;
106 
107     if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
108         SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
109         return (NULL);
110     }
111 
112     joysticklist = SDL_joysticks;
113     /* If the joystick is already open, return it
114     * it is important that we have a single joystick * for each instance id
115     */
116     while (joysticklist) {
117         if (SDL_SYS_GetInstanceIdOfDeviceIndex(device_index) == joysticklist->instance_id) {
118                 joystick = joysticklist;
119                 ++joystick->ref_count;
120                 return (joystick);
121         }
122         joysticklist = joysticklist->next;
123     }
124 
125     /* Create and initialize the joystick */
126     joystick = (SDL_Joystick *) SDL_malloc((sizeof *joystick));
127     if (joystick == NULL) {
128         SDL_OutOfMemory();
129         return NULL;
130     }
131 
132     SDL_memset(joystick, 0, (sizeof *joystick));
133     if (SDL_SYS_JoystickOpen(joystick, device_index) < 0) {
134         SDL_free(joystick);
135         return NULL;
136     }
137 
138     joystickname = SDL_SYS_JoystickNameForDeviceIndex(device_index);
139     if (joystickname)
140         joystick->name = SDL_strdup(joystickname);
141     else
142         joystick->name = NULL;
143 
144     if (joystick->naxes > 0) {
145         joystick->axes = (Sint16 *) SDL_malloc(joystick->naxes * sizeof(Sint16));
146         joystick->axes_zero = (Sint16 *) SDL_malloc(joystick->naxes * sizeof(Sint16));
147     }
148     if (joystick->nhats > 0) {
149         joystick->hats = (Uint8 *) SDL_malloc
150             (joystick->nhats * sizeof(Uint8));
151     }
152     if (joystick->nballs > 0) {
153         joystick->balls = (struct balldelta *) SDL_malloc
154             (joystick->nballs * sizeof(*joystick->balls));
155     }
156     if (joystick->nbuttons > 0) {
157         joystick->buttons = (Uint8 *) SDL_malloc
158             (joystick->nbuttons * sizeof(Uint8));
159     }
160     if (((joystick->naxes > 0) && !joystick->axes)
161         || ((joystick->nhats > 0) && !joystick->hats)
162         || ((joystick->nballs > 0) && !joystick->balls)
163         || ((joystick->nbuttons > 0) && !joystick->buttons)) {
164         SDL_OutOfMemory();
165         SDL_JoystickClose(joystick);
166         return NULL;
167     }
168     if (joystick->axes) {
169         SDL_memset(joystick->axes, 0, joystick->naxes * sizeof(Sint16));
170         SDL_memset(joystick->axes_zero, 0, joystick->naxes * sizeof(Sint16));
171     }
172     if (joystick->hats) {
173         SDL_memset(joystick->hats, 0, joystick->nhats * sizeof(Uint8));
174     }
175     if (joystick->balls) {
176         SDL_memset(joystick->balls, 0,
177             joystick->nballs * sizeof(*joystick->balls));
178     }
179     if (joystick->buttons) {
180         SDL_memset(joystick->buttons, 0, joystick->nbuttons * sizeof(Uint8));
181     }
182     joystick->epowerlevel = SDL_JOYSTICK_POWER_UNKNOWN;
183 
184     /* Add joystick to list */
185     ++joystick->ref_count;
186     /* Link the joystick in the list */
187     joystick->next = SDL_joysticks;
188     SDL_joysticks = joystick;
189 
190     SDL_SYS_JoystickUpdate(joystick);
191 
192     return (joystick);
193 }
194 
195 
196 /*
197  * Checks to make sure the joystick is valid.
198  */
199 int
SDL_PrivateJoystickValid(SDL_Joystick * joystick)200 SDL_PrivateJoystickValid(SDL_Joystick * joystick)
201 {
202     int valid;
203 
204     if (joystick == NULL) {
205         SDL_SetError("Joystick hasn't been opened yet");
206         valid = 0;
207     } else {
208         valid = 1;
209     }
210 
211     return valid;
212 }
213 
214 /*
215  * Get the number of multi-dimensional axis controls on a joystick
216  */
217 int
SDL_JoystickNumAxes(SDL_Joystick * joystick)218 SDL_JoystickNumAxes(SDL_Joystick * joystick)
219 {
220     if (!SDL_PrivateJoystickValid(joystick)) {
221         return (-1);
222     }
223     return (joystick->naxes);
224 }
225 
226 /*
227  * Get the number of hats on a joystick
228  */
229 int
SDL_JoystickNumHats(SDL_Joystick * joystick)230 SDL_JoystickNumHats(SDL_Joystick * joystick)
231 {
232     if (!SDL_PrivateJoystickValid(joystick)) {
233         return (-1);
234     }
235     return (joystick->nhats);
236 }
237 
238 /*
239  * Get the number of trackballs on a joystick
240  */
241 int
SDL_JoystickNumBalls(SDL_Joystick * joystick)242 SDL_JoystickNumBalls(SDL_Joystick * joystick)
243 {
244     if (!SDL_PrivateJoystickValid(joystick)) {
245         return (-1);
246     }
247     return (joystick->nballs);
248 }
249 
250 /*
251  * Get the number of buttons on a joystick
252  */
253 int
SDL_JoystickNumButtons(SDL_Joystick * joystick)254 SDL_JoystickNumButtons(SDL_Joystick * joystick)
255 {
256     if (!SDL_PrivateJoystickValid(joystick)) {
257         return (-1);
258     }
259     return (joystick->nbuttons);
260 }
261 
262 /*
263  * Get the current state of an axis control on a joystick
264  */
265 Sint16
SDL_JoystickGetAxis(SDL_Joystick * joystick,int axis)266 SDL_JoystickGetAxis(SDL_Joystick * joystick, int axis)
267 {
268     Sint16 state;
269 
270     if (!SDL_PrivateJoystickValid(joystick)) {
271         return (0);
272     }
273     if (axis < joystick->naxes) {
274         state = joystick->axes[axis];
275     } else {
276         SDL_SetError("Joystick only has %d axes", joystick->naxes);
277         state = 0;
278     }
279     return (state);
280 }
281 
282 /*
283  * Get the current state of a hat on a joystick
284  */
285 Uint8
SDL_JoystickGetHat(SDL_Joystick * joystick,int hat)286 SDL_JoystickGetHat(SDL_Joystick * joystick, int hat)
287 {
288     Uint8 state;
289 
290     if (!SDL_PrivateJoystickValid(joystick)) {
291         return (0);
292     }
293     if (hat < joystick->nhats) {
294         state = joystick->hats[hat];
295     } else {
296         SDL_SetError("Joystick only has %d hats", joystick->nhats);
297         state = 0;
298     }
299     return (state);
300 }
301 
302 /*
303  * Get the ball axis change since the last poll
304  */
305 int
SDL_JoystickGetBall(SDL_Joystick * joystick,int ball,int * dx,int * dy)306 SDL_JoystickGetBall(SDL_Joystick * joystick, int ball, int *dx, int *dy)
307 {
308     int retval;
309 
310     if (!SDL_PrivateJoystickValid(joystick)) {
311         return (-1);
312     }
313 
314     retval = 0;
315     if (ball < joystick->nballs) {
316         if (dx) {
317             *dx = joystick->balls[ball].dx;
318         }
319         if (dy) {
320             *dy = joystick->balls[ball].dy;
321         }
322         joystick->balls[ball].dx = 0;
323         joystick->balls[ball].dy = 0;
324     } else {
325         return SDL_SetError("Joystick only has %d balls", joystick->nballs);
326     }
327     return (retval);
328 }
329 
330 /*
331  * Get the current state of a button on a joystick
332  */
333 Uint8
SDL_JoystickGetButton(SDL_Joystick * joystick,int button)334 SDL_JoystickGetButton(SDL_Joystick * joystick, int button)
335 {
336     Uint8 state;
337 
338     if (!SDL_PrivateJoystickValid(joystick)) {
339         return (0);
340     }
341     if (button < joystick->nbuttons) {
342         state = joystick->buttons[button];
343     } else {
344         SDL_SetError("Joystick only has %d buttons", joystick->nbuttons);
345         state = 0;
346     }
347     return (state);
348 }
349 
350 /*
351  * Return if the joystick in question is currently attached to the system,
352  *  \return SDL_FALSE if not plugged in, SDL_TRUE if still present.
353  */
354 SDL_bool
SDL_JoystickGetAttached(SDL_Joystick * joystick)355 SDL_JoystickGetAttached(SDL_Joystick * joystick)
356 {
357     if (!SDL_PrivateJoystickValid(joystick)) {
358         return SDL_FALSE;
359     }
360 
361     return SDL_SYS_JoystickAttached(joystick);
362 }
363 
364 /*
365  * Get the instance id for this opened joystick
366  */
367 SDL_JoystickID
SDL_JoystickInstanceID(SDL_Joystick * joystick)368 SDL_JoystickInstanceID(SDL_Joystick * joystick)
369 {
370     if (!SDL_PrivateJoystickValid(joystick)) {
371         return (-1);
372     }
373 
374     return (joystick->instance_id);
375 }
376 
377 /*
378  * Find the SDL_Joystick that owns this instance id
379  */
380 SDL_Joystick *
SDL_JoystickFromInstanceID(SDL_JoystickID joyid)381 SDL_JoystickFromInstanceID(SDL_JoystickID joyid)
382 {
383     SDL_Joystick *joystick = SDL_joysticks;
384     while (joystick) {
385         if (joystick->instance_id == joyid) {
386             return joystick;
387         }
388         joystick = joystick->next;
389     }
390 
391     return NULL;
392 }
393 
394 /*
395  * Get the friendly name of this joystick
396  */
397 const char *
SDL_JoystickName(SDL_Joystick * joystick)398 SDL_JoystickName(SDL_Joystick * joystick)
399 {
400     if (!SDL_PrivateJoystickValid(joystick)) {
401         return (NULL);
402     }
403 
404     return (joystick->name);
405 }
406 
407 /*
408  * Close a joystick previously opened with SDL_JoystickOpen()
409  */
410 void
SDL_JoystickClose(SDL_Joystick * joystick)411 SDL_JoystickClose(SDL_Joystick * joystick)
412 {
413     SDL_Joystick *joysticklist;
414     SDL_Joystick *joysticklistprev;
415 
416     if (!joystick) {
417         return;
418     }
419 
420     /* First decrement ref count */
421     if (--joystick->ref_count > 0) {
422         return;
423     }
424 
425     if (joystick == SDL_updating_joystick) {
426         return;
427     }
428 
429     SDL_SYS_JoystickClose(joystick);
430     joystick->hwdata = NULL;
431 
432     joysticklist = SDL_joysticks;
433     joysticklistprev = NULL;
434     while (joysticklist) {
435         if (joystick == joysticklist) {
436             if (joysticklistprev) {
437                 /* unlink this entry */
438                 joysticklistprev->next = joysticklist->next;
439             } else {
440                 SDL_joysticks = joystick->next;
441             }
442             break;
443         }
444         joysticklistprev = joysticklist;
445         joysticklist = joysticklist->next;
446     }
447 
448     SDL_free(joystick->name);
449 
450     /* Free the data associated with this joystick */
451     SDL_free(joystick->axes);
452     SDL_free(joystick->hats);
453     SDL_free(joystick->balls);
454     SDL_free(joystick->buttons);
455     SDL_free(joystick);
456 }
457 
458 void
SDL_JoystickQuit(void)459 SDL_JoystickQuit(void)
460 {
461     /* Make sure we're not getting called in the middle of updating joysticks */
462     SDL_assert(!SDL_updating_joystick);
463 
464     /* Stop the event polling */
465     while (SDL_joysticks) {
466         SDL_joysticks->ref_count = 1;
467         SDL_JoystickClose(SDL_joysticks);
468     }
469 
470     /* Quit the joystick setup */
471     SDL_SYS_JoystickQuit();
472 
473 #if !SDL_EVENTS_DISABLED
474     SDL_QuitSubSystem(SDL_INIT_EVENTS);
475 #endif
476 }
477 
478 
479 static SDL_bool
SDL_PrivateJoystickShouldIgnoreEvent()480 SDL_PrivateJoystickShouldIgnoreEvent()
481 {
482     if (SDL_joystick_allows_background_events) {
483         return SDL_FALSE;
484     }
485 
486     if (SDL_WasInit(SDL_INIT_VIDEO)) {
487         if (SDL_GetKeyboardFocus() == NULL) {
488             /* Video is initialized and we don't have focus, ignore the event. */
489             return SDL_TRUE;
490         } else {
491             return SDL_FALSE;
492         }
493     }
494 
495     /* Video subsystem wasn't initialized, always allow the event */
496     return SDL_FALSE;
497 }
498 
499 /* These are global for SDL_sysjoystick.c and SDL_events.c */
500 
SDL_PrivateJoystickAdded(int device_index)501 void SDL_PrivateJoystickAdded(int device_index)
502 {
503 #if !SDL_EVENTS_DISABLED
504     SDL_Event event;
505 
506     event.type = SDL_JOYDEVICEADDED;
507 
508     if (SDL_GetEventState(event.type) == SDL_ENABLE) {
509         event.jdevice.which = device_index;
510         if ( (SDL_EventOK == NULL) ||
511              (*SDL_EventOK) (SDL_EventOKParam, &event) ) {
512             SDL_PushEvent(&event);
513         }
514     }
515 #endif /* !SDL_EVENTS_DISABLED */
516 }
517 
518 /*
519  * If there is an existing add event in the queue, it needs to be modified
520  * to have the right value for which, because the number of controllers in
521  * the system is now one less.
522  */
UpdateEventsForDeviceRemoval()523 static void UpdateEventsForDeviceRemoval()
524 {
525     int i, num_events;
526     SDL_Event *events;
527 
528     num_events = SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, SDL_JOYDEVICEADDED, SDL_JOYDEVICEADDED);
529     if (num_events <= 0) {
530         return;
531     }
532 
533     events = SDL_stack_alloc(SDL_Event, num_events);
534     if (!events) {
535         return;
536     }
537 
538     num_events = SDL_PeepEvents(events, num_events, SDL_GETEVENT, SDL_JOYDEVICEADDED, SDL_JOYDEVICEADDED);
539     for (i = 0; i < num_events; ++i) {
540         --events[i].jdevice.which;
541     }
542     SDL_PeepEvents(events, num_events, SDL_ADDEVENT, 0, 0);
543 
544     SDL_stack_free(events);
545 }
546 
SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance)547 void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance)
548 {
549 #if !SDL_EVENTS_DISABLED
550     SDL_Event event;
551 
552     event.type = SDL_JOYDEVICEREMOVED;
553 
554     if (SDL_GetEventState(event.type) == SDL_ENABLE) {
555         event.jdevice.which = device_instance;
556         if ( (SDL_EventOK == NULL) ||
557              (*SDL_EventOK) (SDL_EventOKParam, &event) ) {
558             SDL_PushEvent(&event);
559         }
560     }
561 
562     UpdateEventsForDeviceRemoval();
563 #endif /* !SDL_EVENTS_DISABLED */
564 }
565 
566 int
SDL_PrivateJoystickAxis(SDL_Joystick * joystick,Uint8 axis,Sint16 value)567 SDL_PrivateJoystickAxis(SDL_Joystick * joystick, Uint8 axis, Sint16 value)
568 {
569     int posted;
570 
571     /* Make sure we're not getting garbage or duplicate events */
572     if (axis >= joystick->naxes) {
573         return 0;
574     }
575     if (value == joystick->axes[axis]) {
576         return 0;
577     }
578 
579     /* We ignore events if we don't have keyboard focus, except for centering
580      * events.
581      */
582     if (SDL_PrivateJoystickShouldIgnoreEvent()) {
583         if ((value > joystick->axes_zero[axis] && value >= joystick->axes[axis]) ||
584             (value < joystick->axes_zero[axis] && value <= joystick->axes[axis])) {
585             return 0;
586         }
587     }
588 
589     /* Update internal joystick state */
590     joystick->axes[axis] = value;
591 
592     /* Post the event, if desired */
593     posted = 0;
594 #if !SDL_EVENTS_DISABLED
595     if (SDL_GetEventState(SDL_JOYAXISMOTION) == SDL_ENABLE) {
596         SDL_Event event;
597         event.type = SDL_JOYAXISMOTION;
598         event.jaxis.which = joystick->instance_id;
599         event.jaxis.axis = axis;
600         event.jaxis.value = value;
601         posted = SDL_PushEvent(&event) == 1;
602     }
603 #endif /* !SDL_EVENTS_DISABLED */
604     return (posted);
605 }
606 
607 int
SDL_PrivateJoystickHat(SDL_Joystick * joystick,Uint8 hat,Uint8 value)608 SDL_PrivateJoystickHat(SDL_Joystick * joystick, Uint8 hat, Uint8 value)
609 {
610     int posted;
611 
612     /* Make sure we're not getting garbage or duplicate events */
613     if (hat >= joystick->nhats) {
614         return 0;
615     }
616     if (value == joystick->hats[hat]) {
617         return 0;
618     }
619 
620     /* We ignore events if we don't have keyboard focus, except for centering
621      * events.
622      */
623     if (SDL_PrivateJoystickShouldIgnoreEvent()) {
624         if (value != SDL_HAT_CENTERED) {
625             return 0;
626         }
627     }
628 
629     /* Update internal joystick state */
630     joystick->hats[hat] = value;
631 
632     /* Post the event, if desired */
633     posted = 0;
634 #if !SDL_EVENTS_DISABLED
635     if (SDL_GetEventState(SDL_JOYHATMOTION) == SDL_ENABLE) {
636         SDL_Event event;
637         event.jhat.type = SDL_JOYHATMOTION;
638         event.jhat.which = joystick->instance_id;
639         event.jhat.hat = hat;
640         event.jhat.value = value;
641         posted = SDL_PushEvent(&event) == 1;
642     }
643 #endif /* !SDL_EVENTS_DISABLED */
644     return (posted);
645 }
646 
647 int
SDL_PrivateJoystickBall(SDL_Joystick * joystick,Uint8 ball,Sint16 xrel,Sint16 yrel)648 SDL_PrivateJoystickBall(SDL_Joystick * joystick, Uint8 ball,
649                         Sint16 xrel, Sint16 yrel)
650 {
651     int posted;
652 
653     /* Make sure we're not getting garbage events */
654     if (ball >= joystick->nballs) {
655         return 0;
656     }
657 
658     /* We ignore events if we don't have keyboard focus. */
659     if (SDL_PrivateJoystickShouldIgnoreEvent()) {
660         return 0;
661     }
662 
663     /* Update internal mouse state */
664     joystick->balls[ball].dx += xrel;
665     joystick->balls[ball].dy += yrel;
666 
667     /* Post the event, if desired */
668     posted = 0;
669 #if !SDL_EVENTS_DISABLED
670     if (SDL_GetEventState(SDL_JOYBALLMOTION) == SDL_ENABLE) {
671         SDL_Event event;
672         event.jball.type = SDL_JOYBALLMOTION;
673         event.jball.which = joystick->instance_id;
674         event.jball.ball = ball;
675         event.jball.xrel = xrel;
676         event.jball.yrel = yrel;
677         posted = SDL_PushEvent(&event) == 1;
678     }
679 #endif /* !SDL_EVENTS_DISABLED */
680     return (posted);
681 }
682 
683 int
SDL_PrivateJoystickButton(SDL_Joystick * joystick,Uint8 button,Uint8 state)684 SDL_PrivateJoystickButton(SDL_Joystick * joystick, Uint8 button, Uint8 state)
685 {
686     int posted;
687 #if !SDL_EVENTS_DISABLED
688     SDL_Event event;
689 
690     switch (state) {
691     case SDL_PRESSED:
692         event.type = SDL_JOYBUTTONDOWN;
693         break;
694     case SDL_RELEASED:
695         event.type = SDL_JOYBUTTONUP;
696         break;
697     default:
698         /* Invalid state -- bail */
699         return (0);
700     }
701 #endif /* !SDL_EVENTS_DISABLED */
702 
703     /* Make sure we're not getting garbage or duplicate events */
704     if (button >= joystick->nbuttons) {
705         return 0;
706     }
707     if (state == joystick->buttons[button]) {
708         return 0;
709     }
710 
711     /* We ignore events if we don't have keyboard focus, except for button
712      * release. */
713     if (SDL_PrivateJoystickShouldIgnoreEvent()) {
714         if (state == SDL_PRESSED) {
715             return 0;
716         }
717     }
718 
719     /* Update internal joystick state */
720     joystick->buttons[button] = state;
721 
722     /* Post the event, if desired */
723     posted = 0;
724 #if !SDL_EVENTS_DISABLED
725     if (SDL_GetEventState(event.type) == SDL_ENABLE) {
726         event.jbutton.which = joystick->instance_id;
727         event.jbutton.button = button;
728         event.jbutton.state = state;
729         posted = SDL_PushEvent(&event) == 1;
730     }
731 #endif /* !SDL_EVENTS_DISABLED */
732     return (posted);
733 }
734 
735 void
SDL_JoystickUpdate(void)736 SDL_JoystickUpdate(void)
737 {
738     SDL_Joystick *joystick;
739 
740     joystick = SDL_joysticks;
741     while (joystick) {
742         SDL_Joystick *joysticknext;
743         /* save off the next pointer, the Update call may cause a joystick removed event
744          * and cause our joystick pointer to be freed
745          */
746         joysticknext = joystick->next;
747 
748         SDL_updating_joystick = joystick;
749 
750         SDL_SYS_JoystickUpdate(joystick);
751 
752         if (joystick->force_recentering) {
753             int i;
754 
755             /* Tell the app that everything is centered/unpressed...  */
756             for (i = 0; i < joystick->naxes; i++) {
757                 SDL_PrivateJoystickAxis(joystick, i, joystick->axes_zero[i]);
758             }
759 
760             for (i = 0; i < joystick->nbuttons; i++) {
761                 SDL_PrivateJoystickButton(joystick, i, 0);
762             }
763 
764             for (i = 0; i < joystick->nhats; i++) {
765                 SDL_PrivateJoystickHat(joystick, i, SDL_HAT_CENTERED);
766             }
767 
768             joystick->force_recentering = SDL_FALSE;
769         }
770 
771         SDL_updating_joystick = NULL;
772 
773         /* If the joystick was closed while updating, free it here */
774         if (joystick->ref_count <= 0) {
775             SDL_JoystickClose(joystick);
776         }
777 
778         joystick = joysticknext;
779     }
780 
781     /* this needs to happen AFTER walking the joystick list above, so that any
782        dangling hardware data from removed devices can be free'd
783      */
784     SDL_SYS_JoystickDetect();
785 }
786 
787 int
SDL_JoystickEventState(int state)788 SDL_JoystickEventState(int state)
789 {
790 #if SDL_EVENTS_DISABLED
791     return SDL_DISABLE;
792 #else
793     const Uint32 event_list[] = {
794         SDL_JOYAXISMOTION, SDL_JOYBALLMOTION, SDL_JOYHATMOTION,
795         SDL_JOYBUTTONDOWN, SDL_JOYBUTTONUP, SDL_JOYDEVICEADDED, SDL_JOYDEVICEREMOVED
796     };
797     unsigned int i;
798 
799     switch (state) {
800     case SDL_QUERY:
801         state = SDL_DISABLE;
802         for (i = 0; i < SDL_arraysize(event_list); ++i) {
803             state = SDL_EventState(event_list[i], SDL_QUERY);
804             if (state == SDL_ENABLE) {
805                 break;
806             }
807         }
808         break;
809     default:
810         for (i = 0; i < SDL_arraysize(event_list); ++i) {
811             SDL_EventState(event_list[i], state);
812         }
813         break;
814     }
815     return (state);
816 #endif /* SDL_EVENTS_DISABLED */
817 }
818 
819 /* return the guid for this index */
SDL_JoystickGetDeviceGUID(int device_index)820 SDL_JoystickGUID SDL_JoystickGetDeviceGUID(int device_index)
821 {
822     if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
823         SDL_JoystickGUID emptyGUID;
824         SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
825         SDL_zero(emptyGUID);
826         return emptyGUID;
827     }
828     return SDL_SYS_JoystickGetDeviceGUID(device_index);
829 }
830 
831 /* return the guid for this opened device */
SDL_JoystickGetGUID(SDL_Joystick * joystick)832 SDL_JoystickGUID SDL_JoystickGetGUID(SDL_Joystick * joystick)
833 {
834     if (!SDL_PrivateJoystickValid(joystick)) {
835         SDL_JoystickGUID emptyGUID;
836         SDL_zero(emptyGUID);
837         return emptyGUID;
838     }
839     return SDL_SYS_JoystickGetGUID(joystick);
840 }
841 
842 /* convert the guid to a printable string */
SDL_JoystickGetGUIDString(SDL_JoystickGUID guid,char * pszGUID,int cbGUID)843 void SDL_JoystickGetGUIDString(SDL_JoystickGUID guid, char *pszGUID, int cbGUID)
844 {
845     static const char k_rgchHexToASCII[] = "0123456789abcdef";
846     int i;
847 
848     if ((pszGUID == NULL) || (cbGUID <= 0)) {
849         return;
850     }
851 
852     for (i = 0; i < sizeof(guid.data) && i < (cbGUID-1)/2; i++) {
853         /* each input byte writes 2 ascii chars, and might write a null byte. */
854         /* If we don't have room for next input byte, stop */
855         unsigned char c = guid.data[i];
856 
857         *pszGUID++ = k_rgchHexToASCII[c >> 4];
858         *pszGUID++ = k_rgchHexToASCII[c & 0x0F];
859     }
860     *pszGUID = '\0';
861 }
862 
863 
864 /*-----------------------------------------------------------------------------
865  * Purpose: Returns the 4 bit nibble for a hex character
866  * Input  : c -
867  * Output : unsigned char
868  *-----------------------------------------------------------------------------*/
nibble(char c)869 static unsigned char nibble(char c)
870 {
871     if ((c >= '0') && (c <= '9')) {
872         return (unsigned char)(c - '0');
873     }
874 
875     if ((c >= 'A') && (c <= 'F')) {
876         return (unsigned char)(c - 'A' + 0x0a);
877     }
878 
879     if ((c >= 'a') && (c <= 'f')) {
880         return (unsigned char)(c - 'a' + 0x0a);
881     }
882 
883     /* received an invalid character, and no real way to return an error */
884     /* AssertMsg1(false, "Q_nibble invalid hex character '%c' ", c); */
885     return 0;
886 }
887 
888 
889 /* convert the string version of a joystick guid to the struct */
SDL_JoystickGetGUIDFromString(const char * pchGUID)890 SDL_JoystickGUID SDL_JoystickGetGUIDFromString(const char *pchGUID)
891 {
892     SDL_JoystickGUID guid;
893     int maxoutputbytes= sizeof(guid);
894     size_t len = SDL_strlen(pchGUID);
895     Uint8 *p;
896     size_t i;
897 
898     /* Make sure it's even */
899     len = (len) & ~0x1;
900 
901     SDL_memset(&guid, 0x00, sizeof(guid));
902 
903     p = (Uint8 *)&guid;
904     for (i = 0; (i < len) && ((p - (Uint8 *)&guid) < maxoutputbytes); i+=2, p++) {
905         *p = (nibble(pchGUID[i]) << 4) | nibble(pchGUID[i+1]);
906     }
907 
908     return guid;
909 }
910 
911 
912 /* update the power level for this joystick */
SDL_PrivateJoystickBatteryLevel(SDL_Joystick * joystick,SDL_JoystickPowerLevel ePowerLevel)913 void SDL_PrivateJoystickBatteryLevel(SDL_Joystick * joystick, SDL_JoystickPowerLevel ePowerLevel)
914 {
915     joystick->epowerlevel = ePowerLevel;
916 }
917 
918 
919 /* return its power level */
SDL_JoystickCurrentPowerLevel(SDL_Joystick * joystick)920 SDL_JoystickPowerLevel SDL_JoystickCurrentPowerLevel(SDL_Joystick * joystick)
921 {
922     if (!SDL_PrivateJoystickValid(joystick)) {
923         return (SDL_JOYSTICK_POWER_UNKNOWN);
924     }
925     return joystick->epowerlevel;
926 }
927 
928 
929 /* vi: set ts=4 sw=4 expandtab: */
930