sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_joystick.c (76295B)


      1 /*
      2   Simple DirectMedia Layer
      3   Copyright (C) 1997-2020 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_atomic.h"
     27 #include "SDL_events.h"
     28 #include "SDL_sysjoystick.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 #include "hidapi/SDL_hidapijoystick_c.h"
     36 
     37 /* This is included in only one place because it has a large static list of controllers */
     38 #include "controller_type.h"
     39 
     40 #ifdef __WIN32__
     41 /* Needed for checking for input remapping programs */
     42 #include "../core/windows/SDL_windows.h"
     43 
     44 #undef UNICODE          /* We want ASCII functions */
     45 #include <tlhelp32.h>
     46 #endif
     47 
     48 #if SDL_JOYSTICK_VIRTUAL
     49 #include "./virtual/SDL_virtualjoystick_c.h"
     50 #endif
     51 
     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,
     55 #endif
     56 #ifdef SDL_JOYSTICK_RAWINPUT /* Before WINDOWS_ driver, as WINDOWS wants to check if this driver is handling things */
     57     &SDL_RAWINPUT_JoystickDriver,
     58 #endif
     59 #if defined(SDL_JOYSTICK_WGI)
     60     &SDL_WGI_JoystickDriver,
     61 #endif
     62 #if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT)
     63     &SDL_WINDOWS_JoystickDriver,
     64 #endif
     65 #ifdef SDL_JOYSTICK_LINUX
     66     &SDL_LINUX_JoystickDriver,
     67 #endif
     68 #ifdef SDL_JOYSTICK_IOKIT
     69     &SDL_DARWIN_JoystickDriver,
     70 #endif
     71 #if (defined(__MACOSX__) || defined(__IPHONEOS__) || defined(__TVOS__)) && !defined(SDL_JOYSTICK_DISABLED)
     72     &SDL_IOS_JoystickDriver,
     73 #endif
     74 #ifdef SDL_JOYSTICK_ANDROID
     75     &SDL_ANDROID_JoystickDriver,
     76 #endif
     77 #ifdef SDL_JOYSTICK_EMSCRIPTEN
     78     &SDL_EMSCRIPTEN_JoystickDriver,
     79 #endif
     80 #ifdef SDL_JOYSTICK_HAIKU
     81     &SDL_HAIKU_JoystickDriver,
     82 #endif
     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,
     85 #endif
     86 #ifdef SDL_JOYSTICK_VIRTUAL
     87     &SDL_VIRTUAL_JoystickDriver,
     88 #endif
     89 #if defined(SDL_JOYSTICK_DUMMY) || defined(SDL_JOYSTICK_DISABLED)
     90     &SDL_DUMMY_JoystickDriver
     91 #endif
     92 };
     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;
    100 
    101 void
    102 SDL_LockJoysticks(void)
    103 {
    104     if (SDL_joystick_lock) {
    105         SDL_LockMutex(SDL_joystick_lock);
    106     }
    107 }
    108 
    109 void
    110 SDL_UnlockJoysticks(void)
    111 {
    112     if (SDL_joystick_lock) {
    113         SDL_UnlockMutex(SDL_joystick_lock);
    114     }
    115 }
    116 
    117 static int
    118 SDL_FindFreePlayerIndex()
    119 {
    120     int player_index;
    121 
    122     for (player_index = 0; player_index < SDL_joystick_player_count; ++player_index) {
    123         if (SDL_joystick_players[player_index] == -1) {
    124             return player_index;
    125         }
    126     }
    127     return player_index;
    128 }
    129 
    130 static int
    131 SDL_GetPlayerIndexForJoystickID(SDL_JoystickID instance_id)
    132 {
    133     int player_index;
    134 
    135     for (player_index = 0; player_index < SDL_joystick_player_count; ++player_index) {
    136         if (instance_id == SDL_joystick_players[player_index]) {
    137             break;
    138         }
    139     }
    140     if (player_index == SDL_joystick_player_count) {
    141         player_index = -1;
    142     }
    143     return player_index;
    144 }
    145 
    146 static SDL_JoystickID
    147 SDL_GetJoystickIDForPlayerIndex(int player_index)
    148 {
    149     if (player_index < 0 || player_index >= SDL_joystick_player_count) {
    150         return -1;
    151     }
    152     return SDL_joystick_players[player_index];
    153 }
    154 
    155 static SDL_bool
    156 SDL_SetJoystickIDForPlayerIndex(int player_index, SDL_JoystickID instance_id)
    157 {
    158     SDL_JoystickID existing_instance = SDL_GetJoystickIDForPlayerIndex(player_index);
    159     SDL_JoystickDriver *driver;
    160     int device_index;
    161     int existing_player_index;
    162 
    163     if (player_index < 0) {
    164         return SDL_FALSE;
    165     }
    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));
    168         if (!new_players) {
    169             SDL_OutOfMemory();
    170             return SDL_FALSE;
    171         }
    172 
    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 */
    178         return SDL_TRUE;
    179     }
    180 
    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;
    185     }
    186 
    187     SDL_joystick_players[player_index] = instance_id;
    188 
    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);
    193     }
    194 
    195     /* Move any existing joystick to another slot */
    196     if (existing_instance >= 0) {
    197         SDL_SetJoystickIDForPlayerIndex(SDL_FindFreePlayerIndex(), existing_instance);
    198     }
    199     return SDL_TRUE;
    200 }
    201 
    202 static void SDLCALL
    203 SDL_JoystickAllowBackgroundEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
    204 {
    205     if (hint && *hint == '1') {
    206         SDL_joystick_allows_background_events = SDL_TRUE;
    207     } else {
    208         SDL_joystick_allows_background_events = SDL_FALSE;
    209     }
    210 }
    211 
    212 int
    213 SDL_JoystickInit(void)
    214 {
    215     int i, status;
    216 
    217     SDL_GameControllerInitMappings();
    218 
    219     /* Create the joystick list lock */
    220     if (!SDL_joystick_lock) {
    221         SDL_joystick_lock = SDL_CreateMutex();
    222     }
    223 
    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);
    227 
    228 #if !SDL_EVENTS_DISABLED
    229     if (SDL_InitSubSystem(SDL_INIT_EVENTS) < 0) {
    230         return -1;
    231     }
    232 #endif /* !SDL_EVENTS_DISABLED */
    233 
    234     status = -1;
    235     for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) {
    236         if (SDL_joystick_drivers[i]->Init() >= 0) {
    237             status = 0;
    238         }
    239     }
    240     return status;
    241 }
    242 
    243 /*
    244  * Count the number of joysticks attached to the system
    245  */
    246 int
    247 SDL_NumJoysticks(void)
    248 {
    249     int i, total_joysticks = 0;
    250     SDL_LockJoysticks();
    251     for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) {
    252         total_joysticks += SDL_joystick_drivers[i]->GetCount();
    253     }
    254     SDL_UnlockJoysticks();
    255     return total_joysticks;
    256 }
    257 
    258 /*
    259  * Return the next available joystick instance ID
    260  * This may be called by drivers from multiple threads, unprotected by any locks
    261  */
    262 SDL_JoystickID SDL_GetNextJoystickInstanceID()
    263 {
    264     return SDL_AtomicIncRef(&SDL_next_joystick_instance_id);
    265 }
    266 
    267 /*
    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
    270  */
    271 SDL_bool
    272 SDL_GetDriverAndJoystickIndex(int device_index, SDL_JoystickDriver **driver, int *driver_index)
    273 {
    274     int i, num_joysticks, total_joysticks = 0;
    275 
    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;
    282                 return SDL_TRUE;
    283             }
    284             device_index -= num_joysticks;
    285             total_joysticks += num_joysticks;
    286         }
    287     }
    288 
    289     SDL_SetError("There are %d joysticks available", total_joysticks);
    290     return SDL_FALSE;
    291 }
    292 
    293 /*
    294  * Get the implementation dependent name of a joystick
    295  */
    296 const char *
    297 SDL_JoystickNameForIndex(int device_index)
    298 {
    299     SDL_JoystickDriver *driver;
    300     const char *name = NULL;
    301 
    302     SDL_LockJoysticks();
    303     if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) {
    304         name = driver->GetDeviceName(device_index);
    305     }
    306     SDL_UnlockJoysticks();
    307 
    308     /* FIXME: Really we should reference count this name so it doesn't go away after unlock */
    309     return name;
    310 }
    311 
    312 /*
    313  *  Get the player index of a joystick, or -1 if it's not available
    314  */
    315 int
    316 SDL_JoystickGetDevicePlayerIndex(int device_index)
    317 {
    318     int player_index;
    319 
    320     SDL_LockJoysticks();
    321     player_index = SDL_GetPlayerIndexForJoystickID(SDL_JoystickGetDeviceInstanceID(device_index));
    322     SDL_UnlockJoysticks();
    323 
    324     return player_index;
    325 }
    326 
    327 /*
    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
    331  */
    332 static SDL_bool
    333 SDL_JoystickAxesCenteredAtZero(SDL_Joystick *joystick)
    334 {
    335     static Uint32 zero_centered_joysticks[] = {
    336         MAKE_VIDPID(0x0e8f, 0x3013),    /* HuiJia SNES USB adapter */
    337         MAKE_VIDPID(0x05a0, 0x3232),    /* 8Bitdo Zero Gamepad */
    338     };
    339 
    340     int i;
    341     Uint32 id = MAKE_VIDPID(SDL_JoystickGetVendor(joystick),
    342                             SDL_JoystickGetProduct(joystick));
    343 
    344 /*printf("JOYSTICK '%s' VID/PID 0x%.4x/0x%.4x AXES: %d\n", joystick->name, vendor, product, joystick->naxes);*/
    345 
    346     if (joystick->naxes == 2) {
    347         /* Assume D-pad or thumbstick style axes are centered at 0 */
    348         return SDL_TRUE;
    349     }
    350 
    351     for (i = 0; i < SDL_arraysize(zero_centered_joysticks); ++i) {
    352         if (id == zero_centered_joysticks[i]) {
    353             return SDL_TRUE;
    354         }
    355     }
    356     return SDL_FALSE;
    357 }
    358 
    359 /*
    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.
    363  *
    364  * This function returns a joystick identifier, or NULL if an error occurred.
    365  */
    366 SDL_Joystick *
    367 SDL_JoystickOpen(int device_index)
    368 {
    369     SDL_JoystickDriver *driver;
    370     SDL_JoystickID instance_id;
    371     SDL_Joystick *joystick;
    372     SDL_Joystick *joysticklist;
    373     const char *joystickname = NULL;
    374 
    375     SDL_LockJoysticks();
    376 
    377     if (!SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) {
    378         SDL_UnlockJoysticks();
    379         return NULL;
    380     }
    381 
    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
    385      */
    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();
    392                 return joystick;
    393         }
    394         joysticklist = joysticklist->next;
    395     }
    396 
    397     /* Create and initialize the joystick */
    398     joystick = (SDL_Joystick *) SDL_calloc(sizeof(*joystick), 1);
    399     if (joystick == NULL) {
    400         SDL_OutOfMemory();
    401         SDL_UnlockJoysticks();
    402         return NULL;
    403     }
    404     joystick->driver = driver;
    405     joystick->instance_id = instance_id;
    406     joystick->attached = SDL_TRUE;
    407     joystick->epowerlevel = SDL_JOYSTICK_POWER_UNKNOWN;
    408 
    409     if (driver->Open(joystick, device_index) < 0) {
    410         SDL_free(joystick);
    411         SDL_UnlockJoysticks();
    412         return NULL;
    413     }
    414 
    415     joystickname = driver->GetDeviceName(device_index);
    416     if (joystickname) {
    417         joystick->name = SDL_strdup(joystickname);
    418     } else {
    419         joystick->name = NULL;
    420     }
    421 
    422     joystick->guid = driver->GetDeviceGUID(device_index);
    423 
    424     if (joystick->naxes > 0) {
    425         joystick->axes = (SDL_JoystickAxisInfo *) SDL_calloc(joystick->naxes, sizeof(SDL_JoystickAxisInfo));
    426     }
    427     if (joystick->nhats > 0) {
    428         joystick->hats = (Uint8 *) SDL_calloc(joystick->nhats, sizeof(Uint8));
    429     }
    430     if (joystick->nballs > 0) {
    431         joystick->balls = (struct balldelta *) SDL_calloc(joystick->nballs, sizeof(*joystick->balls));
    432     }
    433     if (joystick->nbuttons > 0) {
    434         joystick->buttons = (Uint8 *) SDL_calloc(joystick->nbuttons, sizeof(Uint8));
    435     }
    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)) {
    440         SDL_OutOfMemory();
    441         SDL_JoystickClose(joystick);
    442         SDL_UnlockJoysticks();
    443         return NULL;
    444     }
    445 
    446     /* If this joystick is known to have all zero centered axes, skip the auto-centering code */
    447     if (SDL_JoystickAxesCenteredAtZero(joystick)) {
    448         int i;
    449 
    450         for (i = 0; i < joystick->naxes; ++i) {
    451             joystick->axes[i].has_initial_value = SDL_TRUE;
    452         }
    453     }
    454 
    455     joystick->is_game_controller = SDL_IsGameController(device_index);
    456 
    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;
    462 
    463     SDL_UnlockJoysticks();
    464 
    465     driver->Update(joystick);
    466 
    467     return joystick;
    468 }
    469 
    470 int
    471 SDL_JoystickAttachVirtual(SDL_JoystickType type,
    472                           int naxes, int nbuttons, int nhats)
    473 {
    474 #if SDL_JOYSTICK_VIRTUAL
    475     return SDL_JoystickAttachVirtualInner(type, naxes, nbuttons, nhats);
    476 #else
    477     return SDL_SetError("SDL not built with virtual-joystick support");
    478 #endif
    479 }
    480 
    481 int
    482 SDL_JoystickDetachVirtual(int device_index)
    483 {
    484 #if SDL_JOYSTICK_VIRTUAL
    485     SDL_JoystickDriver *driver;
    486 
    487     SDL_LockJoysticks();
    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();
    492             return result;
    493         }
    494     }
    495     SDL_UnlockJoysticks();
    496 
    497     return SDL_SetError("Virtual joystick not found at provided index");
    498 #else
    499     return SDL_SetError("SDL not built with virtual-joystick support");
    500 #endif
    501 }
    502 
    503 SDL_bool
    504 SDL_JoystickIsVirtual(int device_index)
    505 {
    506 #if SDL_JOYSTICK_VIRTUAL
    507     SDL_JoystickDriver *driver;
    508     int driver_device_index;
    509     SDL_bool is_virtual = SDL_FALSE;
    510 
    511     SDL_LockJoysticks();
    512     if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &driver_device_index)) {
    513         if (driver == &SDL_VIRTUAL_JoystickDriver) {
    514             is_virtual = SDL_TRUE;
    515         }
    516     }
    517     SDL_UnlockJoysticks();
    518 
    519     return is_virtual;
    520 #else
    521     return SDL_FALSE;
    522 #endif
    523 }
    524 
    525 int
    526 SDL_JoystickSetVirtualAxis(SDL_Joystick *joystick, int axis, Sint16 value)
    527 {
    528 #if SDL_JOYSTICK_VIRTUAL
    529     return SDL_JoystickSetVirtualAxisInner(joystick, axis, value);
    530 #else
    531     return SDL_SetError("SDL not built with virtual-joystick support");
    532 #endif
    533 }
    534 
    535 int
    536 SDL_JoystickSetVirtualButton(SDL_Joystick *joystick, int button, Uint8 value)
    537 {
    538 #if SDL_JOYSTICK_VIRTUAL
    539     return SDL_JoystickSetVirtualButtonInner(joystick, button, value);
    540 #else
    541     return SDL_SetError("SDL not built with virtual-joystick support");
    542 #endif
    543 }
    544 
    545 int
    546 SDL_JoystickSetVirtualHat(SDL_Joystick *joystick, int hat, Uint8 value)
    547 {
    548 #if SDL_JOYSTICK_VIRTUAL
    549     return SDL_JoystickSetVirtualHatInner(joystick, hat, value);
    550 #else
    551     return SDL_SetError("SDL not built with virtual-joystick support");
    552 #endif
    553 }
    554 
    555 /*
    556  * Checks to make sure the joystick is valid.
    557  */
    558 SDL_bool
    559 SDL_PrivateJoystickValid(SDL_Joystick *joystick)
    560 {
    561     SDL_bool valid;
    562 
    563     if (joystick == NULL) {
    564         SDL_SetError("Joystick hasn't been opened yet");
    565         valid = SDL_FALSE;
    566     } else {
    567         valid = SDL_TRUE;
    568     }
    569 
    570     return valid;
    571 }
    572 
    573 SDL_bool
    574 SDL_PrivateJoystickGetAutoGamepadMapping(int device_index, SDL_GamepadMapping * out)
    575 {
    576     SDL_JoystickDriver *driver;
    577     SDL_bool is_ok = SDL_FALSE;
    578 
    579     SDL_LockJoysticks();
    580     if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) {
    581         is_ok = driver->GetGamepadMapping(device_index, out);
    582     }
    583     SDL_UnlockJoysticks();
    584 
    585     return is_ok;
    586 }
    587 
    588 /*
    589  * Get the number of multi-dimensional axis controls on a joystick
    590  */
    591 int
    592 SDL_JoystickNumAxes(SDL_Joystick *joystick)
    593 {
    594     if (!SDL_PrivateJoystickValid(joystick)) {
    595         return -1;
    596     }
    597     return joystick->naxes;
    598 }
    599 
    600 /*
    601  * Get the number of hats on a joystick
    602  */
    603 int
    604 SDL_JoystickNumHats(SDL_Joystick *joystick)
    605 {
    606     if (!SDL_PrivateJoystickValid(joystick)) {
    607         return -1;
    608     }
    609     return joystick->nhats;
    610 }
    611 
    612 /*
    613  * Get the number of trackballs on a joystick
    614  */
    615 int
    616 SDL_JoystickNumBalls(SDL_Joystick *joystick)
    617 {
    618     if (!SDL_PrivateJoystickValid(joystick)) {
    619         return -1;
    620     }
    621     return joystick->nballs;
    622 }
    623 
    624 /*
    625  * Get the number of buttons on a joystick
    626  */
    627 int
    628 SDL_JoystickNumButtons(SDL_Joystick *joystick)
    629 {
    630     if (!SDL_PrivateJoystickValid(joystick)) {
    631         return -1;
    632     }
    633     return joystick->nbuttons;
    634 }
    635 
    636 /*
    637  * Get the current state of an axis control on a joystick
    638  */
    639 Sint16
    640 SDL_JoystickGetAxis(SDL_Joystick *joystick, int axis)
    641 {
    642     Sint16 state;
    643 
    644     if (!SDL_PrivateJoystickValid(joystick)) {
    645         return 0;
    646     }
    647     if (axis < joystick->naxes) {
    648         state = joystick->axes[axis].value;
    649     } else {
    650         SDL_SetError("Joystick only has %d axes", joystick->naxes);
    651         state = 0;
    652     }
    653     return state;
    654 }
    655 
    656 /*
    657  * Get the initial state of an axis control on a joystick
    658  */
    659 SDL_bool
    660 SDL_JoystickGetAxisInitialState(SDL_Joystick *joystick, int axis, Sint16 *state)
    661 {
    662     if (!SDL_PrivateJoystickValid(joystick)) {
    663         return SDL_FALSE;
    664     }
    665     if (axis >= joystick->naxes) {
    666         SDL_SetError("Joystick only has %d axes", joystick->naxes);
    667         return SDL_FALSE;
    668     }
    669     if (state) {
    670         *state = joystick->axes[axis].initial_value;
    671     }
    672     return joystick->axes[axis].has_initial_value;
    673 }
    674 
    675 /*
    676  * Get the current state of a hat on a joystick
    677  */
    678 Uint8
    679 SDL_JoystickGetHat(SDL_Joystick *joystick, int hat)
    680 {
    681     Uint8 state;
    682 
    683     if (!SDL_PrivateJoystickValid(joystick)) {
    684         return 0;
    685     }
    686     if (hat < joystick->nhats) {
    687         state = joystick->hats[hat];
    688     } else {
    689         SDL_SetError("Joystick only has %d hats", joystick->nhats);
    690         state = 0;
    691     }
    692     return state;
    693 }
    694 
    695 /*
    696  * Get the ball axis change since the last poll
    697  */
    698 int
    699 SDL_JoystickGetBall(SDL_Joystick *joystick, int ball, int *dx, int *dy)
    700 {
    701     int retval;
    702 
    703     if (!SDL_PrivateJoystickValid(joystick)) {
    704         return -1;
    705     }
    706 
    707     retval = 0;
    708     if (ball < joystick->nballs) {
    709         if (dx) {
    710             *dx = joystick->balls[ball].dx;
    711         }
    712         if (dy) {
    713             *dy = joystick->balls[ball].dy;
    714         }
    715         joystick->balls[ball].dx = 0;
    716         joystick->balls[ball].dy = 0;
    717     } else {
    718         return SDL_SetError("Joystick only has %d balls", joystick->nballs);
    719     }
    720     return retval;
    721 }
    722 
    723 /*
    724  * Get the current state of a button on a joystick
    725  */
    726 Uint8
    727 SDL_JoystickGetButton(SDL_Joystick *joystick, int button)
    728 {
    729     Uint8 state;
    730 
    731     if (!SDL_PrivateJoystickValid(joystick)) {
    732         return 0;
    733     }
    734     if (button < joystick->nbuttons) {
    735         state = joystick->buttons[button];
    736     } else {
    737         SDL_SetError("Joystick only has %d buttons", joystick->nbuttons);
    738         state = 0;
    739     }
    740     return state;
    741 }
    742 
    743 /*
    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.
    746  */
    747 SDL_bool
    748 SDL_JoystickGetAttached(SDL_Joystick *joystick)
    749 {
    750     if (!SDL_PrivateJoystickValid(joystick)) {
    751         return SDL_FALSE;
    752     }
    753 
    754     return joystick->attached;
    755 }
    756 
    757 /*
    758  * Get the instance id for this opened joystick
    759  */
    760 SDL_JoystickID
    761 SDL_JoystickInstanceID(SDL_Joystick *joystick)
    762 {
    763     if (!SDL_PrivateJoystickValid(joystick)) {
    764         return -1;
    765     }
    766 
    767     return joystick->instance_id;
    768 }
    769 
    770 /*
    771  * Return the SDL_Joystick associated with an instance id.
    772  */
    773 SDL_Joystick *
    774 SDL_JoystickFromInstanceID(SDL_JoystickID instance_id)
    775 {
    776     SDL_Joystick *joystick;
    777 
    778     SDL_LockJoysticks();
    779     for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
    780         if (joystick->instance_id == instance_id) {
    781             break;
    782         }
    783     }
    784     SDL_UnlockJoysticks();
    785     return joystick;
    786 }
    787 
    788 /**
    789  * Return the SDL_Joystick associated with a player index.
    790  */
    791 SDL_Joystick *
    792 SDL_JoystickFromPlayerIndex(int player_index)
    793 {
    794     SDL_JoystickID instance_id;
    795     SDL_Joystick *joystick;
    796 
    797     SDL_LockJoysticks();
    798     instance_id = SDL_GetJoystickIDForPlayerIndex(player_index);
    799     for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
    800         if (joystick->instance_id == instance_id) {
    801             break;
    802         }
    803     }
    804     SDL_UnlockJoysticks();
    805     return joystick;
    806 }
    807 
    808 /*
    809  * Get the friendly name of this joystick
    810  */
    811 const char *
    812 SDL_JoystickName(SDL_Joystick *joystick)
    813 {
    814     if (!SDL_PrivateJoystickValid(joystick)) {
    815         return NULL;
    816     }
    817 
    818     return joystick->name;
    819 }
    820 
    821 /**
    822  *  Get the player index of an opened joystick, or -1 if it's not available
    823  */
    824 int
    825 SDL_JoystickGetPlayerIndex(SDL_Joystick *joystick)
    826 {
    827     int player_index;
    828 
    829     if (!SDL_PrivateJoystickValid(joystick)) {
    830         return -1;
    831     }
    832 
    833     SDL_LockJoysticks();
    834     player_index = SDL_GetPlayerIndexForJoystickID(joystick->instance_id);
    835     SDL_UnlockJoysticks();
    836 
    837     return player_index;
    838 }
    839 
    840 /**
    841  *  Set the player index of an opened joystick
    842  */
    843 void
    844 SDL_JoystickSetPlayerIndex(SDL_Joystick *joystick, int player_index)
    845 {
    846     if (!SDL_PrivateJoystickValid(joystick)) {
    847         return;
    848     }
    849 
    850     SDL_LockJoysticks();
    851     SDL_SetJoystickIDForPlayerIndex(player_index, joystick->instance_id);
    852     SDL_UnlockJoysticks();
    853 }
    854 
    855 int
    856 SDL_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
    857 {
    858     int result;
    859 
    860     if (!SDL_PrivateJoystickValid(joystick)) {
    861         return -1;
    862     }
    863 
    864     SDL_LockJoysticks();
    865     if (low_frequency_rumble == joystick->low_frequency_rumble &&
    866         high_frequency_rumble == joystick->high_frequency_rumble) {
    867         /* Just update the expiration */
    868         result = 0;
    869     } else {
    870         result = joystick->driver->Rumble(joystick, low_frequency_rumble, high_frequency_rumble);
    871     }
    872 
    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;
    876 
    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;
    881         }
    882     } else {
    883         joystick->rumble_expiration = 0;
    884     }
    885     SDL_UnlockJoysticks();
    886 
    887     return result;
    888 }
    889 
    890 int
    891 SDL_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble, Uint32 duration_ms)
    892 {
    893     int result;
    894 
    895     if (!SDL_PrivateJoystickValid(joystick)) {
    896         return -1;
    897     }
    898 
    899     SDL_LockJoysticks();
    900     if (left_rumble == joystick->left_trigger_rumble && right_rumble == joystick->right_trigger_rumble) {
    901         /* Just update the expiration */
    902         result = 0;
    903     } else {
    904         result = joystick->driver->RumbleTriggers(joystick, left_rumble, right_rumble);
    905     }
    906 
    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;
    910 
    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;
    915         }
    916     } else {
    917         joystick->trigger_rumble_expiration = 0;
    918     }
    919     SDL_UnlockJoysticks();
    920 
    921     return result;
    922 }
    923 
    924 SDL_bool
    925 SDL_JoystickHasLED(SDL_Joystick *joystick)
    926 {
    927     SDL_bool result;
    928 
    929     if (!SDL_PrivateJoystickValid(joystick)) {
    930         return SDL_FALSE;
    931     }
    932 
    933     SDL_LockJoysticks();
    934 
    935     result = joystick->driver->HasLED(joystick);
    936 
    937     SDL_UnlockJoysticks();
    938 
    939     return result;
    940 }
    941 
    942 int
    943 SDL_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
    944 {
    945     int result;
    946 
    947     if (!SDL_PrivateJoystickValid(joystick)) {
    948         return -1;
    949     }
    950 
    951     SDL_LockJoysticks();
    952 
    953     if (red == joystick->led_red &&
    954         green == joystick->led_green &&
    955         blue == joystick->led_blue) {
    956         /* Avoid spamming the driver */
    957         result = 0;
    958     } else {
    959         result = joystick->driver->SetLED(joystick, red, green, blue);
    960     }
    961 
    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;
    966 
    967     SDL_UnlockJoysticks();
    968 
    969     return result;
    970 }
    971 
    972 /*
    973  * Close a joystick previously opened with SDL_JoystickOpen()
    974  */
    975 void
    976 SDL_JoystickClose(SDL_Joystick *joystick)
    977 {
    978     SDL_Joystick *joysticklist;
    979     SDL_Joystick *joysticklistprev;
    980     int i;
    981 
    982     if (!SDL_PrivateJoystickValid(joystick)) {
    983         return;
    984     }
    985 
    986     SDL_LockJoysticks();
    987 
    988     /* First decrement ref count */
    989     if (--joystick->ref_count > 0) {
    990         SDL_UnlockJoysticks();
    991         return;
    992     }
    993 
    994     if (SDL_updating_joystick) {
    995         SDL_UnlockJoysticks();
    996         return;
    997     }
    998 
    999     if (joystick->rumble_expiration) {
   1000         SDL_JoystickRumble(joystick, 0, 0, 0);
   1001     }
   1002     if (joystick->trigger_rumble_expiration) {
   1003         SDL_JoystickRumbleTriggers(joystick, 0, 0, 0);
   1004     }
   1005 
   1006     joystick->driver->Close(joystick);
   1007     joystick->hwdata = NULL;
   1008 
   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;
   1016             } else {
   1017                 SDL_joysticks = joystick->next;
   1018             }
   1019             break;
   1020         }
   1021         joysticklistprev = joysticklist;
   1022         joysticklist = joysticklist->next;
   1023     }
   1024 
   1025     SDL_free(joystick->name);
   1026     SDL_free(joystick->serial);
   1027 
   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);
   1036     }
   1037     SDL_free(joystick->touchpads);
   1038     SDL_free(joystick->sensors);
   1039     SDL_free(joystick);
   1040 
   1041     SDL_UnlockJoysticks();
   1042 }
   1043 
   1044 void
   1045 SDL_JoystickQuit(void)
   1046 {
   1047     int i;
   1048 
   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();
   1053         SDL_Delay(1);
   1054         SDL_LockJoysticks();
   1055     }
   1056 
   1057     /* Stop the event polling */
   1058     while (SDL_joysticks) {
   1059         SDL_joysticks->ref_count = 1;
   1060         SDL_JoystickClose(SDL_joysticks);
   1061     }
   1062 
   1063     /* Quit the joystick setup */
   1064     for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) {
   1065        SDL_joystick_drivers[i]->Quit();
   1066     }
   1067 
   1068     if (SDL_joystick_players) {
   1069         SDL_free(SDL_joystick_players);
   1070         SDL_joystick_players = NULL;
   1071         SDL_joystick_player_count = 0;
   1072     }
   1073     SDL_UnlockJoysticks();
   1074 
   1075 #if !SDL_EVENTS_DISABLED
   1076     SDL_QuitSubSystem(SDL_INIT_EVENTS);
   1077 #endif
   1078 
   1079     SDL_DelHintCallback(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS,
   1080                         SDL_JoystickAllowBackgroundEventsChanged, NULL);
   1081 
   1082     if (SDL_joystick_lock) {
   1083         SDL_mutex *mutex = SDL_joystick_lock;
   1084         SDL_joystick_lock = NULL;
   1085         SDL_DestroyMutex(mutex);
   1086     }
   1087 
   1088     SDL_GameControllerQuitMappings();
   1089 }
   1090 
   1091 
   1092 static SDL_bool
   1093 SDL_PrivateJoystickShouldIgnoreEvent()
   1094 {
   1095     if (SDL_joystick_allows_background_events) {
   1096         return SDL_FALSE;
   1097     }
   1098 
   1099     if (SDL_HasWindows() && SDL_GetKeyboardFocus() == NULL) {
   1100         /* We have windows but we don't have focus, ignore the event. */
   1101         return SDL_TRUE;
   1102     }
   1103     return SDL_FALSE;
   1104 }
   1105 
   1106 /* These are global for SDL_sysjoystick.c and SDL_events.c */
   1107 
   1108 void SDL_PrivateJoystickAddTouchpad(SDL_Joystick *joystick, int nfingers)
   1109 {
   1110     int ntouchpads = joystick->ntouchpads + 1;
   1111     SDL_JoystickTouchpadInfo *touchpads = (SDL_JoystickTouchpadInfo *)SDL_realloc(joystick->touchpads, (ntouchpads * sizeof(SDL_JoystickTouchpadInfo)));
   1112     if (touchpads) {
   1113         SDL_JoystickTouchpadInfo *touchpad = &touchpads[ntouchpads - 1];
   1114         SDL_JoystickTouchpadFingerInfo *fingers = (SDL_JoystickTouchpadFingerInfo *)SDL_calloc(nfingers, sizeof(SDL_JoystickTouchpadFingerInfo));
   1115 
   1116         if (fingers) {
   1117             touchpad->nfingers = nfingers;
   1118             touchpad->fingers = fingers;
   1119         } else {
   1120             /* Out of memory, this touchpad won't be active */
   1121             touchpad->nfingers = 0;
   1122             touchpad->fingers = NULL;
   1123         }
   1124 
   1125         joystick->ntouchpads = ntouchpads;
   1126         joystick->touchpads = touchpads;
   1127     }
   1128 }
   1129 
   1130 void SDL_PrivateJoystickAddSensor(SDL_Joystick *joystick, SDL_SensorType type)
   1131 {
   1132     int nsensors = joystick->nsensors + 1;
   1133     SDL_JoystickSensorInfo *sensors = (SDL_JoystickSensorInfo *)SDL_realloc(joystick->sensors, (nsensors * sizeof(SDL_JoystickSensorInfo)));
   1134     if (sensors) {
   1135         SDL_JoystickSensorInfo *sensor = &sensors[nsensors - 1];
   1136 
   1137         SDL_zerop(sensor);
   1138         sensor->type = type;
   1139 
   1140         joystick->nsensors = nsensors;
   1141         joystick->sensors = sensors;
   1142     }
   1143 }
   1144 
   1145 void SDL_PrivateJoystickAdded(SDL_JoystickID device_instance)
   1146 {
   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) {
   1152         return;
   1153     }
   1154 
   1155     SDL_LockJoysticks();
   1156     if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &driver_device_index)) {
   1157         player_index = driver->GetDevicePlayerIndex(driver_device_index);
   1158     }
   1159     if (player_index < 0 && SDL_IsGameController(device_index)) {
   1160         player_index = SDL_FindFreePlayerIndex();
   1161     }
   1162     if (player_index >= 0) {
   1163         SDL_SetJoystickIDForPlayerIndex(player_index, device_instance);
   1164     }
   1165     SDL_UnlockJoysticks();
   1166 
   1167 #if !SDL_EVENTS_DISABLED
   1168     {
   1169         SDL_Event event;
   1170 
   1171         event.type = SDL_JOYDEVICEADDED;
   1172 
   1173         if (SDL_GetEventState(event.type) == SDL_ENABLE) {
   1174             event.jdevice.which = device_index;
   1175             SDL_PushEvent(&event);
   1176         }
   1177     }
   1178 #endif /* !SDL_EVENTS_DISABLED */
   1179 }
   1180 
   1181 /*
   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.
   1185  */
   1186 static void UpdateEventsForDeviceRemoval(int device_index)
   1187 {
   1188     int i, num_events;
   1189     SDL_Event *events;
   1190     SDL_bool isstack;
   1191 
   1192     num_events = SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, SDL_JOYDEVICEADDED, SDL_JOYDEVICEADDED);
   1193     if (num_events <= 0) {
   1194         return;
   1195     }
   1196 
   1197     events = SDL_small_alloc(SDL_Event, num_events, &isstack);
   1198     if (!events) {
   1199         return;
   1200     }
   1201 
   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 */
   1206         }
   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)));
   1210             --num_events;
   1211             --i;
   1212         }
   1213         else {
   1214             /* Fix up the device index if greater than the removed device */
   1215             --events[i].cdevice.which;
   1216         }
   1217     }
   1218     SDL_PeepEvents(events, num_events, SDL_ADDEVENT, 0, 0);
   1219 
   1220     SDL_small_free(events, isstack);
   1221 }
   1222 
   1223 static void
   1224 SDL_PrivateJoystickForceRecentering(SDL_Joystick *joystick)
   1225 {
   1226     int i, j;
   1227 
   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);
   1232         }
   1233     }
   1234 
   1235     for (i = 0; i < joystick->nbuttons; i++) {
   1236         SDL_PrivateJoystickButton(joystick, i, SDL_RELEASED);
   1237     }
   1238 
   1239     for (i = 0; i < joystick->nhats; i++) {
   1240         SDL_PrivateJoystickHat(joystick, i, SDL_HAT_CENTERED);
   1241     }
   1242 
   1243     for (i = 0; i < joystick->ntouchpads; i++) {
   1244         SDL_JoystickTouchpadInfo *touchpad = &joystick->touchpads[i];
   1245 
   1246         for (j = 0; j < touchpad->nfingers; ++j) {
   1247             SDL_PrivateJoystickTouchpad(joystick, i, j, SDL_RELEASED, 0.0f, 0.0f, 0.0f);
   1248         }
   1249     }
   1250 
   1251 }
   1252 
   1253 void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance)
   1254 {
   1255     SDL_Joystick *joystick = NULL;
   1256     int player_index;
   1257     int device_index;
   1258 #if !SDL_EVENTS_DISABLED
   1259     SDL_Event event;
   1260 #endif
   1261 
   1262     /* Find this joystick... */
   1263     device_index = 0;
   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;
   1268             break;
   1269         }
   1270 
   1271         ++device_index;
   1272     }
   1273 
   1274 #if !SDL_EVENTS_DISABLED
   1275     SDL_zero(event);
   1276     event.type = SDL_JOYDEVICEREMOVED;
   1277 
   1278     if (SDL_GetEventState(event.type) == SDL_ENABLE) {
   1279         event.jdevice.which = device_instance;
   1280         SDL_PushEvent(&event);
   1281     }
   1282 
   1283     UpdateEventsForDeviceRemoval(device_index);
   1284 #endif /* !SDL_EVENTS_DISABLED */
   1285 
   1286     SDL_LockJoysticks();
   1287     player_index = SDL_GetPlayerIndexForJoystickID(device_instance);
   1288     if (player_index >= 0) {
   1289         SDL_joystick_players[player_index] = -1;
   1290     }
   1291     SDL_UnlockJoysticks();
   1292 }
   1293 
   1294 int
   1295 SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
   1296 {
   1297     int posted;
   1298     SDL_JoystickAxisInfo *info;
   1299 
   1300     /* Make sure we're not getting garbage or duplicate events */
   1301     if (axis >= joystick->naxes) {
   1302         return 0;
   1303     }
   1304 
   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;
   1310         info->zero = value;
   1311         info->has_initial_value = SDL_TRUE;
   1312     } else if (value == info->value) {
   1313         return 0;
   1314     } else {
   1315         info->has_second_value = SDL_TRUE;
   1316     }
   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) {
   1321             return 0;
   1322         }
   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);
   1326     }
   1327 
   1328     /* We ignore events if we don't have keyboard focus, except for centering
   1329      * events.
   1330      */
   1331     if (SDL_PrivateJoystickShouldIgnoreEvent()) {
   1332         if ((value > info->zero && value >= info->value) ||
   1333             (value < info->zero && value <= info->value)) {
   1334             return 0;
   1335         }
   1336     }
   1337 
   1338     /* Update internal joystick state */
   1339     info->value = value;
   1340 
   1341     /* Post the event, if desired */
   1342     posted = 0;
   1343 #if !SDL_EVENTS_DISABLED
   1344     if (SDL_GetEventState(SDL_JOYAXISMOTION) == SDL_ENABLE) {
   1345         SDL_Event event;
   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;
   1351     }
   1352 #endif /* !SDL_EVENTS_DISABLED */
   1353     return posted;
   1354 }
   1355 
   1356 int
   1357 SDL_PrivateJoystickHat(SDL_Joystick *joystick, Uint8 hat, Uint8 value)
   1358 {
   1359     int posted;
   1360 
   1361     /* Make sure we're not getting garbage or duplicate events */
   1362     if (hat >= joystick->nhats) {
   1363         return 0;
   1364     }
   1365     if (value == joystick->hats[hat]) {
   1366         return 0;
   1367     }
   1368 
   1369     /* We ignore events if we don't have keyboard focus, except for centering
   1370      * events.
   1371      */
   1372     if (SDL_PrivateJoystickShouldIgnoreEvent()) {
   1373         if (value != SDL_HAT_CENTERED) {
   1374             return 0;
   1375         }
   1376     }
   1377 
   1378     /* Update internal joystick state */
   1379     joystick->hats[hat] = value;
   1380 
   1381     /* Post the event, if desired */
   1382     posted = 0;
   1383 #if !SDL_EVENTS_DISABLED
   1384     if (SDL_GetEventState(SDL_JOYHATMOTION) == SDL_ENABLE) {
   1385         SDL_Event event;
   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;
   1391     }
   1392 #endif /* !SDL_EVENTS_DISABLED */
   1393     return posted;
   1394 }
   1395 
   1396 int
   1397 SDL_PrivateJoystickBall(SDL_Joystick *joystick, Uint8 ball,
   1398                         Sint16 xrel, Sint16 yrel)
   1399 {
   1400     int posted;
   1401 
   1402     /* Make sure we're not getting garbage events */
   1403     if (ball >= joystick->nballs) {
   1404         return 0;
   1405     }
   1406 
   1407     /* We ignore events if we don't have keyboard focus. */
   1408     if (SDL_PrivateJoystickShouldIgnoreEvent()) {
   1409         return 0;
   1410     }
   1411 
   1412     /* Update internal mouse state */
   1413     joystick->balls[ball].dx += xrel;
   1414     joystick->balls[ball].dy += yrel;
   1415 
   1416     /* Post the event, if desired */
   1417     posted = 0;
   1418 #if !SDL_EVENTS_DISABLED
   1419     if (SDL_GetEventState(SDL_JOYBALLMOTION) == SDL_ENABLE) {
   1420         SDL_Event event;
   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;
   1427     }
   1428 #endif /* !SDL_EVENTS_DISABLED */
   1429     return posted;
   1430 }
   1431 
   1432 int
   1433 SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
   1434 {
   1435     int posted;
   1436 #if !SDL_EVENTS_DISABLED
   1437     SDL_Event event;
   1438 
   1439     switch (state) {
   1440     case SDL_PRESSED:
   1441         event.type = SDL_JOYBUTTONDOWN;
   1442         break;
   1443     case SDL_RELEASED:
   1444         event.type = SDL_JOYBUTTONUP;
   1445         break;
   1446     default:
   1447         /* Invalid state -- bail */
   1448         return 0;
   1449     }
   1450 #endif /* !SDL_EVENTS_DISABLED */
   1451 
   1452     /* Make sure we're not getting garbage or duplicate events */
   1453     if (button >= joystick->nbuttons) {
   1454         return 0;
   1455     }
   1456     if (state == joystick->buttons[button]) {
   1457         return 0;
   1458     }
   1459 
   1460     /* We ignore events if we don't have keyboard focus, except for button
   1461      * release. */
   1462     if (SDL_PrivateJoystickShouldIgnoreEvent()) {
   1463         if (state == SDL_PRESSED) {
   1464             return 0;
   1465         }
   1466     }
   1467 
   1468     /* Update internal joystick state */
   1469     joystick->buttons[button] = state;
   1470 
   1471     /* Post the event, if desired */
   1472     posted = 0;
   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;
   1479     }
   1480 #endif /* !SDL_EVENTS_DISABLED */
   1481     return posted;
   1482 }
   1483 
   1484 void
   1485 SDL_JoystickUpdate(void)
   1486 {
   1487     int i;
   1488     SDL_Joystick *joystick, *next;
   1489 
   1490     if (!SDL_WasInit(SDL_INIT_JOYSTICK)) {
   1491         return;
   1492     }
   1493 
   1494     SDL_LockJoysticks();
   1495 
   1496     if (SDL_updating_joystick) {
   1497         /* The joysticks are already being updated */
   1498         SDL_UnlockJoysticks();
   1499         return;
   1500     }
   1501 
   1502     SDL_updating_joystick = SDL_TRUE;
   1503 
   1504     /* Make sure the list is unlocked while dispatching events to prevent application deadlocks */
   1505     SDL_UnlockJoysticks();
   1506 
   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 */
   1511 
   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);
   1517             }
   1518 
   1519             if (joystick->delayed_guide_button) {
   1520                 SDL_GameControllerHandleDelayedGuideButton(joystick);
   1521             }
   1522         }
   1523 
   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);
   1530             }
   1531             SDL_UnlockJoysticks();
   1532         }
   1533 
   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);
   1540             }
   1541             SDL_UnlockJoysticks();
   1542         }
   1543     }
   1544 
   1545     SDL_LockJoysticks();
   1546 
   1547     SDL_updating_joystick = SDL_FALSE;
   1548 
   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);
   1554         }
   1555     }
   1556 
   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
   1559      */
   1560     for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) {
   1561         SDL_joystick_drivers[i]->Detect();
   1562     }
   1563 
   1564     SDL_UnlockJoysticks();
   1565 }
   1566 
   1567 int
   1568 SDL_JoystickEventState(int state)
   1569 {
   1570 #if SDL_EVENTS_DISABLED
   1571     return SDL_DISABLE;
   1572 #else
   1573     const Uint32 event_list[] = {
   1574         SDL_JOYAXISMOTION, SDL_JOYBALLMOTION, SDL_JOYHATMOTION,
   1575         SDL_JOYBUTTONDOWN, SDL_JOYBUTTONUP, SDL_JOYDEVICEADDED, SDL_JOYDEVICEREMOVED
   1576     };
   1577     unsigned int i;
   1578 
   1579     switch (state) {
   1580     case SDL_QUERY:
   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) {
   1585                 break;
   1586             }
   1587         }
   1588         break;
   1589     default:
   1590         for (i = 0; i < SDL_arraysize(event_list); ++i) {
   1591             SDL_EventState(event_list[i], state);
   1592         }
   1593         break;
   1594     }
   1595     return state;
   1596 #endif /* SDL_EVENTS_DISABLED */
   1597 }
   1598 
   1599 void SDL_GetJoystickGUIDInfo(SDL_JoystickGUID guid, Uint16 *vendor, Uint16 *product, Uint16 *version)
   1600 {
   1601     Uint16 *guid16 = (Uint16 *)guid.data;
   1602 
   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 */
   1609         guid16[5] == 0x0000
   1610         /* guid16[6] is product version */
   1611    ) {
   1612         if (vendor) {
   1613             *vendor = guid16[2];
   1614         }
   1615         if (product) {
   1616             *product = guid16[4];
   1617         }
   1618         if (version) {
   1619             *version = guid16[6];
   1620         }
   1621     } else {
   1622         if (vendor) {
   1623             *vendor = 0;
   1624         }
   1625         if (product) {
   1626             *product = 0;
   1627         }
   1628         if (version) {
   1629             *version = 0;
   1630         }
   1631     }
   1632 }
   1633 
   1634 static int
   1635 PrefixMatch(const char *a, const char *b)
   1636 {
   1637     int matchlen = 0;
   1638     while (*a && *b) {
   1639         if (SDL_tolower(*a++) == SDL_tolower(*b++)) {
   1640             ++matchlen;
   1641         } else {
   1642             break;
   1643         }
   1644     }
   1645     return matchlen;
   1646 }
   1647 
   1648 char *
   1649 SDL_CreateJoystickName(Uint16 vendor, Uint16 product, const char *vendor_name, const char *product_name)
   1650 {
   1651     static struct {
   1652         const char *prefix;
   1653         const char *replacement;
   1654     } replacements[] = {
   1655         { "NVIDIA Corporation ", "" },
   1656         { "Performance Designed Products", "PDP" },
   1657         { "HORI CO.,LTD.", "HORI" },
   1658         { "HORI CO.,LTD", "HORI" },
   1659     };
   1660     const char *custom_name;
   1661     char *name;
   1662     size_t i, len;
   1663 
   1664     custom_name = GuessControllerName(vendor, product);
   1665     if (custom_name) {
   1666         return SDL_strdup(custom_name);
   1667     }
   1668 
   1669     if (!vendor_name) {
   1670         vendor_name = "";
   1671     }
   1672     if (!product_name) {
   1673         product_name = "";
   1674     }
   1675 
   1676     while (*vendor_name == ' ') {
   1677         ++vendor_name;
   1678     }
   1679     while (*product_name == ' ') {
   1680         ++product_name;
   1681     }
   1682 
   1683     if (*vendor_name && *product_name) {
   1684         len = (SDL_strlen(vendor_name) + 1 + SDL_strlen(product_name) + 1);
   1685         name = (char *)SDL_malloc(len);
   1686         if (!name) {
   1687             return NULL;
   1688         }
   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);
   1695         if (!name) {
   1696             return NULL;
   1697         }
   1698         SDL_snprintf(name, len, "0x%.4x/0x%.4x", vendor, product);
   1699     } else {
   1700         name = SDL_strdup("Controller");
   1701     }
   1702 
   1703     /* Trim trailing whitespace */
   1704     for (len = SDL_strlen(name); (len > 0 && name[len - 1] == ' '); --len) {
   1705         /* continue */
   1706     }
   1707     name[len] = '\0';
   1708 
   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));
   1713             --len;
   1714         } else {
   1715             ++i;
   1716         }
   1717     }
   1718 
   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);
   1724             len -= matchlen;
   1725             break;
   1726         } else if (matchlen > 0 && name[matchlen] == ' ') {
   1727             SDL_memmove(name, name+matchlen+1, len-matchlen);
   1728             len -= (matchlen + 1);
   1729             break;
   1730         }
   1731     }
   1732 
   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));
   1740             break;
   1741         }
   1742     }
   1743 
   1744     return name;
   1745 }
   1746 
   1747 SDL_GameControllerType
   1748 SDL_GetJoystickGameControllerTypeFromVIDPID(Uint16 vendor, Uint16 product)
   1749 {
   1750     return SDL_GetJoystickGameControllerType(NULL, vendor, product, -1, 0, 0, 0);
   1751 }
   1752 
   1753 SDL_GameControllerType
   1754 SDL_GetJoystickGameControllerTypeFromGUID(SDL_JoystickGUID guid, const char *name)
   1755 {
   1756     SDL_GameControllerType type;
   1757     Uint16 vendor, product;
   1758 
   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;
   1765         }
   1766     }
   1767     return type;
   1768 }
   1769 
   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)
   1772 {
   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;
   1779 
   1780     SDL_GameControllerType type = SDL_CONTROLLER_TYPE_UNKNOWN;
   1781 
   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)) {
   1787 
   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 */
   1797             0x0e6f, /* PDP */
   1798             0x0f0d, /* Hori */
   1799             0x1038, /* SteelSeries */
   1800             0x11c9, /* Nacon */
   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 */
   1810         };
   1811 
   1812         int i;
   1813         for (i = 0; i < SDL_arraysize(SUPPORTED_VENDORS); ++i) {
   1814             if (vendor == SUPPORTED_VENDORS[i]) {
   1815                 type = SDL_CONTROLLER_TYPE_XBOX360;
   1816                 break;
   1817             }
   1818         }
   1819     }
   1820 
   1821     if (interface_number == 0 &&
   1822         interface_class == LIBUSB_CLASS_VENDOR_SPEC &&
   1823         interface_subclass == XBONE_IFACE_SUBCLASS &&
   1824         interface_protocol == XBONE_IFACE_PROTOCOL) {
   1825 
   1826         static const int SUPPORTED_VENDORS[] = {
   1827             0x045e, /* Microsoft */
   1828             0x0738, /* Mad Catz */
   1829             0x0e6f, /* PDP */
   1830             0x0f0d, /* Hori */
   1831             0x1532, /* Razer Wildcat */
   1832             0x24c6, /* PowerA */
   1833             0x2e24, /* Hyperkin */
   1834         };
   1835 
   1836         int i;
   1837         for (i = 0; i < SDL_arraysize(SUPPORTED_VENDORS); ++i) {
   1838             if (vendor == SUPPORTED_VENDORS[i]) {
   1839                 type = SDL_CONTROLLER_TYPE_XBOXONE;
   1840                 break;
   1841             }
   1842         }
   1843     }
   1844 
   1845     if (type == SDL_CONTROLLER_TYPE_UNKNOWN) {
   1846         if (vendor == 0x0000 && product == 0x0000) {
   1847             /* Some devices are only identifiable by their name */
   1848             if (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;
   1856             } else {
   1857                 type = SDL_CONTROLLER_TYPE_UNKNOWN;
   1858             }
   1859 
   1860         } else if (vendor == 0x0001 && product == 0x0001) {
   1861             type = SDL_CONTROLLER_TYPE_UNKNOWN;
   1862 
   1863         } else {
   1864             switch (GuessControllerType(vendor, product)) {
   1865             case k_eControllerType_XBox360Controller:
   1866                 type = SDL_CONTROLLER_TYPE_XBOX360;
   1867                 break;
   1868             case k_eControllerType_XBoxOneController:
   1869                 type = SDL_CONTROLLER_TYPE_XBOXONE;
   1870                 break;
   1871             case k_eControllerType_PS3Controller:
   1872                 type = SDL_CONTROLLER_TYPE_PS3;
   1873                 break;
   1874             case k_eControllerType_PS4Controller:
   1875                 type = SDL_CONTROLLER_TYPE_PS4;
   1876                 break;
   1877             case k_eControllerType_PS5Controller:
   1878                 type = SDL_CONTROLLER_TYPE_PS5;
   1879                 break;
   1880             case k_eControllerType_SwitchProController:
   1881             case k_eControllerType_SwitchInputOnlyController:
   1882                 type = SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO;
   1883                 break;
   1884             default:
   1885                 type = SDL_CONTROLLER_TYPE_UNKNOWN;
   1886                 break;
   1887             }
   1888         }
   1889     }
   1890     return type;
   1891 }
   1892 
   1893 SDL_bool
   1894 SDL_IsJoystickXboxOneElite(Uint16 vendor_id, Uint16 product_id)
   1895 {
   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) {
   1900             return SDL_TRUE;
   1901         }
   1902     }
   1903     return SDL_FALSE;
   1904 }
   1905 
   1906 SDL_bool
   1907 SDL_IsJoystickXboxOneSeriesX(Uint16 vendor_id, Uint16 product_id)
   1908 {
   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) {
   1912             return SDL_TRUE;
   1913         }
   1914     }
   1915     return SDL_FALSE;
   1916 }
   1917 
   1918 SDL_bool
   1919 SDL_IsJoystickPS4(Uint16 vendor_id, Uint16 product_id)
   1920 {
   1921     EControllerType eType = GuessControllerType(vendor_id, product_id);
   1922     return (eType == k_eControllerType_PS4Controller);
   1923 }
   1924 
   1925 SDL_bool
   1926 SDL_IsJoystickPS5(Uint16 vendor_id, Uint16 product_id)
   1927 {
   1928     EControllerType eType = GuessControllerType(vendor_id, product_id);
   1929     return (eType == k_eControllerType_PS5Controller);
   1930 }
   1931 
   1932 SDL_bool
   1933 SDL_IsJoystickNintendoSwitchPro(Uint16 vendor_id, Uint16 product_id)
   1934 {
   1935     EControllerType eType = GuessControllerType(vendor_id, product_id);
   1936     return (eType == k_eControllerType_SwitchProController ||
   1937             eType == k_eControllerType_SwitchInputOnlyController);
   1938 }
   1939 
   1940 SDL_bool
   1941 SDL_IsJoystickNintendoSwitchProInputOnly(Uint16 vendor_id, Uint16 product_id)
   1942 {
   1943     EControllerType eType = GuessControllerType(vendor_id, product_id);
   1944     return (eType == k_eControllerType_SwitchInputOnlyController);
   1945 }
   1946 
   1947 SDL_bool
   1948 SDL_IsJoystickSteamController(Uint16 vendor_id, Uint16 product_id)
   1949 {
   1950     EControllerType eType = GuessControllerType(vendor_id, product_id);
   1951     return (eType == k_eControllerType_SteamController ||
   1952             eType == k_eControllerType_SteamControllerV2);
   1953 }
   1954 
   1955 SDL_bool
   1956 SDL_IsJoystickXInput(SDL_JoystickGUID guid)
   1957 {
   1958     return (guid.data[14] == 'x') ? SDL_TRUE : SDL_FALSE;
   1959 }
   1960 
   1961 SDL_bool
   1962 SDL_IsJoystickWGI(SDL_JoystickGUID guid)
   1963 {
   1964     return (guid.data[14] == 'w') ? SDL_TRUE : SDL_FALSE;
   1965 }
   1966 
   1967 SDL_bool
   1968 SDL_IsJoystickHIDAPI(SDL_JoystickGUID guid)
   1969 {
   1970     return (guid.data[14] == 'h') ? SDL_TRUE : SDL_FALSE;
   1971 }
   1972 
   1973 SDL_bool
   1974 SDL_IsJoystickRAWINPUT(SDL_JoystickGUID guid)
   1975 {
   1976     return (guid.data[14] == 'r') ? SDL_TRUE : SDL_FALSE;
   1977 }
   1978 
   1979 SDL_bool
   1980 SDL_IsJoystickVirtual(SDL_JoystickGUID guid)
   1981 {
   1982     return (guid.data[14] == 'v') ? SDL_TRUE : SDL_FALSE;
   1983 }
   1984 
   1985 static SDL_bool SDL_IsJoystickProductWheel(Uint32 vidpid)
   1986 {
   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) */
   2002     };
   2003     int i;
   2004 
   2005     for (i = 0; i < SDL_arraysize(wheel_joysticks); ++i) {
   2006         if (vidpid == wheel_joysticks[i]) {
   2007             return SDL_TRUE;
   2008         }
   2009     }
   2010     return SDL_FALSE;
   2011 }
   2012 
   2013 static SDL_bool SDL_IsJoystickProductFlightStick(Uint32 vidpid)
   2014 {
   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 */
   2018     };
   2019     int i;
   2020 
   2021     for (i = 0; i < SDL_arraysize(flightstick_joysticks); ++i) {
   2022         if (vidpid == flightstick_joysticks[i]) {
   2023             return SDL_TRUE;
   2024         }
   2025     }
   2026     return SDL_FALSE;
   2027 }
   2028 
   2029 static SDL_bool SDL_IsJoystickProductThrottle(Uint32 vidpid)
   2030 {
   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 */
   2034     };
   2035     int i;
   2036 
   2037     for (i = 0; i < SDL_arraysize(throttle_joysticks); ++i) {
   2038         if (vidpid == throttle_joysticks[i]) {
   2039             return SDL_TRUE;
   2040         }
   2041     }
   2042     return SDL_FALSE;
   2043 }
   2044 
   2045 static SDL_JoystickType SDL_GetJoystickGUIDType(SDL_JoystickGUID guid)
   2046 {
   2047     Uint16 vendor;
   2048     Uint16 product;
   2049     Uint32 vidpid;
   2050 
   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;
   2072         default:
   2073             return SDL_JOYSTICK_TYPE_UNKNOWN;
   2074         }
   2075     }
   2076 
   2077     if (SDL_IsJoystickWGI(guid)) {
   2078         return (SDL_JoystickType)guid.data[15];
   2079     }
   2080 
   2081     if (SDL_IsJoystickVirtual(guid)) {
   2082         return (SDL_JoystickType)guid.data[15];
   2083     }
   2084 
   2085     SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL);
   2086     vidpid = MAKE_VIDPID(vendor, product);
   2087 
   2088     if (SDL_IsJoystickProductWheel(vidpid)) {
   2089         return SDL_JOYSTICK_TYPE_WHEEL;
   2090     }
   2091 
   2092     if (SDL_IsJoystickProductFlightStick(vidpid)) {
   2093         return SDL_JOYSTICK_TYPE_FLIGHT_STICK;
   2094     }
   2095 
   2096     if (SDL_IsJoystickProductThrottle(vidpid)) {
   2097         return SDL_JOYSTICK_TYPE_THROTTLE;
   2098     }
   2099 
   2100     if (GuessControllerType(vendor, product) != k_eControllerType_UnknownNonSteamController) {
   2101         return SDL_JOYSTICK_TYPE_GAMECONTROLLER;
   2102     }
   2103 
   2104     return SDL_JOYSTICK_TYPE_UNKNOWN;
   2105 }
   2106 
   2107 static SDL_bool SDL_IsPS4RemapperRunning(void)
   2108 {
   2109 #ifdef __WIN32__
   2110     const char *mapper_processes[] = {
   2111         "DS4Windows.exe",
   2112         "InputMapper.exe",
   2113     };
   2114     int i;
   2115     PROCESSENTRY32 pe32;
   2116     SDL_bool found = SDL_FALSE;
   2117 
   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)) {
   2123             do
   2124             {
   2125                 for (i = 0; i < SDL_arraysize(mapper_processes); ++i) {
   2126                     if (SDL_strcasecmp(pe32.szExeFile, mapper_processes[i]) == 0) {
   2127                         found = SDL_TRUE;
   2128                     }
   2129                 }
   2130             } while (Process32Next(hProcessSnap, &pe32) && !found);
   2131         }
   2132         CloseHandle(hProcessSnap);
   2133     }
   2134     return found;
   2135 #else
   2136     return SDL_FALSE;
   2137 #endif
   2138 }
   2139 
   2140 SDL_bool SDL_ShouldIgnoreJoystick(const char *name, SDL_JoystickGUID guid)
   2141 {
   2142     /* This list is taken from:
   2143        https://raw.githubusercontent.com/denilsonsa/udev-joystick-blacklist/master/generate_rules.py
   2144      */
   2145     static Uint32 joystick_blacklist[] = {
   2146         /* Microsoft Microsoft Wireless Optical Desktop 2.10 */
   2147         /* Microsoft Wireless Desktop - Comfort Edition */
   2148         MAKE_VIDPID(0x045e, 0x009d),
   2149 
   2150         /* Microsoft Microsoft Digital Media Pro Keyboard */
   2151         /* Microsoft Corp. Digital Media Pro Keyboard */
   2152         MAKE_VIDPID(0x045e, 0x00b0),
   2153 
   2154         /* Microsoft Microsoft Digital Media Keyboard */
   2155         /* Microsoft Corp. Digital Media Keyboard 1.0A */
   2156         MAKE_VIDPID(0x045e, 0x00b4),
   2157 
   2158         /* Microsoft Microsoft Digital Media Keyboard 3000 */
   2159         MAKE_VIDPID(0x045e, 0x0730),
   2160 
   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),
   2167 
   2168         /* Microsoft SideWinder(TM) 2.4GHz Transceiver */
   2169         MAKE_VIDPID(0x045e, 0x0748),
   2170 
   2171         /* Microsoft Corp. Wired Keyboard 600 */
   2172         MAKE_VIDPID(0x045e, 0x0750),
   2173 
   2174         /* Microsoft Corp. Sidewinder X4 keyboard */
   2175         MAKE_VIDPID(0x045e, 0x0768),
   2176 
   2177         /* Microsoft Corp. Arc Touch Mouse Transceiver */
   2178         MAKE_VIDPID(0x045e, 0x0773),
   2179 
   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),
   2184 
   2185         /* Microsoft Nano Transceiver v1.0 */
   2186         /* Microsoft Wireless Keyboard 800 */
   2187         MAKE_VIDPID(0x045e, 0x07b2),
   2188 
   2189         /* Microsoft Nano Transceiver v2.0 */
   2190         MAKE_VIDPID(0x045e, 0x0800),
   2191 
   2192         MAKE_VIDPID(0x046d, 0xc30a),  /* Logitech, Inc. iTouch Composite keboard */
   2193 
   2194         MAKE_VIDPID(0x04d9, 0xa0df),  /* Tek Syndicate Mouse (E-Signal USB Gaming Mouse) */
   2195 
   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 */
   2209 
   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 */
   2229 
   2230         MAKE_VIDPID(0x1b1c, 0x1b3c),  /* Corsair Harpoon RGB gaming mouse */
   2231 
   2232         MAKE_VIDPID(0x1d57, 0xad03),  /* [T3] 2.4GHz and IR Air Mouse Remote Control */
   2233 
   2234         MAKE_VIDPID(0x1e7d, 0x2e4a),  /* Roccat Tyon Mouse */
   2235 
   2236         MAKE_VIDPID(0x20a0, 0x422d),  /* Winkeyless.kr Keyboards */
   2237 
   2238         MAKE_VIDPID(0x2516, 0x001f),  /* Cooler Master Storm Mizar Mouse */
   2239         MAKE_VIDPID(0x2516, 0x0028),  /* Cooler Master Storm Alcor Mouse */
   2240     };
   2241 
   2242     unsigned int i;
   2243     Uint32 id;
   2244     Uint16 vendor;
   2245     Uint16 product;
   2246     SDL_GameControllerType type;
   2247 
   2248     SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL);
   2249 
   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]) {
   2254             return SDL_TRUE;
   2255         }
   2256     }
   2257 
   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()) {
   2260         return SDL_TRUE;
   2261     }
   2262 
   2263     if (SDL_IsGameControllerNameAndGUID(name, guid) &&
   2264         SDL_ShouldIgnoreGameController(name, guid)) {
   2265         return SDL_TRUE;
   2266     }
   2267 
   2268     return SDL_FALSE;
   2269 }
   2270 
   2271 /* return the guid for this index */
   2272 SDL_JoystickGUID SDL_JoystickGetDeviceGUID(int device_index)
   2273 {
   2274     SDL_JoystickDriver *driver;
   2275     SDL_JoystickGUID guid;
   2276 
   2277     SDL_LockJoysticks();
   2278     if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) {
   2279         guid = driver->GetDeviceGUID(device_index);
   2280     } else {
   2281         SDL_zero(guid);
   2282     }
   2283     SDL_UnlockJoysticks();
   2284 
   2285     return guid;
   2286 }
   2287 
   2288 Uint16 SDL_JoystickGetDeviceVendor(int device_index)
   2289 {
   2290     Uint16 vendor;
   2291     SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
   2292 
   2293     SDL_GetJoystickGUIDInfo(guid, &vendor, NULL, NULL);
   2294     return vendor;
   2295 }
   2296 
   2297 Uint16 SDL_JoystickGetDeviceProduct(int device_index)
   2298 {
   2299     Uint16 product;
   2300     SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
   2301 
   2302     SDL_GetJoystickGUIDInfo(guid, NULL, &product, NULL);
   2303     return product;
   2304 }
   2305 
   2306 Uint16 SDL_JoystickGetDeviceProductVersion(int device_index)
   2307 {
   2308     Uint16 version;
   2309     SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
   2310 
   2311     SDL_GetJoystickGUIDInfo(guid, NULL, NULL, &version);
   2312     return version;
   2313 }
   2314 
   2315 SDL_JoystickType SDL_JoystickGetDeviceType(int device_index)
   2316 {
   2317     SDL_JoystickType type;
   2318     SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
   2319 
   2320     type = SDL_GetJoystickGUIDType(guid);
   2321     if (type == SDL_JOYSTICK_TYPE_UNKNOWN) {
   2322         if (SDL_IsGameController(device_index)) {
   2323             type = SDL_JOYSTICK_TYPE_GAMECONTROLLER;
   2324         }
   2325     }
   2326     return type;
   2327 }
   2328 
   2329 SDL_JoystickID SDL_JoystickGetDeviceInstanceID(int device_index)
   2330 {
   2331     SDL_JoystickDriver *driver;
   2332     SDL_JoystickID instance_id = -1;
   2333 
   2334     SDL_LockJoysticks();
   2335     if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) {
   2336         instance_id = driver->GetDeviceInstanceID(device_index);
   2337     }
   2338     SDL_UnlockJoysticks();
   2339 
   2340     return instance_id;
   2341 }
   2342 
   2343 int SDL_JoystickGetDeviceIndexFromInstanceID(SDL_JoystickID instance_id)
   2344 {
   2345     int i, num_joysticks, device_index = -1;
   2346 
   2347     SDL_LockJoysticks();
   2348     num_joysticks = SDL_NumJoysticks();
   2349     for (i = 0; i < num_joysticks; ++i) {
   2350         if (SDL_JoystickGetDeviceInstanceID(i) == instance_id) {
   2351             device_index = i;
   2352             break;
   2353         }
   2354     }
   2355     SDL_UnlockJoysticks();
   2356 
   2357     return device_index;
   2358 }
   2359 
   2360 SDL_JoystickGUID SDL_JoystickGetGUID(SDL_Joystick *joystick)
   2361 {
   2362     if (!SDL_PrivateJoystickValid(joystick)) {
   2363         SDL_JoystickGUID emptyGUID;
   2364         SDL_zero(emptyGUID);
   2365         return emptyGUID;
   2366     }
   2367     return joystick->guid;
   2368 }
   2369 
   2370 Uint16 SDL_JoystickGetVendor(SDL_Joystick *joystick)
   2371 {
   2372     Uint16 vendor;
   2373     SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
   2374 
   2375     SDL_GetJoystickGUIDInfo(guid, &vendor, NULL, NULL);
   2376     return vendor;
   2377 }
   2378 
   2379 Uint16 SDL_JoystickGetProduct(SDL_Joystick *joystick)
   2380 {
   2381     Uint16 product;
   2382     SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
   2383 
   2384     SDL_GetJoystickGUIDInfo(guid, NULL, &product, NULL);
   2385     return product;
   2386 }
   2387 
   2388 Uint16 SDL_JoystickGetProductVersion(SDL_Joystick *joystick)
   2389 {
   2390     Uint16 version;
   2391     SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
   2392 
   2393     SDL_GetJoystickGUIDInfo(guid, NULL, NULL, &version);
   2394     return version;
   2395 }
   2396 
   2397 const char *SDL_JoystickGetSerial(SDL_Joystick *joystick)
   2398 {
   2399     if (!SDL_PrivateJoystickValid(joystick)) {
   2400         return NULL;
   2401     }
   2402     return joystick->serial;
   2403 }
   2404 
   2405 SDL_JoystickType SDL_JoystickGetType(SDL_Joystick *joystick)
   2406 {
   2407     SDL_JoystickType type;
   2408     SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
   2409 
   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;
   2414         }
   2415     }
   2416     return type;
   2417 }
   2418 
   2419 /* convert the guid to a printable string */
   2420 void SDL_JoystickGetGUIDString(SDL_JoystickGUID guid, char *pszGUID, int cbGUID)
   2421 {
   2422     static const char k_rgchHexToASCII[] = "0123456789abcdef";
   2423     int i;
   2424 
   2425     if ((pszGUID == NULL) || (cbGUID <= 0)) {
   2426         return;
   2427     }
   2428 
   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];
   2433 
   2434         *pszGUID++ = k_rgchHexToASCII[c >> 4];
   2435         *pszGUID++ = k_rgchHexToASCII[c & 0x0F];
   2436     }
   2437     *pszGUID = '\0';
   2438 }
   2439 
   2440 /*-----------------------------------------------------------------------------
   2441  * Purpose: Returns the 4 bit nibble for a hex character
   2442  * Input  : c -
   2443  * Output : unsigned char
   2444  *-----------------------------------------------------------------------------*/
   2445 static unsigned char nibble(char c)
   2446 {
   2447     if ((c >= '0') && (c <= '9')) {
   2448         return (unsigned char)(c - '0');
   2449     }
   2450 
   2451     if ((c >= 'A') && (c <= 'F')) {
   2452         return (unsigned char)(c - 'A' + 0x0a);
   2453     }
   2454 
   2455     if ((c >= 'a') && (c <= 'f')) {
   2456         return (unsigned char)(c - 'a' + 0x0a);
   2457     }
   2458 
   2459     /* received an invalid character, and no real way to return an error */
   2460     /* AssertMsg1(false, "Q_nibble invalid hex character '%c' ", c); */
   2461     return 0;
   2462 }
   2463 
   2464 /* convert the string version of a joystick guid to the struct */
   2465 SDL_JoystickGUID SDL_JoystickGetGUIDFromString(const char *pchGUID)
   2466 {
   2467     SDL_JoystickGUID guid;
   2468     int maxoutputbytes= sizeof(guid);
   2469     size_t len = SDL_strlen(pchGUID);
   2470     Uint8 *p;
   2471     size_t i;
   2472 
   2473     /* Make sure it's even */
   2474     len = (len) & ~0x1;
   2475 
   2476     SDL_memset(&guid, 0x00, sizeof(guid));
   2477 
   2478     p = (Uint8 *)&guid;
   2479     for (i = 0; (i < len) && ((p - (Uint8 *)&guid) < maxoutputbytes); i+=2, p++) {
   2480         *p = (nibble(pchGUID[i]) << 4) | nibble(pchGUID[i+1]);
   2481     }
   2482 
   2483     return guid;
   2484 }
   2485 
   2486 /* update the power level for this joystick */
   2487 void SDL_PrivateJoystickBatteryLevel(SDL_Joystick *joystick, SDL_JoystickPowerLevel ePowerLevel)
   2488 {
   2489     joystick->epowerlevel = ePowerLevel;
   2490 }
   2491 
   2492 /* return its power level */
   2493 SDL_JoystickPowerLevel SDL_JoystickCurrentPowerLevel(SDL_Joystick *joystick)
   2494 {
   2495     if (!SDL_PrivateJoystickValid(joystick)) {
   2496         return SDL_JOYSTICK_POWER_UNKNOWN;
   2497     }
   2498     return joystick->epowerlevel;
   2499 }
   2500 
   2501 int SDL_PrivateJoystickTouchpad(SDL_Joystick *joystick, int touchpad, int finger, Uint8 state, float x, float y, float pressure)
   2502 {
   2503     SDL_JoystickTouchpadInfo *touchpad_info;
   2504     SDL_JoystickTouchpadFingerInfo *finger_info;
   2505     int posted;
   2506 #if !SDL_EVENTS_DISABLED
   2507     Uint32 event_type;
   2508 #endif
   2509 
   2510     if (touchpad < 0 || touchpad >= joystick->ntouchpads) {
   2511         return 0;
   2512     }
   2513 
   2514     touchpad_info = &joystick->touchpads[touchpad];
   2515     if (finger < 0 || finger >= touchpad_info->nfingers) {
   2516         return 0;
   2517     }
   2518 
   2519     finger_info = &touchpad_info->fingers[finger];
   2520 
   2521     if (!state) {
   2522         if (x == 0.0f && y == 0.0f) {
   2523             x = finger_info->x;
   2524             y = finger_info->y;
   2525         }
   2526         pressure = 0.0f;
   2527     }
   2528 
   2529     if (x < 0.0f) {
   2530         x = 0.0f;
   2531     } else if (x > 1.0f) {
   2532         x = 1.0f;
   2533     }
   2534     if (y < 0.0f) {
   2535         y = 0.0f;
   2536     } else if (y > 1.0f) {
   2537         y = 1.0f;
   2538     }
   2539     if (pressure < 0.0f) {
   2540         pressure = 0.0f;
   2541     } else if (pressure > 1.0f) {
   2542         pressure = 1.0f;
   2543     }
   2544 
   2545     if (state == finger_info->state) {
   2546         if (!state ||
   2547             (x == finger_info->x && y == finger_info->y && pressure == finger_info->pressure)) {
   2548             return 0;
   2549         }
   2550     }
   2551 
   2552 #if !SDL_EVENTS_DISABLED
   2553     if (state == finger_info->state) {
   2554         event_type = SDL_CONTROLLERTOUCHPADMOTION;
   2555     } else if (state) {
   2556         event_type = SDL_CONTROLLERTOUCHPADDOWN;
   2557     } else {
   2558         event_type = SDL_CONTROLLERTOUCHPADUP;
   2559     }
   2560 #endif
   2561 
   2562     /* Update internal joystick state */
   2563     finger_info->state = state;
   2564     finger_info->x = x;
   2565     finger_info->y = y;
   2566     finger_info->pressure = pressure;
   2567 
   2568     /* Post the event, if desired */
   2569     posted = 0;
   2570 #if !SDL_EVENTS_DISABLED
   2571     if (SDL_GetEventState(event_type) == SDL_ENABLE) {
   2572         SDL_Event event;
   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;
   2581     }
   2582 #endif /* !SDL_EVENTS_DISABLED */
   2583     return posted;
   2584 }
   2585 
   2586 int SDL_PrivateJoystickSensor(SDL_Joystick *joystick, SDL_SensorType type, const float *data, int num_values)
   2587 {
   2588     int i;
   2589     int posted = 0;
   2590 
   2591     for (i = 0; i < joystick->nsensors; ++i) {
   2592         SDL_JoystickSensorInfo *sensor = &joystick->sensors[i];
   2593 
   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) {
   2598 
   2599                     /* Update internal sensor state */
   2600                     SDL_memcpy(sensor->data, data, num_values*sizeof(*data));
   2601 
   2602                     /* Post the event, if desired */
   2603 #if !SDL_EVENTS_DISABLED
   2604                     if (SDL_GetEventState(SDL_CONTROLLERSENSORUPDATE) == SDL_ENABLE) {
   2605                         SDL_Event event;
   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;
   2613                     }
   2614 #endif /* !SDL_EVENTS_DISABLED */
   2615                 }
   2616             }
   2617             break;
   2618         }
   2619     }
   2620     return posted;
   2621 }
   2622 
   2623 /* vi: set ts=4 sw=4 expandtab: */