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