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