2018-08-09 18:00:17 -05:00
/*
Simple DirectMedia Layer
2023-01-09 11:41:41 -06:00
Copyright ( C ) 1997 - 2023 Sam Lantinga < slouken @ libsdl . org >
2018-08-09 18:00:17 -05:00
This software is provided ' as - is ' , without any express or implied
warranty . In no event will the authors be held liable for any damages
arising from the use of this software .
Permission is granted to anyone to use this software for any purpose ,
including commercial applications , and to alter it and redistribute it
freely , subject to the following restrictions :
1. The origin of this software must not be misrepresented ; you must not
claim that you wrote the original software . If you use this software
in a product , an acknowledgment in the product documentation would be
appreciated but is not required .
2. Altered source versions must be plainly marked as such , and must not be
misrepresented as being the original software .
3. This notice may not be removed or altered from any source distribution .
*/
2022-11-29 20:34:15 -06:00
# include "SDL_internal.h"
2018-08-09 18:00:17 -05:00
# ifdef SDL_JOYSTICK_HIDAPI
# include "../SDL_sysjoystick.h"
# include "SDL_hidapijoystick_c.h"
2020-02-04 17:26:56 -06:00
# include "SDL_hidapi_rumble.h"
2019-11-13 23:53:01 -06:00
# include "../../SDL_hints_c.h"
2018-08-09 18:00:17 -05:00
2022-06-27 12:19:39 -05:00
# if defined(__WIN32__) || defined(__WINGDK__)
2020-03-16 14:23:38 -05:00
# include "../windows/SDL_rawinputjoystick_c.h"
2018-08-15 21:53:22 -05:00
# endif
2022-08-26 05:28:33 -05:00
# ifdef SDL_USE_LIBUDEV
# include "../../core/linux/SDL_sandbox.h"
# endif
2021-02-16 04:50:20 -06:00
2019-06-19 17:54:21 -05:00
struct joystick_hwdata
2018-08-09 18:00:17 -05:00
{
2019-12-19 17:01:30 -06:00
SDL_HIDAPI_Device * device ;
2019-06-19 17:54:21 -05:00
} ;
2018-08-09 18:00:17 -05:00
static SDL_HIDAPI_DeviceDriver * SDL_HIDAPI_drivers [ ] = {
2021-01-23 13:06:35 -06:00
# ifdef SDL_JOYSTICK_HIDAPI_GAMECUBE
& SDL_HIDAPI_DriverGameCube ,
# endif
2021-07-07 08:05:35 -05:00
# ifdef SDL_JOYSTICK_HIDAPI_LUNA
& SDL_HIDAPI_DriverLuna ,
# endif
2022-07-09 22:55:36 -05:00
# ifdef SDL_JOYSTICK_HIDAPI_SHIELD
& SDL_HIDAPI_DriverShield ,
# endif
2022-08-24 00:45:37 -05:00
# ifdef SDL_JOYSTICK_HIDAPI_PS3
& SDL_HIDAPI_DriverPS3 ,
2022-09-23 04:39:35 -05:00
& SDL_HIDAPI_DriverPS3ThirdParty ,
2022-08-24 00:45:37 -05:00
# endif
2018-08-09 18:00:17 -05:00
# ifdef SDL_JOYSTICK_HIDAPI_PS4
& SDL_HIDAPI_DriverPS4 ,
# endif
2020-11-05 19:03:28 -06:00
# ifdef SDL_JOYSTICK_HIDAPI_PS5
& SDL_HIDAPI_DriverPS5 ,
# endif
2021-01-23 13:06:35 -06:00
# ifdef SDL_JOYSTICK_HIDAPI_STADIA
& SDL_HIDAPI_DriverStadia ,
# endif
2018-08-09 18:00:17 -05:00
# ifdef SDL_JOYSTICK_HIDAPI_STEAM
& SDL_HIDAPI_DriverSteam ,
# endif
# ifdef SDL_JOYSTICK_HIDAPI_SWITCH
2022-08-03 15:07:47 -05:00
& SDL_HIDAPI_DriverNintendoClassic ,
& SDL_HIDAPI_DriverJoyCons ,
2018-08-09 18:00:17 -05:00
& SDL_HIDAPI_DriverSwitch ,
# endif
2022-09-01 17:29:01 -05:00
# ifdef SDL_JOYSTICK_HIDAPI_WII
& SDL_HIDAPI_DriverWii ,
# endif
2018-08-09 18:00:17 -05:00
# ifdef SDL_JOYSTICK_HIDAPI_XBOX360
& SDL_HIDAPI_DriverXbox360 ,
2019-12-19 17:01:32 -06:00
& SDL_HIDAPI_DriverXbox360W ,
2018-08-09 18:00:17 -05:00
# endif
# ifdef SDL_JOYSTICK_HIDAPI_XBOXONE
& SDL_HIDAPI_DriverXboxOne ,
# endif
} ;
2019-07-25 17:21:44 -05:00
static int SDL_HIDAPI_numdrivers = 0 ;
2020-01-14 00:05:54 -06:00
static SDL_SpinLock SDL_HIDAPI_spinlock ;
2022-08-19 13:11:23 -05:00
static SDL_bool SDL_HIDAPI_hints_changed = SDL_FALSE ;
2021-11-11 14:45:38 -06:00
static Uint32 SDL_HIDAPI_change_count = 0 ;
2022-12-13 16:03:40 -06:00
static SDL_HIDAPI_Device * SDL_HIDAPI_devices SDL_GUARDED_BY ( SDL_joystick_lock ) ;
2018-08-09 18:00:17 -05:00
static int SDL_HIDAPI_numjoysticks = 0 ;
2022-07-28 21:22:27 -05:00
static SDL_bool SDL_HIDAPI_combine_joycons = SDL_TRUE ;
2019-07-31 11:14:48 -05:00
static SDL_bool initialized = SDL_FALSE ;
2019-12-19 17:01:30 -06:00
static SDL_bool shutting_down = SDL_FALSE ;
2021-02-22 06:32:42 -06:00
2022-11-30 14:51:59 -06:00
void HIDAPI_DumpPacket ( const char * prefix , const Uint8 * data , int size )
2020-11-06 13:30:52 -06:00
{
int i ;
char * buffer ;
2022-11-30 14:51:59 -06:00
size_t length = SDL_strlen ( prefix ) + 11 * ( USB_PACKET_LENGTH / 8 ) + ( 5 * USB_PACKET_LENGTH * 2 ) + 1 + 1 ;
2020-11-13 15:17:07 -06:00
int start = 0 , amount = size ;
2023-01-03 17:12:47 -06:00
size_t current_len ;
2020-11-06 13:30:52 -06:00
buffer = ( char * ) SDL_malloc ( length ) ;
2023-01-03 17:12:47 -06:00
current_len = SDL_snprintf ( buffer , length , prefix , size ) ;
2022-11-30 14:51:59 -06:00
for ( i = start ; i < start + amount ; + + i ) {
2020-11-06 13:30:52 -06:00
if ( ( i % 8 ) = = 0 ) {
2023-01-03 17:12:47 -06:00
current_len + = SDL_snprintf ( & buffer [ current_len ] , length - current_len , " \n %.2d: " , i ) ;
2020-11-06 13:30:52 -06:00
}
2023-01-03 17:12:47 -06:00
current_len + = SDL_snprintf ( & buffer [ current_len ] , length - current_len , " 0x%.2x " , data [ i ] ) ;
2020-11-06 13:30:52 -06:00
}
SDL_strlcat ( buffer , " \n " , length ) ;
SDL_Log ( " %s " , buffer ) ;
SDL_free ( buffer ) ;
}
2022-11-30 14:51:59 -06:00
float HIDAPI_RemapVal ( float val , float val_min , float val_max , float output_min , float output_max )
2021-01-23 13:21:01 -06:00
{
return output_min + ( output_max - output_min ) * ( val - val_min ) / ( val_max - val_min ) ;
}
2022-08-19 13:11:23 -05:00
static void HIDAPI_UpdateDeviceList ( void ) ;
2021-07-08 15:22:41 -05:00
static void HIDAPI_JoystickClose ( SDL_Joystick * joystick ) ;
2019-12-19 17:01:30 -06:00
2022-12-27 11:46:24 -06:00
static SDL_GamepadType SDL_GetJoystickGameControllerProtocol ( const char * name , Uint16 vendor , Uint16 product , int interface_number , int interface_class , int interface_subclass , int interface_protocol )
2022-06-15 22:44:43 -05:00
{
static const int LIBUSB_CLASS_VENDOR_SPEC = 0xFF ;
static const int XB360_IFACE_SUBCLASS = 93 ;
2022-11-30 14:51:59 -06:00
static const int XB360_IFACE_PROTOCOL = 1 ; /* Wired */
2022-06-15 22:44:43 -05:00
static const int XB360W_IFACE_PROTOCOL = 129 ; /* Wireless */
static const int XBONE_IFACE_SUBCLASS = 71 ;
static const int XBONE_IFACE_PROTOCOL = 208 ;
2022-12-27 11:46:24 -06:00
SDL_GamepadType type = SDL_GAMEPAD_TYPE_UNKNOWN ;
2022-06-15 22:44:43 -05:00
/* This code should match the checks in libusb/hid.c and HIDDeviceManager.java */
if ( interface_class = = LIBUSB_CLASS_VENDOR_SPEC & &
interface_subclass = = XB360_IFACE_SUBCLASS & &
( interface_protocol = = XB360_IFACE_PROTOCOL | |
interface_protocol = = XB360W_IFACE_PROTOCOL ) ) {
static const int SUPPORTED_VENDORS [ ] = {
0x0079 , /* GPD Win 2 */
0x044f , /* Thrustmaster */
0x045e , /* Microsoft */
0x046d , /* Logitech */
0x056e , /* Elecom */
0x06a3 , /* Saitek */
0x0738 , /* Mad Catz */
0x07ff , /* Mad Catz */
0x0e6f , /* PDP */
0x0f0d , /* Hori */
0x1038 , /* SteelSeries */
0x11c9 , /* Nacon */
0x12ab , /* Unknown */
0x1430 , /* RedOctane */
0x146b , /* BigBen */
0x1532 , /* Razer */
0x15e4 , /* Numark */
0x162e , /* Joytech */
0x1689 , /* Razer Onza */
0x1949 , /* Lab126, Inc. */
0x1bad , /* Harmonix */
0x20d6 , /* PowerA */
0x24c6 , /* PowerA */
0x2c22 , /* Qanba */
2022-11-28 15:47:30 -06:00
0x2dc8 , /* 8BitDo */
2022-06-15 22:44:43 -05:00
} ;
int i ;
for ( i = 0 ; i < SDL_arraysize ( SUPPORTED_VENDORS ) ; + + i ) {
if ( vendor = = SUPPORTED_VENDORS [ i ] ) {
2022-12-27 11:46:24 -06:00
type = SDL_GAMEPAD_TYPE_XBOX360 ;
2022-06-15 22:44:43 -05:00
break ;
}
}
}
if ( interface_number = = 0 & &
interface_class = = LIBUSB_CLASS_VENDOR_SPEC & &
interface_subclass = = XBONE_IFACE_SUBCLASS & &
interface_protocol = = XBONE_IFACE_PROTOCOL ) {
static const int SUPPORTED_VENDORS [ ] = {
2023-01-03 17:12:18 -06:00
0x044f , /* Thrustmaster */
2022-06-15 22:44:43 -05:00
0x045e , /* Microsoft */
0x0738 , /* Mad Catz */
0x0e6f , /* PDP */
0x0f0d , /* Hori */
2023-02-06 22:14:12 -06:00
0x10f5 , /* Turtle Beach */
2022-06-15 22:44:43 -05:00
0x1532 , /* Razer */
0x20d6 , /* PowerA */
0x24c6 , /* PowerA */
2022-07-20 13:05:55 -05:00
0x2dc8 , /* 8BitDo */
2022-06-15 22:44:43 -05:00
0x2e24 , /* Hyperkin */
} ;
int i ;
for ( i = 0 ; i < SDL_arraysize ( SUPPORTED_VENDORS ) ; + + i ) {
if ( vendor = = SUPPORTED_VENDORS [ i ] ) {
2022-12-27 11:46:24 -06:00
type = SDL_GAMEPAD_TYPE_XBOXONE ;
2022-06-15 22:44:43 -05:00
break ;
}
}
}
2022-12-27 11:46:24 -06:00
if ( type = = SDL_GAMEPAD_TYPE_UNKNOWN ) {
type = SDL_GetGamepadTypeFromVIDPID ( vendor , product , name , SDL_FALSE ) ;
2022-06-15 22:44:43 -05:00
}
return type ;
}
2022-11-30 14:51:59 -06:00
static SDL_bool HIDAPI_IsDeviceSupported ( Uint16 vendor_id , Uint16 product_id , Uint16 version , const char * name )
2018-08-09 18:04:30 -05:00
{
int i ;
2022-12-27 11:46:24 -06:00
SDL_GamepadType type = SDL_GetJoystickGameControllerProtocol ( name , vendor_id , product_id , - 1 , 0 , 0 , 0 ) ;
2018-08-09 18:04:30 -05:00
for ( i = 0 ; i < SDL_arraysize ( SDL_HIDAPI_drivers ) ; + + i ) {
SDL_HIDAPI_DeviceDriver * driver = SDL_HIDAPI_drivers [ i ] ;
2022-08-30 16:56:11 -05:00
if ( driver - > enabled & & driver - > IsSupportedDevice ( NULL , name , type , vendor_id , product_id , version , - 1 , 0 , 0 , 0 ) ) {
2018-08-09 18:04:30 -05:00
return SDL_TRUE ;
}
}
return SDL_FALSE ;
}
2022-11-30 14:51:59 -06:00
static SDL_HIDAPI_DeviceDriver * HIDAPI_GetDeviceDriver ( SDL_HIDAPI_Device * device )
2018-08-09 18:00:17 -05:00
{
2018-08-31 20:10:21 -05:00
const Uint16 USAGE_PAGE_GENERIC_DESKTOP = 0x0001 ;
const Uint16 USAGE_JOYSTICK = 0x0004 ;
const Uint16 USAGE_GAMEPAD = 0x0005 ;
const Uint16 USAGE_MULTIAXISCONTROLLER = 0x0008 ;
2018-08-09 18:00:17 -05:00
int i ;
2022-05-19 18:49:47 -05:00
2022-07-28 21:22:27 -05:00
if ( device - > num_children > 0 ) {
return & SDL_HIDAPI_DriverCombined ;
}
2022-05-19 18:49:47 -05:00
if ( SDL_ShouldIgnoreJoystick ( device - > name , device - > guid ) ) {
2018-08-09 18:00:17 -05:00
return NULL ;
}
2020-12-03 20:17:03 -06:00
if ( device - > vendor_id ! = USB_VENDOR_VALVE ) {
2020-03-20 23:05:07 -05:00
if ( device - > usage_page & & device - > usage_page ! = USAGE_PAGE_GENERIC_DESKTOP ) {
return NULL ;
}
if ( device - > usage & & device - > usage ! = USAGE_JOYSTICK & & device - > usage ! = USAGE_GAMEPAD & & device - > usage ! = USAGE_MULTIAXISCONTROLLER ) {
return NULL ;
}
2018-08-31 20:10:21 -05:00
}
2018-08-09 18:00:17 -05:00
for ( i = 0 ; i < SDL_arraysize ( SDL_HIDAPI_drivers ) ; + + i ) {
SDL_HIDAPI_DeviceDriver * driver = SDL_HIDAPI_drivers [ i ] ;
2022-09-23 01:42:25 -05:00
if ( driver - > enabled & & driver - > IsSupportedDevice ( device , device - > name , device - > type , device - > vendor_id , device - > product_id , device - > version , device - > interface_number , device - > interface_class , device - > interface_subclass , device - > interface_protocol ) ) {
2018-08-09 18:00:17 -05:00
return driver ;
}
}
return NULL ;
}
2022-11-30 14:51:59 -06:00
static SDL_HIDAPI_Device * HIDAPI_GetDeviceByIndex ( int device_index , SDL_JoystickID * pJoystickID )
2018-08-09 18:00:17 -05:00
{
2022-07-28 21:22:27 -05:00
SDL_HIDAPI_Device * device ;
2022-12-13 16:03:40 -06:00
SDL_AssertJoysticksLocked ( ) ;
2022-07-28 21:22:27 -05:00
for ( device = SDL_HIDAPI_devices ; device ; device = device - > next ) {
if ( device - > parent ) {
continue ;
}
2018-08-09 18:00:17 -05:00
if ( device - > driver ) {
2019-12-19 17:01:30 -06:00
if ( device_index < device - > num_joysticks ) {
if ( pJoystickID ) {
* pJoystickID = device - > joysticks [ device_index ] ;
}
return device ;
2018-08-09 18:00:17 -05:00
}
2019-12-19 17:01:30 -06:00
device_index - = device - > num_joysticks ;
2018-08-09 18:00:17 -05:00
}
}
2019-12-19 17:01:30 -06:00
return NULL ;
2018-08-09 18:00:17 -05:00
}
2022-11-30 14:51:59 -06:00
static SDL_HIDAPI_Device * HIDAPI_GetJoystickByInfo ( const char * path , Uint16 vendor_id , Uint16 product_id )
2018-08-09 18:00:17 -05:00
{
2022-07-28 21:22:27 -05:00
SDL_HIDAPI_Device * device ;
2022-12-13 16:03:40 -06:00
SDL_AssertJoysticksLocked ( ) ;
2022-07-28 21:22:27 -05:00
for ( device = SDL_HIDAPI_devices ; device ; device = device - > next ) {
2018-08-09 18:00:17 -05:00
if ( device - > vendor_id = = vendor_id & & device - > product_id = = product_id & &
SDL_strcmp ( device - > path , path ) = = 0 ) {
break ;
}
}
return device ;
}
2022-11-30 14:51:59 -06:00
static void HIDAPI_CleanupDeviceDriver ( SDL_HIDAPI_Device * device )
2022-07-28 21:22:27 -05:00
{
if ( ! device - > driver ) {
return ; /* Already cleaned up */
}
/* Disconnect any joysticks */
while ( device - > num_joysticks & & device - > joysticks ) {
HIDAPI_JoystickDisconnected ( device , device - > joysticks [ 0 ] ) ;
}
device - > driver - > FreeDevice ( device ) ;
device - > driver = NULL ;
2022-09-22 20:22:17 -05:00
SDL_LockMutex ( device - > dev_lock ) ;
{
if ( device - > dev ) {
SDL_hid_close ( device - > dev ) ;
device - > dev = NULL ;
}
if ( device - > context ) {
SDL_free ( device - > context ) ;
device - > context = NULL ;
}
}
SDL_UnlockMutex ( device - > dev_lock ) ;
2022-07-28 21:22:27 -05:00
}
2022-12-13 16:03:40 -06:00
static void HIDAPI_SetupDeviceDriver ( SDL_HIDAPI_Device * device , SDL_bool * removed ) SDL_NO_THREAD_SAFETY_ANALYSIS /* We unlock the joystick lock to be able to open the HID device on Android */
2019-12-19 17:01:30 -06:00
{
2022-10-06 20:23:07 -05:00
* removed = SDL_FALSE ;
2019-12-19 17:01:30 -06:00
if ( device - > driver ) {
2022-07-28 21:22:27 -05:00
SDL_bool enabled ;
2022-08-08 10:22:20 -05:00
if ( device - > vendor_id = = USB_VENDOR_NINTENDO & & device - > product_id = = USB_PRODUCT_NINTENDO_SWITCH_JOYCON_PAIR ) {
2022-07-28 21:22:27 -05:00
enabled = SDL_HIDAPI_combine_joycons ;
} else {
enabled = device - > driver - > enabled ;
}
2022-08-03 15:18:00 -05:00
if ( device - > children ) {
int i ;
for ( i = 0 ; i < device - > num_children ; + + i ) {
SDL_HIDAPI_Device * child = device - > children [ i ] ;
if ( ! child - > driver | | ! child - > driver - > enabled ) {
enabled = SDL_FALSE ;
break ;
}
}
}
2022-07-28 21:22:27 -05:00
if ( ! enabled ) {
HIDAPI_CleanupDeviceDriver ( device ) ;
}
2021-11-13 02:50:02 -06:00
return ; /* Already setup */
2019-12-19 17:01:30 -06:00
}
2022-10-07 13:29:49 -05:00
if ( HIDAPI_GetDeviceDriver ( device ) ) {
/* We might have a device driver for this device, try opening it and see */
if ( device - > num_children = = 0 ) {
/* On Android we need to leave joysticks unlocked because it calls
* out to the main thread for permissions and the main thread can
* be in the process of handling controller input .
*
* See https : //github.com/libsdl-org/SDL/issues/6347 for details
*/
2022-10-17 13:10:53 -05:00
int lock_count = 0 ;
2022-10-07 13:29:49 -05:00
SDL_HIDAPI_Device * curr ;
SDL_hid_device * dev ;
2022-10-17 13:10:53 -05:00
char * path = SDL_strdup ( device - > path ) ;
2022-10-07 13:29:49 -05:00
2022-11-03 14:37:54 -05:00
/* Wait a little bit for the device to initialize */
SDL_Delay ( 10 ) ;
2022-10-07 13:29:49 -05:00
SDL_AssertJoysticksLocked ( ) ;
2022-10-17 13:10:53 -05:00
while ( SDL_JoysticksLocked ( ) ) {
+ + lock_count ;
SDL_UnlockJoysticks ( ) ;
}
2022-11-03 14:37:54 -05:00
dev = SDL_hid_open_path ( path , 0 ) ;
2022-10-17 13:10:53 -05:00
while ( lock_count > 0 ) {
- - lock_count ;
SDL_LockJoysticks ( ) ;
}
2022-10-07 13:29:49 -05:00
SDL_free ( path ) ;
/* Make sure the device didn't get removed while opening the HID path */
for ( curr = SDL_HIDAPI_devices ; curr & & curr ! = device ; curr = curr - > next ) {
}
2022-11-27 10:38:43 -06:00
if ( curr = = NULL ) {
2022-10-07 13:29:49 -05:00
* removed = SDL_TRUE ;
if ( dev ) {
SDL_hid_close ( dev ) ;
}
return ;
2022-10-06 20:23:07 -05:00
}
2022-11-27 10:38:43 -06:00
if ( dev = = NULL ) {
2022-10-07 13:29:49 -05:00
SDL_LogDebug ( SDL_LOG_CATEGORY_INPUT ,
" HIDAPI_SetupDeviceDriver() couldn't open %s: %s \n " ,
device - > path , SDL_GetError ( ) ) ;
return ;
}
SDL_hid_set_nonblocking ( dev , 1 ) ;
2022-10-06 20:23:07 -05:00
2022-10-07 13:29:49 -05:00
device - > dev = dev ;
}
2022-09-22 20:22:17 -05:00
2022-10-07 13:29:49 -05:00
device - > driver = HIDAPI_GetDeviceDriver ( device ) ;
2019-12-19 17:01:30 -06:00
2022-10-07 13:29:49 -05:00
/* Initialize the device, which may cause a connected event */
if ( device - > driver & & ! device - > driver - > InitDevice ( device ) ) {
HIDAPI_CleanupDeviceDriver ( device ) ;
}
2022-09-22 20:22:17 -05:00
2022-10-07 13:29:49 -05:00
if ( ! device - > driver & & device - > dev ) {
/* No driver claimed this device, go ahead and close it */
SDL_hid_close ( device - > dev ) ;
device - > dev = NULL ;
}
2019-12-19 17:01:30 -06:00
}
}
2022-11-30 14:51:59 -06:00
static void SDL_HIDAPI_UpdateDrivers ( void )
2018-08-09 18:00:17 -05:00
{
int i ;
2020-01-26 12:32:39 -06:00
SDL_HIDAPI_Device * device ;
2022-10-06 20:23:07 -05:00
SDL_bool removed ;
2018-08-09 18:00:17 -05:00
2022-12-13 16:03:40 -06:00
SDL_AssertJoysticksLocked ( ) ;
2019-07-25 17:21:44 -05:00
SDL_HIDAPI_numdrivers = 0 ;
for ( i = 0 ; i < SDL_arraysize ( SDL_HIDAPI_drivers ) ; + + i ) {
SDL_HIDAPI_DeviceDriver * driver = SDL_HIDAPI_drivers [ i ] ;
2022-08-19 13:11:23 -05:00
driver - > enabled = driver - > IsEnabled ( ) ;
if ( driver - > enabled & & driver ! = & SDL_HIDAPI_DriverCombined ) {
2019-07-25 17:21:44 -05:00
+ + SDL_HIDAPI_numdrivers ;
}
}
2022-10-06 20:23:07 -05:00
removed = SDL_FALSE ;
do {
for ( device = SDL_HIDAPI_devices ; device ; device = device - > next ) {
HIDAPI_SetupDeviceDriver ( device , & removed ) ;
if ( removed ) {
break ;
}
}
} while ( removed ) ;
2022-08-19 13:11:23 -05:00
}
2018-08-09 18:00:17 -05:00
2022-11-30 14:51:59 -06:00
static void SDLCALL SDL_HIDAPIDriverHintChanged ( void * userdata , const char * name , const char * oldValue , const char * hint )
2022-08-19 13:11:23 -05:00
{
if ( SDL_strcmp ( name , SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS ) = = 0 ) {
SDL_HIDAPI_combine_joycons = SDL_GetStringBoolean ( hint , SDL_TRUE ) ;
}
SDL_HIDAPI_hints_changed = SDL_TRUE ;
2022-07-28 21:22:27 -05:00
SDL_HIDAPI_change_count = 0 ;
2019-12-19 17:01:30 -06:00
}
2018-08-09 18:00:17 -05:00
2022-11-30 14:51:59 -06:00
static int HIDAPI_JoystickInit ( void )
2018-08-09 18:00:17 -05:00
{
int i ;
2019-07-31 11:14:48 -05:00
if ( initialized ) {
return 0 ;
}
2021-02-16 04:50:20 -06:00
# if defined(SDL_USE_LIBUDEV)
if ( linux_enumeration_method = = ENUMERATION_UNSET ) {
if ( SDL_getenv ( " SDL_HIDAPI_JOYSTICK_DISABLE_UDEV " ) ! = NULL ) {
SDL_LogDebug ( SDL_LOG_CATEGORY_INPUT ,
" udev disabled by SDL_HIDAPI_JOYSTICK_DISABLE_UDEV " ) ;
linux_enumeration_method = ENUMERATION_FALLBACK ;
2022-08-26 05:28:33 -05:00
} else if ( SDL_DetectSandbox ( ) ! = SDL_SANDBOX_NONE ) {
2021-02-16 07:13:30 -06:00
SDL_LogDebug ( SDL_LOG_CATEGORY_INPUT ,
" Container detected, disabling HIDAPI udev integration " ) ;
linux_enumeration_method = ENUMERATION_FALLBACK ;
2021-02-16 04:50:20 -06:00
} else {
SDL_LogDebug ( SDL_LOG_CATEGORY_INPUT ,
" Using udev for HIDAPI joystick device discovery " ) ;
linux_enumeration_method = ENUMERATION_LIBUDEV ;
}
}
# endif
2021-11-08 00:58:44 -06:00
if ( SDL_hid_init ( ) < 0 ) {
2022-01-17 10:22:30 -06:00
return SDL_SetError ( " Couldn't initialize hidapi " ) ;
2018-08-09 18:00:17 -05:00
}
for ( i = 0 ; i < SDL_arraysize ( SDL_HIDAPI_drivers ) ; + + i ) {
SDL_HIDAPI_DeviceDriver * driver = SDL_HIDAPI_drivers [ i ] ;
2022-08-19 13:11:23 -05:00
driver - > RegisterHints ( SDL_HIDAPIDriverHintChanged , driver ) ;
2018-08-09 18:00:17 -05:00
}
2022-08-03 15:07:47 -05:00
SDL_AddHintCallback ( SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS ,
2022-07-28 21:22:27 -05:00
SDL_HIDAPIDriverHintChanged , NULL ) ;
2018-08-09 18:00:17 -05:00
SDL_AddHintCallback ( SDL_HINT_JOYSTICK_HIDAPI ,
SDL_HIDAPIDriverHintChanged , NULL ) ;
2022-08-19 13:11:23 -05:00
SDL_HIDAPI_change_count = SDL_hid_device_change_count ( ) ;
HIDAPI_UpdateDeviceList ( ) ;
2019-12-19 17:01:35 -06:00
HIDAPI_UpdateDevices ( ) ;
2019-07-31 11:14:48 -05:00
initialized = SDL_TRUE ;
2018-08-09 18:00:17 -05:00
return 0 ;
}
2022-11-30 14:51:59 -06:00
static SDL_bool HIDAPI_AddJoystickInstanceToDevice ( SDL_HIDAPI_Device * device , SDL_JoystickID joystickID )
2019-12-19 17:01:30 -06:00
{
2022-11-30 14:51:59 -06:00
SDL_JoystickID * joysticks = ( SDL_JoystickID * ) SDL_realloc ( device - > joysticks , ( device - > num_joysticks + 1 ) * sizeof ( * device - > joysticks ) ) ;
2022-11-27 10:38:43 -06:00
if ( joysticks = = NULL ) {
2019-12-19 17:01:30 -06:00
return SDL_FALSE ;
}
device - > joysticks = joysticks ;
device - > joysticks [ device - > num_joysticks + + ] = joystickID ;
2022-07-28 21:22:27 -05:00
return SDL_TRUE ;
}
2022-11-30 14:51:59 -06:00
static SDL_bool HIDAPI_DelJoystickInstanceFromDevice ( SDL_HIDAPI_Device * device , SDL_JoystickID joystickID )
2022-07-28 21:22:27 -05:00
{
int i , size ;
for ( i = 0 ; i < device - > num_joysticks ; + + i ) {
if ( device - > joysticks [ i ] = = joystickID ) {
size = ( device - > num_joysticks - i - 1 ) * sizeof ( SDL_JoystickID ) ;
2022-11-30 14:51:59 -06:00
SDL_memmove ( & device - > joysticks [ i ] , & device - > joysticks [ i + 1 ] , size ) ;
2022-07-28 21:22:27 -05:00
- - device - > num_joysticks ;
if ( device - > num_joysticks = = 0 ) {
SDL_free ( device - > joysticks ) ;
device - > joysticks = NULL ;
}
return SDL_TRUE ;
}
}
return SDL_FALSE ;
}
2022-11-30 14:51:59 -06:00
static SDL_bool HIDAPI_JoystickInstanceIsUnique ( SDL_HIDAPI_Device * device , SDL_JoystickID joystickID )
2022-07-28 21:22:27 -05:00
{
if ( device - > parent & & device - > num_joysticks = = 1 & & device - > parent - > num_joysticks = = 1 & &
device - > joysticks [ 0 ] = = device - > parent - > joysticks [ 0 ] ) {
return SDL_FALSE ;
}
return SDL_TRUE ;
}
2022-11-30 14:51:59 -06:00
void HIDAPI_SetDeviceName ( SDL_HIDAPI_Device * device , const char * name )
2022-09-22 20:22:17 -05:00
{
if ( name & & * name & & SDL_strcmp ( name , device - > name ) ! = 0 ) {
SDL_free ( device - > name ) ;
device - > name = SDL_strdup ( name ) ;
SDL_SetJoystickGUIDCRC ( & device - > guid , SDL_crc16 ( 0 , name , SDL_strlen ( name ) ) ) ;
}
}
2022-11-30 14:51:59 -06:00
void HIDAPI_SetDeviceProduct ( SDL_HIDAPI_Device * device , Uint16 product_id )
2022-09-22 20:22:17 -05:00
{
/* Don't set the device product ID directly, or we'll constantly re-enumerate this device */
SDL_SetJoystickGUIDProduct ( & device - > guid , product_id ) ;
}
2022-11-30 14:51:59 -06:00
void HIDAPI_SetDeviceSerial ( SDL_HIDAPI_Device * device , const char * serial )
2022-09-22 20:22:17 -05:00
{
if ( serial & & * serial & & ( ! device - > serial | | SDL_strcmp ( serial , device - > serial ) ! = 0 ) ) {
SDL_free ( device - > serial ) ;
device - > serial = SDL_strdup ( serial ) ;
}
}
2022-09-26 16:20:34 -05:00
SDL_bool
HIDAPI_HasConnectedUSBDevice ( const char * serial )
{
SDL_HIDAPI_Device * device ;
2022-12-13 16:03:40 -06:00
SDL_AssertJoysticksLocked ( ) ;
2022-11-27 10:38:43 -06:00
if ( serial = = NULL ) {
2022-09-26 22:53:50 -05:00
return SDL_FALSE ;
}
2022-09-26 16:20:34 -05:00
for ( device = SDL_HIDAPI_devices ; device ; device = device - > next ) {
2022-09-26 16:39:51 -05:00
if ( ! device - > driver ) {
continue ;
}
2022-09-26 16:20:34 -05:00
if ( device - > is_bluetooth ) {
continue ;
}
if ( device - > serial & & SDL_strcmp ( serial , device - > serial ) = = 0 ) {
return SDL_TRUE ;
}
}
return SDL_FALSE ;
}
2022-11-30 14:51:59 -06:00
void HIDAPI_DisconnectBluetoothDevice ( const char * serial )
2022-09-26 16:20:34 -05:00
{
SDL_HIDAPI_Device * device ;
2022-12-13 16:03:40 -06:00
SDL_AssertJoysticksLocked ( ) ;
2022-11-27 10:38:43 -06:00
if ( serial = = NULL ) {
2022-09-26 22:53:50 -05:00
return ;
}
2022-09-26 16:20:34 -05:00
for ( device = SDL_HIDAPI_devices ; device ; device = device - > next ) {
2022-09-26 16:39:51 -05:00
if ( ! device - > driver ) {
continue ;
}
2022-09-26 16:20:34 -05:00
if ( ! device - > is_bluetooth ) {
continue ;
}
if ( device - > serial & & SDL_strcmp ( serial , device - > serial ) = = 0 ) {
while ( device - > num_joysticks & & device - > joysticks ) {
HIDAPI_JoystickDisconnected ( device , device - > joysticks [ 0 ] ) ;
}
}
}
}
2022-07-28 21:22:27 -05:00
SDL_bool
HIDAPI_JoystickConnected ( SDL_HIDAPI_Device * device , SDL_JoystickID * pJoystickID )
{
int i , j ;
SDL_JoystickID joystickID ;
2022-12-13 16:03:40 -06:00
SDL_AssertJoysticksLocked ( ) ;
2022-07-28 21:22:27 -05:00
for ( i = 0 ; i < device - > num_children ; + + i ) {
SDL_HIDAPI_Device * child = device - > children [ i ] ;
2022-11-30 14:51:59 -06:00
for ( j = child - > num_joysticks ; j - - ; ) {
2022-07-28 21:22:27 -05:00
HIDAPI_JoystickDisconnected ( child , child - > joysticks [ j ] ) ;
}
}
joystickID = SDL_GetNextJoystickInstanceID ( ) ;
HIDAPI_AddJoystickInstanceToDevice ( device , joystickID ) ;
for ( i = 0 ; i < device - > num_children ; + + i ) {
SDL_HIDAPI_Device * child = device - > children [ i ] ;
HIDAPI_AddJoystickInstanceToDevice ( child , joystickID ) ;
}
2020-11-23 20:24:05 -06:00
+ + SDL_HIDAPI_numjoysticks ;
2019-12-19 17:01:30 -06:00
SDL_PrivateJoystickAdded ( joystickID ) ;
if ( pJoystickID ) {
* pJoystickID = joystickID ;
}
return SDL_TRUE ;
}
2022-11-30 14:51:59 -06:00
void HIDAPI_JoystickDisconnected ( SDL_HIDAPI_Device * device , SDL_JoystickID joystickID )
2019-12-19 17:01:30 -06:00
{
2022-07-28 21:22:27 -05:00
int i , j ;
2022-11-30 14:51:59 -06:00
2022-08-15 19:27:33 -05:00
SDL_LockJoysticks ( ) ;
2022-07-28 21:22:27 -05:00
2022-08-15 19:27:33 -05:00
if ( ! HIDAPI_JoystickInstanceIsUnique ( device , joystickID ) ) {
2022-07-28 21:22:27 -05:00
/* Disconnecting a child always disconnects the parent */
device = device - > parent ;
}
2019-12-19 17:01:30 -06:00
for ( i = 0 ; i < device - > num_joysticks ; + + i ) {
if ( device - > joysticks [ i ] = = joystickID ) {
2022-12-27 07:50:46 -06:00
SDL_Joystick * joystick = SDL_GetJoystickFromInstanceID ( joystickID ) ;
2022-08-15 19:27:33 -05:00
if ( joystick ) {
HIDAPI_JoystickClose ( joystick ) ;
2020-01-09 16:53:30 -06:00
}
2022-07-28 21:22:27 -05:00
HIDAPI_DelJoystickInstanceFromDevice ( device , joystickID ) ;
2020-05-29 23:22:11 -05:00
2022-07-28 21:22:27 -05:00
for ( j = 0 ; j < device - > num_children ; + + j ) {
SDL_HIDAPI_Device * child = device - > children [ j ] ;
HIDAPI_DelJoystickInstanceFromDevice ( child , joystickID ) ;
2020-02-14 18:15:46 -06:00
}
2019-12-19 17:01:30 -06:00
2022-08-15 19:27:33 -05:00
- - SDL_HIDAPI_numjoysticks ;
2022-07-28 21:22:27 -05:00
2022-08-15 19:27:33 -05:00
if ( ! shutting_down ) {
SDL_PrivateJoystickRemoved ( joystickID ) ;
2019-12-19 17:01:30 -06:00
}
}
}
2022-08-09 18:54:11 -05:00
/* Rescan the device list in case device state has changed */
SDL_HIDAPI_change_count = 0 ;
2022-08-15 19:27:33 -05:00
SDL_UnlockJoysticks ( ) ;
2019-12-19 17:01:30 -06:00
}
2022-11-30 14:51:59 -06:00
static int HIDAPI_JoystickGetCount ( void )
2018-08-09 18:00:17 -05:00
{
return SDL_HIDAPI_numjoysticks ;
}
2022-11-30 14:51:59 -06:00
static char * HIDAPI_ConvertString ( const wchar_t * wide_string )
2020-11-16 19:36:47 -06:00
{
char * string = NULL ;
if ( wide_string ) {
2022-11-30 14:51:59 -06:00
string = SDL_iconv_string ( " UTF-8 " , " WCHAR_T " , ( char * ) wide_string , ( SDL_wcslen ( wide_string ) + 1 ) * sizeof ( wchar_t ) ) ;
2022-11-27 10:38:43 -06:00
if ( string = = NULL ) {
2021-11-13 02:50:02 -06:00
switch ( sizeof ( wchar_t ) ) {
case 2 :
2022-11-30 14:51:59 -06:00
string = SDL_iconv_string ( " UTF-8 " , " UCS-2-INTERNAL " , ( char * ) wide_string , ( SDL_wcslen ( wide_string ) + 1 ) * sizeof ( wchar_t ) ) ;
2021-11-13 02:50:02 -06:00
break ;
case 4 :
2022-11-30 14:51:59 -06:00
string = SDL_iconv_string ( " UTF-8 " , " UCS-4-INTERNAL " , ( char * ) wide_string , ( SDL_wcslen ( wide_string ) + 1 ) * sizeof ( wchar_t ) ) ;
2021-11-13 02:50:02 -06:00
break ;
2020-11-16 19:36:47 -06:00
}
}
}
return string ;
}
2022-11-30 14:51:59 -06:00
static SDL_HIDAPI_Device * HIDAPI_AddDevice ( const struct SDL_hid_device_info * info , int num_children , SDL_HIDAPI_Device * * children )
2018-08-09 18:00:17 -05:00
{
SDL_HIDAPI_Device * device ;
SDL_HIDAPI_Device * curr , * last = NULL ;
2022-10-06 20:23:07 -05:00
SDL_bool removed ;
2018-08-09 18:00:17 -05:00
2022-12-13 16:03:40 -06:00
SDL_AssertJoysticksLocked ( ) ;
2018-08-09 18:00:17 -05:00
for ( curr = SDL_HIDAPI_devices , last = NULL ; curr ; last = curr , curr = curr - > next ) {
}
device = ( SDL_HIDAPI_Device * ) SDL_calloc ( 1 , sizeof ( * device ) ) ;
2022-11-27 10:38:43 -06:00
if ( device = = NULL ) {
2022-07-28 21:22:27 -05:00
return NULL ;
2018-08-09 18:00:17 -05:00
}
2019-12-19 17:01:30 -06:00
device - > path = SDL_strdup ( info - > path ) ;
if ( ! device - > path ) {
SDL_free ( device ) ;
2022-07-28 21:22:27 -05:00
return NULL ;
2019-12-19 17:01:30 -06:00
}
2018-08-09 18:00:17 -05:00
device - > seen = SDL_TRUE ;
device - > vendor_id = info - > vendor_id ;
device - > product_id = info - > product_id ;
2018-08-29 22:23:36 -05:00
device - > version = info - > release_number ;
2018-08-09 18:00:17 -05:00
device - > interface_number = info - > interface_number ;
2020-01-18 13:21:14 -06:00
device - > interface_class = info - > interface_class ;
device - > interface_subclass = info - > interface_subclass ;
device - > interface_protocol = info - > interface_protocol ;
2018-08-09 18:00:17 -05:00
device - > usage_page = info - > usage_page ;
device - > usage = info - > usage ;
2020-02-04 17:26:56 -06:00
device - > dev_lock = SDL_CreateMutex ( ) ;
2018-08-09 18:00:17 -05:00
2018-09-14 14:41:29 -05:00
/* Need the device name before getting the driver to know whether to ignore this device */
2020-03-12 21:47:30 -05:00
{
2020-11-16 19:36:47 -06:00
char * manufacturer_string = HIDAPI_ConvertString ( info - > manufacturer_string ) ;
char * product_string = HIDAPI_ConvertString ( info - > product_string ) ;
char * serial_number = HIDAPI_ConvertString ( info - > serial_number ) ;
2019-12-11 19:46:59 -06:00
2020-03-12 21:47:30 -05:00
device - > name = SDL_CreateJoystickName ( device - > vendor_id , device - > product_id , manufacturer_string , product_string ) ;
2019-12-11 19:46:59 -06:00
2018-08-09 18:00:17 -05:00
if ( manufacturer_string ) {
SDL_free ( manufacturer_string ) ;
}
if ( product_string ) {
SDL_free ( product_string ) ;
}
2020-03-12 21:47:30 -05:00
2020-11-16 19:36:47 -06:00
if ( serial_number & & * serial_number ) {
device - > serial = serial_number ;
} else {
SDL_free ( serial_number ) ;
}
2018-08-09 18:00:17 -05:00
if ( ! device - > name ) {
2020-11-16 19:36:47 -06:00
SDL_free ( device - > serial ) ;
2019-12-19 17:01:30 -06:00
SDL_free ( device - > path ) ;
2018-08-09 18:00:17 -05:00
SDL_free ( device ) ;
2022-07-28 21:22:27 -05:00
return NULL ;
}
}
2022-08-22 21:28:21 -05:00
/* FIXME: Is there any way to tell whether this is a Bluetooth device? */
device - > guid = SDL_CreateJoystickGUID ( SDL_HARDWARE_BUS_USB , device - > vendor_id , device - > product_id , device - > version , device - > name , ' h ' , 0 ) ;
2022-12-27 13:31:54 -06:00
device - > joystick_type = SDL_JOYSTICK_TYPE_GAMEPAD ;
2022-09-23 01:42:25 -05:00
device - > type = SDL_GetJoystickGameControllerProtocol ( device - > name , device - > vendor_id , device - > product_id , device - > interface_number , device - > interface_class , device - > interface_subclass , device - > interface_protocol ) ;
2022-08-22 18:46:55 -05:00
2022-07-28 21:22:27 -05:00
if ( num_children > 0 ) {
int i ;
device - > num_children = num_children ;
device - > children = children ;
for ( i = 0 ; i < num_children ; + + i ) {
children [ i ] - > parent = device ;
2018-08-09 18:00:17 -05:00
}
}
/* Add it to the list */
if ( last ) {
last - > next = device ;
} else {
SDL_HIDAPI_devices = device ;
}
2022-10-06 20:23:07 -05:00
removed = SDL_FALSE ;
HIDAPI_SetupDeviceDriver ( device , & removed ) ;
if ( removed ) {
return NULL ;
}
2019-12-30 11:44:32 -06:00
2019-12-19 17:01:30 -06:00
# ifdef DEBUG_HIDAPI
2022-08-19 13:11:23 -05:00
SDL_Log ( " Added HIDAPI device '%s' VID 0x%.4x, PID 0x%.4x, version %d, serial %s, interface %d, interface_class %d, interface_subclass %d, interface_protocol %d, usage page 0x%.4x, usage 0x%.4x, path = %s, driver = %s (%s) \n " , device - > name , device - > vendor_id , device - > product_id , device - > version , device - > serial ? device - > serial : " NONE " , device - > interface_number , device - > interface_class , device - > interface_subclass , device - > interface_protocol , device - > usage_page , device - > usage , device - > path , device - > driver ? device - > driver - > name : " NONE " , device - > driver & & device - > driver - > enabled ? " ENABLED " : " DISABLED " ) ;
2019-12-19 17:01:30 -06:00
# endif
2022-07-28 21:22:27 -05:00
return device ;
2018-08-09 18:00:17 -05:00
}
2022-11-30 14:51:59 -06:00
static void HIDAPI_DelDevice ( SDL_HIDAPI_Device * device )
2018-08-09 18:00:17 -05:00
{
SDL_HIDAPI_Device * curr , * last ;
2022-10-02 10:48:38 -05:00
int i ;
2020-12-13 03:20:38 -06:00
2022-12-13 16:03:40 -06:00
SDL_AssertJoysticksLocked ( ) ;
2020-12-13 03:20:38 -06:00
# ifdef DEBUG_HIDAPI
2022-08-19 13:11:23 -05:00
SDL_Log ( " Removing HIDAPI device '%s' VID 0x%.4x, PID 0x%.4x, version %d, serial %s, interface %d, interface_class %d, interface_subclass %d, interface_protocol %d, usage page 0x%.4x, usage 0x%.4x, path = %s, driver = %s (%s) \n " , device - > name , device - > vendor_id , device - > product_id , device - > version , device - > serial ? device - > serial : " NONE " , device - > interface_number , device - > interface_class , device - > interface_subclass , device - > interface_protocol , device - > usage_page , device - > usage , device - > path , device - > driver ? device - > driver - > name : " NONE " , device - > driver & & device - > driver - > enabled ? " ENABLED " : " DISABLED " ) ;
2020-12-13 03:20:38 -06:00
# endif
2018-08-09 18:00:17 -05:00
for ( curr = SDL_HIDAPI_devices , last = NULL ; curr ; last = curr , curr = curr - > next ) {
if ( curr = = device ) {
if ( last ) {
last - > next = curr - > next ;
} else {
SDL_HIDAPI_devices = curr - > next ;
}
2019-12-19 17:01:30 -06:00
HIDAPI_CleanupDeviceDriver ( device ) ;
2018-08-09 18:00:17 -05:00
2020-12-07 11:38:21 -06:00
/* Make sure the rumble thread is done with this device */
while ( SDL_AtomicGet ( & device - > rumble_pending ) > 0 ) {
SDL_Delay ( 10 ) ;
}
2022-10-02 10:48:38 -05:00
for ( i = 0 ; i < device - > num_children ; + + i ) {
device - > children [ i ] - > parent = NULL ;
}
2020-02-04 17:26:56 -06:00
SDL_DestroyMutex ( device - > dev_lock ) ;
2020-11-16 19:36:47 -06:00
SDL_free ( device - > serial ) ;
2018-08-09 18:00:17 -05:00
SDL_free ( device - > name ) ;
SDL_free ( device - > path ) ;
2022-08-02 07:42:25 -05:00
SDL_free ( device - > children ) ;
2018-08-09 18:00:17 -05:00
SDL_free ( device ) ;
return ;
}
}
}
2022-11-30 14:51:59 -06:00
static SDL_bool HIDAPI_CreateCombinedJoyCons ( )
2022-07-28 21:22:27 -05:00
{
SDL_HIDAPI_Device * device , * combined ;
SDL_HIDAPI_Device * joycons [ 2 ] = { NULL , NULL } ;
2022-12-13 16:03:40 -06:00
SDL_AssertJoysticksLocked ( ) ;
2022-07-28 21:22:27 -05:00
if ( ! SDL_HIDAPI_combine_joycons ) {
return SDL_FALSE ;
}
for ( device = SDL_HIDAPI_devices ; device ; device = device - > next ) {
2022-08-30 16:14:38 -05:00
Uint16 vendor , product ;
2022-07-28 21:22:27 -05:00
if ( ! device - > driver ) {
/* Unsupported device */
continue ;
}
if ( device - > parent ) {
/* This device is already part of a combined device */
continue ;
}
2022-08-30 16:14:38 -05:00
SDL_GetJoystickGUIDInfo ( device - > guid , & vendor , & product , NULL , NULL ) ;
2022-08-03 20:01:10 -05:00
if ( ! joycons [ 0 ] & &
2022-08-30 16:14:38 -05:00
( SDL_IsJoystickNintendoSwitchJoyConLeft ( vendor , product ) | |
( SDL_IsJoystickNintendoSwitchJoyConGrip ( vendor , product ) & &
2022-08-03 20:01:10 -05:00
SDL_strstr ( device - > name , " (L) " ) ! = NULL ) ) ) {
2022-07-28 21:22:27 -05:00
joycons [ 0 ] = device ;
}
2022-08-03 20:01:10 -05:00
if ( ! joycons [ 1 ] & &
2022-08-30 16:14:38 -05:00
( SDL_IsJoystickNintendoSwitchJoyConRight ( vendor , product ) | |
( SDL_IsJoystickNintendoSwitchJoyConGrip ( vendor , product ) & &
2022-08-03 20:01:10 -05:00
SDL_strstr ( device - > name , " (R) " ) ! = NULL ) ) ) {
2022-07-28 21:22:27 -05:00
joycons [ 1 ] = device ;
}
if ( joycons [ 0 ] & & joycons [ 1 ] ) {
SDL_hid_device_info info ;
SDL_HIDAPI_Device * * children = ( SDL_HIDAPI_Device * * ) SDL_malloc ( 2 * sizeof ( SDL_HIDAPI_Device * ) ) ;
2022-11-27 10:38:43 -06:00
if ( children = = NULL ) {
2022-07-28 21:22:27 -05:00
return SDL_FALSE ;
}
children [ 0 ] = joycons [ 0 ] ;
children [ 1 ] = joycons [ 1 ] ;
SDL_zero ( info ) ;
info . path = " nintendo_joycons_combined " ;
info . vendor_id = USB_VENDOR_NINTENDO ;
2022-08-08 10:22:20 -05:00
info . product_id = USB_PRODUCT_NINTENDO_SWITCH_JOYCON_PAIR ;
2022-07-28 21:22:27 -05:00
info . interface_number = - 1 ;
info . usage_page = USB_USAGEPAGE_GENERIC_DESKTOP ;
info . usage = USB_USAGE_GENERIC_GAMEPAD ;
info . manufacturer_string = L " Nintendo " ;
info . product_string = L " Switch Joy-Con (L/R) " ;
combined = HIDAPI_AddDevice ( & info , 2 , children ) ;
if ( combined & & combined - > driver ) {
return SDL_TRUE ;
} else {
2022-10-02 10:48:38 -05:00
if ( combined ) {
HIDAPI_DelDevice ( combined ) ;
} else {
2022-08-02 07:42:25 -05:00
SDL_free ( children ) ;
}
2022-07-28 21:22:27 -05:00
return SDL_FALSE ;
}
}
}
return SDL_FALSE ;
}
2022-11-30 14:51:59 -06:00
static void HIDAPI_UpdateDeviceList ( void )
2018-08-09 18:00:17 -05:00
{
SDL_HIDAPI_Device * device ;
2021-11-08 00:58:44 -06:00
struct SDL_hid_device_info * devs , * info ;
2018-08-09 18:00:17 -05:00
2020-01-14 00:05:54 -06:00
SDL_LockJoysticks ( ) ;
2019-12-19 17:01:30 -06:00
2022-08-19 13:11:23 -05:00
if ( SDL_HIDAPI_hints_changed ) {
SDL_HIDAPI_UpdateDrivers ( ) ;
SDL_HIDAPI_hints_changed = SDL_FALSE ;
}
2018-08-09 18:00:17 -05:00
/* Prepare the existing device list */
2022-07-28 21:22:27 -05:00
for ( device = SDL_HIDAPI_devices ; device ; device = device - > next ) {
if ( device - > children ) {
continue ;
}
2018-08-09 18:00:17 -05:00
device - > seen = SDL_FALSE ;
}
/* Enumerate the devices */
2019-07-25 17:21:44 -05:00
if ( SDL_HIDAPI_numdrivers > 0 ) {
2021-11-08 00:58:44 -06:00
devs = SDL_hid_enumerate ( 0 , 0 ) ;
2019-07-25 17:21:44 -05:00
if ( devs ) {
for ( info = devs ; info ; info = info - > next ) {
device = HIDAPI_GetJoystickByInfo ( info - > path , info - > vendor_id , info - > product_id ) ;
if ( device ) {
device - > seen = SDL_TRUE ;
} else {
2022-07-28 21:22:27 -05:00
HIDAPI_AddDevice ( info , 0 , NULL ) ;
2019-07-25 17:21:44 -05:00
}
2018-08-09 18:00:17 -05:00
}
2021-11-08 00:58:44 -06:00
SDL_hid_free_enumeration ( devs ) ;
2018-08-09 18:00:17 -05:00
}
}
2021-02-21 00:51:57 -06:00
/* Remove any devices that weren't seen or have been disconnected due to read errors */
2022-07-28 21:22:27 -05:00
check_removed :
2018-08-09 18:00:17 -05:00
device = SDL_HIDAPI_devices ;
while ( device ) {
SDL_HIDAPI_Device * next = device - > next ;
2021-02-21 00:51:57 -06:00
if ( ! device - > seen | |
2022-08-03 15:18:00 -05:00
( ( device - > driver | | device - > children ) & & device - > num_joysticks = = 0 & & ! device - > dev ) ) {
2022-07-28 21:22:27 -05:00
if ( device - > parent ) {
/* When a child device goes away, so does the parent */
int i ;
device = device - > parent ;
for ( i = 0 ; i < device - > num_children ; + + i ) {
HIDAPI_DelDevice ( device - > children [ i ] ) ;
}
HIDAPI_DelDevice ( device ) ;
/* Update the device list again to pick up any children left */
SDL_HIDAPI_change_count = 0 ;
/* We deleted more than one device here, restart the loop */
goto check_removed ;
} else {
HIDAPI_DelDevice ( device ) ;
2022-09-01 23:13:16 -05:00
/* Update the device list again in case this device comes back */
SDL_HIDAPI_change_count = 0 ;
2022-07-28 21:22:27 -05:00
}
2018-08-09 18:00:17 -05:00
}
device = next ;
}
2019-12-19 17:01:30 -06:00
2022-07-28 21:22:27 -05:00
/* See if we can create any combined Joy-Con controllers */
while ( HIDAPI_CreateCombinedJoyCons ( ) ) {
}
2020-01-14 00:05:54 -06:00
SDL_UnlockJoysticks ( ) ;
2018-08-09 18:00:17 -05:00
}
2022-11-30 14:51:59 -06:00
static SDL_bool HIDAPI_IsEquivalentToDevice ( Uint16 vendor_id , Uint16 product_id , SDL_HIDAPI_Device * device )
2020-11-25 00:25:26 -06:00
{
if ( vendor_id = = device - > vendor_id & & product_id = = device - > product_id ) {
return SDL_TRUE ;
}
if ( vendor_id = = USB_VENDOR_MICROSOFT ) {
/* If we're looking for the wireless XBox 360 controller, also look for the dongle */
2021-05-17 06:50:33 -05:00
if ( product_id = = USB_PRODUCT_XBOX360_XUSB_CONTROLLER & & device - > product_id = = USB_PRODUCT_XBOX360_WIRELESS_RECEIVER ) {
2020-12-03 20:17:03 -06:00
return SDL_TRUE ;
}
/* If we're looking for the raw input Xbox One controller, match it against any other Xbox One controller */
2021-05-17 06:50:33 -05:00
if ( product_id = = USB_PRODUCT_XBOX_ONE_XBOXGIP_CONTROLLER & &
2022-12-27 11:46:24 -06:00
device - > type = = SDL_GAMEPAD_TYPE_XBOXONE ) {
2020-12-03 20:17:03 -06:00
return SDL_TRUE ;
}
/* If we're looking for an XInput controller, match it against any other Xbox controller */
if ( product_id = = USB_PRODUCT_XBOX_ONE_XINPUT_CONTROLLER ) {
2022-12-27 11:46:24 -06:00
if ( device - > type = = SDL_GAMEPAD_TYPE_XBOX360 | | device - > type = = SDL_GAMEPAD_TYPE_XBOXONE ) {
2020-12-03 20:17:03 -06:00
return SDL_TRUE ;
}
}
2020-11-25 00:25:26 -06:00
}
2022-10-25 12:23:51 -05:00
if ( vendor_id = = USB_VENDOR_NVIDIA ) {
/* If we're looking for the NVIDIA SHIELD controller Xbox interface, match it against any NVIDIA SHIELD controller */
if ( product_id = = 0xb400 & &
2022-12-27 11:46:24 -06:00
device - > type = = SDL_GAMEPAD_TYPE_NVIDIA_SHIELD ) {
2022-10-25 12:23:51 -05:00
return SDL_TRUE ;
}
}
2020-11-25 00:25:26 -06:00
return SDL_FALSE ;
}
2021-07-27 01:29:20 -05:00
SDL_bool
2022-12-27 11:46:24 -06:00
HIDAPI_IsDeviceTypePresent ( SDL_GamepadType type )
2021-07-27 01:29:20 -05:00
{
SDL_HIDAPI_Device * device ;
SDL_bool result = SDL_FALSE ;
/* Make sure we're initialized, as this could be called from other drivers during startup */
if ( HIDAPI_JoystickInit ( ) < 0 ) {
return SDL_FALSE ;
}
if ( SDL_AtomicTryLock ( & SDL_HIDAPI_spinlock ) ) {
HIDAPI_UpdateDeviceList ( ) ;
SDL_AtomicUnlock ( & SDL_HIDAPI_spinlock ) ;
}
SDL_LockJoysticks ( ) ;
2022-07-28 21:22:27 -05:00
for ( device = SDL_HIDAPI_devices ; device ; device = device - > next ) {
2022-09-23 01:42:25 -05:00
if ( device - > driver & & device - > type = = type ) {
2021-07-27 01:29:20 -05:00
result = SDL_TRUE ;
break ;
}
}
SDL_UnlockJoysticks ( ) ;
# ifdef DEBUG_HIDAPI
SDL_Log ( " HIDAPI_IsDeviceTypePresent() returning %s for %d \n " , result ? " true " : " false " , type ) ;
# endif
return result ;
}
2018-08-09 18:00:17 -05:00
SDL_bool
2019-10-22 12:57:07 -05:00
HIDAPI_IsDevicePresent ( Uint16 vendor_id , Uint16 product_id , Uint16 version , const char * name )
2018-08-09 18:00:17 -05:00
{
SDL_HIDAPI_Device * device ;
2020-01-18 13:21:14 -06:00
SDL_bool supported = SDL_FALSE ;
2020-01-14 00:05:54 -06:00
SDL_bool result = SDL_FALSE ;
2018-08-09 18:00:17 -05:00
2019-07-31 12:20:37 -05:00
/* Make sure we're initialized, as this could be called from other drivers during startup */
if ( HIDAPI_JoystickInit ( ) < 0 ) {
return SDL_FALSE ;
}
2020-01-18 13:21:14 -06:00
/* Only update the device list for devices we know might be supported.
2022-11-30 14:51:59 -06:00
If we did this for every device , it would hit the USB driver too hard and potentially
lock up the system . This won ' t catch devices that we support but can only detect using
2020-01-18 13:21:14 -06:00
USB interface details , like Xbox controllers , but hopefully the device list update is
responsive enough to catch those .
*/
supported = HIDAPI_IsDeviceSupported ( vendor_id , product_id , version , name ) ;
# if defined(SDL_JOYSTICK_HIDAPI_XBOX360) || defined(SDL_JOYSTICK_HIDAPI_XBOXONE)
if ( ! supported & &
( SDL_strstr ( name , " Xbox " ) | | SDL_strstr ( name , " X-Box " ) | | SDL_strstr ( name , " XBOX " ) ) ) {
supported = SDL_TRUE ;
}
# endif /* SDL_JOYSTICK_HIDAPI_XBOX360 || SDL_JOYSTICK_HIDAPI_XBOXONE */
if ( supported ) {
if ( SDL_AtomicTryLock ( & SDL_HIDAPI_spinlock ) ) {
HIDAPI_UpdateDeviceList ( ) ;
SDL_AtomicUnlock ( & SDL_HIDAPI_spinlock ) ;
}
2020-01-14 00:05:54 -06:00
}
2018-08-09 18:00:17 -05:00
2019-10-22 12:57:07 -05:00
/* Note that this isn't a perfect check - there may be multiple devices with 0 VID/PID,
or a different name than we have it listed here , etc , but if we support the device
and we have something similar in our device list , mark it as present .
*/
2020-01-14 00:05:54 -06:00
SDL_LockJoysticks ( ) ;
2022-07-28 21:22:27 -05:00
for ( device = SDL_HIDAPI_devices ; device ; device = device - > next ) {
2020-11-25 00:25:26 -06:00
if ( device - > driver & &
HIDAPI_IsEquivalentToDevice ( vendor_id , product_id , device ) ) {
2020-01-14 00:05:54 -06:00
result = SDL_TRUE ;
2021-07-27 01:29:20 -05:00
break ;
2018-08-09 18:00:17 -05:00
}
}
2020-01-14 00:05:54 -06:00
SDL_UnlockJoysticks ( ) ;
2020-01-17 12:43:14 -06:00
# ifdef DEBUG_HIDAPI
SDL_Log ( " HIDAPI_IsDevicePresent() returning %s for 0x%.4x / 0x%.4x \n " , result ? " true " : " false " , vendor_id , product_id ) ;
# endif
2020-01-14 00:05:54 -06:00
return result ;
2018-08-09 18:00:17 -05:00
}
2022-09-23 02:15:40 -05:00
SDL_JoystickType
HIDAPI_GetJoystickTypeFromGUID ( SDL_JoystickGUID guid )
{
SDL_HIDAPI_Device * device ;
SDL_JoystickType type = SDL_JOYSTICK_TYPE_UNKNOWN ;
SDL_LockJoysticks ( ) ;
for ( device = SDL_HIDAPI_devices ; device ; device = device - > next ) {
if ( SDL_memcmp ( & guid , & device - > guid , sizeof ( guid ) ) = = 0 ) {
type = device - > joystick_type ;
break ;
}
}
SDL_UnlockJoysticks ( ) ;
return type ;
}
2022-12-27 11:46:24 -06:00
SDL_GamepadType
HIDAPI_GetGamepadTypeFromGUID ( SDL_JoystickGUID guid )
2022-09-23 01:42:25 -05:00
{
SDL_HIDAPI_Device * device ;
2022-12-27 11:46:24 -06:00
SDL_GamepadType type = SDL_GAMEPAD_TYPE_UNKNOWN ;
2022-09-23 01:42:25 -05:00
SDL_LockJoysticks ( ) ;
for ( device = SDL_HIDAPI_devices ; device ; device = device - > next ) {
if ( SDL_memcmp ( & guid , & device - > guid , sizeof ( guid ) ) = = 0 ) {
type = device - > type ;
break ;
}
}
SDL_UnlockJoysticks ( ) ;
return type ;
}
2022-11-30 14:51:59 -06:00
static void HIDAPI_JoystickDetect ( void )
2018-08-09 18:00:17 -05:00
{
2020-01-14 00:05:54 -06:00
if ( SDL_AtomicTryLock ( & SDL_HIDAPI_spinlock ) ) {
2021-11-11 14:45:38 -06:00
Uint32 count = SDL_hid_device_change_count ( ) ;
if ( SDL_HIDAPI_change_count ! = count ) {
SDL_HIDAPI_change_count = count ;
2022-07-28 21:22:27 -05:00
HIDAPI_UpdateDeviceList ( ) ;
2020-01-14 00:05:54 -06:00
}
SDL_AtomicUnlock ( & SDL_HIDAPI_spinlock ) ;
2018-08-09 18:00:17 -05:00
}
2019-12-19 17:01:35 -06:00
}
2022-11-30 14:51:59 -06:00
void HIDAPI_UpdateDevices ( void )
2019-12-19 17:01:35 -06:00
{
SDL_HIDAPI_Device * device ;
2019-12-19 17:01:30 -06:00
2022-12-13 16:03:40 -06:00
SDL_AssertJoysticksLocked ( ) ;
2019-12-19 17:01:30 -06:00
/* Update the devices, which may change connected joysticks and send events */
/* Prepare the existing device list */
2020-01-14 00:05:54 -06:00
if ( SDL_AtomicTryLock ( & SDL_HIDAPI_spinlock ) ) {
2022-07-28 21:22:27 -05:00
for ( device = SDL_HIDAPI_devices ; device ; device = device - > next ) {
if ( device - > parent ) {
continue ;
}
2020-01-14 00:05:54 -06:00
if ( device - > driver ) {
2020-02-04 17:26:56 -06:00
if ( SDL_TryLockMutex ( device - > dev_lock ) = = 0 ) {
2020-12-13 03:20:38 -06:00
device - > updating = SDL_TRUE ;
2022-08-09 18:54:11 -05:00
device - > driver - > UpdateDevice ( device ) ;
2020-12-13 03:20:38 -06:00
device - > updating = SDL_FALSE ;
2020-02-04 17:26:56 -06:00
SDL_UnlockMutex ( device - > dev_lock ) ;
}
2020-01-14 00:05:54 -06:00
}
2019-12-19 17:01:30 -06:00
}
2020-01-14 00:05:54 -06:00
SDL_AtomicUnlock ( & SDL_HIDAPI_spinlock ) ;
2019-12-19 17:01:30 -06:00
}
2018-08-09 18:00:17 -05:00
}
2022-11-30 14:51:59 -06:00
static const char * HIDAPI_JoystickGetDeviceName ( int device_index )
2018-08-09 18:00:17 -05:00
{
2019-12-19 17:01:30 -06:00
SDL_HIDAPI_Device * device ;
const char * name = NULL ;
device = HIDAPI_GetDeviceByIndex ( device_index , NULL ) ;
if ( device ) {
/* FIXME: The device could be freed after this name is returned... */
name = device - > name ;
}
return name ;
2018-08-09 18:00:17 -05:00
}
2022-11-30 14:51:59 -06:00
static const char * HIDAPI_JoystickGetDevicePath ( int device_index )
2022-04-26 16:54:14 -05:00
{
SDL_HIDAPI_Device * device ;
const char * path = NULL ;
device = HIDAPI_GetDeviceByIndex ( device_index , NULL ) ;
if ( device ) {
/* FIXME: The device could be freed after this path is returned... */
path = device - > path ;
}
return path ;
}
2022-11-30 14:51:59 -06:00
static int HIDAPI_JoystickGetDevicePlayerIndex ( int device_index )
2018-10-25 18:53:14 -05:00
{
2019-12-20 22:12:03 -06:00
SDL_HIDAPI_Device * device ;
SDL_JoystickID instance_id ;
int player_index = - 1 ;
device = HIDAPI_GetDeviceByIndex ( device_index , & instance_id ) ;
if ( device ) {
player_index = device - > driver - > GetDevicePlayerIndex ( device , instance_id ) ;
}
return player_index ;
}
2022-11-30 14:51:59 -06:00
static void HIDAPI_JoystickSetDevicePlayerIndex ( int device_index , int player_index )
2019-12-20 22:12:03 -06:00
{
SDL_HIDAPI_Device * device ;
SDL_JoystickID instance_id ;
device = HIDAPI_GetDeviceByIndex ( device_index , & instance_id ) ;
if ( device ) {
device - > driver - > SetDevicePlayerIndex ( device , instance_id , player_index ) ;
}
2018-10-25 18:53:14 -05:00
}
2022-11-30 14:51:59 -06:00
static SDL_JoystickGUID HIDAPI_JoystickGetDeviceGUID ( int device_index )
2018-08-09 18:00:17 -05:00
{
2019-12-19 17:01:30 -06:00
SDL_HIDAPI_Device * device ;
SDL_JoystickGUID guid ;
device = HIDAPI_GetDeviceByIndex ( device_index , NULL ) ;
if ( device ) {
SDL_memcpy ( & guid , & device - > guid , sizeof ( guid ) ) ;
} else {
SDL_zero ( guid ) ;
}
return guid ;
2018-08-09 18:00:17 -05:00
}
2022-11-30 14:51:59 -06:00
static SDL_JoystickID HIDAPI_JoystickGetDeviceInstanceID ( int device_index )
2018-08-09 18:00:17 -05:00
{
2019-12-19 17:58:16 -06:00
SDL_JoystickID joystickID = - 1 ;
2019-12-19 17:01:30 -06:00
HIDAPI_GetDeviceByIndex ( device_index , & joystickID ) ;
return joystickID ;
2018-08-09 18:00:17 -05:00
}
2022-11-30 14:51:59 -06:00
static int HIDAPI_JoystickOpen ( SDL_Joystick * joystick , int device_index )
2018-08-09 18:00:17 -05:00
{
2022-08-10 08:00:30 -05:00
SDL_JoystickID joystickID = - 1 ;
2019-12-19 17:01:30 -06:00
SDL_HIDAPI_Device * device = HIDAPI_GetDeviceByIndex ( device_index , & joystickID ) ;
2019-06-19 17:54:21 -05:00
struct joystick_hwdata * hwdata ;
2018-08-09 18:00:17 -05:00
2022-12-13 16:03:40 -06:00
SDL_AssertJoysticksLocked ( ) ;
2022-11-27 10:38:43 -06:00
if ( device = = NULL | | ! device - > driver ) {
2022-08-10 08:00:30 -05:00
/* This should never happen - validated before being called */
return SDL_SetError ( " Couldn't find HIDAPI device at index %d \n " , device_index ) ;
}
2019-06-19 17:54:21 -05:00
hwdata = ( struct joystick_hwdata * ) SDL_calloc ( 1 , sizeof ( * hwdata ) ) ;
2022-11-27 10:38:43 -06:00
if ( hwdata = = NULL ) {
2019-06-19 17:54:21 -05:00
return SDL_OutOfMemory ( ) ;
}
2019-12-19 17:01:30 -06:00
hwdata - > device = device ;
2019-06-19 17:54:21 -05:00
2022-09-22 20:22:17 -05:00
/* Process any pending reports before opening the device */
SDL_LockMutex ( device - > dev_lock ) ;
device - > updating = SDL_TRUE ;
device - > driver - > UpdateDevice ( device ) ;
device - > updating = SDL_FALSE ;
SDL_UnlockMutex ( device - > dev_lock ) ;
2019-12-19 17:01:30 -06:00
if ( ! device - > driver - > OpenJoystick ( device , joystick ) ) {
2022-08-09 19:04:26 -05:00
/* The open failed, mark this device as disconnected and update devices */
HIDAPI_JoystickDisconnected ( device , joystickID ) ;
2019-06-19 17:54:21 -05:00
SDL_free ( hwdata ) ;
2018-08-09 18:00:17 -05:00
return - 1 ;
}
2020-11-16 19:36:47 -06:00
if ( ! joystick - > serial & & device - > serial ) {
joystick - > serial = SDL_strdup ( device - > serial ) ;
}
2019-06-19 17:54:21 -05:00
joystick - > hwdata = hwdata ;
2018-08-09 18:00:17 -05:00
return 0 ;
}
2022-11-30 14:51:59 -06:00
static int HIDAPI_JoystickRumble ( SDL_Joystick * joystick , Uint16 low_frequency_rumble , Uint16 high_frequency_rumble )
2018-08-09 18:00:17 -05:00
{
2018-10-02 22:51:33 -05:00
int result ;
2022-12-13 16:03:40 -06:00
SDL_AssertJoysticksLocked ( ) ;
2019-12-19 17:01:30 -06:00
if ( joystick - > hwdata ) {
SDL_HIDAPI_Device * device = joystick - > hwdata - > device ;
2020-02-04 14:48:53 -06:00
result = device - > driver - > RumbleJoystick ( device , joystick , low_frequency_rumble , high_frequency_rumble ) ;
2019-12-19 17:01:30 -06:00
} else {
2022-01-17 10:22:30 -06:00
result = SDL_SetError ( " Rumble failed, device disconnected " ) ;
2019-12-19 17:01:30 -06:00
}
2018-10-02 22:51:33 -05:00
return result ;
2018-08-09 18:00:17 -05:00
}
2022-11-30 14:51:59 -06:00
static int HIDAPI_JoystickRumbleTriggers ( SDL_Joystick * joystick , Uint16 left_rumble , Uint16 right_rumble )
2020-11-11 20:57:37 -06:00
{
int result ;
2022-12-13 16:03:40 -06:00
SDL_AssertJoysticksLocked ( ) ;
2020-11-11 20:57:37 -06:00
if ( joystick - > hwdata ) {
SDL_HIDAPI_Device * device = joystick - > hwdata - > device ;
result = device - > driver - > RumbleJoystickTriggers ( device , joystick , left_rumble , right_rumble ) ;
} else {
2022-01-17 10:22:30 -06:00
result = SDL_SetError ( " Rumble failed, device disconnected " ) ;
2020-11-11 20:57:37 -06:00
}
return result ;
}
2022-11-30 14:51:59 -06:00
static Uint32 HIDAPI_JoystickGetCapabilities ( SDL_Joystick * joystick )
2020-11-05 13:07:54 -06:00
{
2021-11-11 11:13:08 -06:00
Uint32 result = 0 ;
2020-11-05 13:07:54 -06:00
2022-12-13 16:03:40 -06:00
SDL_AssertJoysticksLocked ( ) ;
2020-11-05 13:07:54 -06:00
if ( joystick - > hwdata ) {
SDL_HIDAPI_Device * device = joystick - > hwdata - > device ;
2021-11-11 11:13:08 -06:00
result = device - > driver - > GetJoystickCapabilities ( device , joystick ) ;
2020-11-05 13:07:54 -06:00
}
return result ;
}
2022-11-30 14:51:59 -06:00
static int HIDAPI_JoystickSetLED ( SDL_Joystick * joystick , Uint8 red , Uint8 green , Uint8 blue )
2020-04-30 10:57:29 -05:00
{
int result ;
2022-12-13 16:03:40 -06:00
SDL_AssertJoysticksLocked ( ) ;
2020-04-30 10:57:29 -05:00
if ( joystick - > hwdata ) {
SDL_HIDAPI_Device * device = joystick - > hwdata - > device ;
result = device - > driver - > SetJoystickLED ( device , joystick , red , green , blue ) ;
} else {
2022-01-17 10:22:30 -06:00
result = SDL_SetError ( " SetLED failed, device disconnected " ) ;
2020-04-30 10:57:29 -05:00
}
return result ;
}
2022-11-30 14:51:59 -06:00
static int HIDAPI_JoystickSendEffect ( SDL_Joystick * joystick , const void * data , int size )
2021-07-08 15:22:41 -05:00
{
int result ;
2022-12-13 16:03:40 -06:00
SDL_AssertJoysticksLocked ( ) ;
2021-07-08 15:22:41 -05:00
if ( joystick - > hwdata ) {
SDL_HIDAPI_Device * device = joystick - > hwdata - > device ;
result = device - > driver - > SendJoystickEffect ( device , joystick , data , size ) ;
} else {
2022-01-17 10:22:30 -06:00
result = SDL_SetError ( " SendEffect failed, device disconnected " ) ;
2021-07-08 15:22:41 -05:00
}
return result ;
}
2022-11-30 14:51:59 -06:00
static int HIDAPI_JoystickSetSensorsEnabled ( SDL_Joystick * joystick , SDL_bool enabled )
2020-11-17 12:30:20 -06:00
{
int result ;
2022-12-13 16:03:40 -06:00
SDL_AssertJoysticksLocked ( ) ;
2020-11-17 12:30:20 -06:00
if ( joystick - > hwdata ) {
SDL_HIDAPI_Device * device = joystick - > hwdata - > device ;
result = device - > driver - > SetJoystickSensorsEnabled ( device , joystick , enabled ) ;
} else {
2022-01-17 10:22:30 -06:00
result = SDL_SetError ( " SetSensorsEnabled failed, device disconnected " ) ;
2020-11-17 12:30:20 -06:00
}
return result ;
}
2022-11-30 14:51:59 -06:00
static void HIDAPI_JoystickUpdate ( SDL_Joystick * joystick )
2018-08-09 18:00:17 -05:00
{
2019-12-19 17:01:35 -06:00
/* This is handled in SDL_HIDAPI_UpdateDevices() */
2018-08-09 18:00:17 -05:00
}
2022-12-13 16:03:40 -06:00
static void HIDAPI_JoystickClose ( SDL_Joystick * joystick ) SDL_NO_THREAD_SAFETY_ANALYSIS /* We unlock the device lock so rumble can complete */
2018-08-09 18:00:17 -05:00
{
2022-12-13 16:03:40 -06:00
SDL_AssertJoysticksLocked ( ) ;
2019-12-19 17:01:30 -06:00
if ( joystick - > hwdata ) {
SDL_HIDAPI_Device * device = joystick - > hwdata - > device ;
2020-12-07 11:38:21 -06:00
int i ;
2019-06-19 17:54:21 -05:00
2020-12-07 11:38:21 -06:00
/* Wait up to 30 ms for pending rumble to complete */
2020-12-13 03:20:38 -06:00
if ( device - > updating ) {
/* Unlock the device so rumble can complete */
SDL_UnlockMutex ( device - > dev_lock ) ;
}
2020-12-07 11:38:21 -06:00
for ( i = 0 ; i < 3 ; + + i ) {
2020-12-13 03:20:38 -06:00
if ( SDL_AtomicGet ( & device - > rumble_pending ) > 0 ) {
2020-12-07 11:38:21 -06:00
SDL_Delay ( 10 ) ;
}
2020-02-04 17:26:56 -06:00
}
2020-12-13 03:20:38 -06:00
if ( device - > updating ) {
/* Relock the device */
SDL_LockMutex ( device - > dev_lock ) ;
}
2020-02-04 17:26:56 -06:00
2019-12-19 17:01:30 -06:00
device - > driver - > CloseJoystick ( device , joystick ) ;
SDL_free ( joystick - > hwdata ) ;
joystick - > hwdata = NULL ;
}
2018-08-09 18:00:17 -05:00
}
2022-11-30 14:51:59 -06:00
static void HIDAPI_JoystickQuit ( void )
2018-08-09 18:00:17 -05:00
{
int i ;
2022-12-13 16:03:40 -06:00
SDL_AssertJoysticksLocked ( ) ;
2019-12-19 17:01:30 -06:00
shutting_down = SDL_TRUE ;
2020-12-07 11:38:21 -06:00
SDL_HIDAPI_QuitRumble ( ) ;
2018-08-09 18:00:17 -05:00
while ( SDL_HIDAPI_devices ) {
2022-07-28 21:22:27 -05:00
SDL_HIDAPI_Device * device = SDL_HIDAPI_devices ;
if ( device - > parent ) {
/* When a child device goes away, so does the parent */
device = device - > parent ;
for ( i = 0 ; i < device - > num_children ; + + i ) {
HIDAPI_DelDevice ( device - > children [ i ] ) ;
}
HIDAPI_DelDevice ( device ) ;
} else {
HIDAPI_DelDevice ( device ) ;
}
2018-08-09 18:00:17 -05:00
}
2020-02-04 17:26:56 -06:00
2020-12-07 11:38:21 -06:00
/* Make sure the drivers cleaned up properly */
SDL_assert ( SDL_HIDAPI_numjoysticks = = 0 ) ;
2020-02-04 17:26:56 -06:00
2018-08-09 18:00:17 -05:00
for ( i = 0 ; i < SDL_arraysize ( SDL_HIDAPI_drivers ) ; + + i ) {
SDL_HIDAPI_DeviceDriver * driver = SDL_HIDAPI_drivers [ i ] ;
2022-08-19 13:11:23 -05:00
driver - > UnregisterHints ( SDL_HIDAPIDriverHintChanged , driver ) ;
2018-08-09 18:00:17 -05:00
}
2022-08-03 15:07:47 -05:00
SDL_DelHintCallback ( SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS ,
2022-07-28 21:22:27 -05:00
SDL_HIDAPIDriverHintChanged , NULL ) ;
2018-08-09 18:00:17 -05:00
SDL_DelHintCallback ( SDL_HINT_JOYSTICK_HIDAPI ,
SDL_HIDAPIDriverHintChanged , NULL ) ;
2021-11-08 00:58:44 -06:00
SDL_hid_exit ( ) ;
2019-07-31 11:14:48 -05:00
2022-06-30 20:36:45 -05:00
SDL_HIDAPI_change_count = 0 ;
2019-12-19 17:01:30 -06:00
shutting_down = SDL_FALSE ;
2019-07-31 11:14:48 -05:00
initialized = SDL_FALSE ;
2018-08-09 18:00:17 -05:00
}
2022-11-30 14:51:59 -06:00
static SDL_bool HIDAPI_JoystickGetGamepadMapping ( int device_index , SDL_GamepadMapping * out )
2020-05-29 15:37:21 -05:00
{
return SDL_FALSE ;
}
2022-11-30 14:51:59 -06:00
SDL_JoystickDriver SDL_HIDAPI_JoystickDriver = {
2018-08-09 18:00:17 -05:00
HIDAPI_JoystickInit ,
HIDAPI_JoystickGetCount ,
HIDAPI_JoystickDetect ,
HIDAPI_JoystickGetDeviceName ,
2022-04-26 16:54:14 -05:00
HIDAPI_JoystickGetDevicePath ,
2018-10-25 18:53:14 -05:00
HIDAPI_JoystickGetDevicePlayerIndex ,
2019-12-20 22:12:03 -06:00
HIDAPI_JoystickSetDevicePlayerIndex ,
2018-08-09 18:00:17 -05:00
HIDAPI_JoystickGetDeviceGUID ,
HIDAPI_JoystickGetDeviceInstanceID ,
HIDAPI_JoystickOpen ,
HIDAPI_JoystickRumble ,
2020-11-11 20:57:37 -06:00
HIDAPI_JoystickRumbleTriggers ,
2021-11-11 11:13:08 -06:00
HIDAPI_JoystickGetCapabilities ,
2020-04-30 10:57:29 -05:00
HIDAPI_JoystickSetLED ,
2021-07-08 15:22:41 -05:00
HIDAPI_JoystickSendEffect ,
2020-11-17 12:30:20 -06:00
HIDAPI_JoystickSetSensorsEnabled ,
2018-08-09 18:00:17 -05:00
HIDAPI_JoystickUpdate ,
HIDAPI_JoystickClose ,
HIDAPI_JoystickQuit ,
2020-05-29 15:37:21 -05:00
HIDAPI_JoystickGetGamepadMapping
2018-08-09 18:00:17 -05:00
} ;
# endif /* SDL_JOYSTICK_HIDAPI */