Atlas - SDL_joystick.c

Home / ext / SDL / src / joystick Lines: 2 | Size: 130400 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2026 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "SDL_internal.h" 22 23// This is the joystick API for Simple DirectMedia Layer 24 25#include "SDL_sysjoystick.h" 26#include "../SDL_hints_c.h" 27#include "SDL_gamepad_c.h" 28#include "SDL_joystick_c.h" 29#include "SDL_steam_virtual_gamepad.h" 30 31#include "../events/SDL_events_c.h" 32#include "../video/SDL_sysvideo.h" 33#include "../sensor/SDL_sensor_c.h" 34#include "hidapi/SDL_hidapijoystick_c.h" 35 36// This is included in only one place because it has a large static list of controllers 37#include "controller_type.h" 38 39#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK) 40// Needed for checking for input remapping programs 41#include "../core/windows/SDL_windows.h" 42 43#undef UNICODE // We want ASCII functions 44#include <tlhelp32.h> 45#endif 46 47#ifdef SDL_JOYSTICK_VIRTUAL 48#include "./virtual/SDL_virtualjoystick_c.h" 49#endif 50 51static SDL_JoystickDriver *SDL_joystick_drivers[] = { 52#ifdef SDL_JOYSTICK_HIDAPI // Highest priority driver for supported devices 53 &SDL_HIDAPI_JoystickDriver, 54#endif 55#ifdef SDL_JOYSTICK_PRIVATE 56 &SDL_PRIVATE_JoystickDriver, 57#endif 58#ifdef SDL_JOYSTICK_GAMEINPUT // Higher priority than other Windows drivers 59 &SDL_GAMEINPUT_JoystickDriver, 60#endif 61#ifdef SDL_JOYSTICK_RAWINPUT // Before WINDOWS driver, as WINDOWS wants to check if this driver is handling things 62 &SDL_RAWINPUT_JoystickDriver, 63#endif 64#if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT) // Before WGI driver, as WGI wants to check if this driver is handling things 65 &SDL_WINDOWS_JoystickDriver, 66#endif 67#ifdef SDL_JOYSTICK_WGI 68 &SDL_WGI_JoystickDriver, 69#endif 70#ifdef SDL_JOYSTICK_WINMM 71 &SDL_WINMM_JoystickDriver, 72#endif 73#ifdef SDL_JOYSTICK_LINUX 74 &SDL_LINUX_JoystickDriver, 75#endif 76#ifdef SDL_JOYSTICK_IOKIT 77 &SDL_DARWIN_JoystickDriver, 78#endif 79#if (defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_TVOS)) && !defined(SDL_JOYSTICK_DISABLED) 80 &SDL_IOS_JoystickDriver, 81#endif 82#ifdef SDL_JOYSTICK_ANDROID 83 &SDL_ANDROID_JoystickDriver, 84#endif 85#ifdef SDL_JOYSTICK_EMSCRIPTEN 86 &SDL_EMSCRIPTEN_JoystickDriver, 87#endif 88#ifdef SDL_JOYSTICK_HAIKU 89 &SDL_HAIKU_JoystickDriver, 90#endif 91#ifdef SDL_JOYSTICK_USBHID /* !!! FIXME: "USBHID" is a generic name, and doubly-confusing with HIDAPI next to it. This is the *BSD interface, rename this. */ 92 &SDL_BSD_JoystickDriver, 93#endif 94#ifdef SDL_JOYSTICK_PS2 95 &SDL_PS2_JoystickDriver, 96#endif 97#ifdef SDL_JOYSTICK_PSP 98 &SDL_PSP_JoystickDriver, 99#endif 100#ifdef SDL_JOYSTICK_VIRTUAL 101 &SDL_VIRTUAL_JoystickDriver, 102#endif 103#ifdef SDL_JOYSTICK_VITA 104 &SDL_VITA_JoystickDriver, 105#endif 106#ifdef SDL_JOYSTICK_N3DS 107 &SDL_N3DS_JoystickDriver, 108#endif 109#ifdef SDL_JOYSTICK_DOS 110 &SDL_DOS_JoystickDriver, 111#endif 112#if defined(SDL_JOYSTICK_DUMMY) || defined(SDL_JOYSTICK_DISABLED) 113 &SDL_DUMMY_JoystickDriver 114#endif 115}; 116 117#ifndef SDL_THREAD_SAFETY_ANALYSIS 118static 119#endif 120SDL_Mutex *SDL_joystick_lock = NULL; // This needs to support recursive locks 121static SDL_AtomicInt SDL_joystick_lock_pending; 122static int SDL_joysticks_locked; 123static bool SDL_joysticks_initialized; 124static bool SDL_joysticks_quitting; 125static bool SDL_joystick_being_added; 126static SDL_Joystick *SDL_joysticks SDL_GUARDED_BY(SDL_joystick_lock) = NULL; 127static int SDL_joystick_player_count SDL_GUARDED_BY(SDL_joystick_lock) = 0; 128static SDL_JoystickID *SDL_joystick_players SDL_GUARDED_BY(SDL_joystick_lock) = NULL; 129static SDL_HashTable *SDL_joystick_names SDL_GUARDED_BY(SDL_joystick_lock) = NULL; 130static bool SDL_joystick_allows_background_events = false; 131 132static Uint32 initial_old_xboxone_controllers[] = { 133 MAKE_VIDPID(0x0000, 0x6686), 134 MAKE_VIDPID(0x0079, 0x18a1), 135 MAKE_VIDPID(0x0079, 0x18c2), 136 MAKE_VIDPID(0x0079, 0x18c8), 137 MAKE_VIDPID(0x0079, 0x18cf), 138 MAKE_VIDPID(0x03f0, 0x0495), 139 MAKE_VIDPID(0x045e, 0x02d1), 140 MAKE_VIDPID(0x045e, 0x02dd), 141 MAKE_VIDPID(0x045e, 0x02e0), 142 MAKE_VIDPID(0x045e, 0x02e3), 143 MAKE_VIDPID(0x045e, 0x02ea), 144 MAKE_VIDPID(0x045e, 0x02fd), 145 MAKE_VIDPID(0x045e, 0x02ff), 146 MAKE_VIDPID(0x045e, 0x0867), 147 MAKE_VIDPID(0x045e, 0x0b00), 148 MAKE_VIDPID(0x045e, 0x0b05), 149 MAKE_VIDPID(0x045e, 0x0b0a), 150 MAKE_VIDPID(0x045e, 0x0b0c), 151 MAKE_VIDPID(0x045e, 0x0b20), 152 MAKE_VIDPID(0x045e, 0x0b21), 153 MAKE_VIDPID(0x045e, 0x0b22), 154 MAKE_VIDPID(0x046d, 0x0000), 155 MAKE_VIDPID(0x046d, 0x1004), 156 MAKE_VIDPID(0x046d, 0x1007), 157 MAKE_VIDPID(0x046d, 0x1008), 158 MAKE_VIDPID(0x046d, 0xf301), 159 MAKE_VIDPID(0x0738, 0x02a0), 160 MAKE_VIDPID(0x0738, 0x4a01), 161 MAKE_VIDPID(0x0738, 0x7263), 162 MAKE_VIDPID(0x0738, 0xb738), 163 MAKE_VIDPID(0x0738, 0xcb29), 164 MAKE_VIDPID(0x0738, 0xf401), 165 MAKE_VIDPID(0x0c12, 0x0e17), 166 MAKE_VIDPID(0x0c12, 0x0e1c), 167 MAKE_VIDPID(0x0c12, 0x0e22), 168 MAKE_VIDPID(0x0c12, 0x0e30), 169 MAKE_VIDPID(0x0d62, 0x9a1a), 170 MAKE_VIDPID(0x0d62, 0x9a1b), 171 MAKE_VIDPID(0x0e00, 0x0e00), 172 MAKE_VIDPID(0x0e6f, 0x012a), 173 MAKE_VIDPID(0x0e6f, 0x0139), 174 MAKE_VIDPID(0x0e6f, 0x013B), 175 MAKE_VIDPID(0x0e6f, 0x013a), 176 MAKE_VIDPID(0x0e6f, 0x0145), 177 MAKE_VIDPID(0x0e6f, 0x0146), 178 MAKE_VIDPID(0x0e6f, 0x0152), 179 MAKE_VIDPID(0x0e6f, 0x015b), 180 MAKE_VIDPID(0x0e6f, 0x015c), 181 MAKE_VIDPID(0x0e6f, 0x015d), 182 MAKE_VIDPID(0x0e6f, 0x015f), 183 MAKE_VIDPID(0x0e6f, 0x0160), 184 MAKE_VIDPID(0x0e6f, 0x0161), 185 MAKE_VIDPID(0x0e6f, 0x0162), 186 MAKE_VIDPID(0x0e6f, 0x0163), 187 MAKE_VIDPID(0x0e6f, 0x0164), 188 MAKE_VIDPID(0x0e6f, 0x0165), 189 MAKE_VIDPID(0x0e6f, 0x0166), 190 MAKE_VIDPID(0x0e6f, 0x0167), 191 MAKE_VIDPID(0x0e6f, 0x0205), 192 MAKE_VIDPID(0x0e6f, 0x0206), 193 MAKE_VIDPID(0x0e6f, 0x0246), 194 MAKE_VIDPID(0x0e6f, 0x0261), 195 MAKE_VIDPID(0x0e6f, 0x0262), 196 MAKE_VIDPID(0x0e6f, 0x02a0), 197 MAKE_VIDPID(0x0e6f, 0x02a1), 198 MAKE_VIDPID(0x0e6f, 0x02a2), 199 MAKE_VIDPID(0x0e6f, 0x02a3), 200 MAKE_VIDPID(0x0e6f, 0x02a4), 201 MAKE_VIDPID(0x0e6f, 0x02a5), 202 MAKE_VIDPID(0x0e6f, 0x02a6), 203 MAKE_VIDPID(0x0e6f, 0x02a7), 204 MAKE_VIDPID(0x0e6f, 0x02a8), 205 MAKE_VIDPID(0x0e6f, 0x02a9), 206 MAKE_VIDPID(0x0e6f, 0x02aa), 207 MAKE_VIDPID(0x0e6f, 0x02ab), 208 MAKE_VIDPID(0x0e6f, 0x02ac), 209 MAKE_VIDPID(0x0e6f, 0x02ad), 210 MAKE_VIDPID(0x0e6f, 0x02ae), 211 MAKE_VIDPID(0x0e6f, 0x02af), 212 MAKE_VIDPID(0x0e6f, 0x02b0), 213 MAKE_VIDPID(0x0e6f, 0x02b1), 214 MAKE_VIDPID(0x0e6f, 0x02b2), 215 MAKE_VIDPID(0x0e6f, 0x02b3), 216 MAKE_VIDPID(0x0e6f, 0x02b5), 217 MAKE_VIDPID(0x0e6f, 0x02b6), 218 MAKE_VIDPID(0x0e6f, 0x02b8), 219 MAKE_VIDPID(0x0e6f, 0x02bd), 220 MAKE_VIDPID(0x0e6f, 0x02be), 221 MAKE_VIDPID(0x0e6f, 0x02bf), 222 MAKE_VIDPID(0x0e6f, 0x02c0), 223 MAKE_VIDPID(0x0e6f, 0x02c1), 224 MAKE_VIDPID(0x0e6f, 0x02c2), 225 MAKE_VIDPID(0x0e6f, 0x02c3), 226 MAKE_VIDPID(0x0e6f, 0x02c4), 227 MAKE_VIDPID(0x0e6f, 0x02c5), 228 MAKE_VIDPID(0x0e6f, 0x02c6), 229 MAKE_VIDPID(0x0e6f, 0x02c7), 230 MAKE_VIDPID(0x0e6f, 0x02c8), 231 MAKE_VIDPID(0x0e6f, 0x02c9), 232 MAKE_VIDPID(0x0e6f, 0x02ca), 233 MAKE_VIDPID(0x0e6f, 0x02cb), 234 MAKE_VIDPID(0x0e6f, 0x02cd), 235 MAKE_VIDPID(0x0e6f, 0x02ce), 236 MAKE_VIDPID(0x0e6f, 0x02cf), 237 MAKE_VIDPID(0x0e6f, 0x02d5), 238 MAKE_VIDPID(0x0e6f, 0x0346), 239 MAKE_VIDPID(0x0e6f, 0x0446), 240 MAKE_VIDPID(0x0e6f, 0xf501), 241 MAKE_VIDPID(0x0f0d, 0x0063), 242 MAKE_VIDPID(0x0f0d, 0x0067), 243 MAKE_VIDPID(0x0f0d, 0x0078), 244 MAKE_VIDPID(0x0f0d, 0x0097), 245 MAKE_VIDPID(0x0f0d, 0x00ba), 246 MAKE_VIDPID(0x0f0d, 0x00c0), 247 MAKE_VIDPID(0x0f0d, 0x00c5), 248 MAKE_VIDPID(0x0f0d, 0x00d8), 249 MAKE_VIDPID(0x0f0d, 0x00ed), 250 MAKE_VIDPID(0x0fff, 0x02a1), 251 MAKE_VIDPID(0x12ab, 0x0304), 252 MAKE_VIDPID(0x1430, 0x0291), 253 MAKE_VIDPID(0x1430, 0x02a9), 254 MAKE_VIDPID(0x1430, 0x070b), 255 MAKE_VIDPID(0x1430, 0x0719), 256 MAKE_VIDPID(0x146b, 0x0611), 257 MAKE_VIDPID(0x1532, 0x0a00), 258 MAKE_VIDPID(0x1532, 0x0a03), 259 MAKE_VIDPID(0x1532, 0x0a14), 260 MAKE_VIDPID(0x1532, 0x0a15), 261 MAKE_VIDPID(0x16d0, 0x0f3f), 262 MAKE_VIDPID(0x1bad, 0x028e), 263 MAKE_VIDPID(0x1bad, 0x02a0), 264 MAKE_VIDPID(0x1bad, 0x5500), 265 MAKE_VIDPID(0x20ab, 0x55ef), 266 MAKE_VIDPID(0x24c6, 0x541a), 267 MAKE_VIDPID(0x24c6, 0x542a), 268 MAKE_VIDPID(0x24c6, 0x543a), 269 MAKE_VIDPID(0x24c6, 0x5509), 270 MAKE_VIDPID(0x24c6, 0x551a), 271 MAKE_VIDPID(0x24c6, 0x561a), 272 MAKE_VIDPID(0x24c6, 0x581a), 273 MAKE_VIDPID(0x24c6, 0x591a), 274 MAKE_VIDPID(0x24c6, 0x592a), 275 MAKE_VIDPID(0x24c6, 0x791a), 276 MAKE_VIDPID(0x2516, 0x0069), 277 MAKE_VIDPID(0x25b1, 0x0360), 278 MAKE_VIDPID(0x2c22, 0x2203), 279 MAKE_VIDPID(0x2e24, 0x0652), 280 MAKE_VIDPID(0x2e24, 0x1618), 281 MAKE_VIDPID(0x2e24, 0x1688), 282 MAKE_VIDPID(0x2f24, 0x0011), 283 MAKE_VIDPID(0x2f24, 0x002e), 284 MAKE_VIDPID(0x2f24, 0x0050), 285 MAKE_VIDPID(0x2f24, 0x0053), 286 MAKE_VIDPID(0x2f24, 0x008f), 287 MAKE_VIDPID(0x2f24, 0x0091), 288 MAKE_VIDPID(0x2f24, 0x00b7), 289 MAKE_VIDPID(0xd2d2, 0xd2d2), 290}; 291static SDL_vidpid_list old_xboxone_controllers = { 292 "SDL_JOYSTICK_OLD_XBOXONE_CONTROLLERS", 0, 0, NULL, 293 "SDL_JOYSTICK_OLD_XBOXONE_CONTROLLERS_EXCLUDED", 0, 0, NULL, 294 SDL_arraysize(initial_old_xboxone_controllers), initial_old_xboxone_controllers, 295 false 296}; 297 298static Uint32 initial_arcadestick_devices[] = { 299 MAKE_VIDPID(0x0079, 0x181a), // Venom Arcade Stick 300 MAKE_VIDPID(0x0079, 0x181b), // Venom Arcade Stick 301 MAKE_VIDPID(0x0c12, 0x0ef6), // Hitbox Arcade Stick 302 MAKE_VIDPID(0x0e6f, 0x0109), // PDP Versus Fighting Pad 303 MAKE_VIDPID(0x0f0d, 0x0016), // Hori Real Arcade Pro.EX 304 MAKE_VIDPID(0x0f0d, 0x001b), // Hori Real Arcade Pro VX 305 MAKE_VIDPID(0x0f0d, 0x0063), // Hori Real Arcade Pro Hayabusa (USA) Xbox One 306 MAKE_VIDPID(0x0f0d, 0x006a), // Real Arcade Pro 4 307 MAKE_VIDPID(0x0f0d, 0x0078), // Hori Real Arcade Pro V Kai Xbox One 308 MAKE_VIDPID(0x0f0d, 0x008a), // HORI Real Arcade Pro 4 309 MAKE_VIDPID(0x0f0d, 0x008c), // Hori Real Arcade Pro 4 310 MAKE_VIDPID(0x0f0d, 0x00aa), // HORI Real Arcade Pro V Hayabusa in Switch Mode 311 MAKE_VIDPID(0x0f0d, 0x00ed), // Hori Fighting Stick mini 4 kai 312 MAKE_VIDPID(0x0f0d, 0x011c), // Hori Fighting Stick Alpha in PS4 Mode 313 MAKE_VIDPID(0x0f0d, 0x011e), // Hori Fighting Stick Alpha in PC Mode 314 MAKE_VIDPID(0x0f0d, 0x0184), // Hori Fighting Stick Alpha in PS5 Mode 315 MAKE_VIDPID(0x146b, 0x0604), // NACON Daija Arcade Stick 316 MAKE_VIDPID(0x1532, 0x0a00), // Razer Atrox Arcade Stick 317 MAKE_VIDPID(0x1bad, 0xf03d), // Street Fighter IV Arcade Stick TE - Chun Li 318 MAKE_VIDPID(0x1bad, 0xf502), // Hori Real Arcade Pro.VX SA 319 MAKE_VIDPID(0x1bad, 0xf504), // Hori Real Arcade Pro. EX 320 MAKE_VIDPID(0x1bad, 0xf506), // Hori Real Arcade Pro.EX Premium VLX 321 MAKE_VIDPID(0x20d6, 0xa715), // PowerA Nintendo Switch Fusion Arcade Stick 322 MAKE_VIDPID(0x24c6, 0x5000), // Razer Atrox Arcade Stick 323 MAKE_VIDPID(0x24c6, 0x5501), // Hori Real Arcade Pro VX-SA 324 MAKE_VIDPID(0x24c6, 0x550e), // Hori Real Arcade Pro V Kai 360 325 MAKE_VIDPID(0x2c22, 0x2300), // Qanba Obsidian Arcade Joystick in PS4 Mode 326 MAKE_VIDPID(0x2c22, 0x2302), // Qanba Obsidian Arcade Joystick in PS3 Mode 327 MAKE_VIDPID(0x2c22, 0x2303), // Qanba Obsidian Arcade Joystick in PC Mode 328 MAKE_VIDPID(0x2c22, 0x2500), // Qanba Dragon Arcade Joystick in PS4 Mode 329 MAKE_VIDPID(0x2c22, 0x2502), // Qanba Dragon Arcade Joystick in PS3 Mode 330 MAKE_VIDPID(0x2c22, 0x2503), // Qanba Dragon Arcade Joystick in PC Mode 331}; 332static SDL_vidpid_list arcadestick_devices = { 333 SDL_HINT_JOYSTICK_ARCADESTICK_DEVICES, 0, 0, NULL, 334 SDL_HINT_JOYSTICK_ARCADESTICK_DEVICES_EXCLUDED, 0, 0, NULL, 335 SDL_arraysize(initial_arcadestick_devices), initial_arcadestick_devices, 336 false 337}; 338 339/* This list is taken from: 340 https://raw.githubusercontent.com/denilsonsa/udev-joystick-blacklist/master/generate_rules.py 341 */ 342static Uint32 initial_blacklist_devices[] = { 343 // Microsoft Microsoft Wireless Optical Desktop 2.10 344 // Microsoft Wireless Desktop - Comfort Edition 345 MAKE_VIDPID(0x045e, 0x009d), 346 347 // Microsoft Microsoft Digital Media Pro Keyboard 348 // Microsoft Corp. Digital Media Pro Keyboard 349 MAKE_VIDPID(0x045e, 0x00b0), 350 351 // Microsoft Microsoft Digital Media Keyboard 352 // Microsoft Corp. Digital Media Keyboard 1.0A 353 MAKE_VIDPID(0x045e, 0x00b4), 354 355 // Microsoft Microsoft Digital Media Keyboard 3000 356 MAKE_VIDPID(0x045e, 0x0730), 357 358 // Microsoft Microsoft 2.4GHz Transceiver v6.0 359 // Microsoft Microsoft 2.4GHz Transceiver v8.0 360 // Microsoft Corp. Nano Transceiver v1.0 for Bluetooth 361 // Microsoft Wireless Mobile Mouse 1000 362 // Microsoft Wireless Desktop 3000 363 MAKE_VIDPID(0x045e, 0x0745), 364 365 // Microsoft SideWinder(TM) 2.4GHz Transceiver 366 MAKE_VIDPID(0x045e, 0x0748), 367 368 // Microsoft Corp. Wired Keyboard 600 369 MAKE_VIDPID(0x045e, 0x0750), 370 371 // Microsoft Corp. Sidewinder X4 keyboard 372 MAKE_VIDPID(0x045e, 0x0768), 373 374 // Microsoft Corp. Arc Touch Mouse Transceiver 375 MAKE_VIDPID(0x045e, 0x0773), 376 377 // Microsoft 2.4GHz Transceiver v9.0 378 // Microsoft Nano Transceiver v2.1 379 // Microsoft Sculpt Ergonomic Keyboard (5KV-00001) 380 MAKE_VIDPID(0x045e, 0x07a5), 381 382 // Microsoft Nano Transceiver v1.0 383 // Microsoft Wireless Keyboard 800 384 MAKE_VIDPID(0x045e, 0x07b2), 385 386 // Microsoft Nano Transceiver v2.0 387 MAKE_VIDPID(0x045e, 0x0800), 388 389 MAKE_VIDPID(0x046d, 0xc30a), // Logitech, Inc. iTouch Composite keyboard 390 391 MAKE_VIDPID(0x04d9, 0xa0df), // Tek Syndicate Mouse (E-Signal USB Gaming Mouse) 392 393 // List of Wacom devices at: http://linuxwacom.sourceforge.net/wiki/index.php/Device_IDs 394 MAKE_VIDPID(0x056a, 0x0010), // Wacom ET-0405 Graphire 395 MAKE_VIDPID(0x056a, 0x0011), // Wacom ET-0405A Graphire2 (4x5) 396 MAKE_VIDPID(0x056a, 0x0012), // Wacom ET-0507A Graphire2 (5x7) 397 MAKE_VIDPID(0x056a, 0x0013), // Wacom CTE-430 Graphire3 (4x5) 398 MAKE_VIDPID(0x056a, 0x0014), // Wacom CTE-630 Graphire3 (6x8) 399 MAKE_VIDPID(0x056a, 0x0015), // Wacom CTE-440 Graphire4 (4x5) 400 MAKE_VIDPID(0x056a, 0x0016), // Wacom CTE-640 Graphire4 (6x8) 401 MAKE_VIDPID(0x056a, 0x0017), // Wacom CTE-450 Bamboo Fun (4x5) 402 MAKE_VIDPID(0x056a, 0x0018), // Wacom CTE-650 Bamboo Fun 6x8 403 MAKE_VIDPID(0x056a, 0x0019), // Wacom CTE-631 Bamboo One 404 MAKE_VIDPID(0x056a, 0x00d1), // Wacom Bamboo Pen and Touch CTH-460 405 MAKE_VIDPID(0x056a, 0x030e), // Wacom Intuos Pen (S) CTL-480 406 407 MAKE_VIDPID(0x09da, 0x054f), // A4 Tech Co., G7 750 mouse 408 MAKE_VIDPID(0x09da, 0x1410), // A4 Tech Co., Ltd Bloody AL9 mouse 409 MAKE_VIDPID(0x09da, 0x3043), // A4 Tech Co., Ltd Bloody R8A Gaming Mouse 410 MAKE_VIDPID(0x09da, 0x31b5), // A4 Tech Co., Ltd Bloody TL80 Terminator Laser Gaming Mouse 411 MAKE_VIDPID(0x09da, 0x3997), // A4 Tech Co., Ltd Bloody RT7 Terminator Wireless 412 MAKE_VIDPID(0x09da, 0x3f8b), // A4 Tech Co., Ltd Bloody V8 mouse 413 MAKE_VIDPID(0x09da, 0x51f4), // Modecom MC-5006 Keyboard 414 MAKE_VIDPID(0x09da, 0x5589), // A4 Tech Co., Ltd Terminator TL9 Laser Gaming Mouse 415 MAKE_VIDPID(0x09da, 0x7b22), // A4 Tech Co., Ltd Bloody V5 416 MAKE_VIDPID(0x09da, 0x7f2d), // A4 Tech Co., Ltd Bloody R3 mouse 417 MAKE_VIDPID(0x09da, 0x8090), // A4 Tech Co., Ltd X-718BK Oscar Optical Gaming Mouse 418 MAKE_VIDPID(0x09da, 0x9033), // A4 Tech Co., X7 X-705K 419 MAKE_VIDPID(0x09da, 0x9066), // A4 Tech Co., Sharkoon Fireglider Optical 420 MAKE_VIDPID(0x09da, 0x9090), // A4 Tech Co., Ltd XL-730K / XL-750BK / XL-755BK Laser Mouse 421 MAKE_VIDPID(0x09da, 0x90c0), // A4 Tech Co., Ltd X7 G800V keyboard 422 MAKE_VIDPID(0x09da, 0xf012), // A4 Tech Co., Ltd Bloody V7 mouse 423 MAKE_VIDPID(0x09da, 0xf32a), // A4 Tech Co., Ltd Bloody B540 keyboard 424 MAKE_VIDPID(0x09da, 0xf613), // A4 Tech Co., Ltd Bloody V2 mouse 425 MAKE_VIDPID(0x09da, 0xf624), // A4 Tech Co., Ltd Bloody B120 Keyboard 426 427 MAKE_VIDPID(0x1b1c, 0x1b3c), // Corsair Harpoon RGB gaming mouse 428 429 MAKE_VIDPID(0x1d57, 0xad03), // [T3] 2.4GHz and IR Air Mouse Remote Control 430 431 MAKE_VIDPID(0x1e7d, 0x2e4a), // Roccat Tyon Mouse 432 433 MAKE_VIDPID(0x20a0, 0x422d), // Winkeyless.kr Keyboards 434 435 MAKE_VIDPID(0x2516, 0x001f), // Cooler Master Storm Mizar Mouse 436 MAKE_VIDPID(0x2516, 0x0028), // Cooler Master Storm Alcor Mouse 437 438 /*****************************************************************/ 439 // Additional entries 440 /*****************************************************************/ 441 442 MAKE_VIDPID(0x04d9, 0x8008), // OBINLB USB-HID Keyboard (Anne Pro II) 443 MAKE_VIDPID(0x04d9, 0x8009), // OBINLB USB-HID Keyboard (Anne Pro II) 444 MAKE_VIDPID(0x04d9, 0xa292), // OBINLB USB-HID Keyboard (Anne Pro II) 445 MAKE_VIDPID(0x04d9, 0xa293), // OBINLB USB-HID Keyboard (Anne Pro II) 446 MAKE_VIDPID(0x04f2, 0xa13c), // HP Deluxe Webcam KQ246AA 447 MAKE_VIDPID(0x0e6f, 0x018a), // PDP REALMz Wireless Controller for Switch, USB charging 448 MAKE_VIDPID(0x1532, 0x0266), // Razer Huntsman V2 Analog, non-functional DInput device 449 MAKE_VIDPID(0x1532, 0x0282), // Razer Huntsman Mini Analog, non-functional DInput device 450 MAKE_VIDPID(0x26ce, 0x01a2), // ASRock LED Controller 451 MAKE_VIDPID(0x20d6, 0x0002), // PowerA Enhanced Wireless Controller for Nintendo Switch (charging port only) 452 MAKE_VIDPID(0x31e3, 0x1310), // Wooting 60HE (ARM) 453 MAKE_VIDPID(0x3297, 0x1969), // Moonlander MK1 Keyboard 454 MAKE_VIDPID(0x3434, 0x0121), // Keychron Q3 System Control 455 MAKE_VIDPID(0x3434, 0x0211), // Keychron K1 Pro System Control 456 MAKE_VIDPID(0x3434, 0x0353), // Keychron V5 System Control 457 MAKE_VIDPID(0x3434, 0xd030), // Keychron Link 458}; 459static SDL_vidpid_list blacklist_devices = { 460 SDL_HINT_JOYSTICK_BLACKLIST_DEVICES, 0, 0, NULL, 461 SDL_HINT_JOYSTICK_BLACKLIST_DEVICES_EXCLUDED, 0, 0, NULL, 462 SDL_arraysize(initial_blacklist_devices), initial_blacklist_devices, 463 false 464}; 465 466static Uint32 initial_flightstick_devices[] = { 467 MAKE_VIDPID(0x044f, 0x0402), // HOTAS Warthog Joystick 468 MAKE_VIDPID(0x044f, 0xb10a), // ThrustMaster, Inc. T.16000M Joystick 469 MAKE_VIDPID(0x046d, 0xc215), // Logitech Extreme 3D 470 MAKE_VIDPID(0x0583, 0x6258), // Padix USB joystick with viewfinder 471 MAKE_VIDPID(0x0583, 0x688f), // Padix QF-688uv Windstorm Pro 472 MAKE_VIDPID(0x0583, 0x7070), // Padix QF-707u Bazooka 473 MAKE_VIDPID(0x0583, 0xa019), // Padix USB vibration joystick with viewfinder 474 MAKE_VIDPID(0x0583, 0xa131), // Padix USB Wireless 2.4GHz 475 MAKE_VIDPID(0x0583, 0xa209), // Padix MetalStrike ForceFeedback 476 MAKE_VIDPID(0x0583, 0xb010), // Padix MetalStrike Pro 477 MAKE_VIDPID(0x0583, 0xb012), // Padix Wireless MetalStrike 478 MAKE_VIDPID(0x0583, 0xb013), // Padix USB Wireless 2.4GHZ 479 MAKE_VIDPID(0x0738, 0x2221), // Saitek Pro Flight X-56 Rhino Stick 480 MAKE_VIDPID(0x10f5, 0x7084), // Turtle Beach VelocityOne 481 MAKE_VIDPID(0x231d, 0x0126), // Gunfighter Mk.III 'Space Combat Edition' (right) 482 MAKE_VIDPID(0x231d, 0x0127), // Gunfighter Mk.III 'Space Combat Edition' (left) 483 MAKE_VIDPID(0x3344, 0x4391), // VIRPIL Controls R-VPC Stick MT-50CM3 484 MAKE_VIDPID(0x3344, 0x8390), // VIRPIL Controls L-VPC Stick MT-50CM3 485 MAKE_VIDPID(0x362c, 0x0001), // Yawman Arrow 486}; 487static SDL_vidpid_list flightstick_devices = { 488 SDL_HINT_JOYSTICK_FLIGHTSTICK_DEVICES, 0, 0, NULL, 489 SDL_HINT_JOYSTICK_FLIGHTSTICK_DEVICES_EXCLUDED, 0, 0, NULL, 490 SDL_arraysize(initial_flightstick_devices), initial_flightstick_devices, 491 false 492}; 493 494static Uint32 initial_gamecube_devices[] = { 495 MAKE_VIDPID(0x0079, 0x1843), // DragonRise GameCube Controller Adapter 496 MAKE_VIDPID(0x0079, 0x1844), // DragonRise GameCube Controller Adapter 497 MAKE_VIDPID(0x0079, 0x1846), // DragonRise GameCube Controller Adapter 498 MAKE_VIDPID(0x057e, 0x0337), // Nintendo Wii U GameCube Controller Adapter 499 MAKE_VIDPID(0x057e, 0x2073), // Nintendo Switch 2 NSO GameCube Controller 500 MAKE_VIDPID(0x0926, 0x8888), // Cyber Gadget GameCube Controller 501 MAKE_VIDPID(0x0e6f, 0x0185), // PDP Wired Fight Pad Pro for Nintendo Switch 502 MAKE_VIDPID(0x1a34, 0xf705), // GameCube {HuiJia USB box} 503 MAKE_VIDPID(0x20d6, 0xa711), // PowerA Wired Controller Nintendo GameCube Style 504}; 505static SDL_vidpid_list gamecube_devices = { 506 SDL_HINT_JOYSTICK_GAMECUBE_DEVICES, 0, 0, NULL, 507 SDL_HINT_JOYSTICK_GAMECUBE_DEVICES_EXCLUDED, 0, 0, NULL, 508 SDL_arraysize(initial_gamecube_devices), initial_gamecube_devices, 509 false 510}; 511 512static Uint32 initial_rog_gamepad_mice[] = { 513 MAKE_VIDPID(0x0b05, 0x18e3), // ROG Chakram (wired) Mouse 514 MAKE_VIDPID(0x0b05, 0x18e5), // ROG Chakram (wireless) Mouse 515 MAKE_VIDPID(0x0b05, 0x1906), // ROG Pugio II 516 MAKE_VIDPID(0x0b05, 0x1958), // ROG Chakram Core Mouse 517 MAKE_VIDPID(0x0b05, 0x1a18), // ROG Chakram X (wired) Mouse 518 MAKE_VIDPID(0x0b05, 0x1a1a), // ROG Chakram X (wireless) Mouse 519 MAKE_VIDPID(0x0b05, 0x1a1c), // ROG Chakram X (Bluetooth) Mouse 520}; 521static SDL_vidpid_list rog_gamepad_mice = { 522 SDL_HINT_ROG_GAMEPAD_MICE, 0, 0, NULL, 523 SDL_HINT_ROG_GAMEPAD_MICE_EXCLUDED, 0, 0, NULL, 524 SDL_arraysize(initial_rog_gamepad_mice), initial_rog_gamepad_mice, 525 false 526}; 527 528static Uint32 initial_throttle_devices[] = { 529 MAKE_VIDPID(0x044f, 0x0404), // HOTAS Warthog Throttle 530 MAKE_VIDPID(0x0738, 0xa221), // Saitek Pro Flight X-56 Rhino Throttle 531 MAKE_VIDPID(0x10f5, 0x7085), // Turtle Beach VelocityOne Throttle 532 MAKE_VIDPID(0x3344, 0x0196), // VIRPIL Controls VPC VMAX Prime Throttle 533}; 534static SDL_vidpid_list throttle_devices = { 535 SDL_HINT_JOYSTICK_THROTTLE_DEVICES, 0, 0, NULL, 536 SDL_HINT_JOYSTICK_THROTTLE_DEVICES_EXCLUDED, 0, 0, NULL, 537 SDL_arraysize(initial_throttle_devices), initial_throttle_devices, 538 false 539}; 540 541static Uint32 initial_wheel_devices[] = { 542 MAKE_VIDPID(0x0079, 0x1864), // DragonRise Inc. Wired Wheel (active mode) (also known as PXN V900 (PS3), Superdrive SV-750, or a Genesis Seaborg 400) 543 MAKE_VIDPID(0x044f, 0xb65d), // Thrustmaster Wheel FFB 544 MAKE_VIDPID(0x044f, 0xb65e), // Thrustmaster T500RS 545 MAKE_VIDPID(0x044f, 0xb664), // Thrustmaster TX (initial mode) 546 MAKE_VIDPID(0x044f, 0xb669), // Thrustmaster TX (active mode) 547 MAKE_VIDPID(0x044f, 0xb66d), // Thrustmaster T300RS (PS4 mode) 548 MAKE_VIDPID(0x044f, 0xb66d), // Thrustmaster Wheel FFB 549 MAKE_VIDPID(0x044f, 0xb66e), // Thrustmaster T300RS (normal mode) 550 MAKE_VIDPID(0x044f, 0xb66f), // Thrustmaster T300RS (advanced mode) 551 MAKE_VIDPID(0x044f, 0xb677), // Thrustmaster T150 552 MAKE_VIDPID(0x044f, 0xb67f), // Thrustmaster TMX 553 MAKE_VIDPID(0x044f, 0xb691), // Thrustmaster TS-XW (initial mode) 554 MAKE_VIDPID(0x044f, 0xb692), // Thrustmaster TS-XW (active mode) 555 MAKE_VIDPID(0x044f, 0xb696), // Thrustmaster T248 556 MAKE_VIDPID(0x046d, 0xc24f), // Logitech G29 (PS3) 557 MAKE_VIDPID(0x046d, 0xc260), // Logitech G29 (PS4) 558 MAKE_VIDPID(0x046d, 0xc261), // Logitech G920 (initial mode) 559 MAKE_VIDPID(0x046d, 0xc262), // Logitech G920 (active mode) 560 MAKE_VIDPID(0x046d, 0xc266), // Logitech G923 for Playstation 4 and PC (PC mode) 561 MAKE_VIDPID(0x046d, 0xc267), // Logitech G923 for Playstation 4 and PC (PS4 mode) 562 MAKE_VIDPID(0x046d, 0xc268), // Logitech PRO Racing Wheel (PC mode) 563 MAKE_VIDPID(0x046d, 0xc269), // Logitech PRO Racing Wheel (PS4/PS5 mode) 564 MAKE_VIDPID(0x046d, 0xc26d), // Logitech G923 (Xbox) 565 MAKE_VIDPID(0x046d, 0xc26e), // Logitech G923 566 MAKE_VIDPID(0x046d, 0xc272), // Logitech PRO Racing Wheel for Xbox (PC mode) 567 MAKE_VIDPID(0x046d, 0xc294), // Logitech generic wheel 568 MAKE_VIDPID(0x046d, 0xc295), // Logitech Momo Force 569 MAKE_VIDPID(0x046d, 0xc298), // Logitech Driving Force Pro 570 MAKE_VIDPID(0x046d, 0xc299), // Logitech G25 571 MAKE_VIDPID(0x046d, 0xc29a), // Logitech Driving Force GT 572 MAKE_VIDPID(0x046d, 0xc29b), // Logitech G27 573 MAKE_VIDPID(0x046d, 0xca03), // Logitech Momo Racing 574 MAKE_VIDPID(0x045e, 0x02a2), // Xbox 360 Wireless Racing Wheel 575 MAKE_VIDPID(0x0483, 0x0522), // Simagic Wheelbase (including M10, Alpha Mini, Alpha, Alpha U) 576 MAKE_VIDPID(0x0483, 0xa355), // VRS DirectForce Pro Wheel Base 577 MAKE_VIDPID(0x0583, 0xa132), // Padix USB Wireless 2.4GHz Wheelpad 578 MAKE_VIDPID(0x0583, 0xa133), // Padix USB Wireless 2.4GHz Wheel 579 MAKE_VIDPID(0x0583, 0xa202), // Padix Force Feedback Wheel 580 MAKE_VIDPID(0x0583, 0xb002), // Padix Vibration USB Wheel 581 MAKE_VIDPID(0x0583, 0xb005), // Padix USB Wheel 582 MAKE_VIDPID(0x0583, 0xb008), // Padix USB Wireless 2.4GHz Wheel 583 MAKE_VIDPID(0x0583, 0xb009), // Padix USB Wheel 584 MAKE_VIDPID(0x0583, 0xb018), // Padix TW6 Wheel 585 MAKE_VIDPID(0x0eb7, 0x0001), // Fanatec ClubSport Wheel Base V2 586 MAKE_VIDPID(0x0eb7, 0x0004), // Fanatec ClubSport Wheel Base V2.5 587 MAKE_VIDPID(0x0eb7, 0x0005), // Fanatec CSL Elite Wheel Base+ (PS4) 588 MAKE_VIDPID(0x0eb7, 0x0006), // Fanatec Podium Wheel Base DD1 589 MAKE_VIDPID(0x0eb7, 0x0007), // Fanatec Podium Wheel Base DD2 590 MAKE_VIDPID(0x0eb7, 0x0011), // Fanatec Forza Motorsport (CSR Wheel / CSR Elite Wheel) 591 MAKE_VIDPID(0x0eb7, 0x0020), // Fanatec generic wheel / CSL DD / GT DD Pro 592 MAKE_VIDPID(0x0eb7, 0x0197), // Fanatec Porsche Wheel (Turbo / GT3 RS / Turbo S / GT3 V2 / GT2) 593 MAKE_VIDPID(0x0eb7, 0x038e), // Fanatec ClubSport Wheel Base V1 594 MAKE_VIDPID(0x0eb7, 0x0e03), // Fanatec CSL Elite Wheel Base 595 MAKE_VIDPID(0x11ff, 0x0511), // DragonRise Inc. Wired Wheel (initial mode) (also known as PXN V900 (PS3), Superdrive SV-750, or a Genesis Seaborg 400) 596 MAKE_VIDPID(0x1209, 0xffb0), // Generic FFBoard OpenFFBoard universal forcefeedback wheel 597 MAKE_VIDPID(0x16d0, 0x0d5a), // Simucube 1 Wheelbase 598 MAKE_VIDPID(0x16d0, 0x0d5f), // Simucube 2 Ultimate Wheelbase 599 MAKE_VIDPID(0x16d0, 0x0d60), // Simucube 2 Pro Wheelbase 600 MAKE_VIDPID(0x16d0, 0x0d61), // Simucube 2 Sport Wheelbase 601 MAKE_VIDPID(0x2433, 0xf300), // Asetek SimSports Invicta Wheelbase 602 MAKE_VIDPID(0x2433, 0xf301), // Asetek SimSports Forte Wheelbase 603 MAKE_VIDPID(0x2433, 0xf303), // Asetek SimSports La Prima Wheelbase 604 MAKE_VIDPID(0x2433, 0xf306), // Asetek SimSports Tony Kannan Wheelbase 605 MAKE_VIDPID(0x3416, 0x0301), // Cammus C5 Wheelbase 606 MAKE_VIDPID(0x3416, 0x0302), // Cammus C12 Wheelbase 607 MAKE_VIDPID(0x346e, 0x0000), // Moza R16/R21 Wheelbase 608 MAKE_VIDPID(0x346e, 0x0002), // Moza R9 Wheelbase 609 MAKE_VIDPID(0x346e, 0x0004), // Moza R5 Wheelbase 610 MAKE_VIDPID(0x346e, 0x0005), // Moza R3 Wheelbase 611 MAKE_VIDPID(0x346e, 0x0006), // Moza R12 Wheelbase 612 MAKE_VIDPID(0x36e6, 0x400f), // PXN VD6 Wheelbase 613}; 614static SDL_vidpid_list wheel_devices = { 615 SDL_HINT_JOYSTICK_WHEEL_DEVICES, 0, 0, NULL, 616 SDL_HINT_JOYSTICK_WHEEL_DEVICES_EXCLUDED, 0, 0, NULL, 617 SDL_arraysize(initial_wheel_devices), initial_wheel_devices, 618 false 619}; 620 621static Uint32 initial_guitar_devices[] = { 622 MAKE_VIDPID(0x12ba, 0x0100), // PS3 Guitar Hero Guitar 623 MAKE_VIDPID(0x12ba, 0x0200), // PS3 Rock Band Guitar 624 MAKE_VIDPID(0x12ba, 0x074b), // PS3 / Wii U Guitar Hero Live Guitar 625 MAKE_VIDPID(0x1BAD, 0x0004), // Wii RB1 Guitar (Uses PS3 protocol) 626 MAKE_VIDPID(0x1BAD, 0x3010), // Wii RB2 Guitar (Uses PS3 protocol) 627 MAKE_VIDPID(0x0351, 0x1000), // CRKD Guitar 628 MAKE_VIDPID(0x0351, 0x2000), // CRKD Guitar 629 MAKE_VIDPID(0x0738, 0x02A6), // Mad Catz Wireless Rock Band Guitar 630 MAKE_VIDPID(0x0738, 0x02AB), // Mad Catz Wireless Precision Bass Guitar 631 MAKE_VIDPID(0x0738, 0x9806), // Mad Catz Precision Bass Guitar 632 MAKE_VIDPID(0x1430, 0x02a7), // Guitar Hero Wireless Guitar (Linux) 633 MAKE_VIDPID(0x1430, 0x0705), // Guitar Hero 5 Guitar 634 MAKE_VIDPID(0x1430, 0x070B), // Guitar Hero Live Guitar 635 MAKE_VIDPID(0x1430, 0x4734), // Guitar Hero World Tour Kiosk 636 MAKE_VIDPID(0x1430, 0x4748), // RedOctane Guitar Hero X-plorer 637 MAKE_VIDPID(0x1bad, 0x02a6), // Rock Band 2 Wireless Guitar (Linux) 638 MAKE_VIDPID(0x1bad, 0x02ab), // Rock Band Wireless Bass Guitar (Linux) 639 MAKE_VIDPID(0x2068, 0x0001), // Power Gig Guitar 640 MAKE_VIDPID(0x3651, 0x1000), // CRKD Guitar 641 MAKE_VIDPID(0x3651, 0x6000), // CRKD Guitar 642}; 643static SDL_vidpid_list guitar_devices = { 644 SDL_HINT_JOYSTICK_GUITAR_DEVICES, 0, 0, NULL, 645 NULL, 0, 0, NULL, 646 SDL_arraysize(initial_guitar_devices), initial_guitar_devices, 647 false 648}; 649 650static Uint32 initial_drum_devices[] = { 651 MAKE_VIDPID(0x12ba, 0x0120), // PS3 Guitar Hero Drums 652 MAKE_VIDPID(0x12ba, 0x0210), // PS3 Rock Band Drums 653 MAKE_VIDPID(0x12ba, 0x0218), // PS3 Midi Pro Adapter - Drums Mode 654 MAKE_VIDPID(0x1BAD, 0x0005), // Wii RB1 Drums (Uses PS3 protocol) 655 MAKE_VIDPID(0x1BAD, 0x3110), // Wii RB2 Drums (Uses PS3 protocol) 656 MAKE_VIDPID(0x1BAD, 0x3138), // Wii RB3 Midi Pro Adapter - Drums Mode (Uses PS3 protocol) 657 MAKE_VIDPID(0x1430, 0x02a8), // Guitar Hero Wireless Drum Kit (Linux) 658 MAKE_VIDPID(0x1430, 0x0805), // Band Hero Wireless Drum Kit 659 MAKE_VIDPID(0x1bad, 0x0003), // Harmonix Rock Band Drumkit 660 MAKE_VIDPID(0x1bad, 0x0130), // ION Drum Rocker 661 MAKE_VIDPID(0x2068, 0x0002), // Power Gig Drums 662}; 663static SDL_vidpid_list drum_devices = { 664 SDL_HINT_JOYSTICK_DRUM_DEVICES, 0, 0, NULL, 665 NULL, 0, 0, NULL, 666 SDL_arraysize(initial_drum_devices), initial_drum_devices, 667 false 668}; 669 670static Uint32 initial_zero_centered_devices[] = { 671 MAKE_VIDPID(0x05a0, 0x3232), // 8Bitdo Zero Gamepad 672 MAKE_VIDPID(0x0e8f, 0x3013), // HuiJia SNES USB adapter 673}; 674static SDL_vidpid_list zero_centered_devices = { 675 SDL_HINT_JOYSTICK_ZERO_CENTERED_DEVICES, 0, 0, NULL, 676 NULL, 0, 0, NULL, 677 SDL_arraysize(initial_zero_centered_devices), initial_zero_centered_devices, 678 false 679}; 680 681#define CHECK_JOYSTICK_MAGIC(joystick, result) \ 682 CHECK_PARAM(!SDL_ObjectValid(joystick, SDL_OBJECT_TYPE_JOYSTICK)) { \ 683 SDL_InvalidParamError("joystick"); \ 684 SDL_UnlockJoysticks(); \ 685 return result; \ 686 } 687 688#define CHECK_JOYSTICK_VIRTUAL(joystick, result) \ 689 CHECK_PARAM(!joystick->is_virtual) { \ 690 SDL_SetError("joystick isn't virtual"); \ 691 SDL_UnlockJoysticks(); \ 692 return result; \ 693 } 694 695bool SDL_JoysticksInitialized(void) 696{ 697 return SDL_joysticks_initialized; 698} 699 700bool SDL_JoysticksQuitting(void) 701{ 702 return SDL_joysticks_quitting; 703} 704 705void SDL_LockJoysticks(void) 706{ 707 (void)SDL_AtomicIncRef(&SDL_joystick_lock_pending); 708 SDL_LockMutex(SDL_joystick_lock); 709 (void)SDL_AtomicDecRef(&SDL_joystick_lock_pending); 710 711 ++SDL_joysticks_locked; 712} 713 714bool SDL_TryLockJoysticks(void) 715{ 716 if (SDL_TryLockMutex(SDL_joystick_lock)) { 717 ++SDL_joysticks_locked; 718 return true; 719 } 720 return false; 721} 722 723void SDL_UnlockJoysticks(void) 724{ 725 bool last_unlock = false; 726 727 --SDL_joysticks_locked; 728 729 if (!SDL_joysticks_initialized) { 730 // NOTE: There's a small window here where another thread could lock the mutex after we've checked for pending locks 731 if (!SDL_joysticks_locked && SDL_GetAtomicInt(&SDL_joystick_lock_pending) == 0) { 732 last_unlock = true; 733 } 734 } 735 736 /* The last unlock after joysticks are uninitialized will cleanup the mutex, 737 * allowing applications to lock joysticks while reinitializing the system. 738 */ 739 if (last_unlock) { 740 SDL_Mutex *joystick_lock = SDL_joystick_lock; 741 742 SDL_LockMutex(joystick_lock); 743 { 744 SDL_UnlockMutex(SDL_joystick_lock); 745 746 SDL_joystick_lock = NULL; 747 } 748 SDL_UnlockMutex(joystick_lock); 749 SDL_DestroyMutex(joystick_lock); 750 } else { 751 SDL_UnlockMutex(SDL_joystick_lock); 752 } 753} 754 755bool SDL_JoysticksLocked(void) 756{ 757 return (SDL_joysticks_locked > 0); 758} 759 760void SDL_AssertJoysticksLocked(void) 761{ 762 SDL_assert(SDL_JoysticksLocked()); 763} 764 765/* 766 * Get the driver and device index for a joystick instance ID 767 * This should be called while the joystick lock is held, to prevent another thread from updating the list 768 */ 769static bool SDL_GetDriverAndJoystickIndex(SDL_JoystickID instance_id, SDL_JoystickDriver **driver, int *driver_index) 770{ 771 int i, num_joysticks, device_index; 772 773 SDL_AssertJoysticksLocked(); 774 775 if (instance_id > 0) { 776 for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) { 777 num_joysticks = SDL_joystick_drivers[i]->GetCount(); 778 for (device_index = 0; device_index < num_joysticks; ++device_index) { 779 SDL_JoystickID joystick_id = SDL_joystick_drivers[i]->GetDeviceInstanceID(device_index); 780 if (joystick_id == instance_id) { 781 *driver = SDL_joystick_drivers[i]; 782 *driver_index = device_index; 783 return true; 784 } 785 } 786 } 787 } 788 789 SDL_SetError("Joystick %" SDL_PRIu32 " not found", instance_id); 790 return false; 791} 792 793static int SDL_FindFreePlayerIndex(void) 794{ 795 int player_index; 796 797 SDL_AssertJoysticksLocked(); 798 799 for (player_index = 0; player_index < SDL_joystick_player_count; ++player_index) { 800 if (SDL_joystick_players[player_index] == 0) { 801 break; 802 } 803 } 804 return player_index; 805} 806 807static int SDL_GetPlayerIndexForJoystickID(SDL_JoystickID instance_id) 808{ 809 int player_index; 810 811 SDL_AssertJoysticksLocked(); 812 813 for (player_index = 0; player_index < SDL_joystick_player_count; ++player_index) { 814 if (instance_id == SDL_joystick_players[player_index]) { 815 break; 816 } 817 } 818 if (player_index == SDL_joystick_player_count) { 819 player_index = -1; 820 } 821 return player_index; 822} 823 824static SDL_JoystickID SDL_GetJoystickIDForPlayerIndex(int player_index) 825{ 826 SDL_AssertJoysticksLocked(); 827 828 if (player_index < 0 || player_index >= SDL_joystick_player_count) { 829 return 0; 830 } 831 return SDL_joystick_players[player_index]; 832} 833 834static bool SDL_SetJoystickIDForPlayerIndex(int player_index, SDL_JoystickID instance_id) 835{ 836 SDL_JoystickID existing_instance = SDL_GetJoystickIDForPlayerIndex(player_index); 837 SDL_JoystickDriver *driver; 838 int device_index; 839 int existing_player_index; 840 841 SDL_AssertJoysticksLocked(); 842 843 if (player_index >= SDL_joystick_player_count) { 844 SDL_JoystickID *new_players = (SDL_JoystickID *)SDL_realloc(SDL_joystick_players, (player_index + 1) * sizeof(*SDL_joystick_players)); 845 if (!new_players) { 846 return false; 847 } 848 849 SDL_joystick_players = new_players; 850 SDL_memset(&SDL_joystick_players[SDL_joystick_player_count], 0, (player_index - SDL_joystick_player_count + 1) * sizeof(SDL_joystick_players[0])); 851 SDL_joystick_player_count = player_index + 1; 852 } else if (player_index >= 0 && SDL_joystick_players[player_index] == instance_id) { 853 // Joystick is already assigned the requested player index 854 return true; 855 } 856 857 // Clear the old player index 858 existing_player_index = SDL_GetPlayerIndexForJoystickID(instance_id); 859 if (existing_player_index >= 0) { 860 SDL_joystick_players[existing_player_index] = 0; 861 } 862 863 if (player_index >= 0) { 864 SDL_joystick_players[player_index] = instance_id; 865 } 866 867 // Update the driver with the new index 868 if (SDL_GetDriverAndJoystickIndex(instance_id, &driver, &device_index)) { 869 driver->SetDevicePlayerIndex(device_index, player_index); 870 } 871 872 // Move any existing joystick to another slot 873 if (existing_instance > 0) { 874 SDL_SetJoystickIDForPlayerIndex(SDL_FindFreePlayerIndex(), existing_instance); 875 } 876 return true; 877} 878 879static void SDLCALL SDL_JoystickAllowBackgroundEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint) 880{ 881 if (SDL_GetStringBoolean(hint, false)) { 882 SDL_joystick_allows_background_events = true; 883 } else { 884 SDL_joystick_allows_background_events = false; 885 } 886} 887 888bool SDL_InitJoysticks(void) 889{ 890 int i; 891 bool result = false; 892 893 // Create the joystick list lock 894 if (SDL_joystick_lock == NULL) { 895 SDL_joystick_lock = SDL_CreateMutex(); 896 } 897 898 if (!SDL_InitSubSystem(SDL_INIT_EVENTS)) { 899 return false; 900 } 901 902 SDL_LockJoysticks(); 903 904 SDL_joysticks_initialized = true; 905 906 SDL_joystick_names = SDL_CreateHashTable(0, false, SDL_HashID, SDL_KeyMatchID, SDL_DestroyHashValue, NULL); 907 908 SDL_LoadVIDPIDList(&old_xboxone_controllers); 909 SDL_LoadVIDPIDList(&arcadestick_devices); 910 SDL_LoadVIDPIDList(&blacklist_devices); 911 SDL_LoadVIDPIDList(&drum_devices); 912 SDL_LoadVIDPIDList(&flightstick_devices); 913 SDL_LoadVIDPIDList(&gamecube_devices); 914 SDL_LoadVIDPIDList(&guitar_devices); 915 SDL_LoadVIDPIDList(&rog_gamepad_mice); 916 SDL_LoadVIDPIDList(&throttle_devices); 917 SDL_LoadVIDPIDList(&wheel_devices); 918 SDL_LoadVIDPIDList(&zero_centered_devices); 919 920 SDL_InitGamepadMappings(); 921 922 // See if we should allow joystick events while in the background 923 SDL_AddHintCallback(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, 924 SDL_JoystickAllowBackgroundEventsChanged, NULL); 925 926 SDL_InitSteamVirtualGamepadInfo(); 927 928 for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) { 929 if (SDL_joystick_drivers[i]->Init()) { 930 result = true; 931 } 932 } 933 SDL_UnlockJoysticks(); 934 935 if (!result) { 936 SDL_QuitJoysticks(); 937 } 938 939 return result; 940} 941 942bool SDL_JoysticksOpened(void) 943{ 944 bool opened; 945 946 SDL_LockJoysticks(); 947 { 948 if (SDL_joysticks != NULL) { 949 opened = true; 950 } else { 951 opened = false; 952 } 953 } 954 SDL_UnlockJoysticks(); 955 956 return opened; 957} 958 959bool SDL_JoystickHandledByAnotherDriver(struct SDL_JoystickDriver *driver, Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name) 960{ 961 int i; 962 bool result = false; 963 964 SDL_LockJoysticks(); 965 { 966 for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) { 967 if (driver == SDL_joystick_drivers[i]) { 968 // Higher priority drivers do not have this device 969 break; 970 } 971 if (SDL_joystick_drivers[i]->IsDevicePresent(vendor_id, product_id, version, name)) { 972 result = true; 973 break; 974 } 975 } 976 } 977 SDL_UnlockJoysticks(); 978 979 return result; 980} 981 982bool SDL_HasJoystick(void) 983{ 984 int i; 985 int total_joysticks = 0; 986 987 SDL_LockJoysticks(); 988 { 989 for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) { 990 total_joysticks += SDL_joystick_drivers[i]->GetCount(); 991 } 992 } 993 SDL_UnlockJoysticks(); 994 995 if (total_joysticks > 0) { 996 return true; 997 } 998 return false; 999} 1000 1001SDL_JoystickID *SDL_GetJoysticks(int *count) 1002{ 1003 int i, num_joysticks, device_index; 1004 int joystick_index = 0, total_joysticks = 0; 1005 SDL_JoystickID *joysticks; 1006 1007 SDL_LockJoysticks(); 1008 { 1009 for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) { 1010 total_joysticks += SDL_joystick_drivers[i]->GetCount(); 1011 } 1012 1013 joysticks = (SDL_JoystickID *)SDL_malloc((total_joysticks + 1) * sizeof(*joysticks)); 1014 if (joysticks) { 1015 if (count) { 1016 *count = total_joysticks; 1017 } 1018 1019 for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) { 1020 num_joysticks = SDL_joystick_drivers[i]->GetCount(); 1021 for (device_index = 0; device_index < num_joysticks; ++device_index) { 1022 SDL_assert(joystick_index < total_joysticks); 1023 joysticks[joystick_index] = SDL_joystick_drivers[i]->GetDeviceInstanceID(device_index); 1024 SDL_assert(joysticks[joystick_index] > 0); 1025 ++joystick_index; 1026 } 1027 } 1028 SDL_assert(joystick_index == total_joysticks); 1029 joysticks[joystick_index] = 0; 1030 } else { 1031 if (count) { 1032 *count = 0; 1033 } 1034 } 1035 } 1036 SDL_UnlockJoysticks(); 1037 1038 return joysticks; 1039} 1040 1041const SDL_SteamVirtualGamepadInfo *SDL_GetJoystickVirtualGamepadInfoForID(SDL_JoystickID instance_id) 1042{ 1043 SDL_JoystickDriver *driver; 1044 int device_index; 1045 const SDL_SteamVirtualGamepadInfo *info = NULL; 1046 1047 if (SDL_SteamVirtualGamepadEnabled() && 1048 SDL_GetDriverAndJoystickIndex(instance_id, &driver, &device_index)) { 1049 info = SDL_GetSteamVirtualGamepadInfo(driver->GetDeviceSteamVirtualGamepadSlot(device_index)); 1050 } 1051 return info; 1052} 1053 1054/* 1055 * Get the implementation dependent name of a joystick 1056 */ 1057static const char *SDL_UpdateJoystickNameForID(SDL_JoystickID instance_id) 1058{ 1059 SDL_JoystickDriver *driver; 1060 int device_index; 1061 const char *current_name = NULL; 1062 const SDL_SteamVirtualGamepadInfo *info; 1063 1064 SDL_AssertJoysticksLocked(); 1065 1066 info = SDL_GetJoystickVirtualGamepadInfoForID(instance_id); 1067 if (info) { 1068 current_name = info->name; 1069 } else if (SDL_GetDriverAndJoystickIndex(instance_id, &driver, &device_index)) { 1070 current_name = driver->GetDeviceName(device_index); 1071 } 1072 1073 if (!SDL_joystick_names) { 1074 return SDL_GetPersistentString(current_name); 1075 } 1076 1077 char *name = NULL; 1078 bool found = SDL_FindInHashTable(SDL_joystick_names, (const void *)(uintptr_t)instance_id, (const void **)&name); 1079 if (!current_name) { 1080 if (!found) { 1081 SDL_SetError("Joystick %" SDL_PRIu32 " not found", instance_id); 1082 return NULL; 1083 } 1084 if (!name) { 1085 // SDL_strdup() failed during insert 1086 SDL_OutOfMemory(); 1087 return NULL; 1088 } 1089 return name; 1090 } 1091 1092 if (!name || SDL_strcmp(name, current_name) != 0) { 1093 name = SDL_strdup(current_name); 1094 SDL_InsertIntoHashTable(SDL_joystick_names, (const void *)(uintptr_t)instance_id, name, true); 1095 } 1096 return name; 1097} 1098 1099const char *SDL_GetJoystickNameForID(SDL_JoystickID instance_id) 1100{ 1101 const char *name; 1102 1103 SDL_LockJoysticks(); 1104 name = SDL_UpdateJoystickNameForID(instance_id); 1105 SDL_UnlockJoysticks(); 1106 1107 return name; 1108} 1109 1110/* 1111 * Get the implementation dependent path of a joystick 1112 */ 1113const char *SDL_GetJoystickPathForID(SDL_JoystickID instance_id) 1114{ 1115 SDL_JoystickDriver *driver; 1116 int device_index; 1117 const char *path = NULL; 1118 1119 SDL_LockJoysticks(); 1120 if (SDL_GetDriverAndJoystickIndex(instance_id, &driver, &device_index)) { 1121 path = SDL_GetPersistentString(driver->GetDevicePath(device_index)); 1122 } 1123 SDL_UnlockJoysticks(); 1124 1125 if (!path) { 1126 SDL_Unsupported(); 1127 } 1128 return path; 1129} 1130 1131/* 1132 * Get the player index of a joystick, or -1 if it's not available 1133 */ 1134int SDL_GetJoystickPlayerIndexForID(SDL_JoystickID instance_id) 1135{ 1136 int player_index; 1137 1138 SDL_LockJoysticks(); 1139 player_index = SDL_GetPlayerIndexForJoystickID(instance_id); 1140 SDL_UnlockJoysticks(); 1141 1142 return player_index; 1143} 1144 1145/* 1146 * Return true if this joystick is known to have all axes centered at zero 1147 * This isn't generally needed unless the joystick never generates an initial axis value near zero, 1148 * e.g. it's emulating axes with digital buttons 1149 */ 1150static bool SDL_JoystickAxesCenteredAtZero(SDL_Joystick *joystick) 1151{ 1152 // printf("JOYSTICK '%s' VID/PID 0x%.4x/0x%.4x AXES: %d\n", joystick->name, vendor, product, joystick->naxes); 1153 1154 SDL_AssertJoysticksLocked(); 1155 1156 if (joystick->naxes == 2) { 1157 // Assume D-pad or thumbstick style axes are centered at 0 1158 return true; 1159 } 1160 1161 return SDL_VIDPIDInList(SDL_GetJoystickVendor(joystick), SDL_GetJoystickProduct(joystick), &zero_centered_devices); 1162} 1163 1164static bool IsROGAlly(SDL_Joystick *joystick) 1165{ 1166 Uint16 vendor, product; 1167 SDL_GUID guid = SDL_GetJoystickGUID(joystick); 1168 1169 // The ROG Ally controller spoofs an Xbox 360 controller 1170 SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL, NULL); 1171 if (vendor == USB_VENDOR_MICROSOFT && product == USB_PRODUCT_XBOX360_WIRED_CONTROLLER) { 1172 // Check to see if this system has the expected sensors 1173 bool has_ally_accel = false; 1174 bool has_ally_gyro = false; 1175 1176 if (SDL_InitSubSystem(SDL_INIT_SENSOR)) { 1177 SDL_SensorID *sensors = SDL_GetSensors(NULL); 1178 if (sensors) { 1179 int i; 1180 for (i = 0; sensors[i]; ++i) { 1181 SDL_SensorID sensor = sensors[i]; 1182 1183 if (!has_ally_accel && SDL_GetSensorTypeForID(sensor) == SDL_SENSOR_ACCEL) { 1184 const char *sensor_name = SDL_GetSensorNameForID(sensor); 1185 if (sensor_name && SDL_strcmp(sensor_name, "Sensor BMI320 Acc") == 0) { 1186 has_ally_accel = true; 1187 } 1188 } 1189 if (!has_ally_gyro && SDL_GetSensorTypeForID(sensor) == SDL_SENSOR_GYRO) { 1190 const char *sensor_name = SDL_GetSensorNameForID(sensor); 1191 if (sensor_name && SDL_strcmp(sensor_name, "Sensor BMI320 Gyr") == 0) { 1192 has_ally_gyro = true; 1193 } 1194 } 1195 } 1196 SDL_free(sensors); 1197 } 1198 SDL_QuitSubSystem(SDL_INIT_SENSOR); 1199 } 1200 if (has_ally_accel && has_ally_gyro) { 1201 return true; 1202 } 1203 } 1204 return false; 1205} 1206 1207static bool ShouldAttemptSensorFusion(SDL_Joystick *joystick, bool *invert_sensors) 1208{ 1209 SDL_AssertJoysticksLocked(); 1210 1211 *invert_sensors = false; 1212 1213 // The SDL controller sensor API is only available for gamepads (at the moment) 1214 if (!SDL_IsGamepad(joystick->instance_id)) { 1215 return false; 1216 } 1217 1218 // If the controller already has sensors, use those 1219 if (joystick->nsensors > 0) { 1220 return false; 1221 } 1222 1223 const char *hint = SDL_GetHint(SDL_HINT_GAMECONTROLLER_SENSOR_FUSION); 1224 if (hint && *hint) { 1225 if (*hint == '@' || SDL_strncmp(hint, "0x", 2) == 0) { 1226 SDL_vidpid_list gamepads; 1227 SDL_GUID guid; 1228 Uint16 vendor, product; 1229 bool enabled; 1230 SDL_zero(gamepads); 1231 1232 // See if the gamepad is in our list of devices to enable 1233 guid = SDL_GetJoystickGUID(joystick); 1234 SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL, NULL); 1235 SDL_LoadVIDPIDListFromHints(&gamepads, hint, NULL); 1236 enabled = SDL_VIDPIDInList(vendor, product, &gamepads); 1237 SDL_FreeVIDPIDList(&gamepads); 1238 if (enabled) { 1239 return true; 1240 } 1241 } else { 1242 return SDL_GetStringBoolean(hint, false); 1243 } 1244 } 1245 1246 // See if this is another known wraparound gamepad 1247 if (joystick->name && 1248 (SDL_strstr(joystick->name, "Backbone One") || 1249 SDL_strstr(joystick->name, "Kishi"))) { 1250 return true; 1251 } 1252 if (IsROGAlly(joystick)) { 1253 /* I'm not sure if this is a Windows thing, or a quirk for ROG Ally, 1254 * but we need to invert the sensor data on all axes. 1255 */ 1256 *invert_sensors = true; 1257 return true; 1258 } 1259 return false; 1260} 1261 1262static void AttemptSensorFusion(SDL_Joystick *joystick, bool invert_sensors) 1263{ 1264 SDL_SensorID *sensors; 1265 unsigned int i, j; 1266 1267 SDL_AssertJoysticksLocked(); 1268 1269 if (!SDL_InitSubSystem(SDL_INIT_SENSOR)) { 1270 return; 1271 } 1272 1273 sensors = SDL_GetSensors(NULL); 1274 if (sensors) { 1275 for (i = 0; sensors[i]; ++i) { 1276 SDL_SensorID sensor = sensors[i]; 1277 1278 if (!joystick->accel_sensor && SDL_GetSensorTypeForID(sensor) == SDL_SENSOR_ACCEL) { 1279 // Increment the sensor subsystem reference count 1280 SDL_InitSubSystem(SDL_INIT_SENSOR); 1281 1282 joystick->accel_sensor = sensor; 1283 SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 0.0f); 1284 } 1285 if (!joystick->gyro_sensor && SDL_GetSensorTypeForID(sensor) == SDL_SENSOR_GYRO) { 1286 // Increment the sensor subsystem reference count 1287 SDL_InitSubSystem(SDL_INIT_SENSOR); 1288 1289 joystick->gyro_sensor = sensor; 1290 SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, 0.0f); 1291 } 1292 } 1293 SDL_free(sensors); 1294 } 1295 SDL_QuitSubSystem(SDL_INIT_SENSOR); 1296 1297 /* SDL defines sensor orientation for phones relative to the natural 1298 orientation, and for gamepads relative to being held in front of you. 1299 When a phone is being used as a gamepad, its orientation changes, 1300 so adjust sensor axes to match. 1301 */ 1302 if (SDL_GetNaturalDisplayOrientation(SDL_GetPrimaryDisplay()) == SDL_ORIENTATION_LANDSCAPE) { 1303 /* When a device in landscape orientation is laid flat, the axes change 1304 orientation as follows: 1305 -X to +X becomes -X to +X 1306 -Y to +Y becomes +Z to -Z 1307 -Z to +Z becomes -Y to +Y 1308 */ 1309 joystick->sensor_transform[0][0] = 1.0f; 1310 joystick->sensor_transform[1][2] = 1.0f; 1311 joystick->sensor_transform[2][1] = -1.0f; 1312 } else { 1313 /* When a device in portrait orientation is rotated left and laid flat, 1314 the axes change orientation as follows: 1315 -X to +X becomes +Z to -Z 1316 -Y to +Y becomes +X to -X 1317 -Z to +Z becomes -Y to +Y 1318 */ 1319 joystick->sensor_transform[0][1] = -1.0f; 1320 joystick->sensor_transform[1][2] = 1.0f; 1321 joystick->sensor_transform[2][0] = -1.0f; 1322 } 1323 1324 if (invert_sensors) { 1325 for (i = 0; i < SDL_arraysize(joystick->sensor_transform); ++i) { 1326 for (j = 0; j < SDL_arraysize(joystick->sensor_transform[i]); ++j) { 1327 joystick->sensor_transform[i][j] *= -1.0f; 1328 } 1329 } 1330 } 1331} 1332 1333static void CleanupSensorFusion(SDL_Joystick *joystick) 1334{ 1335 SDL_AssertJoysticksLocked(); 1336 1337 if (joystick->accel_sensor || joystick->gyro_sensor) { 1338 if (joystick->accel_sensor) { 1339 if (joystick->accel) { 1340 SDL_CloseSensor(joystick->accel); 1341 joystick->accel = NULL; 1342 } 1343 joystick->accel_sensor = 0; 1344 1345 // Decrement the sensor subsystem reference count 1346 SDL_QuitSubSystem(SDL_INIT_SENSOR); 1347 } 1348 if (joystick->gyro_sensor) { 1349 if (joystick->gyro) { 1350 SDL_CloseSensor(joystick->gyro); 1351 joystick->gyro = NULL; 1352 } 1353 joystick->gyro_sensor = 0; 1354 1355 // Decrement the sensor subsystem reference count 1356 SDL_QuitSubSystem(SDL_INIT_SENSOR); 1357 } 1358 } 1359} 1360 1361static bool ShouldSwapFaceButtons(const SDL_SteamVirtualGamepadInfo *info) 1362{ 1363 // When "Use Nintendo Button Layout" is enabled under Steam (the default) 1364 // it will send button 0 for the A (east) button and button 1 for the 1365 // B (south) button. This is done so that games that interpret the 1366 // buttons as Xbox input will get button 0 for "A" as they expect. 1367 // 1368 // However, SDL reports positional buttons, so we need to swap 1369 // the buttons so they show up in the correct position. This provides 1370 // consistent behavior regardless of whether we're running under Steam, 1371 // under the default settings. 1372 if (info && 1373 (info->type == SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO || 1374 info->type == SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT || 1375 info->type == SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT || 1376 info->type == SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_PAIR)) { 1377 return true; 1378 } 1379 return false; 1380} 1381 1382/* 1383 * Open a joystick for use - the index passed as an argument refers to 1384 * the N'th joystick on the system. This index is the value which will 1385 * identify this joystick in future joystick events. 1386 * 1387 * This function returns a joystick identifier, or NULL if an error occurred. 1388 */ 1389SDL_Joystick *SDL_OpenJoystick(SDL_JoystickID instance_id) 1390{ 1391 SDL_JoystickDriver *driver; 1392 int device_index; 1393 SDL_Joystick *joystick; 1394 SDL_Joystick *joysticklist; 1395 const char *joystickname = NULL; 1396 const char *joystickpath = NULL; 1397 bool invert_sensors = false; 1398 const SDL_SteamVirtualGamepadInfo *info; 1399 1400 SDL_LockJoysticks(); 1401 1402 if (!SDL_GetDriverAndJoystickIndex(instance_id, &driver, &device_index)) { 1403 SDL_UnlockJoysticks(); 1404 return NULL; 1405 } 1406 1407 joysticklist = SDL_joysticks; 1408 /* If the joystick is already open, return it 1409 * it is important that we have a single joystick for each instance id 1410 */ 1411 while (joysticklist) { 1412 if (instance_id == joysticklist->instance_id) { 1413 joystick = joysticklist; 1414 ++joystick->ref_count; 1415 SDL_UnlockJoysticks(); 1416 return joystick; 1417 } 1418 joysticklist = joysticklist->next; 1419 } 1420 1421 // Create and initialize the joystick 1422 joystick = (SDL_Joystick *)SDL_calloc(1, sizeof(*joystick)); 1423 if (!joystick) { 1424 SDL_UnlockJoysticks(); 1425 return NULL; 1426 } 1427 SDL_SetObjectValid(joystick, SDL_OBJECT_TYPE_JOYSTICK, true); 1428 joystick->driver = driver; 1429 joystick->instance_id = instance_id; 1430 joystick->attached = true; 1431 joystick->led_expiration = SDL_GetTicks(); 1432 joystick->battery_percent = -1; 1433#ifdef SDL_JOYSTICK_VIRTUAL 1434 joystick->is_virtual = (driver == &SDL_VIRTUAL_JoystickDriver); 1435#endif 1436 1437 if (!driver->Open(joystick, device_index)) { 1438 SDL_SetObjectValid(joystick, SDL_OBJECT_TYPE_JOYSTICK, false); 1439 SDL_free(joystick); 1440 SDL_UnlockJoysticks(); 1441 return NULL; 1442 } 1443 1444 joystickname = driver->GetDeviceName(device_index); 1445 if (joystickname) { 1446 joystick->name = SDL_strdup(joystickname); 1447 } 1448 1449 joystickpath = driver->GetDevicePath(device_index); 1450 if (joystickpath) { 1451 joystick->path = SDL_strdup(joystickpath); 1452 } 1453 1454 joystick->guid = driver->GetDeviceGUID(device_index); 1455 1456 if (joystick->naxes > 0) { 1457 joystick->axes = (SDL_JoystickAxisInfo *)SDL_calloc(joystick->naxes, sizeof(*joystick->axes)); 1458 } 1459 if (joystick->nballs > 0) { 1460 joystick->balls = (SDL_JoystickBallData *)SDL_calloc(joystick->nballs, sizeof(*joystick->balls)); 1461 } 1462 if (joystick->nhats > 0) { 1463 joystick->hats = (Uint8 *)SDL_calloc(joystick->nhats, sizeof(*joystick->hats)); 1464 } 1465 if (joystick->nbuttons > 0) { 1466 joystick->buttons = (bool *)SDL_calloc(joystick->nbuttons, sizeof(*joystick->buttons)); 1467 } 1468 if (((joystick->naxes > 0) && !joystick->axes) || 1469 ((joystick->nballs > 0) && !joystick->balls) || 1470 ((joystick->nhats > 0) && !joystick->hats) || 1471 ((joystick->nbuttons > 0) && !joystick->buttons)) { 1472 SDL_CloseJoystick(joystick); 1473 SDL_UnlockJoysticks(); 1474 return NULL; 1475 } 1476 1477 // If this joystick is known to have all zero centered axes, skip the auto-centering code 1478 if (SDL_JoystickAxesCenteredAtZero(joystick)) { 1479 for (int i = 0; i < joystick->naxes; ++i) { 1480 joystick->axes[i].has_initial_value = true; 1481 } 1482 } 1483 1484 // We know the initial values for HIDAPI and XInput joysticks 1485 if ((SDL_IsJoystickHIDAPI(joystick->guid) || 1486 SDL_IsJoystickXInput(joystick->guid) || 1487 SDL_IsJoystickRAWINPUT(joystick->guid) || 1488 SDL_IsJoystickWGI(joystick->guid)) && 1489 joystick->naxes >= SDL_GAMEPAD_AXIS_COUNT) { 1490 int left_trigger, right_trigger; 1491 if (SDL_IsJoystickXInput(joystick->guid)) { 1492 left_trigger = 2; 1493 right_trigger = 5; 1494 } else { 1495 left_trigger = SDL_GAMEPAD_AXIS_LEFT_TRIGGER; 1496 right_trigger = SDL_GAMEPAD_AXIS_RIGHT_TRIGGER; 1497 } 1498 for (int i = 0; i < SDL_GAMEPAD_AXIS_COUNT; ++i) { 1499 int initial_value; 1500 if (i == left_trigger || i == right_trigger) { 1501 initial_value = SDL_MIN_SINT16; 1502 } else { 1503 initial_value = 0; 1504 } 1505 joystick->axes[i].value = initial_value; 1506 joystick->axes[i].zero = initial_value; 1507 joystick->axes[i].initial_value = initial_value; 1508 joystick->axes[i].has_initial_value = true; 1509 } 1510 } 1511 1512 // Get the Steam Input API handle 1513 info = SDL_GetJoystickVirtualGamepadInfoForID(instance_id); 1514 if (info) { 1515 joystick->steam_handle = info->handle; 1516 joystick->swap_face_buttons = ShouldSwapFaceButtons(info); 1517 } 1518 1519 // Use system gyro and accelerometer if the gamepad doesn't have built-in sensors 1520 if (ShouldAttemptSensorFusion(joystick, &invert_sensors)) { 1521 AttemptSensorFusion(joystick, invert_sensors); 1522 } 1523 1524 // Add joystick to list 1525 ++joystick->ref_count; 1526 // Link the joystick in the list 1527 joystick->next = SDL_joysticks; 1528 SDL_joysticks = joystick; 1529 1530 driver->Update(joystick); 1531 1532 SDL_UnlockJoysticks(); 1533 1534 return joystick; 1535} 1536 1537SDL_JoystickID SDL_AttachVirtualJoystick(const SDL_VirtualJoystickDesc *desc) 1538{ 1539#ifdef SDL_JOYSTICK_VIRTUAL 1540 SDL_JoystickID result; 1541 1542 SDL_LockJoysticks(); 1543 result = SDL_JoystickAttachVirtualInner(desc); 1544 SDL_UnlockJoysticks(); 1545 return result; 1546#else 1547 SDL_SetError("SDL not built with virtual-joystick support"); 1548 return 0; 1549#endif 1550} 1551 1552bool SDL_DetachVirtualJoystick(SDL_JoystickID instance_id) 1553{ 1554#ifdef SDL_JOYSTICK_VIRTUAL 1555 bool result; 1556 1557 SDL_LockJoysticks(); 1558 result = SDL_JoystickDetachVirtualInner(instance_id); 1559 SDL_UnlockJoysticks(); 1560 return result; 1561#else 1562 return SDL_SetError("SDL not built with virtual-joystick support"); 1563#endif 1564} 1565 1566bool SDL_IsJoystickVirtual(SDL_JoystickID instance_id) 1567{ 1568#ifdef SDL_JOYSTICK_VIRTUAL 1569 SDL_JoystickDriver *driver; 1570 int device_index; 1571 bool is_virtual = false; 1572 1573 SDL_LockJoysticks(); 1574 if (SDL_GetDriverAndJoystickIndex(instance_id, &driver, &device_index)) { 1575 if (driver == &SDL_VIRTUAL_JoystickDriver) { 1576 is_virtual = true; 1577 } 1578 } 1579 SDL_UnlockJoysticks(); 1580 1581 return is_virtual; 1582#else 1583 return false; 1584#endif 1585} 1586 1587bool SDL_SetJoystickVirtualAxis(SDL_Joystick *joystick, int axis, Sint16 value) 1588{ 1589 bool result; 1590 1591 SDL_LockJoysticks(); 1592 { 1593 CHECK_JOYSTICK_MAGIC(joystick, false); 1594 CHECK_JOYSTICK_VIRTUAL(joystick, false); 1595 1596#ifdef SDL_JOYSTICK_VIRTUAL 1597 result = SDL_SetJoystickVirtualAxisInner(joystick, axis, value); 1598#else 1599 result = SDL_SetError("SDL not built with virtual-joystick support"); 1600#endif 1601 } 1602 SDL_UnlockJoysticks(); 1603 1604 return result; 1605} 1606 1607bool SDL_SetJoystickVirtualBall(SDL_Joystick *joystick, int ball, Sint16 xrel, Sint16 yrel) 1608{ 1609 bool result; 1610 1611 SDL_LockJoysticks(); 1612 { 1613 CHECK_JOYSTICK_MAGIC(joystick, false); 1614 CHECK_JOYSTICK_VIRTUAL(joystick, false); 1615 1616#ifdef SDL_JOYSTICK_VIRTUAL 1617 result = SDL_SetJoystickVirtualBallInner(joystick, ball, xrel, yrel); 1618#else 1619 result = SDL_SetError("SDL not built with virtual-joystick support"); 1620#endif 1621 } 1622 SDL_UnlockJoysticks(); 1623 1624 return result; 1625} 1626 1627bool SDL_SetJoystickVirtualButton(SDL_Joystick *joystick, int button, bool down) 1628{ 1629 bool result; 1630 1631 SDL_LockJoysticks(); 1632 { 1633 CHECK_JOYSTICK_MAGIC(joystick, false); 1634 CHECK_JOYSTICK_VIRTUAL(joystick, false); 1635 1636#ifdef SDL_JOYSTICK_VIRTUAL 1637 result = SDL_SetJoystickVirtualButtonInner(joystick, button, down); 1638#else 1639 result = SDL_SetError("SDL not built with virtual-joystick support"); 1640#endif 1641 } 1642 SDL_UnlockJoysticks(); 1643 1644 return result; 1645} 1646 1647bool SDL_SetJoystickVirtualHat(SDL_Joystick *joystick, int hat, Uint8 value) 1648{ 1649 bool result; 1650 1651 SDL_LockJoysticks(); 1652 { 1653 CHECK_JOYSTICK_MAGIC(joystick, false); 1654 CHECK_JOYSTICK_VIRTUAL(joystick, false); 1655 1656#ifdef SDL_JOYSTICK_VIRTUAL 1657 result = SDL_SetJoystickVirtualHatInner(joystick, hat, value); 1658#else 1659 result = SDL_SetError("SDL not built with virtual-joystick support"); 1660#endif 1661 } 1662 SDL_UnlockJoysticks(); 1663 1664 return result; 1665} 1666 1667bool SDL_SetJoystickVirtualTouchpad(SDL_Joystick *joystick, int touchpad, int finger, bool down, float x, float y, float pressure) 1668{ 1669 bool result; 1670 1671 SDL_LockJoysticks(); 1672 { 1673 CHECK_JOYSTICK_MAGIC(joystick, false); 1674 CHECK_JOYSTICK_VIRTUAL(joystick, false); 1675 1676#ifdef SDL_JOYSTICK_VIRTUAL 1677 result = SDL_SetJoystickVirtualTouchpadInner(joystick, touchpad, finger, down, x, y, pressure); 1678#else 1679 result = SDL_SetError("SDL not built with virtual-joystick support"); 1680#endif 1681 } 1682 SDL_UnlockJoysticks(); 1683 1684 return result; 1685} 1686 1687bool SDL_SendJoystickVirtualSensorData(SDL_Joystick *joystick, SDL_SensorType type, Uint64 sensor_timestamp, const float *data, int num_values) 1688{ 1689 bool result; 1690 1691 SDL_LockJoysticks(); 1692 { 1693 CHECK_JOYSTICK_MAGIC(joystick, false); 1694 CHECK_JOYSTICK_VIRTUAL(joystick, false); 1695 1696#ifdef SDL_JOYSTICK_VIRTUAL 1697 result = SDL_SendJoystickVirtualSensorDataInner(joystick, type, sensor_timestamp, data, num_values); 1698#else 1699 result = SDL_SetError("SDL not built with virtual-joystick support"); 1700#endif 1701 } 1702 SDL_UnlockJoysticks(); 1703 1704 return result; 1705} 1706 1707/* 1708 * Checks to make sure the joystick is valid. 1709 */ 1710bool SDL_IsJoystickValid(SDL_Joystick *joystick) 1711{ 1712 SDL_AssertJoysticksLocked(); 1713 return SDL_ObjectValid(joystick, SDL_OBJECT_TYPE_JOYSTICK); 1714} 1715 1716bool SDL_PrivateJoystickGetAutoGamepadMapping(SDL_JoystickID instance_id, SDL_GamepadMapping *out) 1717{ 1718 SDL_JoystickDriver *driver; 1719 int device_index; 1720 bool is_ok = false; 1721 1722 SDL_LockJoysticks(); 1723 if (SDL_GetDriverAndJoystickIndex(instance_id, &driver, &device_index)) { 1724 is_ok = driver->GetGamepadMapping(device_index, out); 1725 } 1726 SDL_UnlockJoysticks(); 1727 1728 return is_ok; 1729} 1730 1731/* 1732 * Get the number of multi-dimensional axis controls on a joystick 1733 */ 1734int SDL_GetNumJoystickAxes(SDL_Joystick *joystick) 1735{ 1736 int result; 1737 1738 SDL_LockJoysticks(); 1739 { 1740 CHECK_JOYSTICK_MAGIC(joystick, -1); 1741 1742 result = joystick->naxes; 1743 } 1744 SDL_UnlockJoysticks(); 1745 1746 return result; 1747} 1748 1749/* 1750 * Get the number of hats on a joystick 1751 */ 1752int SDL_GetNumJoystickHats(SDL_Joystick *joystick) 1753{ 1754 int result; 1755 1756 SDL_LockJoysticks(); 1757 { 1758 CHECK_JOYSTICK_MAGIC(joystick, -1); 1759 1760 result = joystick->nhats; 1761 } 1762 SDL_UnlockJoysticks(); 1763 1764 return result; 1765} 1766 1767/* 1768 * Get the number of trackballs on a joystick 1769 */ 1770int SDL_GetNumJoystickBalls(SDL_Joystick *joystick) 1771{ 1772 int result; 1773 1774 SDL_LockJoysticks(); 1775 { 1776 CHECK_JOYSTICK_MAGIC(joystick, -1); 1777 1778 result = joystick->nballs; 1779 } 1780 SDL_UnlockJoysticks(); 1781 1782 return result; 1783} 1784 1785/* 1786 * Get the number of buttons on a joystick 1787 */ 1788int SDL_GetNumJoystickButtons(SDL_Joystick *joystick) 1789{ 1790 int result; 1791 1792 SDL_LockJoysticks(); 1793 { 1794 CHECK_JOYSTICK_MAGIC(joystick, -1); 1795 1796 result = joystick->nbuttons; 1797 } 1798 SDL_UnlockJoysticks(); 1799 1800 return result; 1801} 1802 1803/* 1804 * Get the current state of an axis control on a joystick 1805 */ 1806Sint16 SDL_GetJoystickAxis(SDL_Joystick *joystick, int axis) 1807{ 1808 Sint16 state; 1809 1810 SDL_LockJoysticks(); 1811 { 1812 CHECK_JOYSTICK_MAGIC(joystick, 0); 1813 1814 if (axis < joystick->naxes) { 1815 state = joystick->axes[axis].value; 1816 } else { 1817 SDL_SetError("Joystick only has %d axes", joystick->naxes); 1818 state = 0; 1819 } 1820 } 1821 SDL_UnlockJoysticks(); 1822 1823 return state; 1824} 1825 1826/* 1827 * Get the initial state of an axis control on a joystick 1828 */ 1829bool SDL_GetJoystickAxisInitialState(SDL_Joystick *joystick, int axis, Sint16 *state) 1830{ 1831 bool result; 1832 1833 SDL_LockJoysticks(); 1834 { 1835 CHECK_JOYSTICK_MAGIC(joystick, false); 1836 1837 if (axis >= joystick->naxes) { 1838 SDL_SetError("Joystick only has %d axes", joystick->naxes); 1839 result = false; 1840 } else { 1841 if (state) { 1842 *state = joystick->axes[axis].initial_value; 1843 } 1844 result = joystick->axes[axis].has_initial_value; 1845 } 1846 } 1847 SDL_UnlockJoysticks(); 1848 1849 return result; 1850} 1851 1852/* 1853 * Get the current state of a hat on a joystick 1854 */ 1855Uint8 SDL_GetJoystickHat(SDL_Joystick *joystick, int hat) 1856{ 1857 Uint8 state; 1858 1859 SDL_LockJoysticks(); 1860 { 1861 CHECK_JOYSTICK_MAGIC(joystick, 0); 1862 1863 if (hat < joystick->nhats) { 1864 state = joystick->hats[hat]; 1865 } else { 1866 SDL_SetError("Joystick only has %d hats", joystick->nhats); 1867 state = 0; 1868 } 1869 } 1870 SDL_UnlockJoysticks(); 1871 1872 return state; 1873} 1874 1875/* 1876 * Get the ball axis change since the last poll 1877 */ 1878bool SDL_GetJoystickBall(SDL_Joystick *joystick, int ball, int *dx, int *dy) 1879{ 1880 bool result; 1881 1882 SDL_LockJoysticks(); 1883 { 1884 CHECK_JOYSTICK_MAGIC(joystick, false); 1885 1886 if (ball < joystick->nballs) { 1887 if (dx) { 1888 *dx = joystick->balls[ball].dx; 1889 } 1890 if (dy) { 1891 *dy = joystick->balls[ball].dy; 1892 } 1893 joystick->balls[ball].dx = 0; 1894 joystick->balls[ball].dy = 0; 1895 result = true; 1896 } else { 1897 result = SDL_SetError("Joystick only has %d balls", joystick->nballs); 1898 } 1899 } 1900 SDL_UnlockJoysticks(); 1901 1902 return result; 1903} 1904 1905/* 1906 * Get the current state of a button on a joystick 1907 */ 1908bool SDL_GetJoystickButton(SDL_Joystick *joystick, int button) 1909{ 1910 bool down = false; 1911 1912 SDL_LockJoysticks(); 1913 { 1914 CHECK_JOYSTICK_MAGIC(joystick, false); 1915 1916 if (button < joystick->nbuttons) { 1917 down = joystick->buttons[button]; 1918 } else { 1919 SDL_SetError("Joystick only has %d buttons", joystick->nbuttons); 1920 } 1921 } 1922 SDL_UnlockJoysticks(); 1923 1924 return down; 1925} 1926 1927/* 1928 * Return if the joystick in question is currently attached to the system, 1929 * \return false if not plugged in, true if still present. 1930 */ 1931bool SDL_JoystickConnected(SDL_Joystick *joystick) 1932{ 1933 bool result; 1934 1935 SDL_LockJoysticks(); 1936 { 1937 CHECK_JOYSTICK_MAGIC(joystick, false); 1938 1939 result = joystick->attached; 1940 } 1941 SDL_UnlockJoysticks(); 1942 1943 return result; 1944} 1945 1946/* 1947 * Get the instance id for this opened joystick 1948 */ 1949SDL_JoystickID SDL_GetJoystickID(SDL_Joystick *joystick) 1950{ 1951 SDL_JoystickID result; 1952 1953 SDL_LockJoysticks(); 1954 { 1955 CHECK_JOYSTICK_MAGIC(joystick, 0); 1956 1957 result = joystick->instance_id; 1958 } 1959 SDL_UnlockJoysticks(); 1960 1961 return result; 1962} 1963 1964/* 1965 * Return the SDL_Joystick associated with an instance id. 1966 */ 1967SDL_Joystick *SDL_GetJoystickFromID(SDL_JoystickID instance_id) 1968{ 1969 SDL_Joystick *joystick; 1970 1971 SDL_LockJoysticks(); 1972 for (joystick = SDL_joysticks; joystick; joystick = joystick->next) { 1973 if (joystick->instance_id == instance_id) { 1974 break; 1975 } 1976 } 1977 SDL_UnlockJoysticks(); 1978 return joystick; 1979} 1980 1981/** 1982 * Return the SDL_Joystick associated with a player index. 1983 */ 1984SDL_Joystick *SDL_GetJoystickFromPlayerIndex(int player_index) 1985{ 1986 SDL_JoystickID instance_id; 1987 SDL_Joystick *joystick; 1988 1989 SDL_LockJoysticks(); 1990 instance_id = SDL_GetJoystickIDForPlayerIndex(player_index); 1991 for (joystick = SDL_joysticks; joystick; joystick = joystick->next) { 1992 if (joystick->instance_id == instance_id) { 1993 break; 1994 } 1995 } 1996 SDL_UnlockJoysticks(); 1997 return joystick; 1998} 1999 2000/* 2001 * Get the properties associated with a joystick 2002 */ 2003SDL_PropertiesID SDL_GetJoystickProperties(SDL_Joystick *joystick) 2004{ 2005 SDL_PropertiesID result; 2006 2007 SDL_LockJoysticks(); 2008 { 2009 CHECK_JOYSTICK_MAGIC(joystick, 0); 2010 2011 if (joystick->props == 0) { 2012 joystick->props = SDL_CreateProperties(); 2013 } 2014 result = joystick->props; 2015 } 2016 SDL_UnlockJoysticks(); 2017 2018 return result; 2019} 2020 2021/* 2022 * Get the friendly name of this joystick 2023 */ 2024const char *SDL_GetJoystickName(SDL_Joystick *joystick) 2025{ 2026 const char *result; 2027 const SDL_SteamVirtualGamepadInfo *info; 2028 2029 SDL_LockJoysticks(); 2030 { 2031 CHECK_JOYSTICK_MAGIC(joystick, NULL); 2032 2033 info = SDL_GetJoystickVirtualGamepadInfoForID(joystick->instance_id); 2034 if (info) { 2035 result = SDL_GetPersistentString(info->name); 2036 } else { 2037 result = SDL_GetPersistentString(joystick->name); 2038 } 2039 } 2040 SDL_UnlockJoysticks(); 2041 2042 return result; 2043} 2044 2045/* 2046 * Get the implementation dependent path of this joystick 2047 */ 2048const char *SDL_GetJoystickPath(SDL_Joystick *joystick) 2049{ 2050 const char *result; 2051 2052 SDL_LockJoysticks(); 2053 { 2054 CHECK_JOYSTICK_MAGIC(joystick, NULL); 2055 2056 if (joystick->path) { 2057 result = SDL_GetPersistentString(joystick->path); 2058 } else { 2059 SDL_Unsupported(); 2060 result = NULL; 2061 } 2062 } 2063 SDL_UnlockJoysticks(); 2064 2065 return result; 2066} 2067 2068/** 2069 * Get the player index of an opened joystick, or -1 if it's not available 2070 */ 2071int SDL_GetJoystickPlayerIndex(SDL_Joystick *joystick) 2072{ 2073 int result; 2074 2075 SDL_LockJoysticks(); 2076 { 2077 CHECK_JOYSTICK_MAGIC(joystick, -1); 2078 2079 result = SDL_GetPlayerIndexForJoystickID(joystick->instance_id); 2080 } 2081 SDL_UnlockJoysticks(); 2082 2083 return result; 2084} 2085 2086/** 2087 * Set the player index of an opened joystick 2088 */ 2089bool SDL_SetJoystickPlayerIndex(SDL_Joystick *joystick, int player_index) 2090{ 2091 bool result; 2092 2093 SDL_LockJoysticks(); 2094 { 2095 CHECK_JOYSTICK_MAGIC(joystick, false); 2096 2097 result = SDL_SetJoystickIDForPlayerIndex(player_index, joystick->instance_id); 2098 } 2099 SDL_UnlockJoysticks(); 2100 2101 return result; 2102} 2103 2104bool SDL_RumbleJoystick(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms) 2105{ 2106 bool result; 2107 2108 SDL_LockJoysticks(); 2109 { 2110 CHECK_JOYSTICK_MAGIC(joystick, false); 2111 2112 if (low_frequency_rumble == joystick->low_frequency_rumble && 2113 high_frequency_rumble == joystick->high_frequency_rumble) { 2114 // Just update the expiration 2115 result = true; 2116 } else { 2117 result = joystick->driver->Rumble(joystick, low_frequency_rumble, high_frequency_rumble); 2118 if (result) { 2119 joystick->rumble_resend = SDL_GetTicks() + SDL_RUMBLE_RESEND_MS; 2120 if (joystick->rumble_resend == 0) { 2121 joystick->rumble_resend = 1; 2122 } 2123 } else { 2124 joystick->rumble_resend = 0; 2125 } 2126 } 2127 2128 if (result) { 2129 joystick->low_frequency_rumble = low_frequency_rumble; 2130 joystick->high_frequency_rumble = high_frequency_rumble; 2131 2132 if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) { 2133 joystick->rumble_expiration = SDL_GetTicks() + SDL_min(duration_ms, SDL_MAX_RUMBLE_DURATION_MS); 2134 if (!joystick->rumble_expiration) { 2135 joystick->rumble_expiration = 1; 2136 } 2137 } else { 2138 joystick->rumble_expiration = 0; 2139 joystick->rumble_resend = 0; 2140 } 2141 } 2142 } 2143 SDL_UnlockJoysticks(); 2144 2145 return result; 2146} 2147 2148bool SDL_RumbleJoystickTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble, Uint32 duration_ms) 2149{ 2150 bool result; 2151 2152 SDL_LockJoysticks(); 2153 { 2154 CHECK_JOYSTICK_MAGIC(joystick, false); 2155 2156 if (left_rumble == joystick->left_trigger_rumble && right_rumble == joystick->right_trigger_rumble) { 2157 // Just update the expiration 2158 result = true; 2159 } else { 2160 result = joystick->driver->RumbleTriggers(joystick, left_rumble, right_rumble); 2161 if (result) { 2162 joystick->trigger_rumble_resend = SDL_GetTicks() + SDL_RUMBLE_RESEND_MS; 2163 if (joystick->trigger_rumble_resend == 0) { 2164 joystick->trigger_rumble_resend = 1; 2165 } 2166 } else { 2167 joystick->trigger_rumble_resend = 0; 2168 } 2169 } 2170 2171 if (result) { 2172 joystick->left_trigger_rumble = left_rumble; 2173 joystick->right_trigger_rumble = right_rumble; 2174 2175 if ((left_rumble || right_rumble) && duration_ms) { 2176 joystick->trigger_rumble_expiration = SDL_GetTicks() + SDL_min(duration_ms, SDL_MAX_RUMBLE_DURATION_MS); 2177 } else { 2178 joystick->trigger_rumble_expiration = 0; 2179 joystick->trigger_rumble_resend = 0; 2180 } 2181 } 2182 } 2183 SDL_UnlockJoysticks(); 2184 2185 return result; 2186} 2187 2188bool SDL_SetJoystickLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) 2189{ 2190 bool result; 2191 bool isfreshvalue; 2192 2193 SDL_LockJoysticks(); 2194 { 2195 CHECK_JOYSTICK_MAGIC(joystick, false); 2196 2197 isfreshvalue = red != joystick->led_red || 2198 green != joystick->led_green || 2199 blue != joystick->led_blue; 2200 2201 if (isfreshvalue || SDL_GetTicks() >= joystick->led_expiration) { 2202 result = joystick->driver->SetLED(joystick, red, green, blue); 2203 joystick->led_expiration = SDL_GetTicks() + SDL_LED_MIN_REPEAT_MS; 2204 } else { 2205 // Avoid spamming the driver 2206 result = true; 2207 } 2208 2209 // Save the LED value regardless of success, so we don't spam the driver 2210 joystick->led_red = red; 2211 joystick->led_green = green; 2212 joystick->led_blue = blue; 2213 } 2214 SDL_UnlockJoysticks(); 2215 2216 return result; 2217} 2218 2219bool SDL_SendJoystickEffect(SDL_Joystick *joystick, const void *data, int size) 2220{ 2221 bool result; 2222 2223 SDL_LockJoysticks(); 2224 { 2225 CHECK_JOYSTICK_MAGIC(joystick, false); 2226 2227 result = joystick->driver->SendEffect(joystick, data, size); 2228 } 2229 SDL_UnlockJoysticks(); 2230 2231 return result; 2232} 2233 2234/* 2235 * Close a joystick previously opened with SDL_OpenJoystick() 2236 */ 2237void SDL_CloseJoystick(SDL_Joystick *joystick) 2238{ 2239 SDL_Joystick *joysticklist; 2240 SDL_Joystick *joysticklistprev; 2241 int i; 2242 2243 SDL_LockJoysticks(); 2244 { 2245 CHECK_JOYSTICK_MAGIC(joystick,); 2246 2247 // First decrement ref count 2248 if (--joystick->ref_count > 0) { 2249 SDL_UnlockJoysticks(); 2250 return; 2251 } 2252 2253 SDL_DestroyProperties(joystick->props); 2254 2255 if (joystick->rumble_expiration) { 2256 SDL_RumbleJoystick(joystick, 0, 0, 0); 2257 } 2258 if (joystick->trigger_rumble_expiration) { 2259 SDL_RumbleJoystickTriggers(joystick, 0, 0, 0); 2260 } 2261 2262 CleanupSensorFusion(joystick); 2263 2264 joystick->driver->Close(joystick); 2265 joystick->hwdata = NULL; 2266 SDL_SetObjectValid(joystick, SDL_OBJECT_TYPE_JOYSTICK, false); 2267 2268 joysticklist = SDL_joysticks; 2269 joysticklistprev = NULL; 2270 while (joysticklist) { 2271 if (joystick == joysticklist) { 2272 if (joysticklistprev) { 2273 // unlink this entry 2274 joysticklistprev->next = joysticklist->next; 2275 } else { 2276 SDL_joysticks = joystick->next; 2277 } 2278 break; 2279 } 2280 joysticklistprev = joysticklist; 2281 joysticklist = joysticklist->next; 2282 } 2283 2284 // Free the data associated with this joystick 2285 SDL_free(joystick->name); 2286 SDL_free(joystick->path); 2287 SDL_free(joystick->serial); 2288 SDL_free(joystick->axes); 2289 SDL_free(joystick->balls); 2290 SDL_free(joystick->hats); 2291 SDL_free(joystick->buttons); 2292 for (i = 0; i < joystick->ntouchpads; i++) { 2293 SDL_JoystickTouchpadInfo *touchpad = &joystick->touchpads[i]; 2294 SDL_free(touchpad->fingers); 2295 } 2296 SDL_free(joystick->touchpads); 2297 SDL_free(joystick->sensors); 2298 SDL_free(joystick); 2299 } 2300 SDL_UnlockJoysticks(); 2301} 2302 2303void SDL_QuitJoysticks(void) 2304{ 2305 int i; 2306 SDL_JoystickID *joysticks; 2307 2308 SDL_LockJoysticks(); 2309 2310 SDL_joysticks_quitting = true; 2311 2312 joysticks = SDL_GetJoysticks(NULL); 2313 if (joysticks) { 2314 for (i = 0; joysticks[i]; ++i) { 2315 SDL_PrivateJoystickRemoved(joysticks[i]); 2316 } 2317 SDL_free(joysticks); 2318 } 2319 2320 while (SDL_joysticks) { 2321 SDL_joysticks->ref_count = 1; 2322 SDL_CloseJoystick(SDL_joysticks); 2323 } 2324 2325 // Quit drivers in reverse order to avoid breaking dependencies between drivers 2326 for (i = SDL_arraysize(SDL_joystick_drivers) - 1; i >= 0; --i) { 2327 SDL_joystick_drivers[i]->Quit(); 2328 } 2329 2330 if (SDL_joystick_players) { 2331 SDL_free(SDL_joystick_players); 2332 SDL_joystick_players = NULL; 2333 SDL_joystick_player_count = 0; 2334 } 2335 2336 SDL_QuitSubSystem(SDL_INIT_EVENTS); 2337 2338 SDL_QuitSteamVirtualGamepadInfo(); 2339 2340 SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, 2341 SDL_JoystickAllowBackgroundEventsChanged, NULL); 2342 2343 SDL_FreeVIDPIDList(&old_xboxone_controllers); 2344 SDL_FreeVIDPIDList(&arcadestick_devices); 2345 SDL_FreeVIDPIDList(&blacklist_devices); 2346 SDL_FreeVIDPIDList(&drum_devices); 2347 SDL_FreeVIDPIDList(&flightstick_devices); 2348 SDL_FreeVIDPIDList(&gamecube_devices); 2349 SDL_FreeVIDPIDList(&guitar_devices); 2350 SDL_FreeVIDPIDList(&rog_gamepad_mice); 2351 SDL_FreeVIDPIDList(&throttle_devices); 2352 SDL_FreeVIDPIDList(&wheel_devices); 2353 SDL_FreeVIDPIDList(&zero_centered_devices); 2354 2355 SDL_QuitGamepadMappings(); 2356 2357 if (SDL_joystick_names) { 2358 SDL_DestroyHashTable(SDL_joystick_names); 2359 SDL_joystick_names = NULL; 2360 } 2361 2362 SDL_joysticks_quitting = false; 2363 SDL_joysticks_initialized = false; 2364 2365 SDL_UnlockJoysticks(); 2366} 2367 2368static bool SDL_PrivateJoystickShouldIgnoreEvent(void) 2369{ 2370 if (SDL_joystick_allows_background_events) { 2371 return false; 2372 } 2373 2374 if (SDL_HasWindows() && SDL_GetKeyboardFocus() == NULL) { 2375 // We have windows but we don't have focus, ignore the event. 2376 return true; 2377 } 2378 return false; 2379} 2380 2381// These are global for SDL_sysjoystick.c and SDL_events.c 2382 2383void SDL_PrivateJoystickAddTouchpad(SDL_Joystick *joystick, int nfingers) 2384{ 2385 int ntouchpads; 2386 SDL_JoystickTouchpadInfo *touchpads; 2387 2388 SDL_AssertJoysticksLocked(); 2389 2390 ntouchpads = joystick->ntouchpads + 1; 2391 touchpads = (SDL_JoystickTouchpadInfo *)SDL_realloc(joystick->touchpads, (ntouchpads * sizeof(SDL_JoystickTouchpadInfo))); 2392 if (touchpads) { 2393 SDL_JoystickTouchpadInfo *touchpad = &touchpads[ntouchpads - 1]; 2394 SDL_JoystickTouchpadFingerInfo *fingers = (SDL_JoystickTouchpadFingerInfo *)SDL_calloc(nfingers, sizeof(SDL_JoystickTouchpadFingerInfo)); 2395 2396 if (fingers) { 2397 touchpad->nfingers = nfingers; 2398 touchpad->fingers = fingers; 2399 } else { 2400 // Out of memory, this touchpad won't be active 2401 touchpad->nfingers = 0; 2402 touchpad->fingers = NULL; 2403 } 2404 2405 joystick->ntouchpads = ntouchpads; 2406 joystick->touchpads = touchpads; 2407 } 2408} 2409 2410void SDL_PrivateJoystickAddSensor(SDL_Joystick *joystick, SDL_SensorType type, float rate) 2411{ 2412 int nsensors; 2413 SDL_JoystickSensorInfo *sensors; 2414 2415 SDL_AssertJoysticksLocked(); 2416 2417 nsensors = joystick->nsensors + 1; 2418 sensors = (SDL_JoystickSensorInfo *)SDL_realloc(joystick->sensors, (nsensors * sizeof(SDL_JoystickSensorInfo))); 2419 if (sensors) { 2420 SDL_JoystickSensorInfo *sensor = &sensors[nsensors - 1]; 2421 2422 SDL_zerop(sensor); 2423 sensor->type = type; 2424 sensor->rate = rate; 2425 2426 joystick->nsensors = nsensors; 2427 joystick->sensors = sensors; 2428 } 2429} 2430 2431void SDL_PrivateJoystickSensorRate(SDL_Joystick *joystick, SDL_SensorType type, float rate) 2432{ 2433 int i; 2434 SDL_AssertJoysticksLocked(); 2435 2436 for (i = 0; i < joystick->nsensors; ++i) { 2437 if (joystick->sensors[i].type == type) { 2438 joystick->sensors[i].rate = rate; 2439 } 2440 } 2441} 2442 2443void SDL_PrivateJoystickAdded(SDL_JoystickID instance_id) 2444{ 2445 SDL_JoystickDriver *driver; 2446 int device_index; 2447 int player_index = -1; 2448 bool is_gamepad; 2449 2450 SDL_AssertJoysticksLocked(); 2451 2452 if (SDL_JoysticksQuitting()) { 2453 return; 2454 } 2455 2456 SDL_joystick_being_added = true; 2457 2458 if (SDL_GetDriverAndJoystickIndex(instance_id, &driver, &device_index)) { 2459 player_index = driver->GetDeviceSteamVirtualGamepadSlot(device_index); 2460 if (player_index < 0) { 2461 player_index = driver->GetDevicePlayerIndex(device_index); 2462 } 2463 } 2464 if (player_index < 0 && SDL_IsGamepad(instance_id)) { 2465 player_index = SDL_FindFreePlayerIndex(); 2466 } 2467 if (player_index >= 0) { 2468 SDL_SetJoystickIDForPlayerIndex(player_index, instance_id); 2469 } 2470 2471 SDL_UpdateJoystickNameForID(instance_id); 2472 2473 { 2474 SDL_Event event; 2475 2476 event.type = SDL_EVENT_JOYSTICK_ADDED; 2477 event.common.timestamp = 0; 2478 2479 if (SDL_EventEnabled(event.type)) { 2480 event.jdevice.which = instance_id; 2481 SDL_PushEvent(&event); 2482 } 2483 } 2484 2485 // This might create an automatic gamepad mapping, so wait to send the event 2486 is_gamepad = SDL_IsGamepad(instance_id); 2487 2488 SDL_joystick_being_added = false; 2489 2490 if (is_gamepad) { 2491 SDL_PrivateGamepadAdded(instance_id); 2492 } 2493} 2494 2495bool SDL_IsJoystickBeingAdded(void) 2496{ 2497 return SDL_joystick_being_added; 2498} 2499 2500void SDL_PrivateJoystickForceRecentering(SDL_Joystick *joystick) 2501{ 2502 int i, j; 2503 Uint64 timestamp = SDL_GetTicksNS(); 2504 2505 SDL_AssertJoysticksLocked(); 2506 2507 // Tell the app that everything is centered/unpressed... 2508 for (i = 0; i < joystick->naxes; i++) { 2509 if (joystick->axes[i].has_initial_value) { 2510 SDL_SendJoystickAxis(timestamp, joystick, i, joystick->axes[i].zero); 2511 } 2512 } 2513 2514 for (i = 0; i < joystick->nbuttons; i++) { 2515 SDL_SendJoystickButton(timestamp, joystick, i, false); 2516 } 2517 2518 for (i = 0; i < joystick->nhats; i++) { 2519 SDL_SendJoystickHat(timestamp, joystick, i, SDL_HAT_CENTERED); 2520 } 2521 2522 for (i = 0; i < joystick->ntouchpads; i++) { 2523 SDL_JoystickTouchpadInfo *touchpad = &joystick->touchpads[i]; 2524 2525 for (j = 0; j < touchpad->nfingers; ++j) { 2526 SDL_SendJoystickTouchpad(timestamp, joystick, i, j, false, 0.0f, 0.0f, 0.0f); 2527 } 2528 } 2529} 2530 2531void SDL_PrivateJoystickRemoved(SDL_JoystickID instance_id) 2532{ 2533 SDL_Joystick *joystick = NULL; 2534 int player_index; 2535 SDL_Event event; 2536 2537 SDL_AssertJoysticksLocked(); 2538 2539 // Find this joystick... 2540 for (joystick = SDL_joysticks; joystick; joystick = joystick->next) { 2541 if (joystick->instance_id == instance_id) { 2542 SDL_PrivateJoystickForceRecentering(joystick); 2543 joystick->attached = false; 2544 break; 2545 } 2546 } 2547 2548 if (SDL_IsGamepad(instance_id)) { 2549 SDL_PrivateGamepadRemoved(instance_id); 2550 } 2551 2552 event.type = SDL_EVENT_JOYSTICK_REMOVED; 2553 event.common.timestamp = 0; 2554 2555 if (SDL_EventEnabled(event.type)) { 2556 event.jdevice.which = instance_id; 2557 SDL_PushEvent(&event); 2558 } 2559 2560 player_index = SDL_GetPlayerIndexForJoystickID(instance_id); 2561 if (player_index >= 0) { 2562 SDL_joystick_players[player_index] = 0; 2563 } 2564} 2565 2566void SDL_SendJoystickAxis(Uint64 timestamp, SDL_Joystick *joystick, Uint8 axis, Sint16 value) 2567{ 2568 SDL_JoystickAxisInfo *info; 2569 2570 SDL_AssertJoysticksLocked(); 2571 2572 // Make sure we're not getting garbage or duplicate events 2573 if (axis >= joystick->naxes) { 2574 return; 2575 } 2576 2577 info = &joystick->axes[axis]; 2578 if (!info->has_initial_value || 2579 (!info->has_second_value && (info->initial_value <= -32767 || info->initial_value == 32767) && SDL_abs(value) < (SDL_JOYSTICK_AXIS_MAX / 4))) { 2580 info->initial_value = value; 2581 info->value = value; 2582 info->zero = value; 2583 info->has_initial_value = true; 2584 } else if (value == info->value && !info->sending_initial_value) { 2585 return; 2586 } else { 2587 info->has_second_value = true; 2588 } 2589 if (!info->sent_initial_value) { 2590 // Make sure we don't send motion until there's real activity on this axis 2591 const int MAX_ALLOWED_JITTER = SDL_JOYSTICK_AXIS_MAX / 80; // ShanWan PS3 controller needed 96 2592 if (SDL_abs(value - info->value) <= MAX_ALLOWED_JITTER && 2593 !SDL_IsJoystickVIRTUAL(joystick->guid)) { 2594 return; 2595 } 2596 info->sent_initial_value = true; 2597 info->sending_initial_value = true; 2598 SDL_SendJoystickAxis(timestamp, joystick, axis, info->initial_value); 2599 info->sending_initial_value = false; 2600 } 2601 2602 /* We ignore events if we don't have keyboard focus, except for centering 2603 * events. 2604 */ 2605 if (SDL_PrivateJoystickShouldIgnoreEvent()) { 2606 if (info->sending_initial_value || 2607 (value > info->zero && value >= info->value) || 2608 (value < info->zero && value <= info->value)) { 2609 return; 2610 } 2611 } 2612 2613 // Update internal joystick state 2614 SDL_assert(timestamp != 0); 2615 info->value = value; 2616 joystick->update_complete = timestamp; 2617 2618 // Post the event, if desired 2619 if (SDL_EventEnabled(SDL_EVENT_JOYSTICK_AXIS_MOTION)) { 2620 SDL_Event event; 2621 event.type = SDL_EVENT_JOYSTICK_AXIS_MOTION; 2622 event.common.timestamp = timestamp; 2623 event.jaxis.which = joystick->instance_id; 2624 event.jaxis.axis = axis; 2625 event.jaxis.value = value; 2626 SDL_PushEvent(&event); 2627 } 2628} 2629 2630void SDL_SendJoystickBall(Uint64 timestamp, SDL_Joystick *joystick, Uint8 ball, Sint16 xrel, Sint16 yrel) 2631{ 2632 SDL_AssertJoysticksLocked(); 2633 2634 // Make sure we're not getting garbage events 2635 if (ball >= joystick->nballs) { 2636 return; 2637 } 2638 2639 // We ignore events if we don't have keyboard focus. 2640 if (SDL_PrivateJoystickShouldIgnoreEvent()) { 2641 return; 2642 } 2643 2644 // Update internal mouse state 2645 joystick->balls[ball].dx += xrel; 2646 joystick->balls[ball].dy += yrel; 2647 2648 // Post the event, if desired 2649 if (SDL_EventEnabled(SDL_EVENT_JOYSTICK_BALL_MOTION)) { 2650 SDL_Event event; 2651 event.type = SDL_EVENT_JOYSTICK_BALL_MOTION; 2652 event.common.timestamp = timestamp; 2653 event.jball.which = joystick->instance_id; 2654 event.jball.ball = ball; 2655 event.jball.xrel = xrel; 2656 event.jball.yrel = yrel; 2657 SDL_PushEvent(&event); 2658 } 2659} 2660 2661void SDL_SendJoystickHat(Uint64 timestamp, SDL_Joystick *joystick, Uint8 hat, Uint8 value) 2662{ 2663 SDL_AssertJoysticksLocked(); 2664 2665 // Make sure we're not getting garbage or duplicate events 2666 if (hat >= joystick->nhats) { 2667 return; 2668 } 2669 if (value == joystick->hats[hat]) { 2670 return; 2671 } 2672 2673 /* We ignore events if we don't have keyboard focus, except for centering 2674 * events. 2675 */ 2676 if (SDL_PrivateJoystickShouldIgnoreEvent()) { 2677 if (value != SDL_HAT_CENTERED) { 2678 return; 2679 } 2680 } 2681 2682 // Update internal joystick state 2683 SDL_assert(timestamp != 0); 2684 joystick->hats[hat] = value; 2685 joystick->update_complete = timestamp; 2686 2687 // Post the event, if desired 2688 if (SDL_EventEnabled(SDL_EVENT_JOYSTICK_HAT_MOTION)) { 2689 SDL_Event event; 2690 event.type = SDL_EVENT_JOYSTICK_HAT_MOTION; 2691 event.common.timestamp = timestamp; 2692 event.jhat.which = joystick->instance_id; 2693 event.jhat.hat = hat; 2694 event.jhat.value = value; 2695 SDL_PushEvent(&event); 2696 } 2697} 2698 2699void SDL_SendJoystickButton(Uint64 timestamp, SDL_Joystick *joystick, Uint8 button, bool down) 2700{ 2701 SDL_Event event; 2702 2703 SDL_AssertJoysticksLocked(); 2704 2705 if (down) { 2706 event.type = SDL_EVENT_JOYSTICK_BUTTON_DOWN; 2707 } else { 2708 event.type = SDL_EVENT_JOYSTICK_BUTTON_UP; 2709 } 2710 2711 if (joystick->swap_face_buttons) { 2712 switch (button) { 2713 case 0: 2714 button = 1; 2715 break; 2716 case 1: 2717 button = 0; 2718 break; 2719 case 2: 2720 button = 3; 2721 break; 2722 case 3: 2723 button = 2; 2724 break; 2725 default: 2726 break; 2727 } 2728 } 2729 2730 // Make sure we're not getting garbage or duplicate events 2731 if (button >= joystick->nbuttons) { 2732 return; 2733 } 2734 if (down == joystick->buttons[button]) { 2735 return; 2736 } 2737 2738 /* We ignore events if we don't have keyboard focus, except for button 2739 * release. */ 2740 if (SDL_PrivateJoystickShouldIgnoreEvent()) { 2741 if (down) { 2742 return; 2743 } 2744 } 2745 2746 // Update internal joystick state 2747 SDL_assert(timestamp != 0); 2748 joystick->buttons[button] = down; 2749 joystick->update_complete = timestamp; 2750 2751 // Post the event, if desired 2752 if (SDL_EventEnabled(event.type)) { 2753 event.common.timestamp = timestamp; 2754 event.jbutton.which = joystick->instance_id; 2755 event.jbutton.button = button; 2756 event.jbutton.down = down; 2757 SDL_PushEvent(&event); 2758 } 2759} 2760 2761static void SendSteamHandleUpdateEvents(void) 2762{ 2763 SDL_Joystick *joystick; 2764 const SDL_SteamVirtualGamepadInfo *info; 2765 2766 SDL_AssertJoysticksLocked(); 2767 2768 // Check to see if any Steam handles changed 2769 for (joystick = SDL_joysticks; joystick; joystick = joystick->next) { 2770 bool changed = false; 2771 2772 if (!SDL_IsGamepad(joystick->instance_id)) { 2773 continue; 2774 } 2775 2776 info = SDL_GetJoystickVirtualGamepadInfoForID(joystick->instance_id); 2777 if (info) { 2778 if (joystick->steam_handle != info->handle) { 2779 joystick->steam_handle = info->handle; 2780 joystick->swap_face_buttons = ShouldSwapFaceButtons(info); 2781 changed = true; 2782 } 2783 } else { 2784 if (joystick->steam_handle != 0) { 2785 joystick->steam_handle = 0; 2786 joystick->swap_face_buttons = false; 2787 changed = true; 2788 } 2789 } 2790 if (changed) { 2791 SDL_Event event; 2792 2793 SDL_zero(event); 2794 event.type = SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED; 2795 event.common.timestamp = 0; 2796 event.gdevice.which = joystick->instance_id; 2797 SDL_PushEvent(&event); 2798 } 2799 } 2800} 2801 2802void SDL_UpdateJoysticks(void) 2803{ 2804 int i; 2805 Uint64 now; 2806 SDL_Joystick *joystick; 2807 2808 if (!SDL_joysticks_initialized) { 2809 return; 2810 } 2811 2812 SDL_LockJoysticks(); 2813 2814 if (SDL_UpdateSteamVirtualGamepadInfo()) { 2815 SendSteamHandleUpdateEvents(); 2816 } 2817 2818#ifdef SDL_JOYSTICK_HIDAPI 2819 // Special function for HIDAPI devices, as a single device can provide multiple SDL_Joysticks 2820 HIDAPI_UpdateDevices(); 2821#endif // SDL_JOYSTICK_HIDAPI 2822 2823 for (joystick = SDL_joysticks; joystick; joystick = joystick->next) { 2824 if (!joystick->attached) { 2825 continue; 2826 } 2827 2828 joystick->driver->Update(joystick); 2829 2830 if (joystick->delayed_guide_button) { 2831 SDL_GamepadHandleDelayedGuideButton(joystick); 2832 } 2833 2834 now = SDL_GetTicks(); 2835 if (joystick->rumble_expiration && now >= joystick->rumble_expiration) { 2836 SDL_RumbleJoystick(joystick, 0, 0, 0); 2837 joystick->rumble_resend = 0; 2838 } 2839 2840 if (joystick->rumble_resend && now >= joystick->rumble_resend) { 2841 joystick->driver->Rumble(joystick, joystick->low_frequency_rumble, joystick->high_frequency_rumble); 2842 joystick->rumble_resend = now + SDL_RUMBLE_RESEND_MS; 2843 if (joystick->rumble_resend == 0) { 2844 joystick->rumble_resend = 1; 2845 } 2846 } 2847 2848 if (joystick->trigger_rumble_expiration && now >= joystick->trigger_rumble_expiration) { 2849 SDL_RumbleJoystickTriggers(joystick, 0, 0, 0); 2850 joystick->trigger_rumble_resend = 0; 2851 } 2852 2853 if (joystick->trigger_rumble_resend && now >= joystick->trigger_rumble_resend) { 2854 joystick->driver->RumbleTriggers(joystick, joystick->left_trigger_rumble, joystick->right_trigger_rumble); 2855 joystick->trigger_rumble_resend = now + SDL_RUMBLE_RESEND_MS; 2856 if (joystick->trigger_rumble_resend == 0) { 2857 joystick->trigger_rumble_resend = 1; 2858 } 2859 } 2860 } 2861 2862 if (SDL_EventEnabled(SDL_EVENT_JOYSTICK_UPDATE_COMPLETE)) { 2863 for (joystick = SDL_joysticks; joystick; joystick = joystick->next) { 2864 if (joystick->update_complete) { 2865 SDL_Event event; 2866 2867 event.type = SDL_EVENT_JOYSTICK_UPDATE_COMPLETE; 2868 event.common.timestamp = joystick->update_complete; 2869 event.jdevice.which = joystick->instance_id; 2870 SDL_PushEvent(&event); 2871 2872 joystick->update_complete = 0; 2873 } 2874 } 2875 } 2876 2877 /* this needs to happen AFTER walking the joystick list above, so that any 2878 dangling hardware data from removed devices can be free'd 2879 */ 2880 for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) { 2881 SDL_joystick_drivers[i]->Detect(); 2882 } 2883 2884 SDL_UnlockJoysticks(); 2885} 2886 2887static const Uint32 SDL_joystick_event_list[] = { 2888 SDL_EVENT_JOYSTICK_AXIS_MOTION, 2889 SDL_EVENT_JOYSTICK_BALL_MOTION, 2890 SDL_EVENT_JOYSTICK_HAT_MOTION, 2891 SDL_EVENT_JOYSTICK_BUTTON_DOWN, 2892 SDL_EVENT_JOYSTICK_BUTTON_UP, 2893 SDL_EVENT_JOYSTICK_ADDED, 2894 SDL_EVENT_JOYSTICK_REMOVED, 2895 SDL_EVENT_JOYSTICK_BATTERY_UPDATED 2896}; 2897 2898void SDL_SetJoystickEventsEnabled(bool enabled) 2899{ 2900 unsigned int i; 2901 2902 for (i = 0; i < SDL_arraysize(SDL_joystick_event_list); ++i) { 2903 SDL_SetEventEnabled(SDL_joystick_event_list[i], enabled); 2904 } 2905} 2906 2907bool SDL_JoystickEventsEnabled(void) 2908{ 2909 bool enabled = false; 2910 unsigned int i; 2911 2912 for (i = 0; i < SDL_arraysize(SDL_joystick_event_list); ++i) { 2913 enabled = SDL_EventEnabled(SDL_joystick_event_list[i]); 2914 if (enabled) { 2915 break; 2916 } 2917 } 2918 return enabled; 2919} 2920 2921void SDL_GetJoystickGUIDInfo(SDL_GUID guid, Uint16 *vendor, Uint16 *product, Uint16 *version, Uint16 *crc16) 2922{ 2923 Uint16 *guid16 = (Uint16 *)guid.data; 2924 Uint16 bus = SDL_Swap16LE(guid16[0]); 2925 2926 if ((bus < ' ' || bus == SDL_HARDWARE_BUS_VIRTUAL) && guid16[3] == 0x0000 && guid16[5] == 0x0000) { 2927 /* This GUID fits the standard form: 2928 * 16-bit bus 2929 * 16-bit CRC16 of the joystick name (can be zero) 2930 * 16-bit vendor ID 2931 * 16-bit zero 2932 * 16-bit product ID 2933 * 16-bit zero 2934 * 16-bit version 2935 * 8-bit driver identifier ('h' for HIDAPI, 'x' for XInput, etc.) 2936 * 8-bit driver-dependent type info 2937 */ 2938 if (vendor) { 2939 *vendor = SDL_Swap16LE(guid16[2]); 2940 } 2941 if (product) { 2942 *product = SDL_Swap16LE(guid16[4]); 2943 } 2944 if (version) { 2945 *version = SDL_Swap16LE(guid16[6]); 2946 } 2947 if (crc16) { 2948 *crc16 = SDL_Swap16LE(guid16[1]); 2949 } 2950 } else if (bus < ' ' || bus == SDL_HARDWARE_BUS_VIRTUAL) { 2951 /* This GUID fits the unknown VID/PID form: 2952 * 16-bit bus 2953 * 16-bit CRC16 of the joystick name (can be zero) 2954 * 11 characters of the joystick name, null terminated 2955 */ 2956 if (vendor) { 2957 *vendor = 0; 2958 } 2959 if (product) { 2960 *product = 0; 2961 } 2962 if (version) { 2963 *version = 0; 2964 } 2965 if (crc16) { 2966 *crc16 = SDL_Swap16LE(guid16[1]); 2967 } 2968 } else { 2969 if (vendor) { 2970 *vendor = 0; 2971 } 2972 if (product) { 2973 *product = 0; 2974 } 2975 if (version) { 2976 *version = 0; 2977 } 2978 if (crc16) { 2979 *crc16 = 0; 2980 } 2981 } 2982} 2983 2984char *SDL_CreateJoystickName(Uint16 vendor, Uint16 product, const char *vendor_name, const char *product_name) 2985{ 2986 const char *custom_name = GuessControllerName(vendor, product); 2987 if (custom_name) { 2988 return SDL_strdup(custom_name); 2989 } 2990 2991 return SDL_CreateDeviceName(vendor, product, vendor_name, product_name, "Controller"); 2992} 2993 2994SDL_GUID SDL_CreateJoystickGUID(Uint16 bus, Uint16 vendor, Uint16 product, Uint16 version, const char *vendor_name, const char *product_name, Uint8 driver_signature, Uint8 driver_data) 2995{ 2996 SDL_GUID guid; 2997 Uint16 *guid16 = (Uint16 *)guid.data; 2998 Uint16 crc = 0; 2999 3000 SDL_zero(guid); 3001 3002 if (vendor_name && *vendor_name && product_name && *product_name) { 3003 crc = SDL_crc16(crc, vendor_name, SDL_strlen(vendor_name)); 3004 crc = SDL_crc16(crc, " ", 1); 3005 crc = SDL_crc16(crc, product_name, SDL_strlen(product_name)); 3006 } else if (product_name) { 3007 crc = SDL_crc16(crc, product_name, SDL_strlen(product_name)); 3008 } 3009 3010 // We only need 16 bits for each of these; space them out to fill 128. 3011 // Byteswap so devices get same GUID on little/big endian platforms. 3012 *guid16++ = SDL_Swap16LE(bus); 3013 *guid16++ = SDL_Swap16LE(crc); 3014 3015 if (vendor) { 3016 *guid16++ = SDL_Swap16LE(vendor); 3017 *guid16++ = 0; 3018 *guid16++ = SDL_Swap16LE(product); 3019 *guid16++ = 0; 3020 *guid16++ = SDL_Swap16LE(version); 3021 guid.data[14] = driver_signature; 3022 guid.data[15] = driver_data; 3023 } else { 3024 size_t available_space = sizeof(guid.data) - 4; 3025 3026 if (driver_signature) { 3027 available_space -= 2; 3028 guid.data[14] = driver_signature; 3029 guid.data[15] = driver_data; 3030 } 3031 if (product_name) { 3032 SDL_strlcpy((char *)guid16, product_name, available_space); 3033 } 3034 } 3035 return guid; 3036} 3037 3038SDL_GUID SDL_CreateJoystickGUIDForName(const char *name) 3039{ 3040 return SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_UNKNOWN, 0, 0, 0, NULL, name, 0, 0); 3041} 3042 3043void SDL_SetJoystickGUIDVendor(SDL_GUID *guid, Uint16 vendor) 3044{ 3045 Uint16 *guid16 = (Uint16 *)guid->data; 3046 3047 guid16[2] = SDL_Swap16LE(vendor); 3048} 3049 3050void SDL_SetJoystickGUIDProduct(SDL_GUID *guid, Uint16 product) 3051{ 3052 Uint16 *guid16 = (Uint16 *)guid->data; 3053 3054 guid16[4] = SDL_Swap16LE(product); 3055} 3056 3057void SDL_SetJoystickGUIDVersion(SDL_GUID *guid, Uint16 version) 3058{ 3059 Uint16 *guid16 = (Uint16 *)guid->data; 3060 3061 guid16[6] = SDL_Swap16LE(version); 3062} 3063 3064void SDL_SetJoystickGUIDCRC(SDL_GUID *guid, Uint16 crc) 3065{ 3066 Uint16 *guid16 = (Uint16 *)guid->data; 3067 3068 guid16[1] = SDL_Swap16LE(crc); 3069} 3070 3071SDL_GamepadType SDL_GetGamepadTypeFromVIDPID(Uint16 vendor, Uint16 product, const char *name, bool forUI) 3072{ 3073 SDL_GamepadType type = SDL_GAMEPAD_TYPE_STANDARD; 3074 3075 if (vendor == 0x0000 && product == 0x0000) { 3076 // Some devices are only identifiable by their name 3077 if (name && 3078 (SDL_strcmp(name, "Lic Pro Controller") == 0 || 3079 SDL_strcmp(name, "Nintendo Wireless Gamepad") == 0 || 3080 SDL_strcmp(name, "Wireless Gamepad") == 0)) { 3081 // HORI or PowerA Switch Pro Controller clone 3082 type = SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO; 3083 } 3084 3085 } else if (vendor == 0x0001 && product == 0x0001) { 3086 type = SDL_GAMEPAD_TYPE_STANDARD; 3087 3088 } else if (vendor == USB_VENDOR_NINTENDO && 3089 (product == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_LEFT || 3090 product == USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_LEFT)) { 3091 type = SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT; 3092 3093 } else if (vendor == USB_VENDOR_NINTENDO && 3094 (product == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_RIGHT || 3095 product == USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_RIGHT)) { 3096 if (name && SDL_strstr(name, "NES Controller") != NULL) { 3097 // We don't have a type for the Nintendo Online NES Controller 3098 type = SDL_GAMEPAD_TYPE_STANDARD; 3099 } else { 3100 type = SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT; 3101 } 3102 3103 } else if (vendor == USB_VENDOR_NINTENDO && product == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_GRIP) { 3104 if (name && SDL_strstr(name, "(L)") != NULL) { 3105 type = SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT; 3106 } else { 3107 type = SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT; 3108 } 3109 3110 } else if (vendor == USB_VENDOR_NINTENDO && 3111 (product == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_PAIR || 3112 product == USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_PAIR)) { 3113 type = SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_PAIR; 3114 3115 } else if (forUI && SDL_IsJoystickGameCube(vendor, product)) { 3116 type = SDL_GAMEPAD_TYPE_GAMECUBE; 3117 3118 } else { 3119 switch (GuessControllerType(vendor, product)) { 3120 case k_eControllerType_XBox360Controller: 3121 type = SDL_GAMEPAD_TYPE_XBOX360; 3122 break; 3123 case k_eControllerType_XBoxOneController: 3124 type = SDL_GAMEPAD_TYPE_XBOXONE; 3125 break; 3126 case k_eControllerType_PS3Controller: 3127 type = SDL_GAMEPAD_TYPE_PS3; 3128 break; 3129 case k_eControllerType_PS4Controller: 3130 type = SDL_GAMEPAD_TYPE_PS4; 3131 break; 3132 case k_eControllerType_PS5Controller: 3133 type = SDL_GAMEPAD_TYPE_PS5; 3134 break; 3135 case k_eControllerType_XInputPS4Controller: 3136 if (forUI) { 3137 type = SDL_GAMEPAD_TYPE_PS4; 3138 } else { 3139 type = SDL_GAMEPAD_TYPE_STANDARD; 3140 } 3141 break; 3142 case k_eControllerType_SwitchProController: 3143 case k_eControllerType_SwitchInputOnlyController: 3144 type = SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO; 3145 break; 3146 case k_eControllerType_XInputSwitchController: 3147 if (forUI) { 3148 type = SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO; 3149 } else { 3150 type = SDL_GAMEPAD_TYPE_STANDARD; 3151 } 3152 break; 3153 default: 3154 break; 3155 } 3156 } 3157 return type; 3158} 3159 3160SDL_GamepadType SDL_GetGamepadTypeFromGUID(SDL_GUID guid, const char *name) 3161{ 3162 SDL_GamepadType type; 3163 Uint16 vendor, product; 3164 3165 SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL, NULL); 3166 type = SDL_GetGamepadTypeFromVIDPID(vendor, product, name, true); 3167 if (type == SDL_GAMEPAD_TYPE_STANDARD) { 3168 if (SDL_IsJoystickXInput(guid)) { 3169 // This is probably an Xbox One controller 3170 return SDL_GAMEPAD_TYPE_XBOXONE; 3171 } 3172#ifdef SDL_JOYSTICK_HIDAPI 3173 if (SDL_IsJoystickHIDAPI(guid)) { 3174 return HIDAPI_GetGamepadTypeFromGUID(guid); 3175 } 3176#endif // SDL_JOYSTICK_HIDAPI 3177 } 3178 return type; 3179} 3180 3181bool SDL_JoystickGUIDUsesVersion(SDL_GUID guid) 3182{ 3183 Uint16 vendor, product; 3184 3185 if (SDL_IsJoystickMFI(guid)) { 3186 // The version bits are used as button capability mask 3187 return false; 3188 } 3189 3190 SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL, NULL); 3191 if (vendor && product) { 3192 return true; 3193 } 3194 return false; 3195} 3196 3197bool SDL_IsJoystickXboxOne(Uint16 vendor_id, Uint16 product_id) 3198{ 3199 EControllerType eType = GuessControllerType(vendor_id, product_id); 3200 return eType == k_eControllerType_XBoxOneController; 3201} 3202 3203bool SDL_IsJoystickXboxOneElite(Uint16 vendor_id, Uint16 product_id) 3204{ 3205 if (vendor_id == USB_VENDOR_MICROSOFT) { 3206 if (product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_1 || 3207 product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2 || 3208 product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLUETOOTH || 3209 product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLE) { 3210 return true; 3211 } 3212 } 3213 return false; 3214} 3215 3216bool SDL_IsJoystickXboxSeriesX(Uint16 vendor_id, Uint16 product_id) 3217{ 3218 // Most new controllers have the share button, so we'll default to true and 3219 // have a list of older XBox One controllers that are known not to have it. 3220 if (SDL_VIDPIDInList(vendor_id, product_id, &old_xboxone_controllers)) { 3221 return false; 3222 } 3223 return true; 3224} 3225 3226bool SDL_IsJoystickBluetoothXboxOne(Uint16 vendor_id, Uint16 product_id) 3227{ 3228 if (vendor_id == USB_VENDOR_MICROSOFT) { 3229 if (product_id == USB_PRODUCT_XBOX_ONE_ADAPTIVE_BLUETOOTH || 3230 product_id == USB_PRODUCT_XBOX_ONE_ADAPTIVE_BLE || 3231 product_id == USB_PRODUCT_XBOX_ONE_S_REV1_BLUETOOTH || 3232 product_id == USB_PRODUCT_XBOX_ONE_S_REV2_BLUETOOTH || 3233 product_id == USB_PRODUCT_XBOX_ONE_S_REV2_BLE || 3234 product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLUETOOTH || 3235 product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLE || 3236 product_id == USB_PRODUCT_XBOX_SERIES_X_BLE) { 3237 return true; 3238 } 3239 } 3240 return false; 3241} 3242 3243bool SDL_IsJoystickPS4(Uint16 vendor_id, Uint16 product_id) 3244{ 3245 EControllerType eType = GuessControllerType(vendor_id, product_id); 3246 return eType == k_eControllerType_PS4Controller; 3247} 3248 3249bool SDL_IsJoystickPS5(Uint16 vendor_id, Uint16 product_id) 3250{ 3251 EControllerType eType = GuessControllerType(vendor_id, product_id); 3252 return eType == k_eControllerType_PS5Controller; 3253} 3254 3255bool SDL_IsJoystickDualSenseEdge(Uint16 vendor_id, Uint16 product_id) 3256{ 3257 if (vendor_id == USB_VENDOR_SONY) { 3258 if (product_id == USB_PRODUCT_SONY_DS5_EDGE) { 3259 return true; 3260 } 3261 } 3262 return false; 3263} 3264 3265bool SDL_IsJoystickNintendoSwitchPro(Uint16 vendor_id, Uint16 product_id) 3266{ 3267 EControllerType eType = GuessControllerType(vendor_id, product_id); 3268 return eType == k_eControllerType_SwitchProController || eType == k_eControllerType_SwitchInputOnlyController; 3269} 3270 3271bool SDL_IsJoystickNintendoSwitchProInputOnly(Uint16 vendor_id, Uint16 product_id) 3272{ 3273 EControllerType eType = GuessControllerType(vendor_id, product_id); 3274 return eType == k_eControllerType_SwitchInputOnlyController; 3275} 3276 3277bool SDL_IsJoystickNintendoSwitchJoyCon(Uint16 vendor_id, Uint16 product_id) 3278{ 3279 EControllerType eType = GuessControllerType(vendor_id, product_id); 3280 return eType == k_eControllerType_SwitchJoyConLeft || eType == k_eControllerType_SwitchJoyConRight; 3281} 3282 3283bool SDL_IsJoystickNintendoSwitchJoyConLeft(Uint16 vendor_id, Uint16 product_id) 3284{ 3285 EControllerType eType = GuessControllerType(vendor_id, product_id); 3286 return eType == k_eControllerType_SwitchJoyConLeft; 3287} 3288 3289bool SDL_IsJoystickNintendoSwitchJoyConRight(Uint16 vendor_id, Uint16 product_id) 3290{ 3291 EControllerType eType = GuessControllerType(vendor_id, product_id); 3292 return eType == k_eControllerType_SwitchJoyConRight; 3293} 3294 3295bool SDL_IsJoystickNintendoSwitchJoyConGrip(Uint16 vendor_id, Uint16 product_id) 3296{ 3297 return vendor_id == USB_VENDOR_NINTENDO && product_id == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_GRIP; 3298} 3299 3300bool SDL_IsJoystickNintendoSwitchJoyConPair(Uint16 vendor_id, Uint16 product_id) 3301{ 3302 return vendor_id == USB_VENDOR_NINTENDO && 3303 (product_id == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_PAIR || 3304 product_id == USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_PAIR); 3305} 3306 3307bool SDL_IsJoystickGameCube(Uint16 vendor_id, Uint16 product_id) 3308{ 3309 return SDL_VIDPIDInList(vendor_id, product_id, &gamecube_devices); 3310} 3311 3312bool SDL_IsJoystickAmazonLunaController(Uint16 vendor_id, Uint16 product_id) 3313{ 3314 return ((vendor_id == USB_VENDOR_AMAZON && product_id == USB_PRODUCT_AMAZON_LUNA_CONTROLLER) || 3315 (vendor_id == BLUETOOTH_VENDOR_AMAZON && product_id == BLUETOOTH_PRODUCT_LUNA_CONTROLLER)); 3316} 3317 3318bool SDL_IsJoystickGoogleStadiaController(Uint16 vendor_id, Uint16 product_id) 3319{ 3320 return vendor_id == USB_VENDOR_GOOGLE && product_id == USB_PRODUCT_GOOGLE_STADIA_CONTROLLER; 3321} 3322 3323bool SDL_IsJoystickNVIDIASHIELDController(Uint16 vendor_id, Uint16 product_id) 3324{ 3325 return (vendor_id == USB_VENDOR_NVIDIA && 3326 (product_id == USB_PRODUCT_NVIDIA_SHIELD_CONTROLLER_V103 || 3327 product_id == USB_PRODUCT_NVIDIA_SHIELD_CONTROLLER_V104)); 3328} 3329 3330bool SDL_IsJoystickSteamVirtualGamepad(Uint16 vendor_id, Uint16 product_id, Uint16 version) 3331{ 3332#ifdef SDL_PLATFORM_MACOS 3333 return (vendor_id == USB_VENDOR_MICROSOFT && product_id == USB_PRODUCT_XBOX360_WIRED_CONTROLLER && version == 0); 3334#else 3335 return (vendor_id == USB_VENDOR_VALVE && product_id == USB_PRODUCT_STEAM_VIRTUAL_GAMEPAD); 3336#endif 3337} 3338 3339bool SDL_IsJoystickSteamController(Uint16 vendor_id, Uint16 product_id) 3340{ 3341 EControllerType eType = GuessControllerType(vendor_id, product_id); 3342 return eType == k_eControllerType_SteamController || eType == k_eControllerType_SteamControllerV2; 3343} 3344 3345bool SDL_IsJoystickHoriSteamController(Uint16 vendor_id, Uint16 product_id) 3346{ 3347 return vendor_id == USB_VENDOR_HORI && (product_id == USB_PRODUCT_HORI_STEAM_CONTROLLER || product_id == USB_PRODUCT_HORI_STEAM_CONTROLLER_BT); 3348} 3349 3350bool SDL_IsJoystickSInputController(Uint16 vendor_id, Uint16 product_id) 3351{ 3352 if (vendor_id == USB_VENDOR_RASPBERRYPI) { 3353 if (product_id == USB_PRODUCT_HANDHELDLEGEND_SINPUT_GENERIC || 3354 product_id == USB_PRODUCT_HANDHELDLEGEND_PROGCC || 3355 product_id == USB_PRODUCT_HANDHELDLEGEND_GCULTIMATE || 3356 product_id == USB_PRODUCT_BONZIRICHANNEL_FIREBIRD || 3357 product_id == USB_PRODUCT_VOIDGAMING_PS4FIREBIRD) { 3358 return true; 3359 } 3360 } 3361 return false; 3362} 3363 3364bool SDL_IsJoystickFlydigiController(Uint16 vendor_id, Uint16 product_id) 3365{ 3366 if (vendor_id == USB_VENDOR_FLYDIGI_V1) { 3367 if (product_id == USB_PRODUCT_FLYDIGI_V1_GAMEPAD) { 3368 return true; 3369 } 3370 } 3371 if (vendor_id == USB_VENDOR_FLYDIGI_V2) { 3372 if (product_id == USB_PRODUCT_FLYDIGI_V2_APEX || product_id == USB_PRODUCT_FLYDIGI_V2_VADER) { 3373 return true; 3374 } 3375 } 3376 return false; 3377} 3378 3379bool SDL_IsJoystickGameSirController(Uint16 vendor_id, Uint16 product_id) 3380{ 3381 if (vendor_id != USB_VENDOR_GAMESIR) { 3382 return false; 3383 } 3384 3385 return (product_id == USB_PRODUCT_GAMESIR_GAMEPAD_G7_PRO_8K); 3386} 3387 3388bool SDL_IsJoystickSteamDeck(Uint16 vendor_id, Uint16 product_id) 3389{ 3390 EControllerType eType = GuessControllerType(vendor_id, product_id); 3391 return eType == k_eControllerType_SteamControllerNeptune; 3392} 3393 3394bool SDL_IsJoystickSteamTriton(Uint16 vendor_id, Uint16 product_id) 3395{ 3396 EControllerType eType = GuessControllerType(vendor_id, product_id); 3397 return eType == k_eControllerType_SteamControllerTriton; 3398} 3399 3400bool SDL_IsJoystickXInput(SDL_GUID guid) 3401{ 3402 return (guid.data[14] == 'x') ? true : false; 3403} 3404 3405bool SDL_IsJoystickWGI(SDL_GUID guid) 3406{ 3407 return (guid.data[14] == 'w') ? true : false; 3408} 3409 3410bool SDL_IsJoystickGameInput(SDL_GUID guid) 3411{ 3412 return (guid.data[14] == 'g') ? true : false; 3413} 3414 3415bool SDL_IsJoystickHIDAPI(SDL_GUID guid) 3416{ 3417 return (guid.data[14] == 'h') ? true : false; 3418} 3419 3420bool SDL_IsJoystickMFI(SDL_GUID guid) 3421{ 3422 return (guid.data[14] == 'm') ? true : false; 3423} 3424 3425bool SDL_IsJoystickRAWINPUT(SDL_GUID guid) 3426{ 3427 return (guid.data[14] == 'r') ? true : false; 3428} 3429 3430bool SDL_IsJoystickVIRTUAL(SDL_GUID guid) 3431{ 3432 return (guid.data[14] == 'v') ? true : false; 3433} 3434 3435bool SDL_IsJoystickWheel(Uint16 vendor_id, Uint16 product_id, Uint16 crc) 3436{ 3437 if (vendor_id == 0x11FF && product_id == 0x3331 && (crc == 0xFAF6 || crc == 0x2004)) { 3438 // Oklick W-2 racing wheel controller (on Windows via DirectInput). 3439 return true; 3440 } 3441 return SDL_VIDPIDInList(vendor_id, product_id, &wheel_devices); 3442} 3443 3444static bool SDL_IsJoystickArcadeStick(Uint16 vendor_id, Uint16 product_id) 3445{ 3446 return SDL_VIDPIDInList(vendor_id, product_id, &arcadestick_devices); 3447} 3448 3449static bool SDL_IsJoystickFlightStick(Uint16 vendor_id, Uint16 product_id) 3450{ 3451 return SDL_VIDPIDInList(vendor_id, product_id, &flightstick_devices); 3452} 3453 3454static bool SDL_IsJoystickThrottle(Uint16 vendor_id, Uint16 product_id) 3455{ 3456 return SDL_VIDPIDInList(vendor_id, product_id, &throttle_devices); 3457} 3458 3459static bool SDL_IsJoystickGuitar(Uint16 vendor_id, Uint16 product_id) 3460{ 3461 return SDL_VIDPIDInList(vendor_id, product_id, &guitar_devices); 3462} 3463 3464static bool SDL_IsJoystickDrumKit(Uint16 vendor_id, Uint16 product_id) 3465{ 3466 return SDL_VIDPIDInList(vendor_id, product_id, &drum_devices); 3467} 3468 3469static SDL_JoystickType SDL_GetJoystickGUIDType(SDL_GUID guid) 3470{ 3471 Uint16 vendor; 3472 Uint16 product; 3473 Uint16 crc; 3474 3475 SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL, &crc); 3476 3477 if (SDL_IsJoystickWheel(vendor, product, crc)) { 3478 return SDL_JOYSTICK_TYPE_WHEEL; 3479 } 3480 3481 if (SDL_IsJoystickArcadeStick(vendor, product)) { 3482 return SDL_JOYSTICK_TYPE_ARCADE_STICK; 3483 } 3484 3485 if (SDL_IsJoystickFlightStick(vendor, product)) { 3486 return SDL_JOYSTICK_TYPE_FLIGHT_STICK; 3487 } 3488 3489 if (SDL_IsJoystickThrottle(vendor, product)) { 3490 return SDL_JOYSTICK_TYPE_THROTTLE; 3491 } 3492 3493 if (SDL_IsJoystickGuitar(vendor, product)) { 3494 return SDL_JOYSTICK_TYPE_GUITAR; 3495 } 3496 3497 if (SDL_IsJoystickDrumKit(vendor, product)) { 3498 return SDL_JOYSTICK_TYPE_DRUM_KIT; 3499 } 3500 3501 if (SDL_IsJoystickXInput(guid)) { 3502 // XInput GUID, get the type based on the XInput device subtype 3503 switch (guid.data[15]) { 3504 case 0x01: // XINPUT_DEVSUBTYPE_GAMEPAD 3505 return SDL_JOYSTICK_TYPE_GAMEPAD; 3506 case 0x02: // XINPUT_DEVSUBTYPE_WHEEL 3507 return SDL_JOYSTICK_TYPE_WHEEL; 3508 case 0x03: // XINPUT_DEVSUBTYPE_ARCADE_STICK 3509 return SDL_JOYSTICK_TYPE_ARCADE_STICK; 3510 case 0x04: // XINPUT_DEVSUBTYPE_FLIGHT_STICK 3511 return SDL_JOYSTICK_TYPE_FLIGHT_STICK; 3512 case 0x05: // XINPUT_DEVSUBTYPE_DANCE_PAD 3513 return SDL_JOYSTICK_TYPE_DANCE_PAD; 3514 case 0x06: // XINPUT_DEVSUBTYPE_GUITAR 3515 case 0x07: // XINPUT_DEVSUBTYPE_GUITAR_ALTERNATE 3516 case 0x0B: // XINPUT_DEVSUBTYPE_GUITAR_BASS 3517 return SDL_JOYSTICK_TYPE_GUITAR; 3518 case 0x08: // XINPUT_DEVSUBTYPE_DRUM_KIT 3519 return SDL_JOYSTICK_TYPE_DRUM_KIT; 3520 case 0x13: // XINPUT_DEVSUBTYPE_ARCADE_PAD 3521 return SDL_JOYSTICK_TYPE_ARCADE_PAD; 3522 default: 3523 return SDL_JOYSTICK_TYPE_UNKNOWN; 3524 } 3525 } 3526 3527 if (SDL_IsJoystickWGI(guid)) { 3528 return (SDL_JoystickType)guid.data[15]; 3529 } 3530 3531 if (SDL_IsJoystickGameInput(guid)) { 3532 return (SDL_JoystickType)guid.data[15]; 3533 } 3534 3535 if (SDL_IsJoystickVIRTUAL(guid)) { 3536 return (SDL_JoystickType)guid.data[15]; 3537 } 3538 3539#ifdef SDL_JOYSTICK_HIDAPI 3540 if (SDL_IsJoystickHIDAPI(guid)) { 3541 return HIDAPI_GetJoystickTypeFromGUID(guid); 3542 } 3543#endif // SDL_JOYSTICK_HIDAPI 3544 3545 if (GuessControllerType(vendor, product) != k_eControllerType_UnknownNonSteamController) { 3546 return SDL_JOYSTICK_TYPE_GAMEPAD; 3547 } 3548 3549 return SDL_JOYSTICK_TYPE_UNKNOWN; 3550} 3551 3552bool SDL_ShouldIgnoreJoystick(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name) 3553{ 3554 // Check the joystick blacklist 3555 if (SDL_VIDPIDInList(vendor_id, product_id, &blacklist_devices)) { 3556 return true; 3557 } 3558 if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_ROG_CHAKRAM, false)) { 3559 if (SDL_VIDPIDInList(vendor_id, product_id, &rog_gamepad_mice)) { 3560 return true; 3561 } 3562 } 3563 3564 if (SDL_ShouldIgnoreGamepad(vendor_id, product_id, version, name)) { 3565 return true; 3566 } 3567 3568 return false; 3569} 3570 3571// return the guid for this index 3572SDL_GUID SDL_GetJoystickGUIDForID(SDL_JoystickID instance_id) 3573{ 3574 SDL_JoystickDriver *driver; 3575 int device_index; 3576 SDL_GUID guid; 3577 3578 SDL_LockJoysticks(); 3579 if (SDL_GetDriverAndJoystickIndex(instance_id, &driver, &device_index)) { 3580 guid = driver->GetDeviceGUID(device_index); 3581 } else { 3582 SDL_zero(guid); 3583 } 3584 SDL_UnlockJoysticks(); 3585 3586 return guid; 3587} 3588 3589Uint16 SDL_GetJoystickVendorForID(SDL_JoystickID instance_id) 3590{ 3591 Uint16 vendor; 3592 const SDL_SteamVirtualGamepadInfo *info; 3593 3594 SDL_LockJoysticks(); 3595 info = SDL_GetJoystickVirtualGamepadInfoForID(instance_id); 3596 if (info) { 3597 vendor = info->vendor_id; 3598 } else { 3599 SDL_GUID guid = SDL_GetJoystickGUIDForID(instance_id); 3600 3601 SDL_GetJoystickGUIDInfo(guid, &vendor, NULL, NULL, NULL); 3602 } 3603 SDL_UnlockJoysticks(); 3604 3605 return vendor; 3606} 3607 3608Uint16 SDL_GetJoystickProductForID(SDL_JoystickID instance_id) 3609{ 3610 Uint16 product; 3611 const SDL_SteamVirtualGamepadInfo *info; 3612 3613 SDL_LockJoysticks(); 3614 info = SDL_GetJoystickVirtualGamepadInfoForID(instance_id); 3615 if (info) { 3616 product = info->product_id; 3617 } else { 3618 SDL_GUID guid = SDL_GetJoystickGUIDForID(instance_id); 3619 3620 SDL_GetJoystickGUIDInfo(guid, NULL, &product, NULL, NULL); 3621 } 3622 SDL_UnlockJoysticks(); 3623 3624 return product; 3625} 3626 3627Uint16 SDL_GetJoystickProductVersionForID(SDL_JoystickID instance_id) 3628{ 3629 Uint16 version; 3630 SDL_GUID guid = SDL_GetJoystickGUIDForID(instance_id); 3631 3632 SDL_GetJoystickGUIDInfo(guid, NULL, NULL, &version, NULL); 3633 return version; 3634} 3635 3636SDL_JoystickType SDL_GetJoystickTypeForID(SDL_JoystickID instance_id) 3637{ 3638 SDL_JoystickType type; 3639 SDL_GUID guid = SDL_GetJoystickGUIDForID(instance_id); 3640 3641 type = SDL_GetJoystickGUIDType(guid); 3642 if (type == SDL_JOYSTICK_TYPE_UNKNOWN) { 3643 if (SDL_IsGamepad(instance_id)) { 3644 type = SDL_JOYSTICK_TYPE_GAMEPAD; 3645 } 3646 } 3647 return type; 3648} 3649 3650SDL_GUID SDL_GetJoystickGUID(SDL_Joystick *joystick) 3651{ 3652 SDL_GUID result; 3653 3654 SDL_LockJoysticks(); 3655 { 3656 static SDL_GUID emptyGUID; 3657 3658 CHECK_JOYSTICK_MAGIC(joystick, emptyGUID); 3659 3660 result = joystick->guid; 3661 } 3662 SDL_UnlockJoysticks(); 3663 3664 return result; 3665} 3666 3667Uint16 SDL_GetJoystickVendor(SDL_Joystick *joystick) 3668{ 3669 Uint16 vendor; 3670 const SDL_SteamVirtualGamepadInfo *info; 3671 3672 SDL_LockJoysticks(); 3673 { 3674 CHECK_JOYSTICK_MAGIC(joystick, 0); 3675 3676 info = SDL_GetJoystickVirtualGamepadInfoForID(joystick->instance_id); 3677 if (info) { 3678 vendor = info->vendor_id; 3679 } else { 3680 SDL_GUID guid = SDL_GetJoystickGUID(joystick); 3681 3682 SDL_GetJoystickGUIDInfo(guid, &vendor, NULL, NULL, NULL); 3683 } 3684 } 3685 SDL_UnlockJoysticks(); 3686 3687 return vendor; 3688} 3689 3690Uint16 SDL_GetJoystickProduct(SDL_Joystick *joystick) 3691{ 3692 Uint16 product; 3693 const SDL_SteamVirtualGamepadInfo *info; 3694 3695 SDL_LockJoysticks(); 3696 { 3697 CHECK_JOYSTICK_MAGIC(joystick, 0); 3698 3699 info = SDL_GetJoystickVirtualGamepadInfoForID(joystick->instance_id); 3700 if (info) { 3701 product = info->product_id; 3702 } else { 3703 SDL_GUID guid = SDL_GetJoystickGUID(joystick); 3704 3705 SDL_GetJoystickGUIDInfo(guid, NULL, &product, NULL, NULL); 3706 } 3707 } 3708 SDL_UnlockJoysticks(); 3709 3710 return product; 3711} 3712 3713Uint16 SDL_GetJoystickProductVersion(SDL_Joystick *joystick) 3714{ 3715 Uint16 version; 3716 SDL_GUID guid = SDL_GetJoystickGUID(joystick); 3717 3718 SDL_GetJoystickGUIDInfo(guid, NULL, NULL, &version, NULL); 3719 return version; 3720} 3721 3722Uint16 SDL_GetJoystickFirmwareVersion(SDL_Joystick *joystick) 3723{ 3724 Uint16 result; 3725 3726 SDL_LockJoysticks(); 3727 { 3728 CHECK_JOYSTICK_MAGIC(joystick, 0); 3729 3730 result = joystick->firmware_version; 3731 } 3732 SDL_UnlockJoysticks(); 3733 3734 return result; 3735} 3736 3737const char *SDL_GetJoystickSerial(SDL_Joystick *joystick) 3738{ 3739 const char *result; 3740 3741 SDL_LockJoysticks(); 3742 { 3743 CHECK_JOYSTICK_MAGIC(joystick, NULL); 3744 3745 result = SDL_GetPersistentString(joystick->serial); 3746 } 3747 SDL_UnlockJoysticks(); 3748 3749 return result; 3750} 3751 3752SDL_JoystickType SDL_GetJoystickType(SDL_Joystick *joystick) 3753{ 3754 SDL_JoystickType type; 3755 SDL_GUID guid = SDL_GetJoystickGUID(joystick); 3756 3757 type = SDL_GetJoystickGUIDType(guid); 3758 if (type == SDL_JOYSTICK_TYPE_UNKNOWN) { 3759 SDL_LockJoysticks(); 3760 { 3761 CHECK_JOYSTICK_MAGIC(joystick, SDL_JOYSTICK_TYPE_UNKNOWN); 3762 3763 if (SDL_IsGamepad(joystick->instance_id)) { 3764 type = SDL_JOYSTICK_TYPE_GAMEPAD; 3765 } 3766 } 3767 SDL_UnlockJoysticks(); 3768 } 3769 return type; 3770} 3771 3772void SDL_SendJoystickPowerInfo(SDL_Joystick *joystick, SDL_PowerState state, int percent) 3773{ 3774 SDL_AssertJoysticksLocked(); 3775 3776 if (state != joystick->battery_state || percent != joystick->battery_percent) { 3777 joystick->battery_state = state; 3778 joystick->battery_percent = percent; 3779 3780 if (SDL_EventEnabled(SDL_EVENT_JOYSTICK_BATTERY_UPDATED)) { 3781 SDL_Event event; 3782 event.type = SDL_EVENT_JOYSTICK_BATTERY_UPDATED; 3783 event.common.timestamp = 0; 3784 event.jbattery.which = joystick->instance_id; 3785 event.jbattery.state = state; 3786 event.jbattery.percent = percent; 3787 SDL_PushEvent(&event); 3788 } 3789 } 3790} 3791 3792SDL_JoystickConnectionState SDL_GetJoystickConnectionState(SDL_Joystick *joystick) 3793{ 3794 SDL_JoystickConnectionState result; 3795 3796 SDL_LockJoysticks(); 3797 { 3798 CHECK_JOYSTICK_MAGIC(joystick, SDL_JOYSTICK_CONNECTION_INVALID); 3799 3800 result = joystick->connection_state; 3801 } 3802 SDL_UnlockJoysticks(); 3803 3804 return result; 3805} 3806 3807SDL_PowerState SDL_GetJoystickPowerInfo(SDL_Joystick *joystick, int *percent) 3808{ 3809 SDL_PowerState result; 3810 3811 if (percent) { 3812 *percent = -1; 3813 } 3814 3815 SDL_LockJoysticks(); 3816 { 3817 CHECK_JOYSTICK_MAGIC(joystick, SDL_POWERSTATE_ERROR); 3818 3819 result = joystick->battery_state; 3820 3821 if (percent) { 3822 *percent = joystick->battery_percent; 3823 } 3824 } 3825 SDL_UnlockJoysticks(); 3826 3827 return result; 3828} 3829 3830void SDL_SendJoystickTouchpad(Uint64 timestamp, SDL_Joystick *joystick, int touchpad, int finger, bool down, float x, float y, float pressure) 3831{ 3832 SDL_JoystickTouchpadInfo *touchpad_info; 3833 SDL_JoystickTouchpadFingerInfo *finger_info; 3834 Uint32 event_type; 3835 3836 SDL_AssertJoysticksLocked(); 3837 3838 if (touchpad < 0 || touchpad >= joystick->ntouchpads) { 3839 return; 3840 } 3841 3842 touchpad_info = &joystick->touchpads[touchpad]; 3843 if (finger < 0 || finger >= touchpad_info->nfingers) { 3844 return; 3845 } 3846 3847 finger_info = &touchpad_info->fingers[finger]; 3848 3849 if (!down) { 3850 if (x == 0.0f && y == 0.0f) { 3851 x = finger_info->x; 3852 y = finger_info->y; 3853 } 3854 pressure = 0.0f; 3855 } 3856 3857 if (x < 0.0f) { 3858 x = 0.0f; 3859 } else if (x > 1.0f) { 3860 x = 1.0f; 3861 } 3862 if (y < 0.0f) { 3863 y = 0.0f; 3864 } else if (y > 1.0f) { 3865 y = 1.0f; 3866 } 3867 if (pressure < 0.0f) { 3868 pressure = 0.0f; 3869 } else if (pressure > 1.0f) { 3870 pressure = 1.0f; 3871 } 3872 3873 if (down == finger_info->down) { 3874 if (!down || 3875 (x == finger_info->x && y == finger_info->y && pressure == finger_info->pressure)) { 3876 return; 3877 } 3878 } 3879 3880 if (down == finger_info->down) { 3881 event_type = SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION; 3882 } else if (down) { 3883 event_type = SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN; 3884 } else { 3885 event_type = SDL_EVENT_GAMEPAD_TOUCHPAD_UP; 3886 } 3887 3888 // We ignore events if we don't have keyboard focus, except for touch release 3889 if (SDL_PrivateJoystickShouldIgnoreEvent()) { 3890 if (event_type != SDL_EVENT_GAMEPAD_TOUCHPAD_UP) { 3891 return; 3892 } 3893 } 3894 3895 // Update internal joystick state 3896 SDL_assert(timestamp != 0); 3897 finger_info->down = down; 3898 finger_info->x = x; 3899 finger_info->y = y; 3900 finger_info->pressure = pressure; 3901 joystick->update_complete = timestamp; 3902 3903 // Post the event, if desired 3904 if (SDL_EventEnabled(event_type)) { 3905 SDL_Event event; 3906 event.type = event_type; 3907 event.common.timestamp = timestamp; 3908 event.gtouchpad.which = joystick->instance_id; 3909 event.gtouchpad.touchpad = touchpad; 3910 event.gtouchpad.finger = finger; 3911 event.gtouchpad.x = x; 3912 event.gtouchpad.y = y; 3913 event.gtouchpad.pressure = pressure; 3914 SDL_PushEvent(&event); 3915 } 3916} 3917 3918void SDL_SendJoystickSensor(Uint64 timestamp, SDL_Joystick *joystick, SDL_SensorType type, Uint64 sensor_timestamp, const float *data, int num_values) 3919{ 3920 SDL_AssertJoysticksLocked(); 3921 3922 // We ignore events if we don't have keyboard focus 3923 if (SDL_PrivateJoystickShouldIgnoreEvent()) { 3924 return; 3925 } 3926 3927 for (int i = 0; i < joystick->nsensors; ++i) { 3928 SDL_JoystickSensorInfo *sensor = &joystick->sensors[i]; 3929 3930 if (sensor->type == type) { 3931 if (sensor->enabled) { 3932 num_values = SDL_min(num_values, SDL_arraysize(sensor->data)); 3933 3934 // Update internal sensor state 3935 SDL_memcpy(sensor->data, data, num_values * sizeof(*data)); 3936 joystick->update_complete = timestamp; 3937 3938 // Post the event, if desired 3939 if (SDL_EventEnabled(SDL_EVENT_GAMEPAD_SENSOR_UPDATE)) { 3940 SDL_Event event; 3941 event.type = SDL_EVENT_GAMEPAD_SENSOR_UPDATE; 3942 event.common.timestamp = timestamp; 3943 event.gsensor.which = joystick->instance_id; 3944 event.gsensor.sensor = type; 3945 num_values = SDL_min(num_values, 3946 SDL_arraysize(event.gsensor.data)); 3947 SDL_memset(event.gsensor.data, 0, 3948 sizeof(event.gsensor.data)); 3949 SDL_memcpy(event.gsensor.data, data, 3950 num_values * sizeof(*data)); 3951 event.gsensor.sensor_timestamp = sensor_timestamp; 3952 SDL_PushEvent(&event); 3953 } 3954 } 3955 break; 3956 } 3957 } 3958} 3959 3960static void SDL_LoadVIDPIDListFromHint(const char *hint, int *num_entries, int *max_entries, Uint32 **entries) 3961{ 3962 Uint32 entry; 3963 char *spot; 3964 char *file = NULL; 3965 3966 if (hint && *hint == '@') { 3967 spot = file = (char *)SDL_LoadFile(hint + 1, NULL); 3968 } else { 3969 spot = (char *)hint; 3970 } 3971 3972 if (!spot) { 3973 return; 3974 } 3975 3976 while ((spot = SDL_strstr(spot, "0x")) != NULL) { 3977 entry = (Uint16)SDL_strtol(spot, &spot, 0); 3978 entry <<= 16; 3979 spot = SDL_strstr(spot, "0x"); 3980 if (!spot) { 3981 break; 3982 } 3983 entry |= (Uint16)SDL_strtol(spot, &spot, 0); 3984 3985 if (*num_entries == *max_entries) { 3986 int new_max_entries = *max_entries + 16; 3987 Uint32 *new_entries = (Uint32 *)SDL_realloc(*entries, new_max_entries * sizeof(**entries)); 3988 if (!new_entries) { 3989 // Out of memory, go with what we have already 3990 break; 3991 } 3992 *entries = new_entries; 3993 *max_entries = new_max_entries; 3994 } 3995 (*entries)[(*num_entries)++] = entry; 3996 } 3997 3998 SDL_free(file); 3999} 4000 4001void SDL_LoadVIDPIDListFromHints(SDL_vidpid_list *list, const char *included_list, const char *excluded_list) 4002{ 4003 // Empty the list 4004 list->num_included_entries = 0; 4005 list->num_excluded_entries = 0; 4006 4007 // Add the initial entries 4008 if (list->num_initial_entries > 0) { 4009 if (list->num_included_entries < list->num_initial_entries) { 4010 Uint32 *entries = (Uint32 *)SDL_malloc(list->num_initial_entries * sizeof(*entries)); 4011 if (entries) { 4012 SDL_memcpy(entries, list->initial_entries, list->num_initial_entries * sizeof(*entries)); 4013 list->included_entries = entries; 4014 list->num_included_entries = list->num_initial_entries; 4015 list->max_included_entries = list->num_initial_entries; 4016 } 4017 } 4018 } 4019 4020 // Add the included entries from the hint 4021 SDL_LoadVIDPIDListFromHint(included_list, &list->num_included_entries, &list->max_included_entries, &list->included_entries); 4022 4023 // Add the excluded entries from the hint 4024 SDL_LoadVIDPIDListFromHint(excluded_list, &list->num_excluded_entries, &list->max_excluded_entries, &list->excluded_entries); 4025} 4026 4027static void SDLCALL SDL_VIDPIDIncludedHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint) 4028{ 4029 SDL_vidpid_list *list = (SDL_vidpid_list *)userdata; 4030 const char *included_list = hint; 4031 const char *excluded_list = NULL; 4032 4033 if (!list->initialized) { 4034 return; 4035 } 4036 4037 if (list->excluded_hint_name) { 4038 excluded_list = SDL_GetHint(list->excluded_hint_name); 4039 } 4040 SDL_LoadVIDPIDListFromHints(list, included_list, excluded_list); 4041} 4042 4043static void SDLCALL SDL_VIDPIDExcludedHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint) 4044{ 4045 SDL_vidpid_list *list = (SDL_vidpid_list *)userdata; 4046 const char *included_list = NULL; 4047 const char *excluded_list = hint; 4048 4049 if (!list->initialized) { 4050 return; 4051 } 4052 4053 if (list->included_hint_name) { 4054 included_list = SDL_GetHint(list->included_hint_name); 4055 } 4056 SDL_LoadVIDPIDListFromHints(list, included_list, excluded_list); 4057} 4058 4059void SDL_LoadVIDPIDList(SDL_vidpid_list *list) 4060{ 4061 const char *included_list = NULL; 4062 const char *excluded_list = NULL; 4063 4064 if (list->included_hint_name) { 4065 SDL_AddHintCallback(list->included_hint_name, SDL_VIDPIDIncludedHintChanged, list); 4066 } 4067 4068 if (list->excluded_hint_name) { 4069 SDL_AddHintCallback(list->excluded_hint_name, SDL_VIDPIDExcludedHintChanged, list); 4070 } 4071 4072 list->initialized = true; 4073 4074 if (list->included_hint_name) { 4075 included_list = SDL_GetHint(list->included_hint_name); 4076 if (!included_list) { 4077 included_list = SDL_getenv_unsafe(list->included_hint_name); 4078 } 4079 } 4080 if (list->excluded_hint_name) { 4081 excluded_list = SDL_GetHint(list->excluded_hint_name); 4082 if (!excluded_list) { 4083 excluded_list = SDL_getenv_unsafe(list->excluded_hint_name); 4084 } 4085 } 4086 SDL_LoadVIDPIDListFromHints(list, included_list, excluded_list); 4087} 4088 4089bool SDL_VIDPIDInList(Uint16 vendor_id, Uint16 product_id, const SDL_vidpid_list *list) 4090{ 4091 int i; 4092 Uint32 vidpid = MAKE_VIDPID(vendor_id, product_id); 4093 4094 for (i = 0; i < list->num_excluded_entries; ++i) { 4095 if (vidpid == list->excluded_entries[i]) { 4096 return false; 4097 } 4098 } 4099 for (i = 0; i < list->num_included_entries; ++i) { 4100 if (vidpid == list->included_entries[i]) { 4101 return true; 4102 } 4103 } 4104 return false; 4105} 4106 4107void SDL_FreeVIDPIDList(SDL_vidpid_list *list) 4108{ 4109 if (list->included_hint_name) { 4110 SDL_RemoveHintCallback(list->included_hint_name, SDL_VIDPIDIncludedHintChanged, list); 4111 } 4112 4113 if (list->excluded_hint_name) { 4114 SDL_RemoveHintCallback(list->excluded_hint_name, SDL_VIDPIDExcludedHintChanged, list); 4115 } 4116 4117 if (list->included_entries) { 4118 SDL_free(list->included_entries); 4119 list->included_entries = NULL; 4120 list->num_included_entries = 0; 4121 list->max_included_entries = 0; 4122 } 4123 4124 if (list->excluded_entries) { 4125 SDL_free(list->excluded_entries); 4126 list->excluded_entries = NULL; 4127 list->num_excluded_entries = 0; 4128 list->max_excluded_entries = 0; 4129 } 4130 4131 list->initialized = false; 4132} 4133
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.