src/joystick/SDL_joystick.c
author Cameron Gutman
Sat, 07 Mar 2020 17:20:04 -0800
changeset 13595 36aabb2051e9
parent 13583 88068887c25d
child 13596 501950e51321
permissions -rw-r--r--
Fix incorrect player index when assigning a joystick the same index twice

Prior to this fix, we would hit the existing_instance >= 0 case and move the joystick
again to a different index than the one requested by the caller. It also breaks the assumption
that a SDL_JoystickID is only present in SDL_joystick_players at one location.
     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_assert.h"
    30 #include "SDL_hints.h"
    31 
    32 #if !SDL_EVENTS_DISABLED
    33 #include "../events/SDL_events_c.h"
    34 #endif
    35 #include "../video/SDL_sysvideo.h"
    36 #include "hidapi/SDL_hidapijoystick_c.h"
    37 
    38 /* This is included in only one place because it has a large static list of controllers */
    39 #include "controller_type.h"
    40 
    41 #ifdef __WIN32__
    42 /* Needed for checking for input remapping programs */
    43 #include "../core/windows/SDL_windows.h"
    44 
    45 #undef UNICODE          /* We want ASCII functions */
    46 #include <tlhelp32.h>
    47 #endif
    48 
    49 static SDL_JoystickDriver *SDL_joystick_drivers[] = {
    50 #if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT)
    51     &SDL_WINDOWS_JoystickDriver,
    52 #endif
    53 #ifdef SDL_JOYSTICK_LINUX
    54     &SDL_LINUX_JoystickDriver,
    55 #endif
    56 #ifdef SDL_JOYSTICK_IOKIT
    57     &SDL_DARWIN_JoystickDriver,
    58 #endif
    59 #if defined(__IPHONEOS__) || defined(__TVOS__)
    60     &SDL_IOS_JoystickDriver,
    61 #endif
    62 #ifdef SDL_JOYSTICK_ANDROID
    63     &SDL_ANDROID_JoystickDriver,
    64 #endif
    65 #ifdef SDL_JOYSTICK_EMSCRIPTEN
    66     &SDL_EMSCRIPTEN_JoystickDriver,
    67 #endif
    68 #ifdef SDL_JOYSTICK_HAIKU
    69     &SDL_HAIKU_JoystickDriver,
    70 #endif
    71 #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. */
    72     &SDL_BSD_JoystickDriver,
    73 #endif
    74 #ifdef SDL_JOYSTICK_HIDAPI
    75     &SDL_HIDAPI_JoystickDriver,
    76 #endif
    77 #if defined(SDL_JOYSTICK_DUMMY) || defined(SDL_JOYSTICK_DISABLED)
    78     &SDL_DUMMY_JoystickDriver
    79 #endif
    80 };
    81 static SDL_bool SDL_joystick_allows_background_events = SDL_FALSE;
    82 static SDL_Joystick *SDL_joysticks = NULL;
    83 static SDL_bool SDL_updating_joystick = SDL_FALSE;
    84 static SDL_mutex *SDL_joystick_lock = NULL; /* This needs to support recursive locks */
    85 static SDL_atomic_t SDL_next_joystick_instance_id;
    86 static int SDL_joystick_player_count = 0;
    87 static SDL_JoystickID *SDL_joystick_players = NULL;
    88 
    89 void
    90 SDL_LockJoysticks(void)
    91 {
    92     if (SDL_joystick_lock) {
    93         SDL_LockMutex(SDL_joystick_lock);
    94     }
    95 }
    96 
    97 void
    98 SDL_UnlockJoysticks(void)
    99 {
   100     if (SDL_joystick_lock) {
   101         SDL_UnlockMutex(SDL_joystick_lock);
   102     }
   103 }
   104 
   105 static int
   106 SDL_FindFreePlayerIndex()
   107 {
   108     int player_index;
   109 
   110     for (player_index = 0; player_index < SDL_joystick_player_count; ++player_index) {
   111         if (SDL_joystick_players[player_index] == -1) {
   112             return player_index;
   113         }
   114     }
   115     return player_index;
   116 }
   117 
   118 static int
   119 SDL_GetPlayerIndexForJoystickID(SDL_JoystickID instance_id)
   120 {
   121     int player_index;
   122 
   123     for (player_index = 0; player_index < SDL_joystick_player_count; ++player_index) {
   124         if (instance_id == SDL_joystick_players[player_index]) {
   125             break;
   126         }
   127     }
   128     if (player_index == SDL_joystick_player_count) {
   129         player_index = -1;
   130     }
   131     return player_index;
   132 }
   133 
   134 static SDL_JoystickID
   135 SDL_GetJoystickIDForPlayerIndex(int player_index)
   136 {
   137     if (player_index < 0 || player_index >= SDL_joystick_player_count) {
   138         return -1;
   139     }
   140     return SDL_joystick_players[player_index];
   141 }
   142 
   143 static SDL_bool
   144 SDL_SetJoystickIDForPlayerIndex(int player_index, SDL_JoystickID instance_id)
   145 {
   146     SDL_JoystickID existing_instance = SDL_GetJoystickIDForPlayerIndex(player_index);
   147     SDL_JoystickDriver *driver;
   148     int device_index;
   149 
   150     if (player_index < 0) {
   151         return SDL_FALSE;
   152     }
   153     if (player_index >= SDL_joystick_player_count) {
   154         SDL_JoystickID *new_players = (SDL_JoystickID *)SDL_realloc(SDL_joystick_players, (player_index + 1)*sizeof(*SDL_joystick_players));
   155         if (!new_players) {
   156             SDL_OutOfMemory();
   157             return SDL_FALSE;
   158         }
   159 
   160         SDL_joystick_players = new_players;
   161         SDL_memset(&SDL_joystick_players[SDL_joystick_player_count], 0xFF, (player_index - SDL_joystick_player_count + 1) * sizeof(SDL_joystick_players[0]));
   162         SDL_joystick_player_count = player_index + 1;
   163     } else if (SDL_joystick_players[player_index] == instance_id) {
   164         /* Joystick is already assigned the requested player index */
   165         return SDL_TRUE;
   166     }
   167 
   168     SDL_joystick_players[player_index] = instance_id;
   169 
   170     /* Update the driver with the new index */
   171     device_index = SDL_JoystickGetDeviceIndexFromInstanceID(instance_id);
   172     if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) {
   173         driver->SetDevicePlayerIndex(device_index, player_index);
   174     }
   175 
   176     /* Move any existing joystick to another slot */
   177     if (existing_instance >= 0) {
   178         SDL_SetJoystickIDForPlayerIndex(SDL_FindFreePlayerIndex(), existing_instance);
   179     }
   180     return SDL_TRUE;
   181 }
   182 
   183 static void SDLCALL
   184 SDL_JoystickAllowBackgroundEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
   185 {
   186     if (hint && *hint == '1') {
   187         SDL_joystick_allows_background_events = SDL_TRUE;
   188     } else {
   189         SDL_joystick_allows_background_events = SDL_FALSE;
   190     }
   191 }
   192 
   193 int
   194 SDL_JoystickInit(void)
   195 {
   196     int i, status;
   197 
   198     SDL_GameControllerInitMappings();
   199 
   200     /* Create the joystick list lock */
   201     if (!SDL_joystick_lock) {
   202         SDL_joystick_lock = SDL_CreateMutex();
   203     }
   204 
   205     /* See if we should allow joystick events while in the background */
   206     SDL_AddHintCallback(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS,
   207                         SDL_JoystickAllowBackgroundEventsChanged, NULL);
   208 
   209 #if !SDL_EVENTS_DISABLED
   210     if (SDL_InitSubSystem(SDL_INIT_EVENTS) < 0) {
   211         return -1;
   212     }
   213 #endif /* !SDL_EVENTS_DISABLED */
   214 
   215     status = -1;
   216     for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) {
   217         if (SDL_joystick_drivers[i]->Init() >= 0) {
   218             status = 0;
   219         }
   220     }
   221     return status;
   222 }
   223 
   224 /*
   225  * Count the number of joysticks attached to the system
   226  */
   227 int
   228 SDL_NumJoysticks(void)
   229 {
   230     int i, total_joysticks = 0;
   231     SDL_LockJoysticks();
   232     for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) {
   233         total_joysticks += SDL_joystick_drivers[i]->GetCount();
   234     }
   235     SDL_UnlockJoysticks();
   236     return total_joysticks;
   237 }
   238 
   239 /*
   240  * Return the next available joystick instance ID
   241  * This may be called by drivers from multiple threads, unprotected by any locks
   242  */
   243 SDL_JoystickID SDL_GetNextJoystickInstanceID()
   244 {
   245     return SDL_AtomicIncRef(&SDL_next_joystick_instance_id);
   246 }
   247 
   248 /*
   249  * Get the driver and device index for an API device index
   250  * This should be called while the joystick lock is held, to prevent another thread from updating the list
   251  */
   252 SDL_bool
   253 SDL_GetDriverAndJoystickIndex(int device_index, SDL_JoystickDriver **driver, int *driver_index)
   254 {
   255     int i, num_joysticks, total_joysticks = 0;
   256 
   257     if (device_index >= 0) {
   258         for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) {
   259             num_joysticks = SDL_joystick_drivers[i]->GetCount();
   260             if (device_index < num_joysticks) {
   261                 *driver = SDL_joystick_drivers[i];
   262                 *driver_index = device_index;
   263                 return SDL_TRUE;
   264             }
   265             device_index -= num_joysticks;
   266             total_joysticks += num_joysticks;
   267         }
   268     }
   269 
   270     SDL_SetError("There are %d joysticks available", total_joysticks);
   271     return SDL_FALSE;
   272 }
   273 
   274 /*
   275  * Perform any needed fixups for joystick names
   276  */
   277 static const char *
   278 SDL_FixupJoystickName(const char *name)
   279 {
   280     if (name) {
   281         const char *skip_prefix = "NVIDIA Corporation ";
   282 
   283         if (SDL_strncmp(name, skip_prefix, SDL_strlen(skip_prefix)) == 0) {
   284             name += SDL_strlen(skip_prefix);
   285         }
   286     }
   287     return name;
   288 }
   289 
   290 
   291 /*
   292  * Get the implementation dependent name of a joystick
   293  */
   294 const char *
   295 SDL_JoystickNameForIndex(int device_index)
   296 {
   297     SDL_JoystickDriver *driver;
   298     const char *name = NULL;
   299 
   300     SDL_LockJoysticks();
   301     if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) {
   302         name = SDL_FixupJoystickName(driver->GetDeviceName(device_index));
   303     }
   304     SDL_UnlockJoysticks();
   305 
   306     /* FIXME: Really we should reference count this name so it doesn't go away after unlock */
   307     return name;
   308 }
   309 
   310 /*
   311  *  Get the player index of a joystick, or -1 if it's not available
   312  */
   313 int
   314 SDL_JoystickGetDevicePlayerIndex(int device_index)
   315 {
   316     int player_index;
   317 
   318     SDL_LockJoysticks();
   319     player_index = SDL_GetPlayerIndexForJoystickID(SDL_JoystickGetDeviceInstanceID(device_index));
   320     SDL_UnlockJoysticks();
   321 
   322     return player_index;
   323 }
   324 
   325 /*
   326  * Return true if this joystick is known to have all axes centered at zero
   327  * This isn't generally needed unless the joystick never generates an initial axis value near zero,
   328  * e.g. it's emulating axes with digital buttons
   329  */
   330 static SDL_bool
   331 SDL_JoystickAxesCenteredAtZero(SDL_Joystick *joystick)
   332 {
   333     static Uint32 zero_centered_joysticks[] = {
   334         MAKE_VIDPID(0x0e8f, 0x3013),    /* HuiJia SNES USB adapter */
   335         MAKE_VIDPID(0x05a0, 0x3232),    /* 8Bitdo Zero Gamepad */
   336     };
   337 
   338     int i;
   339     Uint32 id = MAKE_VIDPID(SDL_JoystickGetVendor(joystick),
   340                             SDL_JoystickGetProduct(joystick));
   341 
   342 /*printf("JOYSTICK '%s' VID/PID 0x%.4x/0x%.4x AXES: %d\n", joystick->name, vendor, product, joystick->naxes);*/
   343 
   344     if (joystick->naxes == 2) {
   345         /* Assume D-pad or thumbstick style axes are centered at 0 */
   346         return SDL_TRUE;
   347     }
   348 
   349     for (i = 0; i < SDL_arraysize(zero_centered_joysticks); ++i) {
   350         if (id == zero_centered_joysticks[i]) {
   351             return SDL_TRUE;
   352         }
   353     }
   354     return SDL_FALSE;
   355 }
   356 
   357 /*
   358  * Open a joystick for use - the index passed as an argument refers to
   359  * the N'th joystick on the system.  This index is the value which will
   360  * identify this joystick in future joystick events.
   361  *
   362  * This function returns a joystick identifier, or NULL if an error occurred.
   363  */
   364 SDL_Joystick *
   365 SDL_JoystickOpen(int device_index)
   366 {
   367     SDL_JoystickDriver *driver;
   368     SDL_JoystickID instance_id;
   369     SDL_Joystick *joystick;
   370     SDL_Joystick *joysticklist;
   371     const char *joystickname = NULL;
   372 
   373     SDL_LockJoysticks();
   374 
   375     if (!SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) {
   376         SDL_UnlockJoysticks();
   377         return NULL;
   378     }
   379 
   380     joysticklist = SDL_joysticks;
   381     /* If the joystick is already open, return it
   382      * it is important that we have a single joystick * for each instance id
   383      */
   384     instance_id = driver->GetDeviceInstanceID(device_index);
   385     while (joysticklist) {
   386         if (instance_id == joysticklist->instance_id) {
   387                 joystick = joysticklist;
   388                 ++joystick->ref_count;
   389                 SDL_UnlockJoysticks();
   390                 return joystick;
   391         }
   392         joysticklist = joysticklist->next;
   393     }
   394 
   395     /* Create and initialize the joystick */
   396     joystick = (SDL_Joystick *) SDL_calloc(sizeof(*joystick), 1);
   397     if (joystick == NULL) {
   398         SDL_OutOfMemory();
   399         SDL_UnlockJoysticks();
   400         return NULL;
   401     }
   402     joystick->driver = driver;
   403     joystick->instance_id = instance_id;
   404     joystick->attached = SDL_TRUE;
   405     joystick->epowerlevel = SDL_JOYSTICK_POWER_UNKNOWN;
   406 
   407     if (driver->Open(joystick, device_index) < 0) {
   408         SDL_free(joystick);
   409         SDL_UnlockJoysticks();
   410         return NULL;
   411     }
   412 
   413     joystickname = driver->GetDeviceName(device_index);
   414     if (joystickname) {
   415         joystick->name = SDL_strdup(joystickname);
   416     } else {
   417         joystick->name = NULL;
   418     }
   419 
   420     joystick->guid = driver->GetDeviceGUID(device_index);
   421 
   422     if (joystick->naxes > 0) {
   423         joystick->axes = (SDL_JoystickAxisInfo *) SDL_calloc(joystick->naxes, sizeof(SDL_JoystickAxisInfo));
   424     }
   425     if (joystick->nhats > 0) {
   426         joystick->hats = (Uint8 *) SDL_calloc(joystick->nhats, sizeof(Uint8));
   427     }
   428     if (joystick->nballs > 0) {
   429         joystick->balls = (struct balldelta *) SDL_calloc(joystick->nballs, sizeof(*joystick->balls));
   430     }
   431     if (joystick->nbuttons > 0) {
   432         joystick->buttons = (Uint8 *) SDL_calloc(joystick->nbuttons, sizeof(Uint8));
   433     }
   434     if (((joystick->naxes > 0) && !joystick->axes)
   435         || ((joystick->nhats > 0) && !joystick->hats)
   436         || ((joystick->nballs > 0) && !joystick->balls)
   437         || ((joystick->nbuttons > 0) && !joystick->buttons)) {
   438         SDL_OutOfMemory();
   439         SDL_JoystickClose(joystick);
   440         SDL_UnlockJoysticks();
   441         return NULL;
   442     }
   443 
   444     /* If this joystick is known to have all zero centered axes, skip the auto-centering code */
   445     if (SDL_JoystickAxesCenteredAtZero(joystick)) {
   446         int i;
   447 
   448         for (i = 0; i < joystick->naxes; ++i) {
   449             joystick->axes[i].has_initial_value = SDL_TRUE;
   450         }
   451     }
   452 
   453     joystick->is_game_controller = SDL_IsGameController(device_index);
   454 
   455     /* Add joystick to list */
   456     ++joystick->ref_count;
   457     /* Link the joystick in the list */
   458     joystick->next = SDL_joysticks;
   459     SDL_joysticks = joystick;
   460 
   461     SDL_UnlockJoysticks();
   462 
   463     driver->Update(joystick);
   464 
   465     return joystick;
   466 }
   467 
   468 
   469 /*
   470  * Checks to make sure the joystick is valid.
   471  */
   472 SDL_bool
   473 SDL_PrivateJoystickValid(SDL_Joystick * joystick)
   474 {
   475     SDL_bool valid;
   476 
   477     if (joystick == NULL) {
   478         SDL_SetError("Joystick hasn't been opened yet");
   479         valid = SDL_FALSE;
   480     } else {
   481         valid = SDL_TRUE;
   482     }
   483 
   484     return valid;
   485 }
   486 
   487 /*
   488  * Get the number of multi-dimensional axis controls on a joystick
   489  */
   490 int
   491 SDL_JoystickNumAxes(SDL_Joystick * joystick)
   492 {
   493     if (!SDL_PrivateJoystickValid(joystick)) {
   494         return -1;
   495     }
   496     return joystick->naxes;
   497 }
   498 
   499 /*
   500  * Get the number of hats on a joystick
   501  */
   502 int
   503 SDL_JoystickNumHats(SDL_Joystick * joystick)
   504 {
   505     if (!SDL_PrivateJoystickValid(joystick)) {
   506         return -1;
   507     }
   508     return joystick->nhats;
   509 }
   510 
   511 /*
   512  * Get the number of trackballs on a joystick
   513  */
   514 int
   515 SDL_JoystickNumBalls(SDL_Joystick * joystick)
   516 {
   517     if (!SDL_PrivateJoystickValid(joystick)) {
   518         return -1;
   519     }
   520     return joystick->nballs;
   521 }
   522 
   523 /*
   524  * Get the number of buttons on a joystick
   525  */
   526 int
   527 SDL_JoystickNumButtons(SDL_Joystick * joystick)
   528 {
   529     if (!SDL_PrivateJoystickValid(joystick)) {
   530         return -1;
   531     }
   532     return joystick->nbuttons;
   533 }
   534 
   535 /*
   536  * Get the current state of an axis control on a joystick
   537  */
   538 Sint16
   539 SDL_JoystickGetAxis(SDL_Joystick * joystick, int axis)
   540 {
   541     Sint16 state;
   542 
   543     if (!SDL_PrivateJoystickValid(joystick)) {
   544         return 0;
   545     }
   546     if (axis < joystick->naxes) {
   547         state = joystick->axes[axis].value;
   548     } else {
   549         SDL_SetError("Joystick only has %d axes", joystick->naxes);
   550         state = 0;
   551     }
   552     return state;
   553 }
   554 
   555 /*
   556  * Get the initial state of an axis control on a joystick
   557  */
   558 SDL_bool
   559 SDL_JoystickGetAxisInitialState(SDL_Joystick * joystick, int axis, Sint16 *state)
   560 {
   561     if (!SDL_PrivateJoystickValid(joystick)) {
   562         return SDL_FALSE;
   563     }
   564     if (axis >= joystick->naxes) {
   565         SDL_SetError("Joystick only has %d axes", joystick->naxes);
   566         return SDL_FALSE;
   567     }
   568     if (state) {
   569         *state = joystick->axes[axis].initial_value;
   570     }
   571     return joystick->axes[axis].has_initial_value;
   572 }
   573 
   574 /*
   575  * Get the current state of a hat on a joystick
   576  */
   577 Uint8
   578 SDL_JoystickGetHat(SDL_Joystick * joystick, int hat)
   579 {
   580     Uint8 state;
   581 
   582     if (!SDL_PrivateJoystickValid(joystick)) {
   583         return 0;
   584     }
   585     if (hat < joystick->nhats) {
   586         state = joystick->hats[hat];
   587     } else {
   588         SDL_SetError("Joystick only has %d hats", joystick->nhats);
   589         state = 0;
   590     }
   591     return state;
   592 }
   593 
   594 /*
   595  * Get the ball axis change since the last poll
   596  */
   597 int
   598 SDL_JoystickGetBall(SDL_Joystick * joystick, int ball, int *dx, int *dy)
   599 {
   600     int retval;
   601 
   602     if (!SDL_PrivateJoystickValid(joystick)) {
   603         return -1;
   604     }
   605 
   606     retval = 0;
   607     if (ball < joystick->nballs) {
   608         if (dx) {
   609             *dx = joystick->balls[ball].dx;
   610         }
   611         if (dy) {
   612             *dy = joystick->balls[ball].dy;
   613         }
   614         joystick->balls[ball].dx = 0;
   615         joystick->balls[ball].dy = 0;
   616     } else {
   617         return SDL_SetError("Joystick only has %d balls", joystick->nballs);
   618     }
   619     return retval;
   620 }
   621 
   622 /*
   623  * Get the current state of a button on a joystick
   624  */
   625 Uint8
   626 SDL_JoystickGetButton(SDL_Joystick * joystick, int button)
   627 {
   628     Uint8 state;
   629 
   630     if (!SDL_PrivateJoystickValid(joystick)) {
   631         return 0;
   632     }
   633     if (button < joystick->nbuttons) {
   634         state = joystick->buttons[button];
   635     } else {
   636         SDL_SetError("Joystick only has %d buttons", joystick->nbuttons);
   637         state = 0;
   638     }
   639     return state;
   640 }
   641 
   642 /*
   643  * Return if the joystick in question is currently attached to the system,
   644  *  \return SDL_FALSE if not plugged in, SDL_TRUE if still present.
   645  */
   646 SDL_bool
   647 SDL_JoystickGetAttached(SDL_Joystick * joystick)
   648 {
   649     if (!SDL_PrivateJoystickValid(joystick)) {
   650         return SDL_FALSE;
   651     }
   652 
   653     return joystick->attached;
   654 }
   655 
   656 /*
   657  * Get the instance id for this opened joystick
   658  */
   659 SDL_JoystickID
   660 SDL_JoystickInstanceID(SDL_Joystick * joystick)
   661 {
   662     if (!SDL_PrivateJoystickValid(joystick)) {
   663         return -1;
   664     }
   665 
   666     return joystick->instance_id;
   667 }
   668 
   669 /*
   670  * Return the SDL_Joystick associated with an instance id.
   671  */
   672 SDL_Joystick *
   673 SDL_JoystickFromInstanceID(SDL_JoystickID instance_id)
   674 {
   675     SDL_Joystick *joystick;
   676 
   677     SDL_LockJoysticks();
   678     for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
   679         if (joystick->instance_id == instance_id) {
   680             break;
   681         }
   682     }
   683     SDL_UnlockJoysticks();
   684     return joystick;
   685 }
   686 
   687 /**
   688  * Return the SDL_Joystick associated with a player index.
   689  */
   690 SDL_Joystick *
   691 SDL_JoystickFromPlayerIndex(int player_index)
   692 {
   693     SDL_JoystickID instance_id;
   694     SDL_Joystick *joystick;
   695 
   696     SDL_LockJoysticks();
   697     instance_id = SDL_GetJoystickIDForPlayerIndex(player_index);
   698     for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
   699         if (joystick->instance_id == instance_id) {
   700             break;
   701         }
   702     }
   703     SDL_UnlockJoysticks();
   704     return joystick;
   705 }
   706 
   707 /*
   708  * Get the friendly name of this joystick
   709  */
   710 const char *
   711 SDL_JoystickName(SDL_Joystick * joystick)
   712 {
   713     if (!SDL_PrivateJoystickValid(joystick)) {
   714         return NULL;
   715     }
   716 
   717     return SDL_FixupJoystickName(joystick->name);
   718 }
   719 
   720 /**
   721  *  Get the player index of an opened joystick, or -1 if it's not available
   722  */
   723 int
   724 SDL_JoystickGetPlayerIndex(SDL_Joystick * joystick)
   725 {
   726     int player_index;
   727 
   728     if (!SDL_PrivateJoystickValid(joystick)) {
   729         return -1;
   730     }
   731 
   732     SDL_LockJoysticks();
   733     player_index = SDL_GetPlayerIndexForJoystickID(joystick->instance_id);
   734     SDL_UnlockJoysticks();
   735 
   736     return player_index;
   737 }
   738 
   739 /**
   740  *  Set the player index of an opened joystick
   741  */
   742 void
   743 SDL_JoystickSetPlayerIndex(SDL_Joystick * joystick, int player_index)
   744 {
   745     if (!SDL_PrivateJoystickValid(joystick)) {
   746         return;
   747     }
   748 
   749     SDL_LockJoysticks();
   750     SDL_SetJoystickIDForPlayerIndex(player_index, joystick->instance_id);
   751     SDL_UnlockJoysticks();
   752 }
   753 
   754 int
   755 SDL_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
   756 {
   757     int result;
   758 
   759     if (!SDL_PrivateJoystickValid(joystick)) {
   760         return -1;
   761     }
   762 
   763     SDL_LockJoysticks();
   764     if (low_frequency_rumble == joystick->low_frequency_rumble &&
   765         high_frequency_rumble == joystick->high_frequency_rumble) {
   766         /* Just update the expiration */
   767         result = 0;
   768     } else {
   769         result = joystick->driver->Rumble(joystick, low_frequency_rumble, high_frequency_rumble);
   770     }
   771 
   772     /* Save the rumble value regardless of success, so we don't spam the driver */
   773     joystick->low_frequency_rumble = low_frequency_rumble;
   774     joystick->high_frequency_rumble = high_frequency_rumble;
   775 
   776     if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) {
   777         joystick->rumble_expiration = SDL_GetTicks() + SDL_min(duration_ms, SDL_MAX_RUMBLE_DURATION_MS);
   778         if (!joystick->rumble_expiration) {
   779             joystick->rumble_expiration = 1;
   780         }
   781     } else {
   782         joystick->rumble_expiration = 0;
   783     }
   784     SDL_UnlockJoysticks();
   785 
   786     return result;
   787 }
   788 
   789 /*
   790  * Close a joystick previously opened with SDL_JoystickOpen()
   791  */
   792 void
   793 SDL_JoystickClose(SDL_Joystick * joystick)
   794 {
   795     SDL_Joystick *joysticklist;
   796     SDL_Joystick *joysticklistprev;
   797 
   798     if (!SDL_PrivateJoystickValid(joystick)) {
   799         return;
   800     }
   801 
   802     SDL_LockJoysticks();
   803 
   804     /* First decrement ref count */
   805     if (--joystick->ref_count > 0) {
   806         SDL_UnlockJoysticks();
   807         return;
   808     }
   809 
   810     if (SDL_updating_joystick) {
   811         SDL_UnlockJoysticks();
   812         return;
   813     }
   814 
   815     if (joystick->rumble_expiration) {
   816         SDL_JoystickRumble(joystick, 0, 0, 0);
   817     }
   818 
   819     joystick->driver->Close(joystick);
   820     joystick->hwdata = NULL;
   821 
   822     joysticklist = SDL_joysticks;
   823     joysticklistprev = NULL;
   824     while (joysticklist) {
   825         if (joystick == joysticklist) {
   826             if (joysticklistprev) {
   827                 /* unlink this entry */
   828                 joysticklistprev->next = joysticklist->next;
   829             } else {
   830                 SDL_joysticks = joystick->next;
   831             }
   832             break;
   833         }
   834         joysticklistprev = joysticklist;
   835         joysticklist = joysticklist->next;
   836     }
   837 
   838     SDL_free(joystick->name);
   839 
   840     /* Free the data associated with this joystick */
   841     SDL_free(joystick->axes);
   842     SDL_free(joystick->hats);
   843     SDL_free(joystick->balls);
   844     SDL_free(joystick->buttons);
   845     SDL_free(joystick);
   846 
   847     SDL_UnlockJoysticks();
   848 }
   849 
   850 void
   851 SDL_JoystickQuit(void)
   852 {
   853     int i;
   854 
   855     /* Make sure we're not getting called in the middle of updating joysticks */
   856     SDL_LockJoysticks();
   857     while (SDL_updating_joystick) {
   858         SDL_UnlockJoysticks();
   859         SDL_Delay(1);
   860         SDL_LockJoysticks();
   861     }
   862 
   863     /* Stop the event polling */
   864     while (SDL_joysticks) {
   865         SDL_joysticks->ref_count = 1;
   866         SDL_JoystickClose(SDL_joysticks);
   867     }
   868 
   869     /* Quit the joystick setup */
   870     for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) {
   871        SDL_joystick_drivers[i]->Quit();
   872     }
   873 
   874     if (SDL_joystick_players) {
   875         SDL_free(SDL_joystick_players);
   876         SDL_joystick_players = NULL;
   877         SDL_joystick_player_count = 0;
   878     }
   879     SDL_UnlockJoysticks();
   880 
   881 #if !SDL_EVENTS_DISABLED
   882     SDL_QuitSubSystem(SDL_INIT_EVENTS);
   883 #endif
   884 
   885     SDL_DelHintCallback(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS,
   886                         SDL_JoystickAllowBackgroundEventsChanged, NULL);
   887 
   888     if (SDL_joystick_lock) {
   889         SDL_mutex *mutex = SDL_joystick_lock;
   890         SDL_joystick_lock = NULL;
   891         SDL_DestroyMutex(mutex);
   892     }
   893 
   894     SDL_GameControllerQuitMappings();
   895 }
   896 
   897 
   898 static SDL_bool
   899 SDL_PrivateJoystickShouldIgnoreEvent()
   900 {
   901     if (SDL_joystick_allows_background_events) {
   902         return SDL_FALSE;
   903     }
   904 
   905     if (SDL_HasWindows() && SDL_GetKeyboardFocus() == NULL) {
   906         /* We have windows but we don't have focus, ignore the event. */
   907         return SDL_TRUE;
   908     }
   909     return SDL_FALSE;
   910 }
   911 
   912 /* These are global for SDL_sysjoystick.c and SDL_events.c */
   913 
   914 void SDL_PrivateJoystickAdded(SDL_JoystickID device_instance)
   915 {
   916     SDL_JoystickDriver *driver;
   917     int driver_device_index;
   918     int player_index = -1;
   919     int device_index = SDL_JoystickGetDeviceIndexFromInstanceID(device_instance);
   920     if (device_index < 0) {
   921         return;
   922     }
   923 
   924     SDL_LockJoysticks();
   925     if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &driver_device_index)) {
   926         player_index = driver->GetDevicePlayerIndex(driver_device_index);
   927     }
   928     if (player_index < 0 && SDL_IsGameController(device_index)) {
   929         player_index = SDL_FindFreePlayerIndex();
   930     }
   931     if (player_index >= 0) {
   932         SDL_SetJoystickIDForPlayerIndex(player_index, device_instance);
   933     }
   934     SDL_UnlockJoysticks();
   935 
   936 #if !SDL_EVENTS_DISABLED
   937     {
   938         SDL_Event event;
   939 
   940         event.type = SDL_JOYDEVICEADDED;
   941 
   942         if (SDL_GetEventState(event.type) == SDL_ENABLE) {
   943             event.jdevice.which = device_index;
   944             SDL_PushEvent(&event);
   945         }
   946     }
   947 #endif /* !SDL_EVENTS_DISABLED */
   948 }
   949 
   950 /*
   951  * If there is an existing add event in the queue, it needs to be modified
   952  * to have the right value for which, because the number of controllers in
   953  * the system is now one less.
   954  */
   955 static void UpdateEventsForDeviceRemoval()
   956 {
   957     int i, num_events;
   958     SDL_Event *events;
   959     SDL_bool isstack;
   960 
   961     num_events = SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, SDL_JOYDEVICEADDED, SDL_JOYDEVICEADDED);
   962     if (num_events <= 0) {
   963         return;
   964     }
   965 
   966     events = SDL_small_alloc(SDL_Event, num_events, &isstack);
   967     if (!events) {
   968         return;
   969     }
   970 
   971     num_events = SDL_PeepEvents(events, num_events, SDL_GETEVENT, SDL_JOYDEVICEADDED, SDL_JOYDEVICEADDED);
   972     for (i = 0; i < num_events; ++i) {
   973         --events[i].jdevice.which;
   974     }
   975     SDL_PeepEvents(events, num_events, SDL_ADDEVENT, 0, 0);
   976 
   977     SDL_small_free(events, isstack);
   978 }
   979 
   980 void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance)
   981 {
   982     SDL_Joystick *joystick;
   983     int player_index;
   984 
   985 #if !SDL_EVENTS_DISABLED
   986     SDL_Event event;
   987 
   988     event.type = SDL_JOYDEVICEREMOVED;
   989 
   990     if (SDL_GetEventState(event.type) == SDL_ENABLE) {
   991         event.jdevice.which = device_instance;
   992         SDL_PushEvent(&event);
   993     }
   994 
   995     UpdateEventsForDeviceRemoval();
   996 #endif /* !SDL_EVENTS_DISABLED */
   997 
   998     /* Mark this joystick as no longer attached */
   999     for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
  1000         if (joystick->instance_id == device_instance) {
  1001             joystick->attached = SDL_FALSE;
  1002             joystick->force_recentering = SDL_TRUE;
  1003             break;
  1004         }
  1005     }
  1006 
  1007     SDL_LockJoysticks();
  1008     player_index = SDL_GetPlayerIndexForJoystickID(device_instance);
  1009     if (player_index >= 0) {
  1010         SDL_joystick_players[player_index] = -1;
  1011     }
  1012     SDL_UnlockJoysticks();
  1013 }
  1014 
  1015 int
  1016 SDL_PrivateJoystickAxis(SDL_Joystick * joystick, Uint8 axis, Sint16 value)
  1017 {
  1018     int posted;
  1019     SDL_JoystickAxisInfo *info;
  1020 
  1021     /* Make sure we're not getting garbage or duplicate events */
  1022     if (axis >= joystick->naxes) {
  1023         return 0;
  1024     }
  1025 
  1026     info = &joystick->axes[axis];
  1027     if (!info->has_initial_value ||
  1028         (!info->has_second_value && (info->initial_value == -32768 || info->initial_value == 32767) && SDL_abs(value) < (SDL_JOYSTICK_AXIS_MAX / 4))) {
  1029         info->initial_value = value;
  1030         info->value = value;
  1031         info->zero = value;
  1032         info->has_initial_value = SDL_TRUE;
  1033     } else {
  1034         info->has_second_value = SDL_TRUE;
  1035     }
  1036     if (value == info->value) {
  1037         return 0;
  1038     }
  1039     if (!info->sent_initial_value) {
  1040         /* Make sure we don't send motion until there's real activity on this axis */
  1041         const int MAX_ALLOWED_JITTER = SDL_JOYSTICK_AXIS_MAX / 80;  /* ShanWan PS3 controller needed 96 */
  1042         if (SDL_abs(value - info->value) <= MAX_ALLOWED_JITTER) {
  1043             return 0;
  1044         }
  1045         info->sent_initial_value = SDL_TRUE;
  1046         info->value = value; /* Just so we pass the check above */
  1047         SDL_PrivateJoystickAxis(joystick, axis, info->initial_value);
  1048     }
  1049 
  1050     /* We ignore events if we don't have keyboard focus, except for centering
  1051      * events.
  1052      */
  1053     if (SDL_PrivateJoystickShouldIgnoreEvent()) {
  1054         if ((value > info->zero && value >= info->value) ||
  1055             (value < info->zero && value <= info->value)) {
  1056             return 0;
  1057         }
  1058     }
  1059 
  1060     /* Update internal joystick state */
  1061     info->value = value;
  1062 
  1063     /* Post the event, if desired */
  1064     posted = 0;
  1065 #if !SDL_EVENTS_DISABLED
  1066     if (SDL_GetEventState(SDL_JOYAXISMOTION) == SDL_ENABLE) {
  1067         SDL_Event event;
  1068         event.type = SDL_JOYAXISMOTION;
  1069         event.jaxis.which = joystick->instance_id;
  1070         event.jaxis.axis = axis;
  1071         event.jaxis.value = value;
  1072         posted = SDL_PushEvent(&event) == 1;
  1073     }
  1074 #endif /* !SDL_EVENTS_DISABLED */
  1075     return posted;
  1076 }
  1077 
  1078 int
  1079 SDL_PrivateJoystickHat(SDL_Joystick * joystick, Uint8 hat, Uint8 value)
  1080 {
  1081     int posted;
  1082 
  1083     /* Make sure we're not getting garbage or duplicate events */
  1084     if (hat >= joystick->nhats) {
  1085         return 0;
  1086     }
  1087     if (value == joystick->hats[hat]) {
  1088         return 0;
  1089     }
  1090 
  1091     /* We ignore events if we don't have keyboard focus, except for centering
  1092      * events.
  1093      */
  1094     if (SDL_PrivateJoystickShouldIgnoreEvent()) {
  1095         if (value != SDL_HAT_CENTERED) {
  1096             return 0;
  1097         }
  1098     }
  1099 
  1100     /* Update internal joystick state */
  1101     joystick->hats[hat] = value;
  1102 
  1103     /* Post the event, if desired */
  1104     posted = 0;
  1105 #if !SDL_EVENTS_DISABLED
  1106     if (SDL_GetEventState(SDL_JOYHATMOTION) == SDL_ENABLE) {
  1107         SDL_Event event;
  1108         event.jhat.type = SDL_JOYHATMOTION;
  1109         event.jhat.which = joystick->instance_id;
  1110         event.jhat.hat = hat;
  1111         event.jhat.value = value;
  1112         posted = SDL_PushEvent(&event) == 1;
  1113     }
  1114 #endif /* !SDL_EVENTS_DISABLED */
  1115     return posted;
  1116 }
  1117 
  1118 int
  1119 SDL_PrivateJoystickBall(SDL_Joystick * joystick, Uint8 ball,
  1120                         Sint16 xrel, Sint16 yrel)
  1121 {
  1122     int posted;
  1123 
  1124     /* Make sure we're not getting garbage events */
  1125     if (ball >= joystick->nballs) {
  1126         return 0;
  1127     }
  1128 
  1129     /* We ignore events if we don't have keyboard focus. */
  1130     if (SDL_PrivateJoystickShouldIgnoreEvent()) {
  1131         return 0;
  1132     }
  1133 
  1134     /* Update internal mouse state */
  1135     joystick->balls[ball].dx += xrel;
  1136     joystick->balls[ball].dy += yrel;
  1137 
  1138     /* Post the event, if desired */
  1139     posted = 0;
  1140 #if !SDL_EVENTS_DISABLED
  1141     if (SDL_GetEventState(SDL_JOYBALLMOTION) == SDL_ENABLE) {
  1142         SDL_Event event;
  1143         event.jball.type = SDL_JOYBALLMOTION;
  1144         event.jball.which = joystick->instance_id;
  1145         event.jball.ball = ball;
  1146         event.jball.xrel = xrel;
  1147         event.jball.yrel = yrel;
  1148         posted = SDL_PushEvent(&event) == 1;
  1149     }
  1150 #endif /* !SDL_EVENTS_DISABLED */
  1151     return posted;
  1152 }
  1153 
  1154 int
  1155 SDL_PrivateJoystickButton(SDL_Joystick * joystick, Uint8 button, Uint8 state)
  1156 {
  1157     int posted;
  1158 #if !SDL_EVENTS_DISABLED
  1159     SDL_Event event;
  1160 
  1161     switch (state) {
  1162     case SDL_PRESSED:
  1163         event.type = SDL_JOYBUTTONDOWN;
  1164         break;
  1165     case SDL_RELEASED:
  1166         event.type = SDL_JOYBUTTONUP;
  1167         break;
  1168     default:
  1169         /* Invalid state -- bail */
  1170         return 0;
  1171     }
  1172 #endif /* !SDL_EVENTS_DISABLED */
  1173 
  1174     /* Make sure we're not getting garbage or duplicate events */
  1175     if (button >= joystick->nbuttons) {
  1176         return 0;
  1177     }
  1178     if (state == joystick->buttons[button]) {
  1179         return 0;
  1180     }
  1181 
  1182     /* We ignore events if we don't have keyboard focus, except for button
  1183      * release. */
  1184     if (SDL_PrivateJoystickShouldIgnoreEvent()) {
  1185         if (state == SDL_PRESSED) {
  1186             return 0;
  1187         }
  1188     }
  1189 
  1190     /* Update internal joystick state */
  1191     joystick->buttons[button] = state;
  1192 
  1193     /* Post the event, if desired */
  1194     posted = 0;
  1195 #if !SDL_EVENTS_DISABLED
  1196     if (SDL_GetEventState(event.type) == SDL_ENABLE) {
  1197         event.jbutton.which = joystick->instance_id;
  1198         event.jbutton.button = button;
  1199         event.jbutton.state = state;
  1200         posted = SDL_PushEvent(&event) == 1;
  1201     }
  1202 #endif /* !SDL_EVENTS_DISABLED */
  1203     return posted;
  1204 }
  1205 
  1206 void
  1207 SDL_JoystickUpdate(void)
  1208 {
  1209     int i;
  1210     SDL_Joystick *joystick, *next;
  1211 
  1212     if (!SDL_WasInit(SDL_INIT_JOYSTICK)) {
  1213         return;
  1214     }
  1215 
  1216     SDL_LockJoysticks();
  1217 
  1218     if (SDL_updating_joystick) {
  1219         /* The joysticks are already being updated */
  1220         SDL_UnlockJoysticks();
  1221         return;
  1222     }
  1223 
  1224     SDL_updating_joystick = SDL_TRUE;
  1225 
  1226     /* Make sure the list is unlocked while dispatching events to prevent application deadlocks */
  1227     SDL_UnlockJoysticks();
  1228 
  1229 #ifdef SDL_JOYSTICK_HIDAPI
  1230     /* Special function for HIDAPI devices, as a single device can provide multiple SDL_Joysticks */
  1231     HIDAPI_UpdateDevices();
  1232 #endif /* SDL_JOYSTICK_HIDAPI */
  1233 
  1234     for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
  1235         if (joystick->attached) {
  1236             /* This should always be true, but seeing a crash in the wild...? */
  1237             if (joystick->driver) {
  1238                 joystick->driver->Update(joystick);
  1239             }
  1240 
  1241             if (joystick->delayed_guide_button) {
  1242                 SDL_GameControllerHandleDelayedGuideButton(joystick);
  1243             }
  1244         }
  1245 
  1246         if (joystick->rumble_expiration) {
  1247             SDL_LockJoysticks();
  1248             /* Double check now that the lock is held */
  1249             if (joystick->rumble_expiration &&
  1250                 SDL_TICKS_PASSED(SDL_GetTicks(), joystick->rumble_expiration)) {
  1251                 SDL_JoystickRumble(joystick, 0, 0, 0);
  1252             }
  1253             SDL_UnlockJoysticks();
  1254         }
  1255 
  1256         if (joystick->force_recentering) {
  1257             /* Tell the app that everything is centered/unpressed... */
  1258             for (i = 0; i < joystick->naxes; i++) {
  1259                 if (joystick->axes[i].has_initial_value) {
  1260                     SDL_PrivateJoystickAxis(joystick, i, joystick->axes[i].zero);
  1261                 }
  1262             }
  1263 
  1264             for (i = 0; i < joystick->nbuttons; i++) {
  1265                 SDL_PrivateJoystickButton(joystick, i, 0);
  1266             }
  1267 
  1268             for (i = 0; i < joystick->nhats; i++) {
  1269                 SDL_PrivateJoystickHat(joystick, i, SDL_HAT_CENTERED);
  1270             }
  1271 
  1272             joystick->force_recentering = SDL_FALSE;
  1273         }
  1274     }
  1275 
  1276     SDL_LockJoysticks();
  1277 
  1278     SDL_updating_joystick = SDL_FALSE;
  1279 
  1280     /* If any joysticks were closed while updating, free them here */
  1281     for (joystick = SDL_joysticks; joystick; joystick = next) {
  1282         next = joystick->next;
  1283         if (joystick->ref_count <= 0) {
  1284             SDL_JoystickClose(joystick);
  1285         }
  1286     }
  1287 
  1288     /* this needs to happen AFTER walking the joystick list above, so that any
  1289        dangling hardware data from removed devices can be free'd
  1290      */
  1291     for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) {
  1292         SDL_joystick_drivers[i]->Detect();
  1293     }
  1294 
  1295     SDL_UnlockJoysticks();
  1296 }
  1297 
  1298 int
  1299 SDL_JoystickEventState(int state)
  1300 {
  1301 #if SDL_EVENTS_DISABLED
  1302     return SDL_DISABLE;
  1303 #else
  1304     const Uint32 event_list[] = {
  1305         SDL_JOYAXISMOTION, SDL_JOYBALLMOTION, SDL_JOYHATMOTION,
  1306         SDL_JOYBUTTONDOWN, SDL_JOYBUTTONUP, SDL_JOYDEVICEADDED, SDL_JOYDEVICEREMOVED
  1307     };
  1308     unsigned int i;
  1309 
  1310     switch (state) {
  1311     case SDL_QUERY:
  1312         state = SDL_DISABLE;
  1313         for (i = 0; i < SDL_arraysize(event_list); ++i) {
  1314             state = SDL_EventState(event_list[i], SDL_QUERY);
  1315             if (state == SDL_ENABLE) {
  1316                 break;
  1317             }
  1318         }
  1319         break;
  1320     default:
  1321         for (i = 0; i < SDL_arraysize(event_list); ++i) {
  1322             SDL_EventState(event_list[i], state);
  1323         }
  1324         break;
  1325     }
  1326     return state;
  1327 #endif /* SDL_EVENTS_DISABLED */
  1328 }
  1329 
  1330 void SDL_GetJoystickGUIDInfo(SDL_JoystickGUID guid, Uint16 *vendor, Uint16 *product, Uint16 *version)
  1331 {
  1332     Uint16 *guid16 = (Uint16 *)guid.data;
  1333 
  1334     /* If the GUID fits the form of BUS 0000 VENDOR 0000 PRODUCT 0000, return the data */
  1335     if (/* guid16[0] is device bus type */
  1336         guid16[1] == 0x0000 &&
  1337         /* guid16[2] is vendor ID */
  1338         guid16[3] == 0x0000 &&
  1339         /* guid16[4] is product ID */
  1340         guid16[5] == 0x0000
  1341         /* guid16[6] is product version */
  1342    ) {
  1343         if (vendor) {
  1344             *vendor = guid16[2];
  1345         }
  1346         if (product) {
  1347             *product = guid16[4];
  1348         }
  1349         if (version) {
  1350             *version = guid16[6];
  1351         }
  1352     } else {
  1353         if (vendor) {
  1354             *vendor = 0;
  1355         }
  1356         if (product) {
  1357             *product = 0;
  1358         }
  1359         if (version) {
  1360             *version = 0;
  1361         }
  1362     }
  1363 }
  1364 
  1365 const char *
  1366 SDL_GetCustomJoystickManufacturer(const char *manufacturer)
  1367 {
  1368     if (manufacturer) {
  1369         if (SDL_strcmp(manufacturer, "Performance Designed Products") == 0) {
  1370             return "PDP";
  1371         } else if (SDL_strcmp(manufacturer, "HORI CO.,LTD") == 0) {
  1372             return "HORI";
  1373         }
  1374     }
  1375     return manufacturer;
  1376 }
  1377 
  1378 const char *
  1379 SDL_GetCustomJoystickName(Uint16 vendor, Uint16 product)
  1380 {
  1381     return GuessControllerName(vendor, product);
  1382 }
  1383 
  1384 SDL_GameControllerType
  1385 SDL_GetJoystickGameControllerTypeFromGUID(SDL_JoystickGUID guid, const char *name)
  1386 {
  1387     SDL_GameControllerType type;
  1388     Uint16 vendor, product;
  1389 
  1390     SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL);
  1391     type = SDL_GetJoystickGameControllerType(name, vendor, product, -1, 0, 0, 0);
  1392     if (type == SDL_CONTROLLER_TYPE_UNKNOWN) {
  1393         if (SDL_IsJoystickXInput(guid)) {
  1394             /* This is probably an Xbox One controller */
  1395             return SDL_CONTROLLER_TYPE_XBOXONE;
  1396         }
  1397     }
  1398     return type;
  1399 }
  1400 
  1401 SDL_GameControllerType
  1402 SDL_GetJoystickGameControllerType(const char *name, Uint16 vendor, Uint16 product, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
  1403 {
  1404     static const int LIBUSB_CLASS_VENDOR_SPEC = 0xFF;
  1405     static const int XB360_IFACE_SUBCLASS = 93;
  1406     static const int XB360_IFACE_PROTOCOL = 1; /* Wired */
  1407     static const int XB360W_IFACE_PROTOCOL = 129; /* Wireless */
  1408     static const int XBONE_IFACE_SUBCLASS = 71;
  1409     static const int XBONE_IFACE_PROTOCOL = 208;
  1410 
  1411     SDL_GameControllerType type = SDL_CONTROLLER_TYPE_UNKNOWN;
  1412 
  1413     /* This code should match the checks in libusb/hid.c and HIDDeviceManager.java */
  1414     if (interface_class == LIBUSB_CLASS_VENDOR_SPEC &&
  1415         interface_subclass == XB360_IFACE_SUBCLASS &&
  1416         (interface_protocol == XB360_IFACE_PROTOCOL ||
  1417          interface_protocol == XB360W_IFACE_PROTOCOL)) {
  1418 
  1419         static const int SUPPORTED_VENDORS[] = {
  1420             0x0079, /* GPD Win 2 */
  1421             0x044f, /* Thrustmaster */
  1422             0x045e, /* Microsoft */
  1423             0x046d, /* Logitech */
  1424             0x056e, /* Elecom */
  1425             0x06a3, /* Saitek */
  1426             0x0738, /* Mad Catz */
  1427             0x07ff, /* Mad Catz */
  1428             0x0e6f, /* PDP */
  1429             0x0f0d, /* Hori */
  1430             0x1038, /* SteelSeries */
  1431             0x11c9, /* Nacon */
  1432             0x12ab, /* Unknown */
  1433             0x1430, /* RedOctane */
  1434             0x146b, /* BigBen */
  1435             0x1532, /* Razer Sabertooth */
  1436             0x15e4, /* Numark */
  1437             0x162e, /* Joytech */
  1438             0x1689, /* Razer Onza */
  1439             0x1bad, /* Harmonix */
  1440             0x24c6, /* PowerA */
  1441         };
  1442 
  1443         int i;
  1444         for (i = 0; i < SDL_arraysize(SUPPORTED_VENDORS); ++i) {
  1445             if (vendor == SUPPORTED_VENDORS[i]) {
  1446                 type = SDL_CONTROLLER_TYPE_XBOX360;
  1447                 break;
  1448             }
  1449         }
  1450     }
  1451 
  1452     if (interface_number == 0 &&
  1453         interface_class == LIBUSB_CLASS_VENDOR_SPEC &&
  1454         interface_subclass == XBONE_IFACE_SUBCLASS &&
  1455         interface_protocol == XBONE_IFACE_PROTOCOL) {
  1456 
  1457         static const int SUPPORTED_VENDORS[] = {
  1458             0x045e, /* Microsoft */
  1459             0x0738, /* Mad Catz */
  1460             0x0e6f, /* PDP */
  1461             0x0f0d, /* Hori */
  1462             0x1532, /* Razer Wildcat */
  1463             0x24c6, /* PowerA */
  1464             0x2e24, /* Hyperkin */
  1465         };
  1466 
  1467         int i;
  1468         for (i = 0; i < SDL_arraysize(SUPPORTED_VENDORS); ++i) {
  1469             if (vendor == SUPPORTED_VENDORS[i]) {
  1470                 type = SDL_CONTROLLER_TYPE_XBOXONE;
  1471                 break;
  1472             }
  1473         }
  1474     }
  1475 
  1476     if (type == SDL_CONTROLLER_TYPE_UNKNOWN) {
  1477         if (vendor == 0x0000 && product == 0x0000) {
  1478             /* Some devices are only identifiable by their name */
  1479             if (SDL_strcmp(name, "Lic Pro Controller") == 0 ||
  1480                 SDL_strcmp(name, "Nintendo Wireless Gamepad") == 0 ||
  1481                 SDL_strcmp(name, "Wireless Gamepad") == 0) {
  1482                 /* HORI or PowerA Switch Pro Controller clone */
  1483                 type = SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO;
  1484             } else {
  1485                 type = SDL_CONTROLLER_TYPE_UNKNOWN;
  1486             }
  1487 
  1488         } else if (vendor == 0x0001 && product == 0x0001) {
  1489             type = SDL_CONTROLLER_TYPE_UNKNOWN;
  1490 
  1491         } else {
  1492             switch (GuessControllerType(vendor, product)) {
  1493             case k_eControllerType_XBox360Controller:
  1494                 type = SDL_CONTROLLER_TYPE_XBOX360;
  1495                 break;
  1496             case k_eControllerType_XBoxOneController:
  1497                 type = SDL_CONTROLLER_TYPE_XBOXONE;
  1498                 break;
  1499             case k_eControllerType_PS3Controller:
  1500                 type = SDL_CONTROLLER_TYPE_PS3;
  1501                 break;
  1502             case k_eControllerType_PS4Controller:
  1503                 type = SDL_CONTROLLER_TYPE_PS4;
  1504                 break;
  1505             case k_eControllerType_SwitchProController:
  1506             case k_eControllerType_SwitchInputOnlyController:
  1507                 type = SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO;
  1508                 break;
  1509             default:
  1510                 type = SDL_CONTROLLER_TYPE_UNKNOWN;
  1511                 break;
  1512             }
  1513         }
  1514     }
  1515     return type;
  1516 }
  1517 
  1518 SDL_bool
  1519 SDL_IsJoystickNintendoSwitchProInputOnly(Uint16 vendor, Uint16 product)
  1520 {
  1521     EControllerType eType = GuessControllerType(vendor, product);
  1522     return (eType == k_eControllerType_SwitchInputOnlyController);
  1523 }
  1524 
  1525 SDL_bool
  1526 SDL_IsJoystickSteamController(Uint16 vendor, Uint16 product)
  1527 {
  1528     EControllerType eType = GuessControllerType(vendor, product);
  1529     return (eType == k_eControllerType_SteamController ||
  1530             eType == k_eControllerType_SteamControllerV2);
  1531 }
  1532 
  1533 SDL_bool
  1534 SDL_IsJoystickXInput(SDL_JoystickGUID guid)
  1535 {
  1536     return (guid.data[14] == 'x') ? SDL_TRUE : SDL_FALSE;
  1537 }
  1538 
  1539 SDL_bool
  1540 SDL_IsJoystickHIDAPI(SDL_JoystickGUID guid)
  1541 {
  1542     return (guid.data[14] == 'h') ? SDL_TRUE : SDL_FALSE;
  1543 }
  1544 
  1545 static SDL_bool SDL_IsJoystickProductWheel(Uint32 vidpid)
  1546 {
  1547     static Uint32 wheel_joysticks[] = {
  1548         MAKE_VIDPID(0x046d, 0xc294),    /* Logitech generic wheel */
  1549         MAKE_VIDPID(0x046d, 0xc295),    /* Logitech Momo Force */
  1550         MAKE_VIDPID(0x046d, 0xc298),    /* Logitech Driving Force Pro */
  1551         MAKE_VIDPID(0x046d, 0xc299),    /* Logitech G25 */
  1552         MAKE_VIDPID(0x046d, 0xc29a),    /* Logitech Driving Force GT */
  1553         MAKE_VIDPID(0x046d, 0xc29b),    /* Logitech G27 */
  1554         MAKE_VIDPID(0x046d, 0xc261),    /* Logitech G920 (initial mode) */
  1555         MAKE_VIDPID(0x046d, 0xc262),    /* Logitech G920 (active mode) */
  1556         MAKE_VIDPID(0x044f, 0xb65d),    /* Thrustmaster Wheel FFB */
  1557         MAKE_VIDPID(0x044f, 0xb66d),    /* Thrustmaster Wheel FFB */
  1558         MAKE_VIDPID(0x044f, 0xb677),    /* Thrustmaster T150 */
  1559         MAKE_VIDPID(0x044f, 0xb664),    /* Thrustmaster TX (initial mode) */
  1560         MAKE_VIDPID(0x044f, 0xb669),    /* Thrustmaster TX (active mode) */
  1561     };
  1562     int i;
  1563 
  1564     for (i = 0; i < SDL_arraysize(wheel_joysticks); ++i) {
  1565         if (vidpid == wheel_joysticks[i]) {
  1566             return SDL_TRUE;
  1567         }
  1568     }
  1569     return SDL_FALSE;
  1570 }
  1571 
  1572 static SDL_bool SDL_IsJoystickProductFlightStick(Uint32 vidpid)
  1573 {
  1574     static Uint32 flightstick_joysticks[] = {
  1575         MAKE_VIDPID(0x044f, 0x0402),    /* HOTAS Warthog Joystick */
  1576         MAKE_VIDPID(0x0738, 0x2221),    /* Saitek Pro Flight X-56 Rhino Stick */
  1577     };
  1578     int i;
  1579 
  1580     for (i = 0; i < SDL_arraysize(flightstick_joysticks); ++i) {
  1581         if (vidpid == flightstick_joysticks[i]) {
  1582             return SDL_TRUE;
  1583         }
  1584     }
  1585     return SDL_FALSE;
  1586 }
  1587 
  1588 static SDL_bool SDL_IsJoystickProductThrottle(Uint32 vidpid)
  1589 {
  1590     static Uint32 throttle_joysticks[] = {
  1591         MAKE_VIDPID(0x044f, 0x0404),    /* HOTAS Warthog Throttle */
  1592         MAKE_VIDPID(0x0738, 0xa221),    /* Saitek Pro Flight X-56 Rhino Throttle */
  1593     };
  1594     int i;
  1595 
  1596     for (i = 0; i < SDL_arraysize(throttle_joysticks); ++i) {
  1597         if (vidpid == throttle_joysticks[i]) {
  1598             return SDL_TRUE;
  1599         }
  1600     }
  1601     return SDL_FALSE;
  1602 }
  1603 
  1604 static SDL_JoystickType SDL_GetJoystickGUIDType(SDL_JoystickGUID guid)
  1605 {
  1606     Uint16 vendor;
  1607     Uint16 product;
  1608     Uint32 vidpid;
  1609 
  1610     if (SDL_IsJoystickXInput(guid)) {
  1611         /* XInput GUID, get the type based on the XInput device subtype */
  1612         switch (guid.data[15]) {
  1613         case 0x01:  /* XINPUT_DEVSUBTYPE_GAMEPAD */
  1614             return SDL_JOYSTICK_TYPE_GAMECONTROLLER;
  1615         case 0x02:  /* XINPUT_DEVSUBTYPE_WHEEL */
  1616             return SDL_JOYSTICK_TYPE_WHEEL;
  1617         case 0x03:  /* XINPUT_DEVSUBTYPE_ARCADE_STICK */
  1618             return SDL_JOYSTICK_TYPE_ARCADE_STICK;
  1619         case 0x04:  /* XINPUT_DEVSUBTYPE_FLIGHT_STICK */
  1620             return SDL_JOYSTICK_TYPE_FLIGHT_STICK;
  1621         case 0x05:  /* XINPUT_DEVSUBTYPE_DANCE_PAD */
  1622             return SDL_JOYSTICK_TYPE_DANCE_PAD;
  1623         case 0x06:  /* XINPUT_DEVSUBTYPE_GUITAR */
  1624         case 0x07:  /* XINPUT_DEVSUBTYPE_GUITAR_ALTERNATE */
  1625         case 0x0B:  /* XINPUT_DEVSUBTYPE_GUITAR_BASS */
  1626             return SDL_JOYSTICK_TYPE_GUITAR;
  1627         case 0x08:  /* XINPUT_DEVSUBTYPE_DRUM_KIT */
  1628             return SDL_JOYSTICK_TYPE_DRUM_KIT;
  1629         case 0x13:  /* XINPUT_DEVSUBTYPE_ARCADE_PAD */
  1630             return SDL_JOYSTICK_TYPE_ARCADE_PAD;
  1631         default:
  1632             return SDL_JOYSTICK_TYPE_UNKNOWN;
  1633         }
  1634     }
  1635 
  1636     SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL);
  1637     vidpid = MAKE_VIDPID(vendor, product);
  1638 
  1639     if (SDL_IsJoystickProductWheel(vidpid)) {
  1640         return SDL_JOYSTICK_TYPE_WHEEL;
  1641     }
  1642 
  1643     if (SDL_IsJoystickProductFlightStick(vidpid)) {
  1644         return SDL_JOYSTICK_TYPE_FLIGHT_STICK;
  1645     }
  1646 
  1647     if (SDL_IsJoystickProductThrottle(vidpid)) {
  1648         return SDL_JOYSTICK_TYPE_THROTTLE;
  1649     }
  1650 
  1651     if (GuessControllerType(vendor, product) != k_eControllerType_UnknownNonSteamController) {
  1652         return SDL_JOYSTICK_TYPE_GAMECONTROLLER;
  1653     }
  1654 
  1655     return SDL_JOYSTICK_TYPE_UNKNOWN;
  1656 }
  1657 
  1658 static SDL_bool SDL_IsPS4RemapperRunning(void)
  1659 {
  1660 #ifdef __WIN32__
  1661     const char *mapper_processes[] = {
  1662         "DS4Windows.exe",
  1663         "InputMapper.exe",
  1664     };
  1665     int i;
  1666     PROCESSENTRY32 pe32;
  1667     SDL_bool found = SDL_FALSE;
  1668 
  1669     /* Take a snapshot of all processes in the system */
  1670     HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  1671     if (hProcessSnap != INVALID_HANDLE_VALUE) {
  1672         pe32.dwSize = sizeof(PROCESSENTRY32);
  1673         if (Process32First(hProcessSnap, &pe32)) {
  1674             do
  1675             {
  1676                 for (i = 0; i < SDL_arraysize(mapper_processes); ++i) {
  1677                     if (SDL_strcasecmp(pe32.szExeFile, mapper_processes[i]) == 0) {
  1678                         found = SDL_TRUE;
  1679                     }
  1680                 }
  1681             } while (Process32Next(hProcessSnap, &pe32) && !found);
  1682         }
  1683         CloseHandle(hProcessSnap);
  1684     }
  1685     return found;
  1686 #else
  1687     return SDL_FALSE;
  1688 #endif
  1689 }
  1690 
  1691 SDL_bool SDL_ShouldIgnoreJoystick(const char *name, SDL_JoystickGUID guid)
  1692 {
  1693     /* This list is taken from:
  1694        https://raw.githubusercontent.com/denilsonsa/udev-joystick-blacklist/master/generate_rules.py
  1695      */
  1696     static Uint32 joystick_blacklist[] = {
  1697         /* Microsoft Microsoft Wireless Optical Desktop® 2.10 */
  1698         /* Microsoft Wireless Desktop - Comfort Edition */
  1699         MAKE_VIDPID(0x045e, 0x009d),
  1700 
  1701         /* Microsoft Microsoft® Digital Media Pro Keyboard */
  1702         /* Microsoft Corp. Digital Media Pro Keyboard */
  1703         MAKE_VIDPID(0x045e, 0x00b0),
  1704 
  1705         /* Microsoft Microsoft® Digital Media Keyboard */
  1706         /* Microsoft Corp. Digital Media Keyboard 1.0A */
  1707         MAKE_VIDPID(0x045e, 0x00b4),
  1708 
  1709         /* Microsoft Microsoft® Digital Media Keyboard 3000 */
  1710         MAKE_VIDPID(0x045e, 0x0730),
  1711 
  1712         /* Microsoft Microsoft® 2.4GHz Transceiver v6.0 */
  1713         /* Microsoft Microsoft® 2.4GHz Transceiver v8.0 */
  1714         /* Microsoft Corp. Nano Transceiver v1.0 for Bluetooth */
  1715         /* Microsoft Wireless Mobile Mouse 1000 */
  1716         /* Microsoft Wireless Desktop 3000 */
  1717         MAKE_VIDPID(0x045e, 0x0745),
  1718 
  1719         /* Microsoft® SideWinder(TM) 2.4GHz Transceiver */
  1720         MAKE_VIDPID(0x045e, 0x0748),
  1721 
  1722         /* Microsoft Corp. Wired Keyboard 600 */
  1723         MAKE_VIDPID(0x045e, 0x0750),
  1724 
  1725         /* Microsoft Corp. Sidewinder X4 keyboard */
  1726         MAKE_VIDPID(0x045e, 0x0768),
  1727 
  1728         /* Microsoft Corp. Arc Touch Mouse Transceiver */
  1729         MAKE_VIDPID(0x045e, 0x0773),
  1730 
  1731         /* Microsoft® 2.4GHz Transceiver v9.0 */
  1732         /* Microsoft® Nano Transceiver v2.1 */
  1733         /* Microsoft Sculpt Ergonomic Keyboard (5KV-00001) */
  1734         MAKE_VIDPID(0x045e, 0x07a5),
  1735 
  1736         /* Microsoft® Nano Transceiver v1.0 */
  1737         /* Microsoft Wireless Keyboard 800 */
  1738         MAKE_VIDPID(0x045e, 0x07b2),
  1739 
  1740         /* Microsoft® Nano Transceiver v2.0 */
  1741         MAKE_VIDPID(0x045e, 0x0800),
  1742 
  1743         MAKE_VIDPID(0x046d, 0xc30a),  /* Logitech, Inc. iTouch Composite keboard */
  1744 
  1745         MAKE_VIDPID(0x04d9, 0xa0df),  /* Tek Syndicate Mouse (E-Signal USB Gaming Mouse) */
  1746 
  1747         /* List of Wacom devices at: http://linuxwacom.sourceforge.net/wiki/index.php/Device_IDs */
  1748         MAKE_VIDPID(0x056a, 0x0010),  /* Wacom ET-0405 Graphire */
  1749         MAKE_VIDPID(0x056a, 0x0011),  /* Wacom ET-0405A Graphire2 (4x5) */
  1750         MAKE_VIDPID(0x056a, 0x0012),  /* Wacom ET-0507A Graphire2 (5x7) */
  1751         MAKE_VIDPID(0x056a, 0x0013),  /* Wacom CTE-430 Graphire3 (4x5) */
  1752         MAKE_VIDPID(0x056a, 0x0014),  /* Wacom CTE-630 Graphire3 (6x8) */
  1753         MAKE_VIDPID(0x056a, 0x0015),  /* Wacom CTE-440 Graphire4 (4x5) */
  1754         MAKE_VIDPID(0x056a, 0x0016),  /* Wacom CTE-640 Graphire4 (6x8) */
  1755         MAKE_VIDPID(0x056a, 0x0017),  /* Wacom CTE-450 Bamboo Fun (4x5) */
  1756         MAKE_VIDPID(0x056a, 0x0018),  /* Wacom CTE-650 Bamboo Fun 6x8 */
  1757         MAKE_VIDPID(0x056a, 0x0019),  /* Wacom CTE-631 Bamboo One */
  1758         MAKE_VIDPID(0x056a, 0x00d1),  /* Wacom Bamboo Pen and Touch CTH-460 */
  1759         MAKE_VIDPID(0x056a, 0x030e),  /* Wacom Intuos Pen (S) CTL-480 */
  1760 
  1761         MAKE_VIDPID(0x09da, 0x054f),  /* A4 Tech Co., G7 750 mouse */
  1762         MAKE_VIDPID(0x09da, 0x1410),  /* A4 Tech Co., Ltd Bloody AL9 mouse */
  1763         MAKE_VIDPID(0x09da, 0x3043),  /* A4 Tech Co., Ltd Bloody R8A Gaming Mouse */
  1764         MAKE_VIDPID(0x09da, 0x31b5),  /* A4 Tech Co., Ltd Bloody TL80 Terminator Laser Gaming Mouse */
  1765         MAKE_VIDPID(0x09da, 0x3997),  /* A4 Tech Co., Ltd Bloody RT7 Terminator Wireless */
  1766         MAKE_VIDPID(0x09da, 0x3f8b),  /* A4 Tech Co., Ltd Bloody V8 mouse */
  1767         MAKE_VIDPID(0x09da, 0x51f4),  /* Modecom MC-5006 Keyboard */
  1768         MAKE_VIDPID(0x09da, 0x5589),  /* A4 Tech Co., Ltd Terminator TL9 Laser Gaming Mouse */
  1769         MAKE_VIDPID(0x09da, 0x7b22),  /* A4 Tech Co., Ltd Bloody V5 */
  1770         MAKE_VIDPID(0x09da, 0x7f2d),  /* A4 Tech Co., Ltd Bloody R3 mouse */
  1771         MAKE_VIDPID(0x09da, 0x8090),  /* A4 Tech Co., Ltd X-718BK Oscar Optical Gaming Mouse */
  1772         MAKE_VIDPID(0x09da, 0x9033),  /* A4 Tech Co., X7 X-705K */
  1773         MAKE_VIDPID(0x09da, 0x9066),  /* A4 Tech Co., Sharkoon Fireglider Optical */
  1774         MAKE_VIDPID(0x09da, 0x9090),  /* A4 Tech Co., Ltd XL-730K / XL-750BK / XL-755BK Laser Mouse */
  1775         MAKE_VIDPID(0x09da, 0x90c0),  /* A4 Tech Co., Ltd X7 G800V keyboard */
  1776         MAKE_VIDPID(0x09da, 0xf012),  /* A4 Tech Co., Ltd Bloody V7 mouse */
  1777         MAKE_VIDPID(0x09da, 0xf32a),  /* A4 Tech Co., Ltd Bloody B540 keyboard */
  1778         MAKE_VIDPID(0x09da, 0xf613),  /* A4 Tech Co., Ltd Bloody V2 mouse */
  1779         MAKE_VIDPID(0x09da, 0xf624),  /* A4 Tech Co., Ltd Bloody B120 Keyboard */
  1780 
  1781         MAKE_VIDPID(0x1b1c, 0x1b3c),  /* Corsair Harpoon RGB gaming mouse */
  1782 
  1783         MAKE_VIDPID(0x1d57, 0xad03),  /* [T3] 2.4GHz and IR Air Mouse Remote Control */
  1784 
  1785         MAKE_VIDPID(0x1e7d, 0x2e4a),  /* Roccat Tyon Mouse */
  1786 
  1787         MAKE_VIDPID(0x20a0, 0x422d),  /* Winkeyless.kr Keyboards */
  1788 
  1789         MAKE_VIDPID(0x2516, 0x001f),  /* Cooler Master Storm Mizar Mouse */
  1790         MAKE_VIDPID(0x2516, 0x0028),  /* Cooler Master Storm Alcor Mouse */
  1791     };
  1792 
  1793     unsigned int i;
  1794     Uint32 id;
  1795     Uint16 vendor;
  1796     Uint16 product;
  1797 
  1798     SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL);
  1799 
  1800     /* Check the joystick blacklist */
  1801     id = MAKE_VIDPID(vendor, product);
  1802     for (i = 0; i < SDL_arraysize(joystick_blacklist); ++i) {
  1803         if (id == joystick_blacklist[i]) {
  1804             return SDL_TRUE;
  1805         }
  1806     }
  1807 
  1808     if (SDL_GetJoystickGameControllerType(name, vendor, product, -1, 0, 0, 0) == SDL_CONTROLLER_TYPE_PS4 && SDL_IsPS4RemapperRunning()) {
  1809         return SDL_TRUE;
  1810     }
  1811 
  1812     if (SDL_IsGameControllerNameAndGUID(name, guid) &&
  1813         SDL_ShouldIgnoreGameController(name, guid)) {
  1814         return SDL_TRUE;
  1815     }
  1816 
  1817     return SDL_FALSE;
  1818 }
  1819 
  1820 /* return the guid for this index */
  1821 SDL_JoystickGUID SDL_JoystickGetDeviceGUID(int device_index)
  1822 {
  1823     SDL_JoystickDriver *driver;
  1824     SDL_JoystickGUID guid;
  1825 
  1826     SDL_LockJoysticks();
  1827     if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) {
  1828         guid = driver->GetDeviceGUID(device_index);
  1829     } else {
  1830         SDL_zero(guid);
  1831     }
  1832     SDL_UnlockJoysticks();
  1833 
  1834     return guid;
  1835 }
  1836 
  1837 Uint16 SDL_JoystickGetDeviceVendor(int device_index)
  1838 {
  1839     Uint16 vendor;
  1840     SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
  1841 
  1842     SDL_GetJoystickGUIDInfo(guid, &vendor, NULL, NULL);
  1843     return vendor;
  1844 }
  1845 
  1846 Uint16 SDL_JoystickGetDeviceProduct(int device_index)
  1847 {
  1848     Uint16 product;
  1849     SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
  1850 
  1851     SDL_GetJoystickGUIDInfo(guid, NULL, &product, NULL);
  1852     return product;
  1853 }
  1854 
  1855 Uint16 SDL_JoystickGetDeviceProductVersion(int device_index)
  1856 {
  1857     Uint16 version;
  1858     SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
  1859 
  1860     SDL_GetJoystickGUIDInfo(guid, NULL, NULL, &version);
  1861     return version;
  1862 }
  1863 
  1864 SDL_JoystickType SDL_JoystickGetDeviceType(int device_index)
  1865 {
  1866     SDL_JoystickType type;
  1867     SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
  1868 
  1869     type = SDL_GetJoystickGUIDType(guid);
  1870     if (type == SDL_JOYSTICK_TYPE_UNKNOWN) {
  1871         if (SDL_IsGameController(device_index)) {
  1872             type = SDL_JOYSTICK_TYPE_GAMECONTROLLER;
  1873         }
  1874     }
  1875     return type;
  1876 }
  1877 
  1878 SDL_JoystickID SDL_JoystickGetDeviceInstanceID(int device_index)
  1879 {
  1880     SDL_JoystickDriver *driver;
  1881     SDL_JoystickID instance_id = -1;
  1882 
  1883     SDL_LockJoysticks();
  1884     if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) {
  1885         instance_id = driver->GetDeviceInstanceID(device_index);
  1886     }
  1887     SDL_UnlockJoysticks();
  1888 
  1889     return instance_id;
  1890 }
  1891 
  1892 int SDL_JoystickGetDeviceIndexFromInstanceID(SDL_JoystickID instance_id)
  1893 {
  1894     int i, num_joysticks, device_index = -1;
  1895 
  1896     SDL_LockJoysticks();
  1897     num_joysticks = SDL_NumJoysticks();
  1898     for (i = 0; i < num_joysticks; ++i) {
  1899         if (SDL_JoystickGetDeviceInstanceID(i) == instance_id) {
  1900             device_index = i;
  1901             break;
  1902         }
  1903     }
  1904     SDL_UnlockJoysticks();
  1905 
  1906     return device_index;
  1907 }
  1908 
  1909 SDL_JoystickGUID SDL_JoystickGetGUID(SDL_Joystick * joystick)
  1910 {
  1911     if (!SDL_PrivateJoystickValid(joystick)) {
  1912         SDL_JoystickGUID emptyGUID;
  1913         SDL_zero(emptyGUID);
  1914         return emptyGUID;
  1915     }
  1916     return joystick->guid;
  1917 }
  1918 
  1919 Uint16 SDL_JoystickGetVendor(SDL_Joystick * joystick)
  1920 {
  1921     Uint16 vendor;
  1922     SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
  1923 
  1924     SDL_GetJoystickGUIDInfo(guid, &vendor, NULL, NULL);
  1925     return vendor;
  1926 }
  1927 
  1928 Uint16 SDL_JoystickGetProduct(SDL_Joystick * joystick)
  1929 {
  1930     Uint16 product;
  1931     SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
  1932 
  1933     SDL_GetJoystickGUIDInfo(guid, NULL, &product, NULL);
  1934     return product;
  1935 }
  1936 
  1937 Uint16 SDL_JoystickGetProductVersion(SDL_Joystick * joystick)
  1938 {
  1939     Uint16 version;
  1940     SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
  1941 
  1942     SDL_GetJoystickGUIDInfo(guid, NULL, NULL, &version);
  1943     return version;
  1944 }
  1945 
  1946 SDL_JoystickType SDL_JoystickGetType(SDL_Joystick * joystick)
  1947 {
  1948     SDL_JoystickType type;
  1949     SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
  1950 
  1951     type = SDL_GetJoystickGUIDType(guid);
  1952     if (type == SDL_JOYSTICK_TYPE_UNKNOWN) {
  1953         if (joystick && joystick->is_game_controller) {
  1954             type = SDL_JOYSTICK_TYPE_GAMECONTROLLER;
  1955         }
  1956     }
  1957     return type;
  1958 }
  1959 
  1960 /* convert the guid to a printable string */
  1961 void SDL_JoystickGetGUIDString(SDL_JoystickGUID guid, char *pszGUID, int cbGUID)
  1962 {
  1963     static const char k_rgchHexToASCII[] = "0123456789abcdef";
  1964     int i;
  1965 
  1966     if ((pszGUID == NULL) || (cbGUID <= 0)) {
  1967         return;
  1968     }
  1969 
  1970     for (i = 0; i < sizeof(guid.data) && i < (cbGUID-1)/2; i++) {
  1971         /* each input byte writes 2 ascii chars, and might write a null byte. */
  1972         /* If we don't have room for next input byte, stop */
  1973         unsigned char c = guid.data[i];
  1974 
  1975         *pszGUID++ = k_rgchHexToASCII[c >> 4];
  1976         *pszGUID++ = k_rgchHexToASCII[c & 0x0F];
  1977     }
  1978     *pszGUID = '\0';
  1979 }
  1980 
  1981 /*-----------------------------------------------------------------------------
  1982  * Purpose: Returns the 4 bit nibble for a hex character
  1983  * Input  : c -
  1984  * Output : unsigned char
  1985  *-----------------------------------------------------------------------------*/
  1986 static unsigned char nibble(char c)
  1987 {
  1988     if ((c >= '0') && (c <= '9')) {
  1989         return (unsigned char)(c - '0');
  1990     }
  1991 
  1992     if ((c >= 'A') && (c <= 'F')) {
  1993         return (unsigned char)(c - 'A' + 0x0a);
  1994     }
  1995 
  1996     if ((c >= 'a') && (c <= 'f')) {
  1997         return (unsigned char)(c - 'a' + 0x0a);
  1998     }
  1999 
  2000     /* received an invalid character, and no real way to return an error */
  2001     /* AssertMsg1(false, "Q_nibble invalid hex character '%c' ", c); */
  2002     return 0;
  2003 }
  2004 
  2005 /* convert the string version of a joystick guid to the struct */
  2006 SDL_JoystickGUID SDL_JoystickGetGUIDFromString(const char *pchGUID)
  2007 {
  2008     SDL_JoystickGUID guid;
  2009     int maxoutputbytes= sizeof(guid);
  2010     size_t len = SDL_strlen(pchGUID);
  2011     Uint8 *p;
  2012     size_t i;
  2013 
  2014     /* Make sure it's even */
  2015     len = (len) & ~0x1;
  2016 
  2017     SDL_memset(&guid, 0x00, sizeof(guid));
  2018 
  2019     p = (Uint8 *)&guid;
  2020     for (i = 0; (i < len) && ((p - (Uint8 *)&guid) < maxoutputbytes); i+=2, p++) {
  2021         *p = (nibble(pchGUID[i]) << 4) | nibble(pchGUID[i+1]);
  2022     }
  2023 
  2024     return guid;
  2025 }
  2026 
  2027 /* update the power level for this joystick */
  2028 void SDL_PrivateJoystickBatteryLevel(SDL_Joystick * joystick, SDL_JoystickPowerLevel ePowerLevel)
  2029 {
  2030     joystick->epowerlevel = ePowerLevel;
  2031 }
  2032 
  2033 /* return its power level */
  2034 SDL_JoystickPowerLevel SDL_JoystickCurrentPowerLevel(SDL_Joystick * joystick)
  2035 {
  2036     if (!SDL_PrivateJoystickValid(joystick)) {
  2037         return SDL_JOYSTICK_POWER_UNKNOWN;
  2038     }
  2039     return joystick->epowerlevel;
  2040 }
  2041 
  2042 /* vi: set ts=4 sw=4 expandtab: */