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