From fdc5efe1cbbcbffda016fbab9d5d9083ba040470 Mon Sep 17 00:00:00 2001 From: Sanjay Govind Date: Wed, 18 Mar 2026 05:45:26 +1300 Subject: [PATCH 1/6] add vids and pids for a variety of xbox 360 devices (#15211) Added vids for a variety of xbox 360 devices, mostly for linux use. Corrected wheel vid and pid being flagged as unknown. Internally, when XUSB is building vid and pids for wireless devices, it assigns 0x02a1 for devices with subtype 1 and 0x02a2 for devices with subtype 2, which are wheels. Some of these vids and pids do rely on the following patch being merged into the linux kernel, as I have overhauled how VID and PIDs are handled there for wireless devices. https://patchwork.kernel.org/project/linux-input/patch/20260314075034.1488655-2-sanjay.govind9@gmail.com/ Also added some lists for guitar and drum devices, so we can set controller types correctly for those controllers. --- include/SDL3/SDL_hints.h | 34 ++++++++++++++++ src/joystick/SDL_joystick.c | 71 ++++++++++++++++++++++++++++++++++ src/joystick/SDL_joystick_c.h | 8 +++- src/joystick/controller_list.h | 30 +++++++++++++- 4 files changed, 140 insertions(+), 3 deletions(-) diff --git a/include/SDL3/SDL_hints.h b/include/SDL3/SDL_hints.h index 4ac405d243..0596171b98 100644 --- a/include/SDL3/SDL_hints.h +++ b/include/SDL3/SDL_hints.h @@ -1342,6 +1342,23 @@ extern "C" { */ #define SDL_HINT_JOYSTICK_DEVICE "SDL_JOYSTICK_DEVICE" +/** + * A variable containing a list of drum style controllers. + * + * The format of the string is a comma separated list of USB VID/PID pairs in + * hexadecimal form, e.g. + * + * `0xAAAA/0xBBBB,0xCCCC/0xDDDD` + * + * The variable can also take the form of "@file", in which case the named + * file will be loaded and interpreted as the value of the variable. + * + * This hint can be set anytime. + * + * \since This hint is available since SDL 3.4.4. + */ +#define SDL_HINT_JOYSTICK_DRUM_DEVICES "SDL_JOYSTICK_DRUM_DEVICES" + /** * A variable controlling whether enhanced reports should be used for * controllers when using the HIDAPI driver. @@ -1461,6 +1478,23 @@ extern "C" { */ #define SDL_HINT_JOYSTICK_GAMECUBE_DEVICES_EXCLUDED "SDL_JOYSTICK_GAMECUBE_DEVICES_EXCLUDED" +/** + * A variable containing a list of guitar style controllers. + * + * The format of the string is a comma separated list of USB VID/PID pairs in + * hexadecimal form, e.g. + * + * `0xAAAA/0xBBBB,0xCCCC/0xDDDD` + * + * The variable can also take the form of "@file", in which case the named + * file will be loaded and interpreted as the value of the variable. + * + * This hint can be set anytime. + * + * \since This hint is available since SDL 3.4.4. + */ +#define SDL_HINT_JOYSTICK_GUITAR_DEVICES "SDL_JOYSTICK_GUITAR_DEVICES" + /** * A variable controlling whether the HIDAPI joystick drivers should be used. * diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c index 4b52980d5a..88af27c3d7 100644 --- a/src/joystick/SDL_joystick.c +++ b/src/joystick/SDL_joystick.c @@ -564,6 +564,7 @@ static Uint32 initial_wheel_devices[] = { MAKE_VIDPID(0x046d, 0xc29a), // Logitech Driving Force GT MAKE_VIDPID(0x046d, 0xc29b), // Logitech G27 MAKE_VIDPID(0x046d, 0xca03), // Logitech Momo Racing + MAKE_VIDPID(0x045e, 0x02a2), // Xbox 360 Wireless Racing Wheel MAKE_VIDPID(0x0483, 0x0522), // Simagic Wheelbase (including M10, Alpha Mini, Alpha, Alpha U) MAKE_VIDPID(0x0483, 0xa355), // VRS DirectForce Pro Wheel Base MAKE_VIDPID(0x0583, 0xa132), // Padix USB Wireless 2.4GHz Wheelpad @@ -610,6 +611,55 @@ static SDL_vidpid_list wheel_devices = { false }; +static Uint32 initial_guitar_devices[] = { + MAKE_VIDPID(0x12ba, 0x0100), // PS3 Guitar Hero Guitar + MAKE_VIDPID(0x12ba, 0x0200), // PS3 Rock Band Guitar + MAKE_VIDPID(0x12ba, 0x074b), // PS3 / Wii U Guitar Hero Live Guitar + MAKE_VIDPID(0x1BAD, 0x0004), // Wii RB1 Guitar (Uses PS3 protocol) + MAKE_VIDPID(0x1BAD, 0x3010), // Wii RB2 Guitar (Uses PS3 protocol) + MAKE_VIDPID(0x0351, 0x1000), // CRKD Guitar + MAKE_VIDPID(0x0351, 0x2000), // CRKD Guitar + MAKE_VIDPID(0x0738, 0x02A6), // Mad Catz Wireless Rock Band Guitar + MAKE_VIDPID(0x0738, 0x02AB), // Mad Catz Wireless Precision Bass Guitar + MAKE_VIDPID(0x0738, 0x9806), // Mad Catz Precision Bass Guitar + MAKE_VIDPID(0x1430, 0x02a7), // Guitar Hero Wireless Guitar (Linux) + MAKE_VIDPID(0x1430, 0x0705), // Guitar Hero 5 Guitar + MAKE_VIDPID(0x1430, 0x070B), // Guitar Hero Live Guitar + MAKE_VIDPID(0x1430, 0x4734), // Guitar Hero World Tour Kiosk + MAKE_VIDPID(0x1430, 0x4748), // RedOctane Guitar Hero X-plorer + MAKE_VIDPID(0x1bad, 0x02a6), // Rock Band 2 Wireless Guitar (Linux) + MAKE_VIDPID(0x1bad, 0x02ab), // Rock Band Wireless Bass Guitar (Linux) + MAKE_VIDPID(0x2068, 0x0001), // Power Gig Guitar + MAKE_VIDPID(0x3651, 0x1000), // CRKD Guitar + MAKE_VIDPID(0x3651, 0x6000), // CRKD Guitar +}; +static SDL_vidpid_list guitar_devices = { + SDL_HINT_JOYSTICK_GUITAR_DEVICES, 0, 0, NULL, + NULL, 0, 0, NULL, + SDL_arraysize(initial_guitar_devices), initial_guitar_devices, + false +}; + +static Uint32 initial_drum_devices[] = { + MAKE_VIDPID(0x12ba, 0x0120), // PS3 Guitar Hero Drums + MAKE_VIDPID(0x12ba, 0x0210), // PS3 Rock Band Drums + MAKE_VIDPID(0x12ba, 0x0218), // PS3 Midi Pro Adapter - Drums Mode + MAKE_VIDPID(0x1BAD, 0x0005), // Wii RB1 Drums (Uses PS3 protocol) + MAKE_VIDPID(0x1BAD, 0x3110), // Wii RB2 Drums (Uses PS3 protocol) + MAKE_VIDPID(0x1BAD, 0x3138), // Wii RB3 Midi Pro Adapter - Drums Mode (Uses PS3 protocol) + MAKE_VIDPID(0x1430, 0x02a8), // Guitar Hero Wireless Drum Kit (Linux) + MAKE_VIDPID(0x1430, 0x0805), // Band Hero Wireless Drum Kit + MAKE_VIDPID(0x1bad, 0x0003), // Harmonix Rock Band Drumkit + MAKE_VIDPID(0x1bad, 0x0130), // ION Drum Rocker + MAKE_VIDPID(0x2068, 0x0002), // Power Gig Drums +}; +static SDL_vidpid_list drum_devices = { + SDL_HINT_JOYSTICK_DRUM_DEVICES, 0, 0, NULL, + NULL, 0, 0, NULL, + SDL_arraysize(initial_drum_devices), initial_drum_devices, + false +}; + static Uint32 initial_zero_centered_devices[] = { MAKE_VIDPID(0x05a0, 0x3232), // 8Bitdo Zero Gamepad MAKE_VIDPID(0x0e8f, 0x3013), // HuiJia SNES USB adapter @@ -851,8 +901,10 @@ bool SDL_InitJoysticks(void) SDL_LoadVIDPIDList(&old_xboxone_controllers); SDL_LoadVIDPIDList(&arcadestick_devices); SDL_LoadVIDPIDList(&blacklist_devices); + SDL_LoadVIDPIDList(&drum_devices); SDL_LoadVIDPIDList(&flightstick_devices); SDL_LoadVIDPIDList(&gamecube_devices); + SDL_LoadVIDPIDList(&guitar_devices); SDL_LoadVIDPIDList(&rog_gamepad_mice); SDL_LoadVIDPIDList(&throttle_devices); SDL_LoadVIDPIDList(&wheel_devices); @@ -2284,8 +2336,10 @@ void SDL_QuitJoysticks(void) SDL_FreeVIDPIDList(&old_xboxone_controllers); SDL_FreeVIDPIDList(&arcadestick_devices); SDL_FreeVIDPIDList(&blacklist_devices); + SDL_FreeVIDPIDList(&drum_devices); SDL_FreeVIDPIDList(&flightstick_devices); SDL_FreeVIDPIDList(&gamecube_devices); + SDL_FreeVIDPIDList(&guitar_devices); SDL_FreeVIDPIDList(&rog_gamepad_mice); SDL_FreeVIDPIDList(&throttle_devices); SDL_FreeVIDPIDList(&wheel_devices); @@ -3371,6 +3425,16 @@ bool SDL_IsJoystickVIRTUAL(SDL_GUID guid) return (guid.data[14] == 'v') ? true : false; } +bool SDL_IsJoystickDrumKit(Uint16 vendor_id, Uint16 product_id) +{ + return SDL_VIDPIDInList(vendor_id, product_id, &drum_devices); +} + +bool SDL_IsJoystickGuitar(Uint16 vendor_id, Uint16 product_id) +{ + return SDL_VIDPIDInList(vendor_id, product_id, &guitar_devices); +} + bool SDL_IsJoystickWheel(Uint16 vendor_id, Uint16 product_id) { return SDL_VIDPIDInList(vendor_id, product_id, &wheel_devices); @@ -3398,6 +3462,13 @@ static SDL_JoystickType SDL_GetJoystickGUIDType(SDL_GUID guid) SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL, NULL); + if (SDL_IsJoystickDrumKit(vendor, product)) { + return SDL_JOYSTICK_TYPE_DRUM_KIT; + } + if (SDL_IsJoystickGuitar(vendor, product)) { + return SDL_JOYSTICK_TYPE_GUITAR; + } + if (SDL_IsJoystickWheel(vendor, product)) { return SDL_JOYSTICK_TYPE_WHEEL; } diff --git a/src/joystick/SDL_joystick_c.h b/src/joystick/SDL_joystick_c.h index 8e3639b94a..7d701680a9 100644 --- a/src/joystick/SDL_joystick_c.h +++ b/src/joystick/SDL_joystick_c.h @@ -172,7 +172,13 @@ extern bool SDL_IsJoystickRAWINPUT(SDL_GUID guid); extern bool SDL_IsJoystickVIRTUAL(SDL_GUID guid); // Function to return whether a joystick is a wheel -bool SDL_IsJoystickWheel(Uint16 vendor_id, Uint16 product_id); +extern bool SDL_IsJoystickWheel(Uint16 vendor_id, Uint16 product_id); + +// Function to return whether a joystick is a guitar +extern bool SDL_IsJoystickGuitar(Uint16 vendor_id, Uint16 product_id); + +// Function to return whether a joystick is a drum kit +extern bool SDL_IsJoystickDrumKit(Uint16 vendor_id, Uint16 product_id); // Function to return whether a joystick should be ignored extern bool SDL_ShouldIgnoreJoystick(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name); diff --git a/src/joystick/controller_list.h b/src/joystick/controller_list.h index ca7b85646e..c1d0da9b9f 100644 --- a/src/joystick/controller_list.h +++ b/src/joystick/controller_list.h @@ -193,6 +193,8 @@ static const ControllerDescription_t arrControllers[] = { { MAKE_CONTROLLER_ID( 0x0079, 0x0006 ), k_eControllerType_UnknownNonSteamController, NULL }, // DragonRise Generic USB PCB, sometimes configured as a PC Twin Shock Controller - looks like a DS3 but the face buttons are 1-4 instead of symbols { MAKE_CONTROLLER_ID( 0x0079, 0x18d4 ), k_eControllerType_XBox360Controller, NULL }, // GPD Win 2 X-Box Controller + { MAKE_CONTROLLER_ID( 0x0351, 0x1000 ), k_eControllerType_XBox360Controller, NULL }, // CRKD Guitar + { MAKE_CONTROLLER_ID( 0x0351, 0x2000 ), k_eControllerType_XBox360Controller, NULL }, // CRKD Guitar { MAKE_CONTROLLER_ID( 0x03eb, 0xff02 ), k_eControllerType_XBox360Controller, NULL }, // Wooting Two { MAKE_CONTROLLER_ID( 0x044f, 0xb326 ), k_eControllerType_XBox360Controller, NULL }, // Thrustmaster Gamepad GP XID { MAKE_CONTROLLER_ID( 0x045e, 0x028e ), k_eControllerType_XBox360Controller, "Xbox 360 Controller" }, // Microsoft Xbox 360 Wired Controller @@ -200,6 +202,7 @@ static const ControllerDescription_t arrControllers[] = { { MAKE_CONTROLLER_ID( 0x045e, 0x0291 ), k_eControllerType_XBox360Controller, "Xbox 360 Wireless Controller" }, // X-box 360 Wireless Receiver (third party knockoff) { MAKE_CONTROLLER_ID( 0x045e, 0x02a0 ), k_eControllerType_XBox360Controller, NULL }, // Microsoft Xbox 360 Big Button IR { MAKE_CONTROLLER_ID( 0x045e, 0x02a1 ), k_eControllerType_XBox360Controller, "Xbox 360 Wireless Controller" }, // Microsoft Xbox 360 Wireless Controller with XUSB driver on Windows + { MAKE_CONTROLLER_ID( 0x045e, 0x02a2 ), k_eControllerType_XBox360Controller, "Xbox 360 Wireless Racing Wheel" }, // Xbox 360 Wireless Racing Wheel with XUSB driver on Windows { MAKE_CONTROLLER_ID( 0x045e, 0x02a9 ), k_eControllerType_XBox360Controller, "Xbox 360 Wireless Controller" }, // X-box 360 Wireless Receiver (third party knockoff) { MAKE_CONTROLLER_ID( 0x045e, 0x0719 ), k_eControllerType_XBox360Controller, "Xbox 360 Wireless Controller" }, // Microsoft Xbox 360 Wireless Receiver { MAKE_CONTROLLER_ID( 0x046d, 0xc21d ), k_eControllerType_XBox360Controller, NULL }, // Logitech Gamepad F310 @@ -209,6 +212,8 @@ static const ControllerDescription_t arrControllers[] = { { MAKE_CONTROLLER_ID( 0x056e, 0x2004 ), k_eControllerType_XBox360Controller, NULL }, // Elecom JC-U3613M // This isn't actually an Xbox 360 controller, it just looks like one // { MAKE_CONTROLLER_ID( 0x06a3, 0xf51a ), k_eControllerType_XBox360Controller, NULL }, // Saitek P3600 + { MAKE_CONTROLLER_ID( 0x0738, 0x02A6 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Wireless Rock Band Guitar + { MAKE_CONTROLLER_ID( 0x0738, 0x02AB ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Wireless Precision Bass Guitar { MAKE_CONTROLLER_ID( 0x0738, 0x4716 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Wired Xbox 360 Controller { MAKE_CONTROLLER_ID( 0x0738, 0x4718 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Street Fighter IV FightStick SE { MAKE_CONTROLLER_ID( 0x0738, 0x4726 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Xbox 360 Controller @@ -216,6 +221,7 @@ static const ControllerDescription_t arrControllers[] = { { MAKE_CONTROLLER_ID( 0x0738, 0x4736 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz MicroCon Gamepad { MAKE_CONTROLLER_ID( 0x0738, 0x4738 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Wired Xbox 360 Controller (SFIV) { MAKE_CONTROLLER_ID( 0x0738, 0x4740 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Beat Pad + { MAKE_CONTROLLER_ID( 0x0738, 0x9806 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Precision Bass Guitar { MAKE_CONTROLLER_ID( 0x0738, 0xb726 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Xbox controller - MW2 { MAKE_CONTROLLER_ID( 0x0738, 0xbeef ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz JOYTECH NEO SE Advanced GamePad { MAKE_CONTROLLER_ID( 0x0738, 0xcb02 ), k_eControllerType_XBox360Controller, NULL }, // Saitek Cyborg Rumble Pad - PC/Xbox 360 @@ -259,6 +265,14 @@ static const ControllerDescription_t arrControllers[] = { { MAKE_CONTROLLER_ID( 0x12ab, 0x0301 ), k_eControllerType_XBox360Controller, NULL }, // PDP AFTERGLOW AX.1 { MAKE_CONTROLLER_ID( 0x12ab, 0x0303 ), k_eControllerType_XBox360Controller, NULL }, // Mortal Kombat Klassic FightStick { MAKE_CONTROLLER_ID( 0x1430, 0x02a0 ), k_eControllerType_XBox360Controller, NULL }, // RedOctane Controller Adapter + { MAKE_CONTROLLER_ID( 0x1430, 0x02a7 ), k_eControllerType_XBox360Controller, NULL }, // Guitar Hero Wireless Guitar (Linux) + { MAKE_CONTROLLER_ID( 0x1430, 0x02a8 ), k_eControllerType_XBox360Controller, NULL }, // Guitar Hero Wireless Drum Kit (Linux) + { MAKE_CONTROLLER_ID( 0x1430, 0x0705 ), k_eControllerType_XBox360Controller, NULL }, // Guitar Hero 5 Guitar + { MAKE_CONTROLLER_ID( 0x1430, 0x070B ), k_eControllerType_XBox360Controller, NULL }, // Guitar Hero Live Guitar + { MAKE_CONTROLLER_ID( 0x1430, 0x0805 ), k_eControllerType_XBox360Controller, NULL }, // Band Hero Wireless Drum Kit + { MAKE_CONTROLLER_ID( 0x1430, 0x1715 ), k_eControllerType_XBox360Controller, NULL }, // DJ Hero Turntable (Wired) + { MAKE_CONTROLLER_ID( 0x1430, 0x1705 ), k_eControllerType_XBox360Controller, NULL }, // DJ Hero Turntable (Wireless) + { MAKE_CONTROLLER_ID( 0x1430, 0x4734 ), k_eControllerType_XBox360Controller, NULL }, // Guitar Hero World Tour Kiosk { MAKE_CONTROLLER_ID( 0x1430, 0x4748 ), k_eControllerType_XBox360Controller, NULL }, // RedOctane Guitar Hero X-plorer { MAKE_CONTROLLER_ID( 0x1430, 0xf801 ), k_eControllerType_XBox360Controller, NULL }, // RedOctane Controller { MAKE_CONTROLLER_ID( 0x146b, 0x0601 ), k_eControllerType_XBox360Controller, NULL }, // BigBen Interactive XBOX 360 Controller @@ -271,8 +285,17 @@ static const ControllerDescription_t arrControllers[] = { { MAKE_CONTROLLER_ID( 0x1689, 0xfd01 ), k_eControllerType_XBox360Controller, NULL }, // Razer Onza Classic Edition { MAKE_CONTROLLER_ID( 0x1689, 0xfe00 ), k_eControllerType_XBox360Controller, NULL }, // Razer Sabertooth { MAKE_CONTROLLER_ID( 0x1949, 0x041a ), k_eControllerType_XBox360Controller, "Amazon Luna Controller" }, // Amazon Luna Controller - { MAKE_CONTROLLER_ID( 0x1bad, 0x0002 ), k_eControllerType_XBox360Controller, NULL }, // Harmonix Rock Band Guitar + { MAKE_CONTROLLER_ID( 0x1bad, 0x0002 ), k_eControllerType_XBox360Controller, NULL }, // Harmonix Rock Band 1 Guitar { MAKE_CONTROLLER_ID( 0x1bad, 0x0003 ), k_eControllerType_XBox360Controller, NULL }, // Harmonix Rock Band Drumkit + { MAKE_CONTROLLER_ID( 0x1bad, 0x0130 ), k_eControllerType_XBox360Controller, NULL }, // ION Drum Rocker + { MAKE_CONTROLLER_ID( 0x1bad, 0x02a6 ), k_eControllerType_XBox360Controller, NULL }, // Rock Band 2 Wireless Guitar (Linux) + { MAKE_CONTROLLER_ID( 0x1bad, 0x02ab ), k_eControllerType_XBox360Controller, NULL }, // Rock Band Wireless Bass Guitar (Linux) + { MAKE_CONTROLLER_ID( 0x1bad, 0x1330 ), k_eControllerType_XBox360Controller, NULL }, // Rock Band Keyboard (Mustang) + { MAKE_CONTROLLER_ID( 0x1bad, 0x1338 ), k_eControllerType_XBox360Controller, NULL }, // Rock Band MIDI Pro Adapter (Keyboard) + { MAKE_CONTROLLER_ID( 0x1bad, 0x1430 ), k_eControllerType_XBox360Controller, NULL }, // Rock Band Pro Guitar (Mustang) + { MAKE_CONTROLLER_ID( 0x1bad, 0x1530 ), k_eControllerType_XBox360Controller, NULL }, // Rock Band Pro Guitar (Squire) + { MAKE_CONTROLLER_ID( 0x1bad, 0x1438 ), k_eControllerType_XBox360Controller, NULL }, // Rock Band MIDI Pro Adapter (Mustang Guitar) + { MAKE_CONTROLLER_ID( 0x1bad, 0x1538 ), k_eControllerType_XBox360Controller, NULL }, // Rock Band MIDI Pro Adapter (Squire Guitar) { MAKE_CONTROLLER_ID( 0x1bad, 0xf016 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Xbox 360 Controller { MAKE_CONTROLLER_ID( 0x1bad, 0xf018 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Street Fighter IV SE Fighting Stick { MAKE_CONTROLLER_ID( 0x1bad, 0xf019 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Brawlstick for Xbox 360 @@ -306,6 +329,8 @@ static const ControllerDescription_t arrControllers[] = { { MAKE_CONTROLLER_ID( 0x1bad, 0xfa01 ), k_eControllerType_XBox360Controller, NULL }, // MadCatz GamePad { MAKE_CONTROLLER_ID( 0x1bad, 0xfd00 ), k_eControllerType_XBox360Controller, NULL }, // Razer Onza TE { MAKE_CONTROLLER_ID( 0x1bad, 0xfd01 ), k_eControllerType_XBox360Controller, NULL }, // Razer Onza + { MAKE_CONTROLLER_ID( 0x2068, 0x0001 ), k_eControllerType_XBox360Controller, NULL }, // Power Gig Guitar + { MAKE_CONTROLLER_ID( 0x2068, 0x0002 ), k_eControllerType_XBox360Controller, NULL }, // Power Gig Drums { MAKE_CONTROLLER_ID( 0x24c6, 0x5000 ), k_eControllerType_XBox360Controller, NULL }, // Razer Atrox Arcade Stick { MAKE_CONTROLLER_ID( 0x24c6, 0x5300 ), k_eControllerType_XBox360Controller, NULL }, // PowerA MINI PROEX Controller { MAKE_CONTROLLER_ID( 0x24c6, 0x5303 ), k_eControllerType_XBox360Controller, NULL }, // Xbox Airflo wired controller @@ -330,6 +355,8 @@ static const ControllerDescription_t arrControllers[] = { { MAKE_CONTROLLER_ID( 0x24c6, 0xfafc ), k_eControllerType_XBox360Controller, NULL }, // Afterglow Gamepad 1 { MAKE_CONTROLLER_ID( 0x24c6, 0xfafd ), k_eControllerType_XBox360Controller, NULL }, // Afterglow Gamepad 3 { MAKE_CONTROLLER_ID( 0x24c6, 0xfafe ), k_eControllerType_XBox360Controller, NULL }, // Rock Candy Gamepad for Xbox 360 + { MAKE_CONTROLLER_ID( 0x3651, 0x1000 ), k_eControllerType_XBox360Controller, NULL }, // CRKD Guitar + { MAKE_CONTROLLER_ID( 0x3651, 0x6000 ), k_eControllerType_XBox360Controller, NULL }, // CRKD Guitar { MAKE_CONTROLLER_ID( 0x03f0, 0x0495 ), k_eControllerType_XBoxOneController, NULL }, // HP HyperX Clutch Gladiate { MAKE_CONTROLLER_ID( 0x044f, 0xd012 ), k_eControllerType_XBoxOneController, NULL }, // ThrustMaster eSwap PRO Controller Xbox @@ -470,7 +497,6 @@ static const ControllerDescription_t arrControllers[] = { { MAKE_CONTROLLER_ID( 0x146b, 0x0611 ), k_eControllerType_XBoxOneController, NULL }, // Xbox Controller Mode for NACON Revolution 3 // These have been added via Minidump for unrecognized Xinput controller assert - { MAKE_CONTROLLER_ID( 0x045e, 0x02a2 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller - Microsoft VID { MAKE_CONTROLLER_ID( 0x0e6f, 0x1414 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller { MAKE_CONTROLLER_ID( 0x0e6f, 0x0159 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller { MAKE_CONTROLLER_ID( 0x24c6, 0xfaff ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller From 75dead7f96a3331e620d2a74ce6e3a99b6f9b342 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Tue, 17 Mar 2026 09:49:15 -0700 Subject: [PATCH 2/6] Minor cleanup --- src/joystick/SDL_joystick.c | 35 ++++++++++++++++++----------------- src/joystick/SDL_joystick_c.h | 6 ------ 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c index 88af27c3d7..dde9927008 100644 --- a/src/joystick/SDL_joystick.c +++ b/src/joystick/SDL_joystick.c @@ -3425,16 +3425,6 @@ bool SDL_IsJoystickVIRTUAL(SDL_GUID guid) return (guid.data[14] == 'v') ? true : false; } -bool SDL_IsJoystickDrumKit(Uint16 vendor_id, Uint16 product_id) -{ - return SDL_VIDPIDInList(vendor_id, product_id, &drum_devices); -} - -bool SDL_IsJoystickGuitar(Uint16 vendor_id, Uint16 product_id) -{ - return SDL_VIDPIDInList(vendor_id, product_id, &guitar_devices); -} - bool SDL_IsJoystickWheel(Uint16 vendor_id, Uint16 product_id) { return SDL_VIDPIDInList(vendor_id, product_id, &wheel_devices); @@ -3455,6 +3445,16 @@ static bool SDL_IsJoystickThrottle(Uint16 vendor_id, Uint16 product_id) return SDL_VIDPIDInList(vendor_id, product_id, &throttle_devices); } +static bool SDL_IsJoystickGuitar(Uint16 vendor_id, Uint16 product_id) +{ + return SDL_VIDPIDInList(vendor_id, product_id, &guitar_devices); +} + +static bool SDL_IsJoystickDrumKit(Uint16 vendor_id, Uint16 product_id) +{ + return SDL_VIDPIDInList(vendor_id, product_id, &drum_devices); +} + static SDL_JoystickType SDL_GetJoystickGUIDType(SDL_GUID guid) { Uint16 vendor; @@ -3462,13 +3462,6 @@ static SDL_JoystickType SDL_GetJoystickGUIDType(SDL_GUID guid) SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL, NULL); - if (SDL_IsJoystickDrumKit(vendor, product)) { - return SDL_JOYSTICK_TYPE_DRUM_KIT; - } - if (SDL_IsJoystickGuitar(vendor, product)) { - return SDL_JOYSTICK_TYPE_GUITAR; - } - if (SDL_IsJoystickWheel(vendor, product)) { return SDL_JOYSTICK_TYPE_WHEEL; } @@ -3485,6 +3478,14 @@ static SDL_JoystickType SDL_GetJoystickGUIDType(SDL_GUID guid) return SDL_JOYSTICK_TYPE_THROTTLE; } + if (SDL_IsJoystickGuitar(vendor, product)) { + return SDL_JOYSTICK_TYPE_GUITAR; + } + + if (SDL_IsJoystickDrumKit(vendor, product)) { + return SDL_JOYSTICK_TYPE_DRUM_KIT; + } + if (SDL_IsJoystickXInput(guid)) { // XInput GUID, get the type based on the XInput device subtype switch (guid.data[15]) { diff --git a/src/joystick/SDL_joystick_c.h b/src/joystick/SDL_joystick_c.h index 7d701680a9..46acbc5ca8 100644 --- a/src/joystick/SDL_joystick_c.h +++ b/src/joystick/SDL_joystick_c.h @@ -174,12 +174,6 @@ extern bool SDL_IsJoystickVIRTUAL(SDL_GUID guid); // Function to return whether a joystick is a wheel extern bool SDL_IsJoystickWheel(Uint16 vendor_id, Uint16 product_id); -// Function to return whether a joystick is a guitar -extern bool SDL_IsJoystickGuitar(Uint16 vendor_id, Uint16 product_id); - -// Function to return whether a joystick is a drum kit -extern bool SDL_IsJoystickDrumKit(Uint16 vendor_id, Uint16 product_id); - // Function to return whether a joystick should be ignored extern bool SDL_ShouldIgnoreJoystick(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name); From 3d21b3bc680a9c49f62f6dfc219e2d81fc787ed5 Mon Sep 17 00:00:00 2001 From: Frank Praznik Date: Tue, 17 Mar 2026 12:34:59 -0400 Subject: [PATCH 3/6] wayland: Scale custom cursors with the pointer scale When emulating display modes or using display scaling, custom cursors need to be scaled, or they can appear too large or small relative to the window size. --- src/video/wayland/SDL_waylandmouse.c | 42 +++++++++++++++++++++++---- src/video/wayland/SDL_waylandmouse.h | 1 + src/video/wayland/SDL_waylandwindow.c | 8 +++++ 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/src/video/wayland/SDL_waylandmouse.c b/src/video/wayland/SDL_waylandmouse.c index 72b9d14d5e..2ae9a418ae 100644 --- a/src/video/wayland/SDL_waylandmouse.c +++ b/src/video/wayland/SDL_waylandmouse.c @@ -1103,12 +1103,14 @@ static void Wayland_CursorStateSetCursor(SDL_WaylandCursorState *state, const Wa dst_height = dst_width; } else { - // If viewports aren't available, the scale is always 1.0. - state->scale = viddata->viewporter && focus ? focus->scale_factor : 1.0; - dst_width = cursor_data->cursor_data.custom.width; - dst_height = cursor_data->cursor_data.custom.height; - hot_x = cursor_data->cursor_data.custom.hot_x; - hot_y = cursor_data->cursor_data.custom.hot_y; + /* If viewports aren't available, the scale is always 1.0. + * The dimensions are scaled by the pointer scale, so custom cursors will be scaled relative to the window size. + */ + state->scale = viddata->viewporter && focus ? SDL_min(focus->pointer_scale.x, focus->pointer_scale.y) : 1.0; + dst_width = SDL_max((int)SDL_lround((double)cursor_data->cursor_data.custom.width / state->scale), 1); + dst_height = SDL_max((int)SDL_lround((double)cursor_data->cursor_data.custom.height / state->scale), 1); + hot_x = (int)SDL_lround((double)cursor_data->cursor_data.custom.hot_x / state->scale); + hot_y = (int)SDL_lround((double)cursor_data->cursor_data.custom.hot_y / state->scale); } state->current_cursor = cursor_data; @@ -1180,6 +1182,34 @@ static void Wayland_CursorStateResetCursor(SDL_WaylandCursorState *state) state->current_frame = -1; } +void Wayland_DisplayUpdatePointerFocusedScale(SDL_WindowData *updated_window) +{ + SDL_VideoData *viddata = updated_window->waylandData; + SDL_WaylandSeat *seat; + const double new_scale = SDL_min(updated_window->pointer_scale.x, updated_window->pointer_scale.y); + + wl_list_for_each (seat, &viddata->seat_list, link) { + if (seat->pointer.focus == updated_window) { + SDL_WaylandCursorState *state = &seat->pointer.cursor_state; + if (state->current_cursor && !state->current_cursor->is_system_cursor && state->scale != new_scale) { + Wayland_CursorStateResetCursor(state); + Wayland_SeatUpdatePointerCursor(seat); + } + } + + SDL_WaylandPenTool *tool; + wl_list_for_each (tool, &seat->tablet.tool_list, link) { + if (tool->focus == updated_window) { + SDL_WaylandCursorState *state = &tool->cursor_state; + if (state->current_cursor && !state->current_cursor->is_system_cursor && state->scale != new_scale) { + Wayland_CursorStateResetCursor(&tool->cursor_state); + Wayland_TabletToolUpdateCursor(tool); + } + } + } + } +} + static bool Wayland_ShowCursor(SDL_Cursor *cursor) { SDL_VideoDevice *vd = SDL_GetVideoDevice(); diff --git a/src/video/wayland/SDL_waylandmouse.h b/src/video/wayland/SDL_waylandmouse.h index 85ba5eef24..1707445a35 100644 --- a/src/video/wayland/SDL_waylandmouse.h +++ b/src/video/wayland/SDL_waylandmouse.h @@ -29,6 +29,7 @@ extern void Wayland_FiniMouse(SDL_VideoData *data); extern void Wayland_SeatUpdatePointerCursor(SDL_WaylandSeat *seat); extern void Wayland_SeatSetDefaultCursor(SDL_WaylandSeat *seat); extern void Wayland_SeatResetCursor(SDL_WaylandSeat *seat); +extern void Wayland_DisplayUpdatePointerFocusedScale(SDL_WindowData *updated_window); extern void Wayland_TabletToolUpdateCursor(SDL_WaylandPenTool *tool); extern void Wayland_SeatWarpMouse(SDL_WaylandSeat *seat, SDL_WindowData *window, float x, float y); extern void Wayland_CursorStateSetFrameCallback(SDL_WaylandCursorState *state, void *userdata); diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c index d2ad64974d..20da36b633 100644 --- a/src/video/wayland/SDL_waylandwindow.c +++ b/src/video/wayland/SDL_waylandwindow.c @@ -30,6 +30,7 @@ #include "../../core/unix/SDL_appid.h" #include "../SDL_egl_c.h" #include "SDL_waylandevents_c.h" +#include "SDL_waylandmouse.h" #include "SDL_waylandwindow.h" #include "SDL_waylandvideo.h" #include "../../SDL_hints_c.h" @@ -287,6 +288,8 @@ static void ConfigureWindowGeometry(SDL_Window *window) { SDL_WindowData *data = window->internal; const double scale_factor = GetWindowScale(window); + const double prev_pointer_scale_x = data->pointer_scale.x; + const double prev_pointer_scale_y = data->pointer_scale.y; const int old_pixel_width = data->current.pixel_width; const int old_pixel_height = data->current.pixel_height; int window_width = 0; @@ -566,6 +569,11 @@ static void ConfigureWindowGeometry(SDL_Window *window) } } + // Update the scale for any focused cursors. + if (prev_pointer_scale_x != data->pointer_scale.x || prev_pointer_scale_y != data->pointer_scale.y) { + Wayland_DisplayUpdatePointerFocusedScale(data); + } + /* Update the min/max dimensions, primarily if the state was changed, and for non-resizable * xdg-toplevel windows where the limits should match the window size. */ From c717a20ec87a17ef79b00519e187d6985040a1ea Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Tue, 17 Mar 2026 12:25:13 -0700 Subject: [PATCH 4/6] Fixed initial window size and placement on visionOS --- src/video/uikit/SDL_uikitmetalview.m | 5 +++++ src/video/uikit/SDL_uikitvideo.m | 4 +++- src/video/uikit/SDL_uikitwindow.m | 21 +++++++++++++++++---- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/video/uikit/SDL_uikitmetalview.m b/src/video/uikit/SDL_uikitmetalview.m index da0a8edd4f..596b311165 100644 --- a/src/video/uikit/SDL_uikitmetalview.m +++ b/src/video/uikit/SDL_uikitmetalview.m @@ -69,6 +69,11 @@ size.width *= self.layer.contentsScale; size.height *= self.layer.contentsScale; + // Skip invalid sizes (can happen on visionOS before scene geometry is applied) + if (size.width <= 0 || size.height <= 0) { + return; + } + CAMetalLayer *metallayer = ((CAMetalLayer *)self.layer); if (metallayer.drawableSize.width != size.width || metallayer.drawableSize.height != size.height) { diff --git a/src/video/uikit/SDL_uikitvideo.m b/src/video/uikit/SDL_uikitvideo.m index 43fab3afcd..d31f70a13d 100644 --- a/src/video/uikit/SDL_uikitvideo.m +++ b/src/video/uikit/SDL_uikitvideo.m @@ -213,7 +213,9 @@ SDL_SystemTheme UIKit_GetSystemTheme(void) #ifdef SDL_PLATFORM_VISIONOS CGRect UIKit_ComputeViewFrame(SDL_Window *window) { - return CGRectMake(window->x, window->y, window->w, window->h); + // View origin is always (0,0) relative to the UIWindow. + // window->x/y are screen-level positions (often SDL_WINDOWPOS_UNDEFINED). + return CGRectMake(0, 0, window->w, window->h); } #else CGRect UIKit_ComputeViewFrame(SDL_Window *window, UIScreen *screen) diff --git a/src/video/uikit/SDL_uikitwindow.m b/src/video/uikit/SDL_uikitwindow.m index dd6dc27bd7..3f1f1b464d 100644 --- a/src/video/uikit/SDL_uikitwindow.m +++ b/src/video/uikit/SDL_uikitwindow.m @@ -186,6 +186,23 @@ bool UIKit_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Properti } if (scene) { uiwindow = [[UIWindow alloc] initWithWindowScene:scene]; + +#ifdef SDL_PLATFORM_VISIONOS + /* On visionOS, the window scene may not have its final geometry yet + * when the UIWindow is first created. Request the desired size now + * and set the UIWindow frame to match so views have valid initial + * dimensions before the async geometry update completes. */ + CGSize desiredSize = CGSizeMake(window->w, window->h); + uiwindow.frame = CGRectMake(0, 0, desiredSize.width, desiredSize.height); + + UIWindowSceneGeometryPreferences *preferences = + [[UIWindowSceneGeometryPreferencesVision alloc] initWithSize:desiredSize]; + [scene requestGeometryUpdateWithPreferences:preferences errorHandler:^(NSError * _Nonnull error) { + SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, + "Initial geometry request failed: %s", + [[error localizedDescription] UTF8String]); + }]; +#endif } } if (!uiwindow) { @@ -214,10 +231,6 @@ bool UIKit_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Properti if (!SetupWindowData(_this, window, uiwindow, true)) { return false; } - -#ifdef SDL_PLATFORM_VISIONOS - SDL_SetWindowSize(window, window->w, window->h); -#endif } return true; From d88f76caac150b50a1a26a84f1c64a6f032b4298 Mon Sep 17 00:00:00 2001 From: Frank Praznik Date: Tue, 17 Mar 2026 15:01:56 -0400 Subject: [PATCH 5/6] x11: Fix building when XInput2 is not available --- src/video/x11/SDL_x11xinput2.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/video/x11/SDL_x11xinput2.c b/src/video/x11/SDL_x11xinput2.c index c8b37cec98..5cf75901f2 100644 --- a/src/video/x11/SDL_x11xinput2.c +++ b/src/video/x11/SDL_x11xinput2.c @@ -34,7 +34,6 @@ #ifdef SDL_VIDEO_DRIVER_X11_XINPUT2 static bool xinput2_initialized; -#endif #if defined(SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_SCROLLINFO) || defined(SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH) static bool xinput2_scrolling_supported; static bool xinput2_multitouch_supported; @@ -137,6 +136,7 @@ static SDL_Window *xinput2_get_sdlwindow(SDL_VideoData *videodata, Window window const SDL_WindowData *windowdata = X11_FindWindow(videodata, window); return windowdata ? windowdata->window : NULL; } +#endif // SDL_VIDEO_DRIVER_X11_XINPUT2 #ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_SCROLLINFO static void xinput2_reset_scrollable_valuators(void) @@ -751,12 +751,15 @@ void X11_HandleXinput2Event(SDL_VideoDevice *_this, XGenericEventCookie *cookie) void X11_InitXinput2Multitouch(SDL_VideoDevice *_this) { +#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2 xinput2_grabbed_touch_raised = false; xinput2_active_touch_count = 0; +#endif } bool X11_Xinput2HandlesMotionForWindow(SDL_WindowData *window_data) { +#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2 /* Send the active flag once more after the touch count is zero, to suppress the * emulated motion event when the last touch is raised. */ @@ -765,6 +768,9 @@ bool X11_Xinput2HandlesMotionForWindow(SDL_WindowData *window_data) xinput2_grabbed_touch_raised = false; return ret; +#else + return false; +#endif // SDL_VIDEO_DRIVER_X11_XINPUT2 } void X11_Xinput2Select(SDL_VideoDevice *_this, SDL_Window *window) From b9c227e07d2956b23f43f08fc65835e1a1d3ed7c Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Tue, 17 Mar 2026 12:54:18 -0700 Subject: [PATCH 6/6] Make changing raw input mode on Windows a very fast operation (take 2) The first approach had the drawback that it accumulated handles while raw input was paused, eventually crashing the application. Now we'll keep reading raw events from the queue, we just won't deliver them to the application. --- src/video/windows/SDL_windowsevents.c | 4 +- src/video/windows/SDL_windowsevents.h | 2 +- src/video/windows/SDL_windowsrawinput.c | 68 ++++++++----------------- src/video/windows/SDL_windowsrawinput.h | 2 +- src/video/windows/SDL_windowsvideo.c | 4 +- 5 files changed, 29 insertions(+), 51 deletions(-) diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c index ea57c1ca42..19f49e9b36 100644 --- a/src/video/windows/SDL_windowsevents.c +++ b/src/video/windows/SDL_windowsevents.c @@ -786,7 +786,7 @@ static void WIN_HandleRawKeyboardInput(Uint64 timestamp, SDL_VideoData *data, HA SDL_SendKeyboardKey(timestamp, keyboardID, rawcode, code, down); } -void WIN_PollRawInput(SDL_VideoDevice *_this, Uint64 poll_start, bool process_input) +void WIN_PollRawInput(SDL_VideoDevice *_this, Uint64 poll_start) { SDL_VideoData *data = _this->internal; UINT size, i, count, total = 0; @@ -832,7 +832,7 @@ void WIN_PollRawInput(SDL_VideoDevice *_this, Uint64 poll_start, bool process_in } } - if (total > 0 && process_input) { + if (total > 0) { Uint64 delta = poll_finish - poll_start; UINT mouse_total = 0; for (i = 0, input = (RAWINPUT *)data->rawinput; i < total; ++i, input = NEXTRAWINPUTBLOCK(input)) { diff --git a/src/video/windows/SDL_windowsevents.h b/src/video/windows/SDL_windowsevents.h index 21bd7a420c..45f5527dc6 100644 --- a/src/video/windows/SDL_windowsevents.h +++ b/src/video/windows/SDL_windowsevents.h @@ -29,7 +29,7 @@ extern HINSTANCE SDL_Instance; extern LRESULT CALLBACK WIN_KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam); extern LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); -extern void WIN_PollRawInput(SDL_VideoDevice *_this, Uint64 poll_start, bool process_input); +extern void WIN_PollRawInput(SDL_VideoDevice *_this, Uint64 poll_start); extern void WIN_PumpEvents(SDL_VideoDevice *_this); extern void WIN_PumpEventsForHWND(SDL_VideoDevice *_this, HWND hwnd); extern void WIN_SendWakeupEvent(SDL_VideoDevice *_this, SDL_Window *window); diff --git a/src/video/windows/SDL_windowsrawinput.c b/src/video/windows/SDL_windowsrawinput.c index 3c5d80ab2b..5ae2f51d23 100644 --- a/src/video/windows/SDL_windowsrawinput.c +++ b/src/video/windows/SDL_windowsrawinput.c @@ -40,7 +40,6 @@ typedef struct { bool done; - bool paused; Uint32 flags; HANDLE ready_event; HANDLE signal_event; @@ -48,7 +47,6 @@ typedef struct } RawInputThreadData; static RawInputThreadData thread_data = { - false, false, 0, INVALID_HANDLE_VALUE, @@ -106,34 +104,22 @@ static DWORD WINAPI WIN_RawInputThread(LPVOID param) // Tell the parent we're ready to go! SetEvent(data->ready_event); - while (!data->done) { - Uint64 idle_begin = SDL_GetTicksNS(); - while (!data->done && !data->paused && - // The high-order word of GetQueueStatus() will let us know if there's currently raw input to be processed. - // If there isn't, then we'll wait for new data to arrive with MsgWaitForMultipleObjects(). - ((HIWORD(GetQueueStatus(QS_RAWINPUT)) & QS_RAWINPUT) || - (MsgWaitForMultipleObjects(1, &data->signal_event, FALSE, INFINITE, QS_RAWINPUT) == WAIT_OBJECT_0 + 1))) { + Uint64 idle_begin = SDL_GetTicksNS(); + while (!data->done && + // The high-order word of GetQueueStatus() will let us know if there's currently raw input to be processed. + // If there isn't, then we'll wait for new data to arrive with MsgWaitForMultipleObjects(). + ((HIWORD(GetQueueStatus(QS_RAWINPUT)) & QS_RAWINPUT) || + (MsgWaitForMultipleObjects(1, &data->signal_event, FALSE, INFINITE, QS_RAWINPUT) == WAIT_OBJECT_0 + 1))) { - Uint64 idle_end = SDL_GetTicksNS(); - Uint64 idle_time = idle_end - idle_begin; - Uint64 usb_8khz_interval = SDL_US_TO_NS(125); - Uint64 poll_start = idle_time < usb_8khz_interval ? _this->internal->last_rawinput_poll : idle_end; + Uint64 idle_end = SDL_GetTicksNS(); + Uint64 idle_time = idle_end - idle_begin; + Uint64 usb_8khz_interval = SDL_US_TO_NS(125); + Uint64 poll_start = idle_time < usb_8khz_interval ? _this->internal->last_rawinput_poll : idle_end; - WIN_PollRawInput(_this, poll_start, true); + WIN_PollRawInput(_this, poll_start); - // Reset idle_begin for the next go-around - idle_begin = SDL_GetTicksNS(); - } - - if (data->paused) { - // Wait for the resume signal - while (data->paused) { - WaitForSingleObject(data->signal_event, INFINITE); - } - - // Flush raw input queued while paused - WIN_PollRawInput(_this, SDL_GetTicksNS(), false); - } + // Reset idle_begin for the next go-around + idle_begin = SDL_GetTicksNS(); } if (_this->internal->raw_input_fake_pen_id) { @@ -155,7 +141,6 @@ static DWORD WINAPI WIN_RawInputThread(LPVOID param) static void CleanupRawInputThreadData(RawInputThreadData *data) { if (data->thread != INVALID_HANDLE_VALUE) { - data->paused = false; data->done = true; SetEvent(data->signal_event); WaitForSingleObject(data->thread, 3000); @@ -174,20 +159,10 @@ static void CleanupRawInputThreadData(RawInputThreadData *data) } } -bool WIN_SetRawInputEnabled(SDL_VideoDevice *_this, Uint32 flags, bool force) +bool WIN_SetRawInputEnabled(SDL_VideoDevice *_this, Uint32 flags) { bool result = false; - if (thread_data.thread != INVALID_HANDLE_VALUE && !force) { - if (flags) { - thread_data.paused = false; - } else { - thread_data.paused = true; - } - SetEvent(thread_data.signal_event); - return true; - } - CleanupRawInputThreadData(&thread_data); if (flags) { @@ -248,13 +223,14 @@ static bool WIN_UpdateRawInputEnabled(SDL_VideoDevice *_this) if (data->raw_keyboard_flag_inputsink) { flags |= RAW_KEYBOARD_FLAG_INPUTSINK; } + + // Leave the thread running, as it takes several ms to shut it down and spin it up. + // We'll continue processing them so they don't back up in the thread event queue, + // but we won't deliver raw events in the application. + flags |= (data->raw_input_enabled & (ENABLE_RAW_MOUSE_INPUT | ENABLE_RAW_KEYBOARD_INPUT)); + if (flags != data->raw_input_enabled) { - bool force = false; - if ((flags ^ data->raw_input_enabled) & (RAW_KEYBOARD_FLAG_NOHOTKEYS | RAW_KEYBOARD_FLAG_INPUTSINK)) { - // The keyboard flags have changed - force = true; - } - if (WIN_SetRawInputEnabled(_this, flags, force)) { + if (WIN_SetRawInputEnabled(_this, flags)) { data->raw_input_enabled = flags; } else { return false; @@ -338,7 +314,7 @@ bool WIN_SetRawKeyboardFlag_Inputsink(SDL_VideoDevice *_this, bool enabled) #else -bool WIN_SetRawInputEnabled(SDL_VideoDevice *_this, Uint32 flags, bool force) +bool WIN_SetRawInputEnabled(SDL_VideoDevice *_this, Uint32 flags) { return SDL_Unsupported(); } diff --git a/src/video/windows/SDL_windowsrawinput.h b/src/video/windows/SDL_windowsrawinput.h index e970666a9a..1adeb45f05 100644 --- a/src/video/windows/SDL_windowsrawinput.h +++ b/src/video/windows/SDL_windowsrawinput.h @@ -23,7 +23,7 @@ #ifndef SDL_windowsrawinput_h_ #define SDL_windowsrawinput_h_ -extern bool WIN_SetRawInputEnabled(SDL_VideoDevice *_this, Uint32 flags, bool force); +extern bool WIN_SetRawInputEnabled(SDL_VideoDevice *_this, Uint32 flags); extern bool WIN_SetRawMouseEnabled(SDL_VideoDevice *_this, bool enabled); extern bool WIN_SetRawKeyboardEnabled(SDL_VideoDevice *_this, bool enabled); extern bool WIN_SetRawKeyboardFlag_NoHotkeys(SDL_VideoDevice *_this, bool enabled); diff --git a/src/video/windows/SDL_windowsvideo.c b/src/video/windows/SDL_windowsvideo.c index edb28e838b..019a23c2d6 100644 --- a/src/video/windows/SDL_windowsvideo.c +++ b/src/video/windows/SDL_windowsvideo.c @@ -671,7 +671,9 @@ void WIN_VideoQuit(SDL_VideoDevice *_this) SDL_RemoveHintCallback(SDL_HINT_WINDOWS_ENABLE_MENU_MNEMONICS, UpdateWindowsEnableMenuMnemonics, NULL); SDL_RemoveHintCallback(SDL_HINT_WINDOW_FRAME_USABLE_WHILE_CURSOR_HIDDEN, UpdateWindowFrameUsableWhileCursorHidden, NULL); - WIN_SetRawInputEnabled(_this, 0, true); + WIN_SetRawMouseEnabled(_this, false); + WIN_SetRawKeyboardEnabled(_this, false); + WIN_SetRawInputEnabled(_this, 0); WIN_QuitGameInput(_this); #if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)