2 Simple DirectMedia Layer
3 Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
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.
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:
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.
21 #include "../SDL_internal.h"
23 /* This is the joystick API for Simple DirectMedia Layer */
26 #include "SDL_atomic.h"
27 #include "SDL_events.h"
28 #include "SDL_sysjoystick.h"
29 #include "SDL_hints.h"
31 #if !SDL_EVENTS_DISABLED
32 #include "../events/SDL_events_c.h"
34 #include "../video/SDL_sysvideo.h"
35 #include "hidapi/SDL_hidapijoystick_c.h"
37 /* This is included in only one place because it has a large static list of controllers */
38 #include "controller_type.h"
41 /* Needed for checking for input remapping programs */
42 #include "../core/windows/SDL_windows.h"
44 #undef UNICODE /* We want ASCII functions */
48 #if SDL_JOYSTICK_VIRTUAL
49 #include "./virtual/SDL_virtualjoystick_c.h"
52 static SDL_JoystickDriver *SDL_joystick_drivers[] = {
53 #ifdef SDL_JOYSTICK_HIDAPI /* Before WINDOWS_ driver, as WINDOWS wants to check if this driver is handling things */
54 &SDL_HIDAPI_JoystickDriver,
56 #ifdef SDL_JOYSTICK_RAWINPUT /* Before WINDOWS_ driver, as WINDOWS wants to check if this driver is handling things */
57 &SDL_RAWINPUT_JoystickDriver,
59 #if defined(SDL_JOYSTICK_WGI)
60 &SDL_WGI_JoystickDriver,
62 #if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT)
63 &SDL_WINDOWS_JoystickDriver,
65 #ifdef SDL_JOYSTICK_LINUX
66 &SDL_LINUX_JoystickDriver,
68 #ifdef SDL_JOYSTICK_IOKIT
69 &SDL_DARWIN_JoystickDriver,
71 #if (defined(__MACOSX__) || defined(__IPHONEOS__) || defined(__TVOS__)) && !defined(SDL_JOYSTICK_DISABLED)
72 &SDL_IOS_JoystickDriver,
74 #ifdef SDL_JOYSTICK_ANDROID
75 &SDL_ANDROID_JoystickDriver,
77 #ifdef SDL_JOYSTICK_EMSCRIPTEN
78 &SDL_EMSCRIPTEN_JoystickDriver,
80 #ifdef SDL_JOYSTICK_HAIKU
81 &SDL_HAIKU_JoystickDriver,
83 #ifdef SDL_JOYSTICK_USBHID /* !!! FIXME: "USBHID" is a generic name, and doubly-confusing with HIDAPI next to it. This is the *BSD interface, rename this. */
84 &SDL_BSD_JoystickDriver,
86 #ifdef SDL_JOYSTICK_VIRTUAL
87 &SDL_VIRTUAL_JoystickDriver,
89 #if defined(SDL_JOYSTICK_DUMMY) || defined(SDL_JOYSTICK_DISABLED)
90 &SDL_DUMMY_JoystickDriver
93 static SDL_bool SDL_joystick_allows_background_events = SDL_FALSE;
94 static SDL_Joystick *SDL_joysticks = NULL;
95 static SDL_bool SDL_updating_joystick = SDL_FALSE;
96 static SDL_mutex *SDL_joystick_lock = NULL; /* This needs to support recursive locks */
97 static SDL_atomic_t SDL_next_joystick_instance_id;
98 static int SDL_joystick_player_count = 0;
99 static SDL_JoystickID *SDL_joystick_players = NULL;
102 SDL_LockJoysticks(void)
104 if (SDL_joystick_lock) {
105 SDL_LockMutex(SDL_joystick_lock);
110 SDL_UnlockJoysticks(void)
112 if (SDL_joystick_lock) {
113 SDL_UnlockMutex(SDL_joystick_lock);
118 SDL_FindFreePlayerIndex()
122 for (player_index = 0; player_index < SDL_joystick_player_count; ++player_index) {
123 if (SDL_joystick_players[player_index] == -1) {
131 SDL_GetPlayerIndexForJoystickID(SDL_JoystickID instance_id)
135 for (player_index = 0; player_index < SDL_joystick_player_count; ++player_index) {
136 if (instance_id == SDL_joystick_players[player_index]) {
140 if (player_index == SDL_joystick_player_count) {
146 static SDL_JoystickID
147 SDL_GetJoystickIDForPlayerIndex(int player_index)
149 if (player_index < 0 || player_index >= SDL_joystick_player_count) {
152 return SDL_joystick_players[player_index];
156 SDL_SetJoystickIDForPlayerIndex(int player_index, SDL_JoystickID instance_id)
158 SDL_JoystickID existing_instance = SDL_GetJoystickIDForPlayerIndex(player_index);
159 SDL_JoystickDriver *driver;
161 int existing_player_index;
163 if (player_index < 0) {
166 if (player_index >= SDL_joystick_player_count) {
167 SDL_JoystickID *new_players = (SDL_JoystickID *)SDL_realloc(SDL_joystick_players, (player_index + 1)*sizeof(*SDL_joystick_players));
173 SDL_joystick_players = new_players;
174 SDL_memset(&SDL_joystick_players[SDL_joystick_player_count], 0xFF, (player_index - SDL_joystick_player_count + 1) * sizeof(SDL_joystick_players[0]));
175 SDL_joystick_player_count = player_index + 1;
176 } else if (SDL_joystick_players[player_index] == instance_id) {
177 /* Joystick is already assigned the requested player index */
181 /* Clear the old player index */
182 existing_player_index = SDL_GetPlayerIndexForJoystickID(instance_id);
183 if (existing_player_index >= 0) {
184 SDL_joystick_players[existing_player_index] = -1;
187 SDL_joystick_players[player_index] = instance_id;
189 /* Update the driver with the new index */
190 device_index = SDL_JoystickGetDeviceIndexFromInstanceID(instance_id);
191 if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) {
192 driver->SetDevicePlayerIndex(device_index, player_index);
195 /* Move any existing joystick to another slot */
196 if (existing_instance >= 0) {
197 SDL_SetJoystickIDForPlayerIndex(SDL_FindFreePlayerIndex(), existing_instance);
203 SDL_JoystickAllowBackgroundEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
205 if (hint && *hint == '1') {
206 SDL_joystick_allows_background_events = SDL_TRUE;
208 SDL_joystick_allows_background_events = SDL_FALSE;
213 SDL_JoystickInit(void)
217 SDL_GameControllerInitMappings();
219 /* Create the joystick list lock */
220 if (!SDL_joystick_lock) {
221 SDL_joystick_lock = SDL_CreateMutex();
224 /* See if we should allow joystick events while in the background */
225 SDL_AddHintCallback(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS,
226 SDL_JoystickAllowBackgroundEventsChanged, NULL);
228 #if !SDL_EVENTS_DISABLED
229 if (SDL_InitSubSystem(SDL_INIT_EVENTS) < 0) {
232 #endif /* !SDL_EVENTS_DISABLED */
235 for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) {
236 if (SDL_joystick_drivers[i]->Init() >= 0) {
244 * Count the number of joysticks attached to the system
247 SDL_NumJoysticks(void)
249 int i, total_joysticks = 0;
251 for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) {
252 total_joysticks += SDL_joystick_drivers[i]->GetCount();
254 SDL_UnlockJoysticks();
255 return total_joysticks;
259 * Return the next available joystick instance ID
260 * This may be called by drivers from multiple threads, unprotected by any locks
262 SDL_JoystickID SDL_GetNextJoystickInstanceID()
264 return SDL_AtomicIncRef(&SDL_next_joystick_instance_id);
268 * Get the driver and device index for an API device index
269 * This should be called while the joystick lock is held, to prevent another thread from updating the list
272 SDL_GetDriverAndJoystickIndex(int device_index, SDL_JoystickDriver **driver, int *driver_index)
274 int i, num_joysticks, total_joysticks = 0;
276 if (device_index >= 0) {
277 for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) {
278 num_joysticks = SDL_joystick_drivers[i]->GetCount();
279 if (device_index < num_joysticks) {
280 *driver = SDL_joystick_drivers[i];
281 *driver_index = device_index;
284 device_index -= num_joysticks;
285 total_joysticks += num_joysticks;
289 SDL_SetError("There are %d joysticks available", total_joysticks);
294 * Get the implementation dependent name of a joystick
297 SDL_JoystickNameForIndex(int device_index)
299 SDL_JoystickDriver *driver;
300 const char *name = NULL;
303 if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) {
304 name = driver->GetDeviceName(device_index);
306 SDL_UnlockJoysticks();
308 /* FIXME: Really we should reference count this name so it doesn't go away after unlock */
313 * Get the player index of a joystick, or -1 if it's not available
316 SDL_JoystickGetDevicePlayerIndex(int device_index)
321 player_index = SDL_GetPlayerIndexForJoystickID(SDL_JoystickGetDeviceInstanceID(device_index));
322 SDL_UnlockJoysticks();
328 * Return true if this joystick is known to have all axes centered at zero
329 * This isn't generally needed unless the joystick never generates an initial axis value near zero,
330 * e.g. it's emulating axes with digital buttons
333 SDL_JoystickAxesCenteredAtZero(SDL_Joystick *joystick)
335 static Uint32 zero_centered_joysticks[] = {
336 MAKE_VIDPID(0x0e8f, 0x3013), /* HuiJia SNES USB adapter */
337 MAKE_VIDPID(0x05a0, 0x3232), /* 8Bitdo Zero Gamepad */
341 Uint32 id = MAKE_VIDPID(SDL_JoystickGetVendor(joystick),
342 SDL_JoystickGetProduct(joystick));
344 /*printf("JOYSTICK '%s' VID/PID 0x%.4x/0x%.4x AXES: %d\n", joystick->name, vendor, product, joystick->naxes);*/
346 if (joystick->naxes == 2) {
347 /* Assume D-pad or thumbstick style axes are centered at 0 */
351 for (i = 0; i < SDL_arraysize(zero_centered_joysticks); ++i) {
352 if (id == zero_centered_joysticks[i]) {
360 * Open a joystick for use - the index passed as an argument refers to
361 * the N'th joystick on the system. This index is the value which will
362 * identify this joystick in future joystick events.
364 * This function returns a joystick identifier, or NULL if an error occurred.
367 SDL_JoystickOpen(int device_index)
369 SDL_JoystickDriver *driver;
370 SDL_JoystickID instance_id;
371 SDL_Joystick *joystick;
372 SDL_Joystick *joysticklist;
373 const char *joystickname = NULL;
377 if (!SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) {
378 SDL_UnlockJoysticks();
382 joysticklist = SDL_joysticks;
383 /* If the joystick is already open, return it
384 * it is important that we have a single joystick * for each instance id
386 instance_id = driver->GetDeviceInstanceID(device_index);
387 while (joysticklist) {
388 if (instance_id == joysticklist->instance_id) {
389 joystick = joysticklist;
390 ++joystick->ref_count;
391 SDL_UnlockJoysticks();
394 joysticklist = joysticklist->next;
397 /* Create and initialize the joystick */
398 joystick = (SDL_Joystick *) SDL_calloc(sizeof(*joystick), 1);
399 if (joystick == NULL) {
401 SDL_UnlockJoysticks();
404 joystick->driver = driver;
405 joystick->instance_id = instance_id;
406 joystick->attached = SDL_TRUE;
407 joystick->epowerlevel = SDL_JOYSTICK_POWER_UNKNOWN;
409 if (driver->Open(joystick, device_index) < 0) {
411 SDL_UnlockJoysticks();
415 joystickname = driver->GetDeviceName(device_index);
417 joystick->name = SDL_strdup(joystickname);
419 joystick->name = NULL;
422 joystick->guid = driver->GetDeviceGUID(device_index);
424 if (joystick->naxes > 0) {
425 joystick->axes = (SDL_JoystickAxisInfo *) SDL_calloc(joystick->naxes, sizeof(SDL_JoystickAxisInfo));
427 if (joystick->nhats > 0) {
428 joystick->hats = (Uint8 *) SDL_calloc(joystick->nhats, sizeof(Uint8));
430 if (joystick->nballs > 0) {
431 joystick->balls = (struct balldelta *) SDL_calloc(joystick->nballs, sizeof(*joystick->balls));
433 if (joystick->nbuttons > 0) {
434 joystick->buttons = (Uint8 *) SDL_calloc(joystick->nbuttons, sizeof(Uint8));
436 if (((joystick->naxes > 0) && !joystick->axes)
437 || ((joystick->nhats > 0) && !joystick->hats)
438 || ((joystick->nballs > 0) && !joystick->balls)
439 || ((joystick->nbuttons > 0) && !joystick->buttons)) {
441 SDL_JoystickClose(joystick);
442 SDL_UnlockJoysticks();
446 /* If this joystick is known to have all zero centered axes, skip the auto-centering code */
447 if (SDL_JoystickAxesCenteredAtZero(joystick)) {
450 for (i = 0; i < joystick->naxes; ++i) {
451 joystick->axes[i].has_initial_value = SDL_TRUE;
455 joystick->is_game_controller = SDL_IsGameController(device_index);
457 /* Add joystick to list */
458 ++joystick->ref_count;
459 /* Link the joystick in the list */
460 joystick->next = SDL_joysticks;
461 SDL_joysticks = joystick;
463 SDL_UnlockJoysticks();
465 driver->Update(joystick);
471 SDL_JoystickAttachVirtual(SDL_JoystickType type,
472 int naxes, int nbuttons, int nhats)
474 #if SDL_JOYSTICK_VIRTUAL
475 return SDL_JoystickAttachVirtualInner(type, naxes, nbuttons, nhats);
477 return SDL_SetError("SDL not built with virtual-joystick support");
482 SDL_JoystickDetachVirtual(int device_index)
484 #if SDL_JOYSTICK_VIRTUAL
485 SDL_JoystickDriver *driver;
488 if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) {
489 if (driver == &SDL_VIRTUAL_JoystickDriver) {
490 const int result = SDL_JoystickDetachVirtualInner(device_index);
491 SDL_UnlockJoysticks();
495 SDL_UnlockJoysticks();
497 return SDL_SetError("Virtual joystick not found at provided index");
499 return SDL_SetError("SDL not built with virtual-joystick support");
504 SDL_JoystickIsVirtual(int device_index)
506 #if SDL_JOYSTICK_VIRTUAL
507 SDL_JoystickDriver *driver;
508 int driver_device_index;
509 SDL_bool is_virtual = SDL_FALSE;
512 if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &driver_device_index)) {
513 if (driver == &SDL_VIRTUAL_JoystickDriver) {
514 is_virtual = SDL_TRUE;
517 SDL_UnlockJoysticks();
526 SDL_JoystickSetVirtualAxis(SDL_Joystick *joystick, int axis, Sint16 value)
528 #if SDL_JOYSTICK_VIRTUAL
529 return SDL_JoystickSetVirtualAxisInner(joystick, axis, value);
531 return SDL_SetError("SDL not built with virtual-joystick support");
536 SDL_JoystickSetVirtualButton(SDL_Joystick *joystick, int button, Uint8 value)
538 #if SDL_JOYSTICK_VIRTUAL
539 return SDL_JoystickSetVirtualButtonInner(joystick, button, value);
541 return SDL_SetError("SDL not built with virtual-joystick support");
546 SDL_JoystickSetVirtualHat(SDL_Joystick *joystick, int hat, Uint8 value)
548 #if SDL_JOYSTICK_VIRTUAL
549 return SDL_JoystickSetVirtualHatInner(joystick, hat, value);
551 return SDL_SetError("SDL not built with virtual-joystick support");
556 * Checks to make sure the joystick is valid.
559 SDL_PrivateJoystickValid(SDL_Joystick *joystick)
563 if (joystick == NULL) {
564 SDL_SetError("Joystick hasn't been opened yet");
574 SDL_PrivateJoystickGetAutoGamepadMapping(int device_index, SDL_GamepadMapping * out)
576 SDL_JoystickDriver *driver;
577 SDL_bool is_ok = SDL_FALSE;
580 if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) {
581 is_ok = driver->GetGamepadMapping(device_index, out);
583 SDL_UnlockJoysticks();
589 * Get the number of multi-dimensional axis controls on a joystick
592 SDL_JoystickNumAxes(SDL_Joystick *joystick)
594 if (!SDL_PrivateJoystickValid(joystick)) {
597 return joystick->naxes;
601 * Get the number of hats on a joystick
604 SDL_JoystickNumHats(SDL_Joystick *joystick)
606 if (!SDL_PrivateJoystickValid(joystick)) {
609 return joystick->nhats;
613 * Get the number of trackballs on a joystick
616 SDL_JoystickNumBalls(SDL_Joystick *joystick)
618 if (!SDL_PrivateJoystickValid(joystick)) {
621 return joystick->nballs;
625 * Get the number of buttons on a joystick
628 SDL_JoystickNumButtons(SDL_Joystick *joystick)
630 if (!SDL_PrivateJoystickValid(joystick)) {
633 return joystick->nbuttons;
637 * Get the current state of an axis control on a joystick
640 SDL_JoystickGetAxis(SDL_Joystick *joystick, int axis)
644 if (!SDL_PrivateJoystickValid(joystick)) {
647 if (axis < joystick->naxes) {
648 state = joystick->axes[axis].value;
650 SDL_SetError("Joystick only has %d axes", joystick->naxes);
657 * Get the initial state of an axis control on a joystick
660 SDL_JoystickGetAxisInitialState(SDL_Joystick *joystick, int axis, Sint16 *state)
662 if (!SDL_PrivateJoystickValid(joystick)) {
665 if (axis >= joystick->naxes) {
666 SDL_SetError("Joystick only has %d axes", joystick->naxes);
670 *state = joystick->axes[axis].initial_value;
672 return joystick->axes[axis].has_initial_value;
676 * Get the current state of a hat on a joystick
679 SDL_JoystickGetHat(SDL_Joystick *joystick, int hat)
683 if (!SDL_PrivateJoystickValid(joystick)) {
686 if (hat < joystick->nhats) {
687 state = joystick->hats[hat];
689 SDL_SetError("Joystick only has %d hats", joystick->nhats);
696 * Get the ball axis change since the last poll
699 SDL_JoystickGetBall(SDL_Joystick *joystick, int ball, int *dx, int *dy)
703 if (!SDL_PrivateJoystickValid(joystick)) {
708 if (ball < joystick->nballs) {
710 *dx = joystick->balls[ball].dx;
713 *dy = joystick->balls[ball].dy;
715 joystick->balls[ball].dx = 0;
716 joystick->balls[ball].dy = 0;
718 return SDL_SetError("Joystick only has %d balls", joystick->nballs);
724 * Get the current state of a button on a joystick
727 SDL_JoystickGetButton(SDL_Joystick *joystick, int button)
731 if (!SDL_PrivateJoystickValid(joystick)) {
734 if (button < joystick->nbuttons) {
735 state = joystick->buttons[button];
737 SDL_SetError("Joystick only has %d buttons", joystick->nbuttons);
744 * Return if the joystick in question is currently attached to the system,
745 * \return SDL_FALSE if not plugged in, SDL_TRUE if still present.
748 SDL_JoystickGetAttached(SDL_Joystick *joystick)
750 if (!SDL_PrivateJoystickValid(joystick)) {
754 return joystick->attached;
758 * Get the instance id for this opened joystick
761 SDL_JoystickInstanceID(SDL_Joystick *joystick)
763 if (!SDL_PrivateJoystickValid(joystick)) {
767 return joystick->instance_id;
771 * Return the SDL_Joystick associated with an instance id.
774 SDL_JoystickFromInstanceID(SDL_JoystickID instance_id)
776 SDL_Joystick *joystick;
779 for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
780 if (joystick->instance_id == instance_id) {
784 SDL_UnlockJoysticks();
789 * Return the SDL_Joystick associated with a player index.
792 SDL_JoystickFromPlayerIndex(int player_index)
794 SDL_JoystickID instance_id;
795 SDL_Joystick *joystick;
798 instance_id = SDL_GetJoystickIDForPlayerIndex(player_index);
799 for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
800 if (joystick->instance_id == instance_id) {
804 SDL_UnlockJoysticks();
809 * Get the friendly name of this joystick
812 SDL_JoystickName(SDL_Joystick *joystick)
814 if (!SDL_PrivateJoystickValid(joystick)) {
818 return joystick->name;
822 * Get the player index of an opened joystick, or -1 if it's not available
825 SDL_JoystickGetPlayerIndex(SDL_Joystick *joystick)
829 if (!SDL_PrivateJoystickValid(joystick)) {
834 player_index = SDL_GetPlayerIndexForJoystickID(joystick->instance_id);
835 SDL_UnlockJoysticks();
841 * Set the player index of an opened joystick
844 SDL_JoystickSetPlayerIndex(SDL_Joystick *joystick, int player_index)
846 if (!SDL_PrivateJoystickValid(joystick)) {
851 SDL_SetJoystickIDForPlayerIndex(player_index, joystick->instance_id);
852 SDL_UnlockJoysticks();
856 SDL_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
860 if (!SDL_PrivateJoystickValid(joystick)) {
865 if (low_frequency_rumble == joystick->low_frequency_rumble &&
866 high_frequency_rumble == joystick->high_frequency_rumble) {
867 /* Just update the expiration */
870 result = joystick->driver->Rumble(joystick, low_frequency_rumble, high_frequency_rumble);
873 /* Save the rumble value regardless of success, so we don't spam the driver */
874 joystick->low_frequency_rumble = low_frequency_rumble;
875 joystick->high_frequency_rumble = high_frequency_rumble;
877 if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) {
878 joystick->rumble_expiration = SDL_GetTicks() + SDL_min(duration_ms, SDL_MAX_RUMBLE_DURATION_MS);
879 if (!joystick->rumble_expiration) {
880 joystick->rumble_expiration = 1;
883 joystick->rumble_expiration = 0;
885 SDL_UnlockJoysticks();
891 SDL_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble, Uint32 duration_ms)
895 if (!SDL_PrivateJoystickValid(joystick)) {
900 if (left_rumble == joystick->left_trigger_rumble && right_rumble == joystick->right_trigger_rumble) {
901 /* Just update the expiration */
904 result = joystick->driver->RumbleTriggers(joystick, left_rumble, right_rumble);
907 /* Save the rumble value regardless of success, so we don't spam the driver */
908 joystick->left_trigger_rumble = left_rumble;
909 joystick->right_trigger_rumble = right_rumble;
911 if ((left_rumble || right_rumble) && duration_ms) {
912 joystick->trigger_rumble_expiration = SDL_GetTicks() + SDL_min(duration_ms, SDL_MAX_RUMBLE_DURATION_MS);
913 if (!joystick->trigger_rumble_expiration) {
914 joystick->trigger_rumble_expiration = 1;
917 joystick->trigger_rumble_expiration = 0;
919 SDL_UnlockJoysticks();
925 SDL_JoystickHasLED(SDL_Joystick *joystick)
929 if (!SDL_PrivateJoystickValid(joystick)) {
935 result = joystick->driver->HasLED(joystick);
937 SDL_UnlockJoysticks();
943 SDL_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
947 if (!SDL_PrivateJoystickValid(joystick)) {
953 if (red == joystick->led_red &&
954 green == joystick->led_green &&
955 blue == joystick->led_blue) {
956 /* Avoid spamming the driver */
959 result = joystick->driver->SetLED(joystick, red, green, blue);
962 /* Save the LED value regardless of success, so we don't spam the driver */
963 joystick->led_red = red;
964 joystick->led_green = green;
965 joystick->led_blue = blue;
967 SDL_UnlockJoysticks();
973 * Close a joystick previously opened with SDL_JoystickOpen()
976 SDL_JoystickClose(SDL_Joystick *joystick)
978 SDL_Joystick *joysticklist;
979 SDL_Joystick *joysticklistprev;
982 if (!SDL_PrivateJoystickValid(joystick)) {
988 /* First decrement ref count */
989 if (--joystick->ref_count > 0) {
990 SDL_UnlockJoysticks();
994 if (SDL_updating_joystick) {
995 SDL_UnlockJoysticks();
999 if (joystick->rumble_expiration) {
1000 SDL_JoystickRumble(joystick, 0, 0, 0);
1002 if (joystick->trigger_rumble_expiration) {
1003 SDL_JoystickRumbleTriggers(joystick, 0, 0, 0);
1006 joystick->driver->Close(joystick);
1007 joystick->hwdata = NULL;
1009 joysticklist = SDL_joysticks;
1010 joysticklistprev = NULL;
1011 while (joysticklist) {
1012 if (joystick == joysticklist) {
1013 if (joysticklistprev) {
1014 /* unlink this entry */
1015 joysticklistprev->next = joysticklist->next;
1017 SDL_joysticks = joystick->next;
1021 joysticklistprev = joysticklist;
1022 joysticklist = joysticklist->next;
1025 SDL_free(joystick->name);
1026 SDL_free(joystick->serial);
1028 /* Free the data associated with this joystick */
1029 SDL_free(joystick->axes);
1030 SDL_free(joystick->hats);
1031 SDL_free(joystick->balls);
1032 SDL_free(joystick->buttons);
1033 for (i = 0; i < joystick->ntouchpads; i++) {
1034 SDL_JoystickTouchpadInfo *touchpad = &joystick->touchpads[i];
1035 SDL_free(touchpad->fingers);
1037 SDL_free(joystick->touchpads);
1038 SDL_free(joystick->sensors);
1041 SDL_UnlockJoysticks();
1045 SDL_JoystickQuit(void)
1049 /* Make sure we're not getting called in the middle of updating joysticks */
1050 SDL_LockJoysticks();
1051 while (SDL_updating_joystick) {
1052 SDL_UnlockJoysticks();
1054 SDL_LockJoysticks();
1057 /* Stop the event polling */
1058 while (SDL_joysticks) {
1059 SDL_joysticks->ref_count = 1;
1060 SDL_JoystickClose(SDL_joysticks);
1063 /* Quit the joystick setup */
1064 for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) {
1065 SDL_joystick_drivers[i]->Quit();
1068 if (SDL_joystick_players) {
1069 SDL_free(SDL_joystick_players);
1070 SDL_joystick_players = NULL;
1071 SDL_joystick_player_count = 0;
1073 SDL_UnlockJoysticks();
1075 #if !SDL_EVENTS_DISABLED
1076 SDL_QuitSubSystem(SDL_INIT_EVENTS);
1079 SDL_DelHintCallback(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS,
1080 SDL_JoystickAllowBackgroundEventsChanged, NULL);
1082 if (SDL_joystick_lock) {
1083 SDL_mutex *mutex = SDL_joystick_lock;
1084 SDL_joystick_lock = NULL;
1085 SDL_DestroyMutex(mutex);
1088 SDL_GameControllerQuitMappings();
1093 SDL_PrivateJoystickShouldIgnoreEvent()
1095 if (SDL_joystick_allows_background_events) {
1099 if (SDL_HasWindows() && SDL_GetKeyboardFocus() == NULL) {
1100 /* We have windows but we don't have focus, ignore the event. */
1106 /* These are global for SDL_sysjoystick.c and SDL_events.c */
1108 void SDL_PrivateJoystickAddTouchpad(SDL_Joystick *joystick, int nfingers)
1110 int ntouchpads = joystick->ntouchpads + 1;
1111 SDL_JoystickTouchpadInfo *touchpads = (SDL_JoystickTouchpadInfo *)SDL_realloc(joystick->touchpads, (ntouchpads * sizeof(SDL_JoystickTouchpadInfo)));
1113 SDL_JoystickTouchpadInfo *touchpad = &touchpads[ntouchpads - 1];
1114 SDL_JoystickTouchpadFingerInfo *fingers = (SDL_JoystickTouchpadFingerInfo *)SDL_calloc(nfingers, sizeof(SDL_JoystickTouchpadFingerInfo));
1117 touchpad->nfingers = nfingers;
1118 touchpad->fingers = fingers;
1120 /* Out of memory, this touchpad won't be active */
1121 touchpad->nfingers = 0;
1122 touchpad->fingers = NULL;
1125 joystick->ntouchpads = ntouchpads;
1126 joystick->touchpads = touchpads;
1130 void SDL_PrivateJoystickAddSensor(SDL_Joystick *joystick, SDL_SensorType type)
1132 int nsensors = joystick->nsensors + 1;
1133 SDL_JoystickSensorInfo *sensors = (SDL_JoystickSensorInfo *)SDL_realloc(joystick->sensors, (nsensors * sizeof(SDL_JoystickSensorInfo)));
1135 SDL_JoystickSensorInfo *sensor = &sensors[nsensors - 1];
1138 sensor->type = type;
1140 joystick->nsensors = nsensors;
1141 joystick->sensors = sensors;
1145 void SDL_PrivateJoystickAdded(SDL_JoystickID device_instance)
1147 SDL_JoystickDriver *driver;
1148 int driver_device_index;
1149 int player_index = -1;
1150 int device_index = SDL_JoystickGetDeviceIndexFromInstanceID(device_instance);
1151 if (device_index < 0) {
1155 SDL_LockJoysticks();
1156 if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &driver_device_index)) {
1157 player_index = driver->GetDevicePlayerIndex(driver_device_index);
1159 if (player_index < 0 && SDL_IsGameController(device_index)) {
1160 player_index = SDL_FindFreePlayerIndex();
1162 if (player_index >= 0) {
1163 SDL_SetJoystickIDForPlayerIndex(player_index, device_instance);
1165 SDL_UnlockJoysticks();
1167 #if !SDL_EVENTS_DISABLED
1171 event.type = SDL_JOYDEVICEADDED;
1173 if (SDL_GetEventState(event.type) == SDL_ENABLE) {
1174 event.jdevice.which = device_index;
1175 SDL_PushEvent(&event);
1178 #endif /* !SDL_EVENTS_DISABLED */
1182 * If there is an existing add event in the queue, it needs to be modified
1183 * to have the right value for which, because the number of controllers in
1184 * the system is now one less.
1186 static void UpdateEventsForDeviceRemoval(int device_index)
1192 num_events = SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, SDL_JOYDEVICEADDED, SDL_JOYDEVICEADDED);
1193 if (num_events <= 0) {
1197 events = SDL_small_alloc(SDL_Event, num_events, &isstack);
1202 num_events = SDL_PeepEvents(events, num_events, SDL_GETEVENT, SDL_JOYDEVICEADDED, SDL_JOYDEVICEADDED);
1203 for (i = 0; i < num_events; ++i) {
1204 if (events[i].cdevice.which < device_index) {
1205 /* No change for index values lower than the removed device */
1207 else if (events[i].cdevice.which == device_index) {
1208 /* Drop this event entirely */
1209 SDL_memmove(&events[i], &events[i + 1], sizeof(*events) * (num_events - (i + 1)));
1214 /* Fix up the device index if greater than the removed device */
1215 --events[i].cdevice.which;
1218 SDL_PeepEvents(events, num_events, SDL_ADDEVENT, 0, 0);
1220 SDL_small_free(events, isstack);
1224 SDL_PrivateJoystickForceRecentering(SDL_Joystick *joystick)
1228 /* Tell the app that everything is centered/unpressed... */
1229 for (i = 0; i < joystick->naxes; i++) {
1230 if (joystick->axes[i].has_initial_value) {
1231 SDL_PrivateJoystickAxis(joystick, i, joystick->axes[i].zero);
1235 for (i = 0; i < joystick->nbuttons; i++) {
1236 SDL_PrivateJoystickButton(joystick, i, SDL_RELEASED);
1239 for (i = 0; i < joystick->nhats; i++) {
1240 SDL_PrivateJoystickHat(joystick, i, SDL_HAT_CENTERED);
1243 for (i = 0; i < joystick->ntouchpads; i++) {
1244 SDL_JoystickTouchpadInfo *touchpad = &joystick->touchpads[i];
1246 for (j = 0; j < touchpad->nfingers; ++j) {
1247 SDL_PrivateJoystickTouchpad(joystick, i, j, SDL_RELEASED, 0.0f, 0.0f, 0.0f);
1253 void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance)
1255 SDL_Joystick *joystick = NULL;
1258 #if !SDL_EVENTS_DISABLED
1262 /* Find this joystick... */
1264 for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
1265 if (joystick->instance_id == device_instance) {
1266 SDL_PrivateJoystickForceRecentering(joystick);
1267 joystick->attached = SDL_FALSE;
1274 #if !SDL_EVENTS_DISABLED
1276 event.type = SDL_JOYDEVICEREMOVED;
1278 if (SDL_GetEventState(event.type) == SDL_ENABLE) {
1279 event.jdevice.which = device_instance;
1280 SDL_PushEvent(&event);
1283 UpdateEventsForDeviceRemoval(device_index);
1284 #endif /* !SDL_EVENTS_DISABLED */
1286 SDL_LockJoysticks();
1287 player_index = SDL_GetPlayerIndexForJoystickID(device_instance);
1288 if (player_index >= 0) {
1289 SDL_joystick_players[player_index] = -1;
1291 SDL_UnlockJoysticks();
1295 SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
1298 SDL_JoystickAxisInfo *info;
1300 /* Make sure we're not getting garbage or duplicate events */
1301 if (axis >= joystick->naxes) {
1305 info = &joystick->axes[axis];
1306 if (!info->has_initial_value ||
1307 (!info->has_second_value && (info->initial_value <= -32767 || info->initial_value == 32767) && SDL_abs(value) < (SDL_JOYSTICK_AXIS_MAX / 4))) {
1308 info->initial_value = value;
1309 info->value = value;
1311 info->has_initial_value = SDL_TRUE;
1312 } else if (value == info->value) {
1315 info->has_second_value = SDL_TRUE;
1317 if (!info->sent_initial_value) {
1318 /* Make sure we don't send motion until there's real activity on this axis */
1319 const int MAX_ALLOWED_JITTER = SDL_JOYSTICK_AXIS_MAX / 80; /* ShanWan PS3 controller needed 96 */
1320 if (SDL_abs(value - info->value) <= MAX_ALLOWED_JITTER) {
1323 info->sent_initial_value = SDL_TRUE;
1324 info->value = ~value; /* Just so we pass the check above */
1325 SDL_PrivateJoystickAxis(joystick, axis, info->initial_value);
1328 /* We ignore events if we don't have keyboard focus, except for centering
1331 if (SDL_PrivateJoystickShouldIgnoreEvent()) {
1332 if ((value > info->zero && value >= info->value) ||
1333 (value < info->zero && value <= info->value)) {
1338 /* Update internal joystick state */
1339 info->value = value;
1341 /* Post the event, if desired */
1343 #if !SDL_EVENTS_DISABLED
1344 if (SDL_GetEventState(SDL_JOYAXISMOTION) == SDL_ENABLE) {
1346 event.type = SDL_JOYAXISMOTION;
1347 event.jaxis.which = joystick->instance_id;
1348 event.jaxis.axis = axis;
1349 event.jaxis.value = value;
1350 posted = SDL_PushEvent(&event) == 1;
1352 #endif /* !SDL_EVENTS_DISABLED */
1357 SDL_PrivateJoystickHat(SDL_Joystick *joystick, Uint8 hat, Uint8 value)
1361 /* Make sure we're not getting garbage or duplicate events */
1362 if (hat >= joystick->nhats) {
1365 if (value == joystick->hats[hat]) {
1369 /* We ignore events if we don't have keyboard focus, except for centering
1372 if (SDL_PrivateJoystickShouldIgnoreEvent()) {
1373 if (value != SDL_HAT_CENTERED) {
1378 /* Update internal joystick state */
1379 joystick->hats[hat] = value;
1381 /* Post the event, if desired */
1383 #if !SDL_EVENTS_DISABLED
1384 if (SDL_GetEventState(SDL_JOYHATMOTION) == SDL_ENABLE) {
1386 event.jhat.type = SDL_JOYHATMOTION;
1387 event.jhat.which = joystick->instance_id;
1388 event.jhat.hat = hat;
1389 event.jhat.value = value;
1390 posted = SDL_PushEvent(&event) == 1;
1392 #endif /* !SDL_EVENTS_DISABLED */
1397 SDL_PrivateJoystickBall(SDL_Joystick *joystick, Uint8 ball,
1398 Sint16 xrel, Sint16 yrel)
1402 /* Make sure we're not getting garbage events */
1403 if (ball >= joystick->nballs) {
1407 /* We ignore events if we don't have keyboard focus. */
1408 if (SDL_PrivateJoystickShouldIgnoreEvent()) {
1412 /* Update internal mouse state */
1413 joystick->balls[ball].dx += xrel;
1414 joystick->balls[ball].dy += yrel;
1416 /* Post the event, if desired */
1418 #if !SDL_EVENTS_DISABLED
1419 if (SDL_GetEventState(SDL_JOYBALLMOTION) == SDL_ENABLE) {
1421 event.jball.type = SDL_JOYBALLMOTION;
1422 event.jball.which = joystick->instance_id;
1423 event.jball.ball = ball;
1424 event.jball.xrel = xrel;
1425 event.jball.yrel = yrel;
1426 posted = SDL_PushEvent(&event) == 1;
1428 #endif /* !SDL_EVENTS_DISABLED */
1433 SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
1436 #if !SDL_EVENTS_DISABLED
1441 event.type = SDL_JOYBUTTONDOWN;
1444 event.type = SDL_JOYBUTTONUP;
1447 /* Invalid state -- bail */
1450 #endif /* !SDL_EVENTS_DISABLED */
1452 /* Make sure we're not getting garbage or duplicate events */
1453 if (button >= joystick->nbuttons) {
1456 if (state == joystick->buttons[button]) {
1460 /* We ignore events if we don't have keyboard focus, except for button
1462 if (SDL_PrivateJoystickShouldIgnoreEvent()) {
1463 if (state == SDL_PRESSED) {
1468 /* Update internal joystick state */
1469 joystick->buttons[button] = state;
1471 /* Post the event, if desired */
1473 #if !SDL_EVENTS_DISABLED
1474 if (SDL_GetEventState(event.type) == SDL_ENABLE) {
1475 event.jbutton.which = joystick->instance_id;
1476 event.jbutton.button = button;
1477 event.jbutton.state = state;
1478 posted = SDL_PushEvent(&event) == 1;
1480 #endif /* !SDL_EVENTS_DISABLED */
1485 SDL_JoystickUpdate(void)
1488 SDL_Joystick *joystick, *next;
1490 if (!SDL_WasInit(SDL_INIT_JOYSTICK)) {
1494 SDL_LockJoysticks();
1496 if (SDL_updating_joystick) {
1497 /* The joysticks are already being updated */
1498 SDL_UnlockJoysticks();
1502 SDL_updating_joystick = SDL_TRUE;
1504 /* Make sure the list is unlocked while dispatching events to prevent application deadlocks */
1505 SDL_UnlockJoysticks();
1507 #ifdef SDL_JOYSTICK_HIDAPI
1508 /* Special function for HIDAPI devices, as a single device can provide multiple SDL_Joysticks */
1509 HIDAPI_UpdateDevices();
1510 #endif /* SDL_JOYSTICK_HIDAPI */
1512 for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
1513 if (joystick->attached) {
1514 /* This should always be true, but seeing a crash in the wild...? */
1515 if (joystick->driver) {
1516 joystick->driver->Update(joystick);
1519 if (joystick->delayed_guide_button) {
1520 SDL_GameControllerHandleDelayedGuideButton(joystick);
1524 if (joystick->rumble_expiration) {
1525 SDL_LockJoysticks();
1526 /* Double check now that the lock is held */
1527 if (joystick->rumble_expiration &&
1528 SDL_TICKS_PASSED(SDL_GetTicks(), joystick->rumble_expiration)) {
1529 SDL_JoystickRumble(joystick, 0, 0, 0);
1531 SDL_UnlockJoysticks();
1534 if (joystick->trigger_rumble_expiration) {
1535 SDL_LockJoysticks();
1536 /* Double check now that the lock is held */
1537 if (joystick->trigger_rumble_expiration &&
1538 SDL_TICKS_PASSED(SDL_GetTicks(), joystick->trigger_rumble_expiration)) {
1539 SDL_JoystickRumbleTriggers(joystick, 0, 0, 0);
1541 SDL_UnlockJoysticks();
1545 SDL_LockJoysticks();
1547 SDL_updating_joystick = SDL_FALSE;
1549 /* If any joysticks were closed while updating, free them here */
1550 for (joystick = SDL_joysticks; joystick; joystick = next) {
1551 next = joystick->next;
1552 if (joystick->ref_count <= 0) {
1553 SDL_JoystickClose(joystick);
1557 /* this needs to happen AFTER walking the joystick list above, so that any
1558 dangling hardware data from removed devices can be free'd
1560 for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) {
1561 SDL_joystick_drivers[i]->Detect();
1564 SDL_UnlockJoysticks();
1568 SDL_JoystickEventState(int state)
1570 #if SDL_EVENTS_DISABLED
1573 const Uint32 event_list[] = {
1574 SDL_JOYAXISMOTION, SDL_JOYBALLMOTION, SDL_JOYHATMOTION,
1575 SDL_JOYBUTTONDOWN, SDL_JOYBUTTONUP, SDL_JOYDEVICEADDED, SDL_JOYDEVICEREMOVED
1581 state = SDL_DISABLE;
1582 for (i = 0; i < SDL_arraysize(event_list); ++i) {
1583 state = SDL_EventState(event_list[i], SDL_QUERY);
1584 if (state == SDL_ENABLE) {
1590 for (i = 0; i < SDL_arraysize(event_list); ++i) {
1591 SDL_EventState(event_list[i], state);
1596 #endif /* SDL_EVENTS_DISABLED */
1599 void SDL_GetJoystickGUIDInfo(SDL_JoystickGUID guid, Uint16 *vendor, Uint16 *product, Uint16 *version)
1601 Uint16 *guid16 = (Uint16 *)guid.data;
1603 /* If the GUID fits the form of BUS 0000 VENDOR 0000 PRODUCT 0000, return the data */
1604 if (/* guid16[0] is device bus type */
1605 guid16[1] == 0x0000 &&
1606 /* guid16[2] is vendor ID */
1607 guid16[3] == 0x0000 &&
1608 /* guid16[4] is product ID */
1610 /* guid16[6] is product version */
1613 *vendor = guid16[2];
1616 *product = guid16[4];
1619 *version = guid16[6];
1635 PrefixMatch(const char *a, const char *b)
1639 if (SDL_tolower(*a++) == SDL_tolower(*b++)) {
1649 SDL_CreateJoystickName(Uint16 vendor, Uint16 product, const char *vendor_name, const char *product_name)
1653 const char *replacement;
1654 } replacements[] = {
1655 { "NVIDIA Corporation ", "" },
1656 { "Performance Designed Products", "PDP" },
1657 { "HORI CO.,LTD.", "HORI" },
1658 { "HORI CO.,LTD", "HORI" },
1660 const char *custom_name;
1664 custom_name = GuessControllerName(vendor, product);
1666 return SDL_strdup(custom_name);
1672 if (!product_name) {
1676 while (*vendor_name == ' ') {
1679 while (*product_name == ' ') {
1683 if (*vendor_name && *product_name) {
1684 len = (SDL_strlen(vendor_name) + 1 + SDL_strlen(product_name) + 1);
1685 name = (char *)SDL_malloc(len);
1689 SDL_snprintf(name, len, "%s %s", vendor_name, product_name);
1690 } else if (*product_name) {
1691 name = SDL_strdup(product_name);
1692 } else if (vendor || product) {
1693 len = (6 + 1 + 6 + 1);
1694 name = (char *)SDL_malloc(len);
1698 SDL_snprintf(name, len, "0x%.4x/0x%.4x", vendor, product);
1700 name = SDL_strdup("Controller");
1703 /* Trim trailing whitespace */
1704 for (len = SDL_strlen(name); (len > 0 && name[len - 1] == ' '); --len) {
1709 /* Compress duplicate spaces */
1710 for (i = 0; i < (len - 1); ) {
1711 if (name[i] == ' ' && name[i+1] == ' ') {
1712 SDL_memmove(&name[i], &name[i+1], (len - i));
1719 /* Remove duplicate manufacturer or product in the name */
1720 for (i = 1; i < (len - 1); ++i) {
1721 int matchlen = PrefixMatch(name, &name[i]);
1722 if (matchlen > 0 && name[matchlen-1] == ' ') {
1723 SDL_memmove(name, name+matchlen, len-matchlen+1);
1726 } else if (matchlen > 0 && name[matchlen] == ' ') {
1727 SDL_memmove(name, name+matchlen+1, len-matchlen);
1728 len -= (matchlen + 1);
1733 /* Perform any manufacturer replacements */
1734 for (i = 0; i < SDL_arraysize(replacements); ++i) {
1735 size_t prefixlen = SDL_strlen(replacements[i].prefix);
1736 if (SDL_strncasecmp(name, replacements[i].prefix, prefixlen) == 0) {
1737 size_t replacementlen = SDL_strlen(replacements[i].replacement);
1738 SDL_memcpy(name, replacements[i].replacement, replacementlen);
1739 SDL_memmove(name+replacementlen, name+prefixlen, (len-prefixlen+1));
1747 SDL_GameControllerType
1748 SDL_GetJoystickGameControllerTypeFromVIDPID(Uint16 vendor, Uint16 product)
1750 return SDL_GetJoystickGameControllerType(NULL, vendor, product, -1, 0, 0, 0);
1753 SDL_GameControllerType
1754 SDL_GetJoystickGameControllerTypeFromGUID(SDL_JoystickGUID guid, const char *name)
1756 SDL_GameControllerType type;
1757 Uint16 vendor, product;
1759 SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL);
1760 type = SDL_GetJoystickGameControllerType(name, vendor, product, -1, 0, 0, 0);
1761 if (type == SDL_CONTROLLER_TYPE_UNKNOWN) {
1762 if (SDL_IsJoystickXInput(guid)) {
1763 /* This is probably an Xbox One controller */
1764 return SDL_CONTROLLER_TYPE_XBOXONE;
1770 SDL_GameControllerType
1771 SDL_GetJoystickGameControllerType(const char *name, Uint16 vendor, Uint16 product, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
1773 static const int LIBUSB_CLASS_VENDOR_SPEC = 0xFF;
1774 static const int XB360_IFACE_SUBCLASS = 93;
1775 static const int XB360_IFACE_PROTOCOL = 1; /* Wired */
1776 static const int XB360W_IFACE_PROTOCOL = 129; /* Wireless */
1777 static const int XBONE_IFACE_SUBCLASS = 71;
1778 static const int XBONE_IFACE_PROTOCOL = 208;
1780 SDL_GameControllerType type = SDL_CONTROLLER_TYPE_UNKNOWN;
1782 /* This code should match the checks in libusb/hid.c and HIDDeviceManager.java */
1783 if (interface_class == LIBUSB_CLASS_VENDOR_SPEC &&
1784 interface_subclass == XB360_IFACE_SUBCLASS &&
1785 (interface_protocol == XB360_IFACE_PROTOCOL ||
1786 interface_protocol == XB360W_IFACE_PROTOCOL)) {
1788 static const int SUPPORTED_VENDORS[] = {
1789 0x0079, /* GPD Win 2 */
1790 0x044f, /* Thrustmaster */
1791 0x045e, /* Microsoft */
1792 0x046d, /* Logitech */
1793 0x056e, /* Elecom */
1794 0x06a3, /* Saitek */
1795 0x0738, /* Mad Catz */
1796 0x07ff, /* Mad Catz */
1799 0x1038, /* SteelSeries */
1801 0x12ab, /* Unknown */
1802 0x1430, /* RedOctane */
1803 0x146b, /* BigBen */
1804 0x1532, /* Razer Sabertooth */
1805 0x15e4, /* Numark */
1806 0x162e, /* Joytech */
1807 0x1689, /* Razer Onza */
1808 0x1bad, /* Harmonix */
1809 0x24c6, /* PowerA */
1813 for (i = 0; i < SDL_arraysize(SUPPORTED_VENDORS); ++i) {
1814 if (vendor == SUPPORTED_VENDORS[i]) {
1815 type = SDL_CONTROLLER_TYPE_XBOX360;
1821 if (interface_number == 0 &&
1822 interface_class == LIBUSB_CLASS_VENDOR_SPEC &&
1823 interface_subclass == XBONE_IFACE_SUBCLASS &&
1824 interface_protocol == XBONE_IFACE_PROTOCOL) {
1826 static const int SUPPORTED_VENDORS[] = {
1827 0x045e, /* Microsoft */
1828 0x0738, /* Mad Catz */
1831 0x1532, /* Razer Wildcat */
1832 0x24c6, /* PowerA */
1833 0x2e24, /* Hyperkin */
1837 for (i = 0; i < SDL_arraysize(SUPPORTED_VENDORS); ++i) {
1838 if (vendor == SUPPORTED_VENDORS[i]) {
1839 type = SDL_CONTROLLER_TYPE_XBOXONE;
1845 if (type == SDL_CONTROLLER_TYPE_UNKNOWN) {
1846 if (vendor == 0x0000 && product == 0x0000) {
1847 /* Some devices are only identifiable by their name */
1849 (SDL_strcmp(name, "Lic Pro Controller") == 0 ||
1850 SDL_strcmp(name, "Nintendo Wireless Gamepad") == 0 ||
1851 SDL_strcmp(name, "Wireless Gamepad") == 0)) {
1852 /* HORI or PowerA Switch Pro Controller clone */
1853 type = SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO;
1854 } else if (name && SDL_strcmp(name, "Virtual Joystick") == 0) {
1855 type = SDL_CONTROLLER_TYPE_VIRTUAL;
1857 type = SDL_CONTROLLER_TYPE_UNKNOWN;
1860 } else if (vendor == 0x0001 && product == 0x0001) {
1861 type = SDL_CONTROLLER_TYPE_UNKNOWN;
1864 switch (GuessControllerType(vendor, product)) {
1865 case k_eControllerType_XBox360Controller:
1866 type = SDL_CONTROLLER_TYPE_XBOX360;
1868 case k_eControllerType_XBoxOneController:
1869 type = SDL_CONTROLLER_TYPE_XBOXONE;
1871 case k_eControllerType_PS3Controller:
1872 type = SDL_CONTROLLER_TYPE_PS3;
1874 case k_eControllerType_PS4Controller:
1875 type = SDL_CONTROLLER_TYPE_PS4;
1877 case k_eControllerType_PS5Controller:
1878 type = SDL_CONTROLLER_TYPE_PS5;
1880 case k_eControllerType_SwitchProController:
1881 case k_eControllerType_SwitchInputOnlyController:
1882 type = SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO;
1885 type = SDL_CONTROLLER_TYPE_UNKNOWN;
1894 SDL_IsJoystickXboxOneElite(Uint16 vendor_id, Uint16 product_id)
1896 if (vendor_id == USB_VENDOR_MICROSOFT) {
1897 if (product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_1 ||
1898 product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2 ||
1899 product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLUETOOTH) {
1907 SDL_IsJoystickXboxOneSeriesX(Uint16 vendor_id, Uint16 product_id)
1909 if (vendor_id == USB_VENDOR_MICROSOFT) {
1910 if (product_id == USB_PRODUCT_XBOX_ONE_SERIES_X ||
1911 product_id == USB_PRODUCT_XBOX_ONE_SERIES_X_BLUETOOTH) {
1919 SDL_IsJoystickPS4(Uint16 vendor_id, Uint16 product_id)
1921 EControllerType eType = GuessControllerType(vendor_id, product_id);
1922 return (eType == k_eControllerType_PS4Controller);
1926 SDL_IsJoystickPS5(Uint16 vendor_id, Uint16 product_id)
1928 EControllerType eType = GuessControllerType(vendor_id, product_id);
1929 return (eType == k_eControllerType_PS5Controller);
1933 SDL_IsJoystickNintendoSwitchPro(Uint16 vendor_id, Uint16 product_id)
1935 EControllerType eType = GuessControllerType(vendor_id, product_id);
1936 return (eType == k_eControllerType_SwitchProController ||
1937 eType == k_eControllerType_SwitchInputOnlyController);
1941 SDL_IsJoystickNintendoSwitchProInputOnly(Uint16 vendor_id, Uint16 product_id)
1943 EControllerType eType = GuessControllerType(vendor_id, product_id);
1944 return (eType == k_eControllerType_SwitchInputOnlyController);
1948 SDL_IsJoystickSteamController(Uint16 vendor_id, Uint16 product_id)
1950 EControllerType eType = GuessControllerType(vendor_id, product_id);
1951 return (eType == k_eControllerType_SteamController ||
1952 eType == k_eControllerType_SteamControllerV2);
1956 SDL_IsJoystickXInput(SDL_JoystickGUID guid)
1958 return (guid.data[14] == 'x') ? SDL_TRUE : SDL_FALSE;
1962 SDL_IsJoystickWGI(SDL_JoystickGUID guid)
1964 return (guid.data[14] == 'w') ? SDL_TRUE : SDL_FALSE;
1968 SDL_IsJoystickHIDAPI(SDL_JoystickGUID guid)
1970 return (guid.data[14] == 'h') ? SDL_TRUE : SDL_FALSE;
1974 SDL_IsJoystickRAWINPUT(SDL_JoystickGUID guid)
1976 return (guid.data[14] == 'r') ? SDL_TRUE : SDL_FALSE;
1980 SDL_IsJoystickVirtual(SDL_JoystickGUID guid)
1982 return (guid.data[14] == 'v') ? SDL_TRUE : SDL_FALSE;
1985 static SDL_bool SDL_IsJoystickProductWheel(Uint32 vidpid)
1987 static Uint32 wheel_joysticks[] = {
1988 MAKE_VIDPID(0x046d, 0xc294), /* Logitech generic wheel */
1989 MAKE_VIDPID(0x046d, 0xc295), /* Logitech Momo Force */
1990 MAKE_VIDPID(0x046d, 0xc298), /* Logitech Driving Force Pro */
1991 MAKE_VIDPID(0x046d, 0xc299), /* Logitech G25 */
1992 MAKE_VIDPID(0x046d, 0xc29a), /* Logitech Driving Force GT */
1993 MAKE_VIDPID(0x046d, 0xc29b), /* Logitech G27 */
1994 MAKE_VIDPID(0x046d, 0xc24f), /* Logitech G29 */
1995 MAKE_VIDPID(0x046d, 0xc261), /* Logitech G920 (initial mode) */
1996 MAKE_VIDPID(0x046d, 0xc262), /* Logitech G920 (active mode) */
1997 MAKE_VIDPID(0x044f, 0xb65d), /* Thrustmaster Wheel FFB */
1998 MAKE_VIDPID(0x044f, 0xb66d), /* Thrustmaster Wheel FFB */
1999 MAKE_VIDPID(0x044f, 0xb677), /* Thrustmaster T150 */
2000 MAKE_VIDPID(0x044f, 0xb664), /* Thrustmaster TX (initial mode) */
2001 MAKE_VIDPID(0x044f, 0xb669), /* Thrustmaster TX (active mode) */
2005 for (i = 0; i < SDL_arraysize(wheel_joysticks); ++i) {
2006 if (vidpid == wheel_joysticks[i]) {
2013 static SDL_bool SDL_IsJoystickProductFlightStick(Uint32 vidpid)
2015 static Uint32 flightstick_joysticks[] = {
2016 MAKE_VIDPID(0x044f, 0x0402), /* HOTAS Warthog Joystick */
2017 MAKE_VIDPID(0x0738, 0x2221), /* Saitek Pro Flight X-56 Rhino Stick */
2021 for (i = 0; i < SDL_arraysize(flightstick_joysticks); ++i) {
2022 if (vidpid == flightstick_joysticks[i]) {
2029 static SDL_bool SDL_IsJoystickProductThrottle(Uint32 vidpid)
2031 static Uint32 throttle_joysticks[] = {
2032 MAKE_VIDPID(0x044f, 0x0404), /* HOTAS Warthog Throttle */
2033 MAKE_VIDPID(0x0738, 0xa221), /* Saitek Pro Flight X-56 Rhino Throttle */
2037 for (i = 0; i < SDL_arraysize(throttle_joysticks); ++i) {
2038 if (vidpid == throttle_joysticks[i]) {
2045 static SDL_JoystickType SDL_GetJoystickGUIDType(SDL_JoystickGUID guid)
2051 if (SDL_IsJoystickXInput(guid)) {
2052 /* XInput GUID, get the type based on the XInput device subtype */
2053 switch (guid.data[15]) {
2054 case 0x01: /* XINPUT_DEVSUBTYPE_GAMEPAD */
2055 return SDL_JOYSTICK_TYPE_GAMECONTROLLER;
2056 case 0x02: /* XINPUT_DEVSUBTYPE_WHEEL */
2057 return SDL_JOYSTICK_TYPE_WHEEL;
2058 case 0x03: /* XINPUT_DEVSUBTYPE_ARCADE_STICK */
2059 return SDL_JOYSTICK_TYPE_ARCADE_STICK;
2060 case 0x04: /* XINPUT_DEVSUBTYPE_FLIGHT_STICK */
2061 return SDL_JOYSTICK_TYPE_FLIGHT_STICK;
2062 case 0x05: /* XINPUT_DEVSUBTYPE_DANCE_PAD */
2063 return SDL_JOYSTICK_TYPE_DANCE_PAD;
2064 case 0x06: /* XINPUT_DEVSUBTYPE_GUITAR */
2065 case 0x07: /* XINPUT_DEVSUBTYPE_GUITAR_ALTERNATE */
2066 case 0x0B: /* XINPUT_DEVSUBTYPE_GUITAR_BASS */
2067 return SDL_JOYSTICK_TYPE_GUITAR;
2068 case 0x08: /* XINPUT_DEVSUBTYPE_DRUM_KIT */
2069 return SDL_JOYSTICK_TYPE_DRUM_KIT;
2070 case 0x13: /* XINPUT_DEVSUBTYPE_ARCADE_PAD */
2071 return SDL_JOYSTICK_TYPE_ARCADE_PAD;
2073 return SDL_JOYSTICK_TYPE_UNKNOWN;
2077 if (SDL_IsJoystickWGI(guid)) {
2078 return (SDL_JoystickType)guid.data[15];
2081 if (SDL_IsJoystickVirtual(guid)) {
2082 return (SDL_JoystickType)guid.data[15];
2085 SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL);
2086 vidpid = MAKE_VIDPID(vendor, product);
2088 if (SDL_IsJoystickProductWheel(vidpid)) {
2089 return SDL_JOYSTICK_TYPE_WHEEL;
2092 if (SDL_IsJoystickProductFlightStick(vidpid)) {
2093 return SDL_JOYSTICK_TYPE_FLIGHT_STICK;
2096 if (SDL_IsJoystickProductThrottle(vidpid)) {
2097 return SDL_JOYSTICK_TYPE_THROTTLE;
2100 if (GuessControllerType(vendor, product) != k_eControllerType_UnknownNonSteamController) {
2101 return SDL_JOYSTICK_TYPE_GAMECONTROLLER;
2104 return SDL_JOYSTICK_TYPE_UNKNOWN;
2107 static SDL_bool SDL_IsPS4RemapperRunning(void)
2110 const char *mapper_processes[] = {
2115 PROCESSENTRY32 pe32;
2116 SDL_bool found = SDL_FALSE;
2118 /* Take a snapshot of all processes in the system */
2119 HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
2120 if (hProcessSnap != INVALID_HANDLE_VALUE) {
2121 pe32.dwSize = sizeof(PROCESSENTRY32);
2122 if (Process32First(hProcessSnap, &pe32)) {
2125 for (i = 0; i < SDL_arraysize(mapper_processes); ++i) {
2126 if (SDL_strcasecmp(pe32.szExeFile, mapper_processes[i]) == 0) {
2130 } while (Process32Next(hProcessSnap, &pe32) && !found);
2132 CloseHandle(hProcessSnap);
2140 SDL_bool SDL_ShouldIgnoreJoystick(const char *name, SDL_JoystickGUID guid)
2142 /* This list is taken from:
2143 https://raw.githubusercontent.com/denilsonsa/udev-joystick-blacklist/master/generate_rules.py
2145 static Uint32 joystick_blacklist[] = {
2146 /* Microsoft Microsoft Wireless Optical Desktop 2.10 */
2147 /* Microsoft Wireless Desktop - Comfort Edition */
2148 MAKE_VIDPID(0x045e, 0x009d),
2150 /* Microsoft Microsoft Digital Media Pro Keyboard */
2151 /* Microsoft Corp. Digital Media Pro Keyboard */
2152 MAKE_VIDPID(0x045e, 0x00b0),
2154 /* Microsoft Microsoft Digital Media Keyboard */
2155 /* Microsoft Corp. Digital Media Keyboard 1.0A */
2156 MAKE_VIDPID(0x045e, 0x00b4),
2158 /* Microsoft Microsoft Digital Media Keyboard 3000 */
2159 MAKE_VIDPID(0x045e, 0x0730),
2161 /* Microsoft Microsoft 2.4GHz Transceiver v6.0 */
2162 /* Microsoft Microsoft 2.4GHz Transceiver v8.0 */
2163 /* Microsoft Corp. Nano Transceiver v1.0 for Bluetooth */
2164 /* Microsoft Wireless Mobile Mouse 1000 */
2165 /* Microsoft Wireless Desktop 3000 */
2166 MAKE_VIDPID(0x045e, 0x0745),
2168 /* Microsoft SideWinder(TM) 2.4GHz Transceiver */
2169 MAKE_VIDPID(0x045e, 0x0748),
2171 /* Microsoft Corp. Wired Keyboard 600 */
2172 MAKE_VIDPID(0x045e, 0x0750),
2174 /* Microsoft Corp. Sidewinder X4 keyboard */
2175 MAKE_VIDPID(0x045e, 0x0768),
2177 /* Microsoft Corp. Arc Touch Mouse Transceiver */
2178 MAKE_VIDPID(0x045e, 0x0773),
2180 /* Microsoft 2.4GHz Transceiver v9.0 */
2181 /* Microsoft Nano Transceiver v2.1 */
2182 /* Microsoft Sculpt Ergonomic Keyboard (5KV-00001) */
2183 MAKE_VIDPID(0x045e, 0x07a5),
2185 /* Microsoft Nano Transceiver v1.0 */
2186 /* Microsoft Wireless Keyboard 800 */
2187 MAKE_VIDPID(0x045e, 0x07b2),
2189 /* Microsoft Nano Transceiver v2.0 */
2190 MAKE_VIDPID(0x045e, 0x0800),
2192 MAKE_VIDPID(0x046d, 0xc30a), /* Logitech, Inc. iTouch Composite keboard */
2194 MAKE_VIDPID(0x04d9, 0xa0df), /* Tek Syndicate Mouse (E-Signal USB Gaming Mouse) */
2196 /* List of Wacom devices at: http://linuxwacom.sourceforge.net/wiki/index.php/Device_IDs */
2197 MAKE_VIDPID(0x056a, 0x0010), /* Wacom ET-0405 Graphire */
2198 MAKE_VIDPID(0x056a, 0x0011), /* Wacom ET-0405A Graphire2 (4x5) */
2199 MAKE_VIDPID(0x056a, 0x0012), /* Wacom ET-0507A Graphire2 (5x7) */
2200 MAKE_VIDPID(0x056a, 0x0013), /* Wacom CTE-430 Graphire3 (4x5) */
2201 MAKE_VIDPID(0x056a, 0x0014), /* Wacom CTE-630 Graphire3 (6x8) */
2202 MAKE_VIDPID(0x056a, 0x0015), /* Wacom CTE-440 Graphire4 (4x5) */
2203 MAKE_VIDPID(0x056a, 0x0016), /* Wacom CTE-640 Graphire4 (6x8) */
2204 MAKE_VIDPID(0x056a, 0x0017), /* Wacom CTE-450 Bamboo Fun (4x5) */
2205 MAKE_VIDPID(0x056a, 0x0018), /* Wacom CTE-650 Bamboo Fun 6x8 */
2206 MAKE_VIDPID(0x056a, 0x0019), /* Wacom CTE-631 Bamboo One */
2207 MAKE_VIDPID(0x056a, 0x00d1), /* Wacom Bamboo Pen and Touch CTH-460 */
2208 MAKE_VIDPID(0x056a, 0x030e), /* Wacom Intuos Pen (S) CTL-480 */
2210 MAKE_VIDPID(0x09da, 0x054f), /* A4 Tech Co., G7 750 mouse */
2211 MAKE_VIDPID(0x09da, 0x1410), /* A4 Tech Co., Ltd Bloody AL9 mouse */
2212 MAKE_VIDPID(0x09da, 0x3043), /* A4 Tech Co., Ltd Bloody R8A Gaming Mouse */
2213 MAKE_VIDPID(0x09da, 0x31b5), /* A4 Tech Co., Ltd Bloody TL80 Terminator Laser Gaming Mouse */
2214 MAKE_VIDPID(0x09da, 0x3997), /* A4 Tech Co., Ltd Bloody RT7 Terminator Wireless */
2215 MAKE_VIDPID(0x09da, 0x3f8b), /* A4 Tech Co., Ltd Bloody V8 mouse */
2216 MAKE_VIDPID(0x09da, 0x51f4), /* Modecom MC-5006 Keyboard */
2217 MAKE_VIDPID(0x09da, 0x5589), /* A4 Tech Co., Ltd Terminator TL9 Laser Gaming Mouse */
2218 MAKE_VIDPID(0x09da, 0x7b22), /* A4 Tech Co., Ltd Bloody V5 */
2219 MAKE_VIDPID(0x09da, 0x7f2d), /* A4 Tech Co., Ltd Bloody R3 mouse */
2220 MAKE_VIDPID(0x09da, 0x8090), /* A4 Tech Co., Ltd X-718BK Oscar Optical Gaming Mouse */
2221 MAKE_VIDPID(0x09da, 0x9033), /* A4 Tech Co., X7 X-705K */
2222 MAKE_VIDPID(0x09da, 0x9066), /* A4 Tech Co., Sharkoon Fireglider Optical */
2223 MAKE_VIDPID(0x09da, 0x9090), /* A4 Tech Co., Ltd XL-730K / XL-750BK / XL-755BK Laser Mouse */
2224 MAKE_VIDPID(0x09da, 0x90c0), /* A4 Tech Co., Ltd X7 G800V keyboard */
2225 MAKE_VIDPID(0x09da, 0xf012), /* A4 Tech Co., Ltd Bloody V7 mouse */
2226 MAKE_VIDPID(0x09da, 0xf32a), /* A4 Tech Co., Ltd Bloody B540 keyboard */
2227 MAKE_VIDPID(0x09da, 0xf613), /* A4 Tech Co., Ltd Bloody V2 mouse */
2228 MAKE_VIDPID(0x09da, 0xf624), /* A4 Tech Co., Ltd Bloody B120 Keyboard */
2230 MAKE_VIDPID(0x1b1c, 0x1b3c), /* Corsair Harpoon RGB gaming mouse */
2232 MAKE_VIDPID(0x1d57, 0xad03), /* [T3] 2.4GHz and IR Air Mouse Remote Control */
2234 MAKE_VIDPID(0x1e7d, 0x2e4a), /* Roccat Tyon Mouse */
2236 MAKE_VIDPID(0x20a0, 0x422d), /* Winkeyless.kr Keyboards */
2238 MAKE_VIDPID(0x2516, 0x001f), /* Cooler Master Storm Mizar Mouse */
2239 MAKE_VIDPID(0x2516, 0x0028), /* Cooler Master Storm Alcor Mouse */
2246 SDL_GameControllerType type;
2248 SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL);
2250 /* Check the joystick blacklist */
2251 id = MAKE_VIDPID(vendor, product);
2252 for (i = 0; i < SDL_arraysize(joystick_blacklist); ++i) {
2253 if (id == joystick_blacklist[i]) {
2258 type = SDL_GetJoystickGameControllerType(name, vendor, product, -1, 0, 0, 0);
2259 if ((type == SDL_CONTROLLER_TYPE_PS4 || type == SDL_CONTROLLER_TYPE_PS5) && SDL_IsPS4RemapperRunning()) {
2263 if (SDL_IsGameControllerNameAndGUID(name, guid) &&
2264 SDL_ShouldIgnoreGameController(name, guid)) {
2271 /* return the guid for this index */
2272 SDL_JoystickGUID SDL_JoystickGetDeviceGUID(int device_index)
2274 SDL_JoystickDriver *driver;
2275 SDL_JoystickGUID guid;
2277 SDL_LockJoysticks();
2278 if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) {
2279 guid = driver->GetDeviceGUID(device_index);
2283 SDL_UnlockJoysticks();
2288 Uint16 SDL_JoystickGetDeviceVendor(int device_index)
2291 SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
2293 SDL_GetJoystickGUIDInfo(guid, &vendor, NULL, NULL);
2297 Uint16 SDL_JoystickGetDeviceProduct(int device_index)
2300 SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
2302 SDL_GetJoystickGUIDInfo(guid, NULL, &product, NULL);
2306 Uint16 SDL_JoystickGetDeviceProductVersion(int device_index)
2309 SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
2311 SDL_GetJoystickGUIDInfo(guid, NULL, NULL, &version);
2315 SDL_JoystickType SDL_JoystickGetDeviceType(int device_index)
2317 SDL_JoystickType type;
2318 SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
2320 type = SDL_GetJoystickGUIDType(guid);
2321 if (type == SDL_JOYSTICK_TYPE_UNKNOWN) {
2322 if (SDL_IsGameController(device_index)) {
2323 type = SDL_JOYSTICK_TYPE_GAMECONTROLLER;
2329 SDL_JoystickID SDL_JoystickGetDeviceInstanceID(int device_index)
2331 SDL_JoystickDriver *driver;
2332 SDL_JoystickID instance_id = -1;
2334 SDL_LockJoysticks();
2335 if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) {
2336 instance_id = driver->GetDeviceInstanceID(device_index);
2338 SDL_UnlockJoysticks();
2343 int SDL_JoystickGetDeviceIndexFromInstanceID(SDL_JoystickID instance_id)
2345 int i, num_joysticks, device_index = -1;
2347 SDL_LockJoysticks();
2348 num_joysticks = SDL_NumJoysticks();
2349 for (i = 0; i < num_joysticks; ++i) {
2350 if (SDL_JoystickGetDeviceInstanceID(i) == instance_id) {
2355 SDL_UnlockJoysticks();
2357 return device_index;
2360 SDL_JoystickGUID SDL_JoystickGetGUID(SDL_Joystick *joystick)
2362 if (!SDL_PrivateJoystickValid(joystick)) {
2363 SDL_JoystickGUID emptyGUID;
2364 SDL_zero(emptyGUID);
2367 return joystick->guid;
2370 Uint16 SDL_JoystickGetVendor(SDL_Joystick *joystick)
2373 SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
2375 SDL_GetJoystickGUIDInfo(guid, &vendor, NULL, NULL);
2379 Uint16 SDL_JoystickGetProduct(SDL_Joystick *joystick)
2382 SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
2384 SDL_GetJoystickGUIDInfo(guid, NULL, &product, NULL);
2388 Uint16 SDL_JoystickGetProductVersion(SDL_Joystick *joystick)
2391 SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
2393 SDL_GetJoystickGUIDInfo(guid, NULL, NULL, &version);
2397 const char *SDL_JoystickGetSerial(SDL_Joystick *joystick)
2399 if (!SDL_PrivateJoystickValid(joystick)) {
2402 return joystick->serial;
2405 SDL_JoystickType SDL_JoystickGetType(SDL_Joystick *joystick)
2407 SDL_JoystickType type;
2408 SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
2410 type = SDL_GetJoystickGUIDType(guid);
2411 if (type == SDL_JOYSTICK_TYPE_UNKNOWN) {
2412 if (joystick && joystick->is_game_controller) {
2413 type = SDL_JOYSTICK_TYPE_GAMECONTROLLER;
2419 /* convert the guid to a printable string */
2420 void SDL_JoystickGetGUIDString(SDL_JoystickGUID guid, char *pszGUID, int cbGUID)
2422 static const char k_rgchHexToASCII[] = "0123456789abcdef";
2425 if ((pszGUID == NULL) || (cbGUID <= 0)) {
2429 for (i = 0; i < sizeof(guid.data) && i < (cbGUID-1)/2; i++) {
2430 /* each input byte writes 2 ascii chars, and might write a null byte. */
2431 /* If we don't have room for next input byte, stop */
2432 unsigned char c = guid.data[i];
2434 *pszGUID++ = k_rgchHexToASCII[c >> 4];
2435 *pszGUID++ = k_rgchHexToASCII[c & 0x0F];
2440 /*-----------------------------------------------------------------------------
2441 * Purpose: Returns the 4 bit nibble for a hex character
2443 * Output : unsigned char
2444 *-----------------------------------------------------------------------------*/
2445 static unsigned char nibble(char c)
2447 if ((c >= '0') && (c <= '9')) {
2448 return (unsigned char)(c - '0');
2451 if ((c >= 'A') && (c <= 'F')) {
2452 return (unsigned char)(c - 'A' + 0x0a);
2455 if ((c >= 'a') && (c <= 'f')) {
2456 return (unsigned char)(c - 'a' + 0x0a);
2459 /* received an invalid character, and no real way to return an error */
2460 /* AssertMsg1(false, "Q_nibble invalid hex character '%c' ", c); */
2464 /* convert the string version of a joystick guid to the struct */
2465 SDL_JoystickGUID SDL_JoystickGetGUIDFromString(const char *pchGUID)
2467 SDL_JoystickGUID guid;
2468 int maxoutputbytes= sizeof(guid);
2469 size_t len = SDL_strlen(pchGUID);
2473 /* Make sure it's even */
2476 SDL_memset(&guid, 0x00, sizeof(guid));
2479 for (i = 0; (i < len) && ((p - (Uint8 *)&guid) < maxoutputbytes); i+=2, p++) {
2480 *p = (nibble(pchGUID[i]) << 4) | nibble(pchGUID[i+1]);
2486 /* update the power level for this joystick */
2487 void SDL_PrivateJoystickBatteryLevel(SDL_Joystick *joystick, SDL_JoystickPowerLevel ePowerLevel)
2489 joystick->epowerlevel = ePowerLevel;
2492 /* return its power level */
2493 SDL_JoystickPowerLevel SDL_JoystickCurrentPowerLevel(SDL_Joystick *joystick)
2495 if (!SDL_PrivateJoystickValid(joystick)) {
2496 return SDL_JOYSTICK_POWER_UNKNOWN;
2498 return joystick->epowerlevel;
2501 int SDL_PrivateJoystickTouchpad(SDL_Joystick *joystick, int touchpad, int finger, Uint8 state, float x, float y, float pressure)
2503 SDL_JoystickTouchpadInfo *touchpad_info;
2504 SDL_JoystickTouchpadFingerInfo *finger_info;
2506 #if !SDL_EVENTS_DISABLED
2510 if (touchpad < 0 || touchpad >= joystick->ntouchpads) {
2514 touchpad_info = &joystick->touchpads[touchpad];
2515 if (finger < 0 || finger >= touchpad_info->nfingers) {
2519 finger_info = &touchpad_info->fingers[finger];
2522 if (x == 0.0f && y == 0.0f) {
2531 } else if (x > 1.0f) {
2536 } else if (y > 1.0f) {
2539 if (pressure < 0.0f) {
2541 } else if (pressure > 1.0f) {
2545 if (state == finger_info->state) {
2547 (x == finger_info->x && y == finger_info->y && pressure == finger_info->pressure)) {
2552 #if !SDL_EVENTS_DISABLED
2553 if (state == finger_info->state) {
2554 event_type = SDL_CONTROLLERTOUCHPADMOTION;
2556 event_type = SDL_CONTROLLERTOUCHPADDOWN;
2558 event_type = SDL_CONTROLLERTOUCHPADUP;
2562 /* Update internal joystick state */
2563 finger_info->state = state;
2566 finger_info->pressure = pressure;
2568 /* Post the event, if desired */
2570 #if !SDL_EVENTS_DISABLED
2571 if (SDL_GetEventState(event_type) == SDL_ENABLE) {
2573 event.type = event_type;
2574 event.ctouchpad.which = joystick->instance_id;
2575 event.ctouchpad.touchpad = touchpad;
2576 event.ctouchpad.finger = finger;
2577 event.ctouchpad.x = x;
2578 event.ctouchpad.y = y;
2579 event.ctouchpad.pressure = pressure;
2580 posted = SDL_PushEvent(&event) == 1;
2582 #endif /* !SDL_EVENTS_DISABLED */
2586 int SDL_PrivateJoystickSensor(SDL_Joystick *joystick, SDL_SensorType type, const float *data, int num_values)
2591 for (i = 0; i < joystick->nsensors; ++i) {
2592 SDL_JoystickSensorInfo *sensor = &joystick->sensors[i];
2594 if (sensor->type == type) {
2595 if (sensor->enabled) {
2596 num_values = SDL_min(num_values, SDL_arraysize(sensor->data));
2597 if (SDL_memcmp(data, sensor->data, num_values*sizeof(*data)) != 0) {
2599 /* Update internal sensor state */
2600 SDL_memcpy(sensor->data, data, num_values*sizeof(*data));
2602 /* Post the event, if desired */
2603 #if !SDL_EVENTS_DISABLED
2604 if (SDL_GetEventState(SDL_CONTROLLERSENSORUPDATE) == SDL_ENABLE) {
2606 event.type = SDL_CONTROLLERSENSORUPDATE;
2607 event.csensor.which = joystick->instance_id;
2608 event.csensor.sensor = type;
2609 num_values = SDL_min(num_values, SDL_arraysize(event.csensor.data));
2610 SDL_memset(event.csensor.data, 0, sizeof(event.csensor.data));
2611 SDL_memcpy(event.csensor.data, data, num_values*sizeof(*data));
2612 posted = SDL_PushEvent(&event) == 1;
2614 #endif /* !SDL_EVENTS_DISABLED */
2623 /* vi: set ts=4 sw=4 expandtab: */