Atlas - SDL_hidapijoystick.c

Home / ext / SDL / src / joystick / hidapi Lines: 3 | Size: 56697 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 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#ifdef SDL_JOYSTICK_HIDAPI 24 25#include "../SDL_sysjoystick.h" 26#include "SDL_hidapijoystick_c.h" 27#include "SDL_hidapi_rumble.h" 28#include "../../SDL_hints_c.h" 29 30#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK) 31#include "../windows/SDL_rawinputjoystick_c.h" 32#endif 33 34 35struct joystick_hwdata 36{ 37 SDL_HIDAPI_Device *device; 38}; 39 40static SDL_HIDAPI_DeviceDriver *SDL_HIDAPI_drivers[] = { 41#ifdef SDL_JOYSTICK_HIDAPI_GAMECUBE 42 &SDL_HIDAPI_DriverGameCube, 43#endif 44#ifdef SDL_JOYSTICK_HIDAPI_LUNA 45 &SDL_HIDAPI_DriverLuna, 46#endif 47#ifdef SDL_JOYSTICK_HIDAPI_SHIELD 48 &SDL_HIDAPI_DriverShield, 49#endif 50#ifdef SDL_JOYSTICK_HIDAPI_PS3 51 &SDL_HIDAPI_DriverPS3, 52 &SDL_HIDAPI_DriverPS3ThirdParty, 53 &SDL_HIDAPI_DriverPS3SonySixaxis, 54#endif 55#ifdef SDL_JOYSTICK_HIDAPI_PS4 56 &SDL_HIDAPI_DriverPS4, 57#endif 58#ifdef SDL_JOYSTICK_HIDAPI_PS5 59 &SDL_HIDAPI_DriverPS5, 60#endif 61#ifdef SDL_JOYSTICK_HIDAPI_STADIA 62 &SDL_HIDAPI_DriverStadia, 63#endif 64#ifdef SDL_JOYSTICK_HIDAPI_STEAM 65 &SDL_HIDAPI_DriverSteam, 66#endif 67#ifdef SDL_JOYSTICK_HIDAPI_STEAM_HORI 68 &SDL_HIDAPI_DriverSteamHori, 69#endif 70#ifdef SDL_JOYSTICK_HIDAPI_STEAMDECK 71 &SDL_HIDAPI_DriverSteamDeck, 72#endif 73#ifdef SDL_JOYSTICK_HIDAPI_STEAMDECK 74 &SDL_HIDAPI_DriverSteamTriton, 75#endif 76#ifdef SDL_JOYSTICK_HIDAPI_SWITCH 77 &SDL_HIDAPI_DriverNintendoClassic, 78 &SDL_HIDAPI_DriverJoyCons, 79 &SDL_HIDAPI_DriverSwitch, 80#endif 81#ifdef SDL_JOYSTICK_HIDAPI_SWITCH2 82 &SDL_HIDAPI_DriverSwitch2, 83#endif 84#ifdef SDL_JOYSTICK_HIDAPI_WII 85 &SDL_HIDAPI_DriverWii, 86#endif 87#ifdef SDL_JOYSTICK_HIDAPI_XBOX360 88 &SDL_HIDAPI_DriverXbox360, 89 &SDL_HIDAPI_DriverXbox360W, 90#endif 91#ifdef SDL_JOYSTICK_HIDAPI_GIP 92 &SDL_HIDAPI_DriverGIP, 93#endif 94#ifdef SDL_JOYSTICK_HIDAPI_XBOXONE 95 &SDL_HIDAPI_DriverXboxOne, 96#endif 97#ifdef SDL_JOYSTICK_HIDAPI_LG4FF 98 &SDL_HIDAPI_DriverLg4ff, 99#endif 100#ifdef SDL_JOYSTICK_HIDAPI_8BITDO 101 &SDL_HIDAPI_Driver8BitDo, 102#endif 103#ifdef SDL_JOYSTICK_HIDAPI_FLYDIGI 104 &SDL_HIDAPI_DriverFlydigi, 105#endif 106#ifdef SDL_JOYSTICK_HIDAPI_SINPUT 107 &SDL_HIDAPI_DriverSInput, 108#endif 109#ifdef SDL_JOYSTICK_HIDAPI_ZUIKI 110 &SDL_HIDAPI_DriverZUIKI, 111#endif 112}; 113static int SDL_HIDAPI_numdrivers = 0; 114static SDL_AtomicInt SDL_HIDAPI_updating_devices; 115static bool SDL_HIDAPI_hints_changed = false; 116static Uint32 SDL_HIDAPI_change_count = 0; 117static SDL_HIDAPI_Device *SDL_HIDAPI_devices SDL_GUARDED_BY(SDL_joystick_lock); 118static int SDL_HIDAPI_numjoysticks = 0; 119static bool SDL_HIDAPI_combine_joycons = true; 120static bool initialized = false; 121static bool shutting_down = false; 122 123static char *HIDAPI_ConvertString(const wchar_t *wide_string) 124{ 125 char *string = NULL; 126 127 if (wide_string) { 128 string = SDL_iconv_string("UTF-8", "WCHAR_T", (char *)wide_string, (SDL_wcslen(wide_string) + 1) * sizeof(wchar_t)); 129 if (!string) { 130 switch (sizeof(wchar_t)) { 131 case 2: 132 string = SDL_iconv_string("UTF-8", "UCS-2-INTERNAL", (char *)wide_string, (SDL_wcslen(wide_string) + 1) * sizeof(wchar_t)); 133 break; 134 case 4: 135 string = SDL_iconv_string("UTF-8", "UCS-4-INTERNAL", (char *)wide_string, (SDL_wcslen(wide_string) + 1) * sizeof(wchar_t)); 136 break; 137 } 138 } 139 } 140 return string; 141} 142 143void HIDAPI_DumpPacket(const char *prefix, const Uint8 *data, int size) 144{ 145 int i; 146 char *buffer; 147 size_t length = SDL_strlen(prefix) + 11 * (size / 8) + (5 * size * 2) + 1 + 1; 148 int start = 0, amount = size; 149 size_t current_len; 150 151 buffer = (char *)SDL_malloc(length); 152 current_len = SDL_snprintf(buffer, length, prefix, size); 153 for (i = start; i < start + amount; ++i) { 154 if ((i % 8) == 0) { 155 current_len += SDL_snprintf(&buffer[current_len], length - current_len, "\n%.2d: ", i); 156 } 157 current_len += SDL_snprintf(&buffer[current_len], length - current_len, " 0x%.2x", data[i]); 158 } 159 SDL_strlcat(buffer, "\n", length); 160 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "%s", buffer); 161 SDL_free(buffer); 162} 163 164bool HIDAPI_SupportsPlaystationDetection(Uint16 vendor, Uint16 product) 165{ 166 /* If we already know the controller is a different type, don't try to detect it. 167 * This fixes a hang with the HORIPAD for Nintendo Switch (0x0f0d/0x00c1) 168 */ 169 if (SDL_GetGamepadTypeFromVIDPID(vendor, product, NULL, false) != SDL_GAMEPAD_TYPE_STANDARD) { 170 return false; 171 } 172 173 switch (vendor) { 174 case USB_VENDOR_DRAGONRISE: 175 return true; 176 case USB_VENDOR_HORI: 177 return true; 178 case USB_VENDOR_LOGITECH: 179 /* Most Logitech devices are not PlayStation controllers, and some of them 180 * lock up or reset when we send them the Sony third-party query feature 181 * report, so don't include that vendor here. Instead add devices as 182 * appropriate to controller_list.h 183 */ 184 return false; 185 case USB_VENDOR_MADCATZ: 186 if (product == USB_PRODUCT_MADCATZ_SAITEK_SIDE_PANEL_CONTROL_DECK) { 187 // This is not a Playstation compatible device 188 return false; 189 } 190 return true; 191 case USB_VENDOR_MAYFLASH: 192 return true; 193 case USB_VENDOR_NACON: 194 case USB_VENDOR_NACON_ALT: 195 return true; 196 case USB_VENDOR_PDP: 197 return true; 198 case USB_VENDOR_POWERA: 199 return true; 200 case USB_VENDOR_POWERA_ALT: 201 return true; 202 case USB_VENDOR_QANBA: 203 return true; 204 case USB_VENDOR_RAZER: 205 /* Most Razer devices are not PlayStation controllers, and some of them 206 * lock up or reset when we send them the Sony third-party query feature 207 * report, so don't include that vendor here. Instead add devices as 208 * appropriate to controller_list.h 209 * 210 * Reference: https://github.com/libsdl-org/SDL/issues/6733 211 * https://github.com/libsdl-org/SDL/issues/6799 212 */ 213 return false; 214 case USB_VENDOR_SHANWAN: 215 return true; 216 case USB_VENDOR_SHANWAN_ALT: 217 return true; 218 case USB_VENDOR_THRUSTMASTER: 219 /* Most of these are wheels, don't have the full set of effects, and 220 * at least in the case of the T248 and T300 RS, the hid-tmff2 driver 221 * puts them in a non-standard report mode and they can't be read. 222 * 223 * If these should use the HIDAPI driver, add them to controller_list.h 224 */ 225 return false; 226 case USB_VENDOR_ZEROPLUS: 227 return true; 228 case 0x7545 /* SZ-MYPOWER */: 229 return true; 230 default: 231 return false; 232 } 233} 234 235float HIDAPI_RemapVal(float val, float val_min, float val_max, float output_min, float output_max) 236{ 237 return output_min + (output_max - output_min) * (val - val_min) / (val_max - val_min); 238} 239 240static void HIDAPI_UpdateDeviceList(void); 241static void HIDAPI_JoystickClose(SDL_Joystick *joystick); 242 243static SDL_GamepadType SDL_GetJoystickGameControllerProtocol(const char *name, Uint16 vendor, Uint16 product, int interface_number, int interface_class, int interface_subclass, int interface_protocol) 244{ 245 static const int LIBUSB_CLASS_VENDOR_SPEC = 0xFF; 246 static const int XB360_IFACE_SUBCLASS = 93; 247 static const int XB360_IFACE_PROTOCOL = 1; // Wired 248 static const int XB360W_IFACE_PROTOCOL = 129; // Wireless 249 static const int XBONE_IFACE_SUBCLASS = 71; 250 static const int XBONE_IFACE_PROTOCOL = 208; 251 252 SDL_GamepadType type = SDL_GAMEPAD_TYPE_STANDARD; 253 254 // This code should match the checks in libusb/hid.c and HIDDeviceManager.java 255 if (interface_class == LIBUSB_CLASS_VENDOR_SPEC && 256 interface_subclass == XB360_IFACE_SUBCLASS && 257 (interface_protocol == XB360_IFACE_PROTOCOL || 258 interface_protocol == XB360W_IFACE_PROTOCOL)) { 259 260 static const int SUPPORTED_VENDORS[] = { 261 0x0079, // GPD Win 2 262 0x044f, // Thrustmaster 263 0x045e, // Microsoft 264 0x046d, // Logitech 265 0x056e, // Elecom 266 0x06a3, // Saitek 267 0x0738, // Mad Catz 268 0x07ff, // Mad Catz 269 0x0e6f, // PDP 270 0x0f0d, // Hori 271 0x1038, // SteelSeries 272 0x11c9, // Nacon 273 0x12ab, // Unknown 274 0x1430, // RedOctane 275 0x146b, // BigBen 276 0x1532, // Razer 277 0x15e4, // Numark 278 0x162e, // Joytech 279 0x1689, // Razer Onza 280 0x1949, // Lab126, Inc. 281 0x1bad, // Harmonix 282 0x20d6, // PowerA 283 0x24c6, // PowerA 284 0x2c22, // Qanba 285 0x2dc8, // 8BitDo 286 0x9886, // ASTRO Gaming 287 }; 288 289 int i; 290 for (i = 0; i < SDL_arraysize(SUPPORTED_VENDORS); ++i) { 291 if (vendor == SUPPORTED_VENDORS[i]) { 292 type = SDL_GAMEPAD_TYPE_XBOX360; 293 break; 294 } 295 } 296 } 297 298 if (interface_number == 0 && 299 interface_class == LIBUSB_CLASS_VENDOR_SPEC && 300 interface_subclass == XBONE_IFACE_SUBCLASS && 301 interface_protocol == XBONE_IFACE_PROTOCOL) { 302 303 static const int SUPPORTED_VENDORS[] = { 304 0x03f0, // HP 305 0x044f, // Thrustmaster 306 0x045e, // Microsoft 307 0x0738, // Mad Catz 308 0x0b05, // ASUS 309 0x0e6f, // PDP 310 0x0f0d, // Hori 311 0x10f5, // Turtle Beach 312 0x1532, // Razer 313 0x20d6, // PowerA 314 0x24c6, // PowerA 315 0x294b, // Snakebyte 316 0x2dc8, // 8BitDo 317 0x2e24, // Hyperkin 318 0x2e95, // SCUF 319 0x3285, // Nacon 320 0x3537, // GameSir 321 0x366c, // ByoWave 322 }; 323 324 int i; 325 for (i = 0; i < SDL_arraysize(SUPPORTED_VENDORS); ++i) { 326 if (vendor == SUPPORTED_VENDORS[i]) { 327 type = SDL_GAMEPAD_TYPE_XBOXONE; 328 break; 329 } 330 } 331 } 332 333 if (type == SDL_GAMEPAD_TYPE_STANDARD) { 334 type = SDL_GetGamepadTypeFromVIDPID(vendor, product, name, false); 335 } 336 return type; 337} 338 339static bool HIDAPI_IsDeviceSupported(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name) 340{ 341 int i; 342 SDL_GamepadType type = SDL_GetJoystickGameControllerProtocol(name, vendor_id, product_id, -1, 0, 0, 0); 343 344 for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) { 345 SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i]; 346 if (driver->enabled && driver->IsSupportedDevice(NULL, name, type, vendor_id, product_id, version, -1, 0, 0, 0)) { 347 return true; 348 } 349 } 350 return false; 351} 352 353static SDL_HIDAPI_DeviceDriver *HIDAPI_GetDeviceDriver(SDL_HIDAPI_Device *device) 354{ 355 const Uint16 USAGE_PAGE_GENERIC_DESKTOP = 0x0001; 356 const Uint16 USAGE_JOYSTICK = 0x0004; 357 const Uint16 USAGE_GAMEPAD = 0x0005; 358 const Uint16 USAGE_MULTIAXISCONTROLLER = 0x0008; 359 int i; 360 361 if (device->num_children > 0) { 362 return &SDL_HIDAPI_DriverCombined; 363 } 364 365 if (SDL_ShouldIgnoreJoystick(device->vendor_id, device->product_id, device->version, device->name)) { 366 return NULL; 367 } 368 369 if (device->vendor_id != USB_VENDOR_VALVE && device->vendor_id != USB_VENDOR_FLYDIGI_V1 && device->vendor_id != USB_VENDOR_FLYDIGI_V2) { 370 if (device->usage_page && device->usage_page != USAGE_PAGE_GENERIC_DESKTOP) { 371 return NULL; 372 } 373 if (device->usage && device->usage != USAGE_JOYSTICK && device->usage != USAGE_GAMEPAD && device->usage != USAGE_MULTIAXISCONTROLLER) { 374 return NULL; 375 } 376 } 377 378 for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) { 379 SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i]; 380 if (driver->enabled && driver->IsSupportedDevice(device, device->name, device->type, device->vendor_id, device->product_id, device->version, device->interface_number, device->interface_class, device->interface_subclass, device->interface_protocol)) { 381 return driver; 382 } 383 } 384 return NULL; 385} 386 387static SDL_HIDAPI_Device *HIDAPI_GetDeviceByIndex(int device_index, SDL_JoystickID *pJoystickID) 388{ 389 SDL_HIDAPI_Device *device; 390 391 SDL_AssertJoysticksLocked(); 392 393 for (device = SDL_HIDAPI_devices; device; device = device->next) { 394 if (device->parent || device->broken) { 395 continue; 396 } 397 if (device->driver) { 398 if (device_index < device->num_joysticks) { 399 if (pJoystickID) { 400 *pJoystickID = device->joysticks[device_index]; 401 } 402 return device; 403 } 404 device_index -= device->num_joysticks; 405 } 406 } 407 return NULL; 408} 409 410static SDL_HIDAPI_Device *HIDAPI_GetJoystickByInfo(const char *path, Uint16 vendor_id, Uint16 product_id) 411{ 412 SDL_HIDAPI_Device *device; 413 414 SDL_AssertJoysticksLocked(); 415 416 for (device = SDL_HIDAPI_devices; device; device = device->next) { 417 if (device->vendor_id == vendor_id && device->product_id == product_id && 418 SDL_strcmp(device->path, path) == 0) { 419 break; 420 } 421 } 422 return device; 423} 424 425static void HIDAPI_CleanupDeviceDriver(SDL_HIDAPI_Device *device) 426{ 427 if (!device->driver) { 428 return; // Already cleaned up 429 } 430 431 // Disconnect any joysticks 432 while (device->num_joysticks && device->joysticks) { 433 HIDAPI_JoystickDisconnected(device, device->joysticks[0]); 434 } 435 436 device->driver->FreeDevice(device); 437 device->driver = NULL; 438 439 SDL_LockMutex(device->dev_lock); 440 { 441 if (device->dev) { 442 SDL_hid_close(device->dev); 443 device->dev = NULL; 444 } 445 446 if (device->context) { 447 SDL_free(device->context); 448 device->context = NULL; 449 } 450 } 451 SDL_UnlockMutex(device->dev_lock); 452} 453 454static void HIDAPI_SetupDeviceDriver(SDL_HIDAPI_Device *device, bool *removed) SDL_NO_THREAD_SAFETY_ANALYSIS // We unlock the joystick lock to be able to open the HID device on Android 455{ 456 *removed = false; 457 458 if (device->driver) { 459 bool enabled; 460 461 if (device->vendor_id == USB_VENDOR_NINTENDO && 462 (device->product_id == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_PAIR || 463 device->product_id == USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_PAIR)) { 464 enabled = SDL_HIDAPI_combine_joycons; 465 } else { 466 enabled = device->driver->enabled; 467 } 468 if (device->children) { 469 int i; 470 471 for (i = 0; i < device->num_children; ++i) { 472 SDL_HIDAPI_Device *child = device->children[i]; 473 if (!child->driver || !child->driver->enabled) { 474 enabled = false; 475 break; 476 } 477 } 478 } 479 if (!enabled) { 480 HIDAPI_CleanupDeviceDriver(device); 481 } 482 return; // Already setup 483 } 484 485 if (HIDAPI_GetDeviceDriver(device)) { 486 // We might have a device driver for this device, try opening it and see 487 if (device->num_children == 0) { 488 SDL_hid_device *dev; 489 490 // Wait a little bit for the device to initialize 491 SDL_Delay(10); 492 493 dev = SDL_hid_open_path(device->path); 494 495 if (dev == NULL) { 496 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, 497 "HIDAPI_SetupDeviceDriver() couldn't open %s: %s", 498 device->path, SDL_GetError()); 499 return; 500 } 501 SDL_hid_set_nonblocking(dev, 1); 502 503 device->dev = dev; 504 } 505 506 device->driver = HIDAPI_GetDeviceDriver(device); 507 508 // Initialize the device, which may cause a connected event 509 if (device->driver && !device->driver->InitDevice(device)) { 510 HIDAPI_CleanupDeviceDriver(device); 511 } 512 513 if (!device->driver && device->dev) { 514 // No driver claimed this device, go ahead and close it 515 SDL_hid_close(device->dev); 516 device->dev = NULL; 517 } 518 } 519} 520 521static void SDL_HIDAPI_UpdateDrivers(void) 522{ 523 int i; 524 SDL_HIDAPI_Device *device; 525 bool removed; 526 527 SDL_AssertJoysticksLocked(); 528 529 SDL_HIDAPI_numdrivers = 0; 530 for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) { 531 SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i]; 532 driver->enabled = driver->IsEnabled(); 533 if (driver->enabled && driver != &SDL_HIDAPI_DriverCombined) { 534 ++SDL_HIDAPI_numdrivers; 535 } 536 } 537 538 removed = false; 539 do { 540 for (device = SDL_HIDAPI_devices; device; device = device->next) { 541 HIDAPI_SetupDeviceDriver(device, &removed); 542 if (removed) { 543 break; 544 } 545 } 546 } while (removed); 547} 548 549static void SDLCALL SDL_HIDAPIDriverHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint) 550{ 551 if (SDL_strcmp(name, SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS) == 0) { 552 SDL_HIDAPI_combine_joycons = SDL_GetStringBoolean(hint, true); 553 } 554 SDL_HIDAPI_hints_changed = true; 555 SDL_HIDAPI_change_count = 0; 556} 557 558static bool HIDAPI_JoystickInit(void) 559{ 560 int i; 561 562 if (initialized) { 563 return true; 564 } 565 566 if (SDL_hid_init() < 0) { 567 return SDL_SetError("Couldn't initialize hidapi"); 568 } 569 570 for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) { 571 SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i]; 572 driver->RegisterHints(SDL_HIDAPIDriverHintChanged, driver); 573 } 574 SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS, 575 SDL_HIDAPIDriverHintChanged, NULL); 576 SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI, 577 SDL_HIDAPIDriverHintChanged, NULL); 578 579 SDL_HIDAPI_change_count = SDL_hid_device_change_count(); 580 HIDAPI_UpdateDeviceList(); 581 HIDAPI_UpdateDevices(); 582 583 initialized = true; 584 585 return true; 586} 587 588static bool HIDAPI_AddJoystickInstanceToDevice(SDL_HIDAPI_Device *device, SDL_JoystickID joystickID) 589{ 590 SDL_JoystickID *joysticks = (SDL_JoystickID *)SDL_realloc(device->joysticks, (device->num_joysticks + 1) * sizeof(*device->joysticks)); 591 if (!joysticks) { 592 return false; 593 } 594 595 device->joysticks = joysticks; 596 device->joysticks[device->num_joysticks++] = joystickID; 597 return true; 598} 599 600static bool HIDAPI_DelJoystickInstanceFromDevice(SDL_HIDAPI_Device *device, SDL_JoystickID joystickID) 601{ 602 int i, size; 603 604 for (i = 0; i < device->num_joysticks; ++i) { 605 if (device->joysticks[i] == joystickID) { 606 size = (device->num_joysticks - i - 1) * sizeof(SDL_JoystickID); 607 SDL_memmove(&device->joysticks[i], &device->joysticks[i + 1], size); 608 --device->num_joysticks; 609 if (device->num_joysticks == 0) { 610 SDL_free(device->joysticks); 611 device->joysticks = NULL; 612 } 613 return true; 614 } 615 } 616 return false; 617} 618 619static bool HIDAPI_JoystickInstanceIsUnique(SDL_HIDAPI_Device *device, SDL_JoystickID joystickID) 620{ 621 if (device->parent && device->num_joysticks == 1 && device->parent->num_joysticks == 1 && 622 device->joysticks[0] == device->parent->joysticks[0]) { 623 return false; 624 } 625 return true; 626} 627 628void HIDAPI_SetDeviceName(SDL_HIDAPI_Device *device, const char *name) 629{ 630 if (name && *name && SDL_strcmp(name, device->name) != 0) { 631 SDL_free(device->name); 632 device->name = SDL_strdup(name); 633 SDL_SetJoystickGUIDCRC(&device->guid, SDL_crc16(0, name, SDL_strlen(name))); 634 } 635} 636 637void HIDAPI_SetDeviceProduct(SDL_HIDAPI_Device *device, Uint16 vendor_id, Uint16 product_id) 638{ 639 // Don't set the device product ID directly, or we'll constantly re-enumerate this device 640 device->guid = SDL_CreateJoystickGUID(device->guid.data[0], vendor_id, product_id, device->version, device->manufacturer_string, device->product_string, 'h', 0); 641} 642 643static void HIDAPI_UpdateJoystickSerial(SDL_HIDAPI_Device *device) 644{ 645 int i; 646 647 SDL_AssertJoysticksLocked(); 648 649 for (i = 0; i < device->num_joysticks; ++i) { 650 SDL_Joystick *joystick = SDL_GetJoystickFromID(device->joysticks[i]); 651 if (joystick && device->serial) { 652 SDL_free(joystick->serial); 653 joystick->serial = SDL_strdup(device->serial); 654 } 655 } 656} 657 658static bool HIDAPI_SerialIsEmpty(SDL_HIDAPI_Device *device) 659{ 660 bool all_zeroes = true; 661 662 if (device->serial) { 663 const char *serial = device->serial; 664 for (serial = device->serial; *serial; ++serial) { 665 if (*serial != '0') { 666 all_zeroes = false; 667 break; 668 } 669 } 670 } 671 return all_zeroes; 672} 673 674void HIDAPI_SetDeviceSerial(SDL_HIDAPI_Device *device, const char *serial) 675{ 676 if (serial && *serial && (!device->serial || SDL_strcmp(serial, device->serial) != 0)) { 677 SDL_free(device->serial); 678 device->serial = SDL_strdup(serial); 679 HIDAPI_UpdateJoystickSerial(device); 680 } 681} 682 683static int wcstrcmp(const wchar_t *str1, const char *str2) 684{ 685 int result; 686 687 while (1) { 688 result = (*str1 - *str2); 689 if (result != 0 || *str1 == 0) { 690 break; 691 } 692 ++str1; 693 ++str2; 694 } 695 return result; 696} 697 698static void HIDAPI_SetDeviceSerialW(SDL_HIDAPI_Device *device, const wchar_t *serial) 699{ 700 if (serial && *serial && (!device->serial || wcstrcmp(serial, device->serial) != 0)) { 701 SDL_free(device->serial); 702 device->serial = HIDAPI_ConvertString(serial); 703 HIDAPI_UpdateJoystickSerial(device); 704 } 705} 706 707bool HIDAPI_HasConnectedUSBDevice(const char *serial) 708{ 709 SDL_HIDAPI_Device *device; 710 711 SDL_AssertJoysticksLocked(); 712 713 if (!serial) { 714 return false; 715 } 716 717 for (device = SDL_HIDAPI_devices; device; device = device->next) { 718 if (!device->driver || device->broken) { 719 continue; 720 } 721 722 if (device->is_bluetooth) { 723 continue; 724 } 725 726 if (device->serial && SDL_strcmp(serial, device->serial) == 0) { 727 return true; 728 } 729 } 730 return false; 731} 732 733void HIDAPI_DisconnectBluetoothDevice(const char *serial) 734{ 735 SDL_HIDAPI_Device *device; 736 737 SDL_AssertJoysticksLocked(); 738 739 if (!serial) { 740 return; 741 } 742 743 for (device = SDL_HIDAPI_devices; device; device = device->next) { 744 if (!device->driver || device->broken) { 745 continue; 746 } 747 748 if (!device->is_bluetooth) { 749 continue; 750 } 751 752 if (device->serial && SDL_strcmp(serial, device->serial) == 0) { 753 while (device->num_joysticks && device->joysticks) { 754 HIDAPI_JoystickDisconnected(device, device->joysticks[0]); 755 } 756 } 757 } 758} 759 760bool HIDAPI_JoystickConnected(SDL_HIDAPI_Device *device, SDL_JoystickID *pJoystickID) 761{ 762 int i, j; 763 SDL_JoystickID joystickID; 764 765 SDL_AssertJoysticksLocked(); 766 767 for (i = 0; i < device->num_children; ++i) { 768 SDL_HIDAPI_Device *child = device->children[i]; 769 for (j = child->num_joysticks; j--;) { 770 HIDAPI_JoystickDisconnected(child, child->joysticks[j]); 771 } 772 } 773 774 joystickID = SDL_GetNextObjectID(); 775 HIDAPI_AddJoystickInstanceToDevice(device, joystickID); 776 777 for (i = 0; i < device->num_children; ++i) { 778 SDL_HIDAPI_Device *child = device->children[i]; 779 HIDAPI_AddJoystickInstanceToDevice(child, joystickID); 780 } 781 782 ++SDL_HIDAPI_numjoysticks; 783 784 if (pJoystickID) { 785 *pJoystickID = joystickID; 786 } 787 788 SDL_PrivateJoystickAdded(joystickID); 789 790 return true; 791} 792 793void HIDAPI_JoystickDisconnected(SDL_HIDAPI_Device *device, SDL_JoystickID joystickID) 794{ 795 int i, j; 796 797 SDL_LockJoysticks(); 798 799 if (!HIDAPI_JoystickInstanceIsUnique(device, joystickID)) { 800 // Disconnecting a child always disconnects the parent 801 device = device->parent; 802 } 803 804 for (i = 0; i < device->num_joysticks; ++i) { 805 if (device->joysticks[i] == joystickID) { 806 SDL_Joystick *joystick = SDL_GetJoystickFromID(joystickID); 807 if (joystick) { 808 HIDAPI_JoystickClose(joystick); 809 } 810 811 HIDAPI_DelJoystickInstanceFromDevice(device, joystickID); 812 813 for (j = 0; j < device->num_children; ++j) { 814 SDL_HIDAPI_Device *child = device->children[j]; 815 HIDAPI_DelJoystickInstanceFromDevice(child, joystickID); 816 } 817 818 --SDL_HIDAPI_numjoysticks; 819 820 if (!shutting_down) { 821 SDL_PrivateJoystickRemoved(joystickID); 822 } 823 } 824 } 825 826 // Rescan the device list in case device state has changed 827 SDL_HIDAPI_change_count = 0; 828 829 SDL_UnlockJoysticks(); 830} 831 832static void HIDAPI_UpdateJoystickProperties(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 833{ 834 SDL_PropertiesID props = SDL_GetJoystickProperties(joystick); 835 Uint32 caps = device->driver->GetJoystickCapabilities(device, joystick); 836 837 if (caps & SDL_JOYSTICK_CAP_MONO_LED) { 838 SDL_SetBooleanProperty(props, SDL_PROP_JOYSTICK_CAP_MONO_LED_BOOLEAN, true); 839 } else { 840 SDL_SetBooleanProperty(props, SDL_PROP_JOYSTICK_CAP_MONO_LED_BOOLEAN, false); 841 } 842 if (caps & SDL_JOYSTICK_CAP_RGB_LED) { 843 SDL_SetBooleanProperty(props, SDL_PROP_JOYSTICK_CAP_RGB_LED_BOOLEAN, true); 844 } else { 845 SDL_SetBooleanProperty(props, SDL_PROP_JOYSTICK_CAP_RGB_LED_BOOLEAN, false); 846 } 847 if (caps & SDL_JOYSTICK_CAP_PLAYER_LED) { 848 SDL_SetBooleanProperty(props, SDL_PROP_JOYSTICK_CAP_PLAYER_LED_BOOLEAN, true); 849 } else { 850 SDL_SetBooleanProperty(props, SDL_PROP_JOYSTICK_CAP_PLAYER_LED_BOOLEAN, false); 851 } 852 if (caps & SDL_JOYSTICK_CAP_RUMBLE) { 853 SDL_SetBooleanProperty(props, SDL_PROP_JOYSTICK_CAP_RUMBLE_BOOLEAN, true); 854 } else { 855 SDL_SetBooleanProperty(props, SDL_PROP_JOYSTICK_CAP_RUMBLE_BOOLEAN, false); 856 } 857 if (caps & SDL_JOYSTICK_CAP_TRIGGER_RUMBLE) { 858 SDL_SetBooleanProperty(props, SDL_PROP_JOYSTICK_CAP_TRIGGER_RUMBLE_BOOLEAN, true); 859 } else { 860 SDL_SetBooleanProperty(props, SDL_PROP_JOYSTICK_CAP_TRIGGER_RUMBLE_BOOLEAN, false); 861 } 862} 863 864void HIDAPI_UpdateDeviceProperties(SDL_HIDAPI_Device *device) 865{ 866 int i; 867 868 SDL_LockJoysticks(); 869 870 for (i = 0; i < device->num_joysticks; ++i) { 871 SDL_Joystick *joystick = SDL_GetJoystickFromID(device->joysticks[i]); 872 if (joystick) { 873 HIDAPI_UpdateJoystickProperties(device, joystick); 874 } 875 } 876 877 SDL_UnlockJoysticks(); 878} 879 880static int HIDAPI_JoystickGetCount(void) 881{ 882 return SDL_HIDAPI_numjoysticks; 883} 884 885static SDL_HIDAPI_Device *HIDAPI_AddDevice(const struct SDL_hid_device_info *info, int num_children, SDL_HIDAPI_Device **children) 886{ 887 SDL_HIDAPI_Device *device; 888 SDL_HIDAPI_Device *curr, *last = NULL; 889 bool removed; 890 Uint16 bus; 891 892 SDL_AssertJoysticksLocked(); 893 894 for (curr = SDL_HIDAPI_devices, last = NULL; curr; last = curr, curr = curr->next) { 895 } 896 897 device = (SDL_HIDAPI_Device *)SDL_calloc(1, sizeof(*device)); 898 if (!device) { 899 return NULL; 900 } 901 SDL_SetObjectValid(device, SDL_OBJECT_TYPE_HIDAPI_JOYSTICK, true); 902 if (info->path) { 903 device->path = SDL_strdup(info->path); 904 } 905 device->seen = true; 906 device->vendor_id = info->vendor_id; 907 device->product_id = info->product_id; 908 device->version = info->release_number; 909 device->interface_number = info->interface_number; 910 device->interface_class = info->interface_class; 911 device->interface_subclass = info->interface_subclass; 912 device->interface_protocol = info->interface_protocol; 913 device->usage_page = info->usage_page; 914 device->usage = info->usage; 915 device->is_bluetooth = (info->bus_type == SDL_HID_API_BUS_BLUETOOTH); 916 device->dev_lock = SDL_CreateMutex(); 917 918 // Need the device name before getting the driver to know whether to ignore this device 919 { 920 char *serial_number = HIDAPI_ConvertString(info->serial_number); 921 922 device->manufacturer_string = HIDAPI_ConvertString(info->manufacturer_string); 923 device->product_string = HIDAPI_ConvertString(info->product_string); 924 device->name = SDL_CreateJoystickName(device->vendor_id, device->product_id, device->manufacturer_string, device->product_string); 925 926 if (serial_number && *serial_number) { 927 device->serial = serial_number; 928 } else { 929 SDL_free(serial_number); 930 } 931 932 if (!device->name) { 933 SDL_free(device->manufacturer_string); 934 SDL_free(device->product_string); 935 SDL_free(device->serial); 936 SDL_free(device->path); 937 SDL_free(device); 938 return NULL; 939 } 940 } 941 942 if (info->bus_type == SDL_HID_API_BUS_BLUETOOTH) { 943 bus = SDL_HARDWARE_BUS_BLUETOOTH; 944 } else { 945 bus = SDL_HARDWARE_BUS_USB; 946 } 947 device->guid = SDL_CreateJoystickGUID(bus, device->vendor_id, device->product_id, device->version, device->manufacturer_string, device->product_string, 'h', 0); 948 device->joystick_type = SDL_JOYSTICK_TYPE_GAMEPAD; 949 device->type = SDL_GetJoystickGameControllerProtocol(device->name, device->vendor_id, device->product_id, device->interface_number, device->interface_class, device->interface_subclass, device->interface_protocol); 950 device->steam_virtual_gamepad_slot = -1; 951 952 if (num_children > 0) { 953 int i; 954 955 device->num_children = num_children; 956 device->children = children; 957 for (i = 0; i < num_children; ++i) { 958 children[i]->parent = device; 959 } 960 } 961 962 // Add it to the list 963 if (last) { 964 last->next = device; 965 } else { 966 SDL_HIDAPI_devices = device; 967 } 968 969 removed = false; 970 HIDAPI_SetupDeviceDriver(device, &removed); 971 if (removed) { 972 return NULL; 973 } 974 975 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "Added HIDAPI device '%s' VID 0x%.4x, PID 0x%.4x, bluetooth %d, version %d, serial %s, interface %d, interface_class %d, interface_subclass %d, interface_protocol %d, usage page 0x%.4x, usage 0x%.4x, path = %s, driver = %s (%s)", device->name, device->vendor_id, device->product_id, device->is_bluetooth, device->version, 976 device->serial ? device->serial : "NONE", device->interface_number, device->interface_class, device->interface_subclass, device->interface_protocol, device->usage_page, device->usage, 977 device->path, device->driver ? device->driver->name : "NONE", device->driver && device->driver->enabled ? "ENABLED" : "DISABLED"); 978 979 return device; 980} 981 982static void HIDAPI_DelDevice(SDL_HIDAPI_Device *device) 983{ 984 SDL_HIDAPI_Device *curr, *last; 985 int i; 986 987 SDL_AssertJoysticksLocked(); 988 989 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "Removing HIDAPI device '%s' VID 0x%.4x, PID 0x%.4x, bluetooth %d, version %d, serial %s, interface %d, interface_class %d, interface_subclass %d, interface_protocol %d, usage page 0x%.4x, usage 0x%.4x, path = %s, driver = %s (%s)", device->name, device->vendor_id, device->product_id, device->is_bluetooth, device->version, 990 device->serial ? device->serial : "NONE", device->interface_number, device->interface_class, device->interface_subclass, device->interface_protocol, device->usage_page, device->usage, 991 device->path, device->driver ? device->driver->name : "NONE", device->driver && device->driver->enabled ? "ENABLED" : "DISABLED"); 992 993 for (curr = SDL_HIDAPI_devices, last = NULL; curr; last = curr, curr = curr->next) { 994 if (curr == device) { 995 if (last) { 996 last->next = curr->next; 997 } else { 998 SDL_HIDAPI_devices = curr->next; 999 } 1000 1001 HIDAPI_CleanupDeviceDriver(device); 1002 1003 // Make sure the rumble thread is done with this device 1004 while (SDL_GetAtomicInt(&device->rumble_pending) > 0) { 1005 SDL_Delay(10); 1006 } 1007 1008 for (i = 0; i < device->num_children; ++i) { 1009 device->children[i]->parent = NULL; 1010 } 1011 1012 SDL_SetObjectValid(device, SDL_OBJECT_TYPE_HIDAPI_JOYSTICK, false); 1013 SDL_DestroyMutex(device->dev_lock); 1014 SDL_free(device->manufacturer_string); 1015 SDL_free(device->product_string); 1016 SDL_free(device->serial); 1017 SDL_free(device->name); 1018 SDL_free(device->path); 1019 SDL_free(device->children); 1020 SDL_free(device); 1021 return; 1022 } 1023 } 1024} 1025 1026static bool HIDAPI_CreateCombinedJoyCons(void) 1027{ 1028 SDL_HIDAPI_Device *device, *combined; 1029 SDL_HIDAPI_Device *joycons[2] = { NULL, NULL }; 1030 1031 SDL_AssertJoysticksLocked(); 1032 1033 if (!SDL_HIDAPI_combine_joycons) { 1034 return false; 1035 } 1036 1037 for (device = SDL_HIDAPI_devices; device; device = device->next) { 1038 Uint16 vendor, product; 1039 1040 if (!device->driver) { 1041 // Unsupported device 1042 continue; 1043 } 1044 if (device->parent) { 1045 // This device is already part of a combined device 1046 continue; 1047 } 1048 if (device->broken) { 1049 // This device can't be used 1050 continue; 1051 } 1052 1053 SDL_GetJoystickGUIDInfo(device->guid, &vendor, &product, NULL, NULL); 1054 1055 if (!joycons[0] && 1056 (SDL_IsJoystickNintendoSwitchJoyConLeft(vendor, product) || 1057 (SDL_IsJoystickNintendoSwitchJoyConGrip(vendor, product) && 1058 SDL_strstr(device->name, "(L)") != NULL))) { 1059 joycons[0] = device; 1060 } 1061 if (!joycons[1] && 1062 (SDL_IsJoystickNintendoSwitchJoyConRight(vendor, product) || 1063 (SDL_IsJoystickNintendoSwitchJoyConGrip(vendor, product) && 1064 SDL_strstr(device->name, "(R)") != NULL))) { 1065 joycons[1] = device; 1066 } 1067 if (joycons[0] && joycons[1]) { 1068 SDL_hid_device_info info; 1069 SDL_HIDAPI_Device **children = (SDL_HIDAPI_Device **)SDL_malloc(2 * sizeof(SDL_HIDAPI_Device *)); 1070 if (!children) { 1071 return false; 1072 } 1073 children[0] = joycons[0]; 1074 children[1] = joycons[1]; 1075 1076 SDL_zero(info); 1077 info.path = "nintendo_joycons_combined"; 1078 info.vendor_id = USB_VENDOR_NINTENDO; 1079 if (joycons[0]->product_id == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_LEFT) { 1080 info.product_id = USB_PRODUCT_NINTENDO_SWITCH_JOYCON_PAIR; 1081 } else { 1082 info.product_id = USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_PAIR; 1083 } 1084 info.interface_number = -1; 1085 info.usage_page = USB_USAGEPAGE_GENERIC_DESKTOP; 1086 info.usage = USB_USAGE_GENERIC_GAMEPAD; 1087 info.manufacturer_string = L"Nintendo"; 1088 info.product_string = L"Switch Joy-Con (L/R)"; 1089 if (children[0]->is_bluetooth || children[1]->is_bluetooth) { 1090 info.bus_type = SDL_HID_API_BUS_BLUETOOTH; 1091 } else { 1092 info.bus_type = SDL_HID_API_BUS_USB; 1093 } 1094 1095 combined = HIDAPI_AddDevice(&info, 2, children); 1096 if (combined && combined->driver) { 1097 return true; 1098 } else { 1099 if (combined) { 1100 HIDAPI_DelDevice(combined); 1101 } else { 1102 SDL_free(children); 1103 } 1104 return false; 1105 } 1106 } 1107 } 1108 return false; 1109} 1110 1111static void HIDAPI_UpdateDeviceList(void) 1112{ 1113 SDL_HIDAPI_Device *device; 1114 struct SDL_hid_device_info *devs, *info; 1115 1116 SDL_LockJoysticks(); 1117 1118 if (SDL_HIDAPI_hints_changed) { 1119 SDL_HIDAPI_UpdateDrivers(); 1120 SDL_HIDAPI_hints_changed = false; 1121 } 1122 1123 // Prepare the existing device list 1124 for (device = SDL_HIDAPI_devices; device; device = device->next) { 1125 if (device->children) { 1126 continue; 1127 } 1128 device->seen = false; 1129 } 1130 1131 // Enumerate the devices 1132 if (SDL_HIDAPI_numdrivers > 0) { 1133 devs = SDL_hid_enumerate(0, 0); 1134 if (devs) { 1135 for (info = devs; info; info = info->next) { 1136 device = HIDAPI_GetJoystickByInfo(info->path, info->vendor_id, info->product_id); 1137 if (device) { 1138 device->seen = true; 1139 1140 // Check to see if the serial number is available now 1141 if(HIDAPI_SerialIsEmpty(device)) { 1142 HIDAPI_SetDeviceSerialW(device, info->serial_number); 1143 } 1144 } else { 1145 HIDAPI_AddDevice(info, 0, NULL); 1146 } 1147 } 1148 SDL_hid_free_enumeration(devs); 1149 } 1150 } 1151 1152 // Remove any devices that weren't seen or have been disconnected due to read errors 1153check_removed: 1154 device = SDL_HIDAPI_devices; 1155 while (device) { 1156 SDL_HIDAPI_Device *next = device->next; 1157 1158 if (!device->seen || 1159 ((device->driver || device->children) && device->num_joysticks == 0 && !device->dev)) { 1160 if (device->parent) { 1161 // When a child device goes away, so does the parent 1162 int i; 1163 device = device->parent; 1164 for (i = 0; i < device->num_children; ++i) { 1165 HIDAPI_DelDevice(device->children[i]); 1166 } 1167 HIDAPI_DelDevice(device); 1168 1169 // Update the device list again to pick up any children left 1170 SDL_HIDAPI_change_count = 0; 1171 1172 // We deleted more than one device here, restart the loop 1173 goto check_removed; 1174 } else { 1175 HIDAPI_DelDevice(device); 1176 device = NULL; 1177 1178 // Update the device list again in case this device comes back 1179 SDL_HIDAPI_change_count = 0; 1180 } 1181 } 1182 if (device && device->broken && device->parent) { 1183 HIDAPI_DelDevice(device->parent); 1184 1185 // We deleted a different device here, restart the loop 1186 goto check_removed; 1187 } 1188 device = next; 1189 } 1190 1191 // See if we can create any combined Joy-Con controllers 1192 while (HIDAPI_CreateCombinedJoyCons()) { 1193 } 1194 1195 SDL_UnlockJoysticks(); 1196} 1197 1198static bool HIDAPI_IsEquivalentToDevice(Uint16 vendor_id, Uint16 product_id, SDL_HIDAPI_Device *device) 1199{ 1200 if (vendor_id == device->vendor_id && product_id == device->product_id) { 1201 return true; 1202 } 1203 1204 if (vendor_id == USB_VENDOR_MICROSOFT) { 1205 // If we're looking for the wireless XBox 360 controller, also look for the dongle 1206 if (product_id == USB_PRODUCT_XBOX360_XUSB_CONTROLLER && device->product_id == USB_PRODUCT_XBOX360_WIRELESS_RECEIVER) { 1207 return true; 1208 } 1209 1210 // If we're looking for the raw input Xbox One controller, match it against any other Xbox One controller 1211 if (product_id == USB_PRODUCT_XBOX_ONE_XBOXGIP_CONTROLLER && 1212 device->type == SDL_GAMEPAD_TYPE_XBOXONE) { 1213 return true; 1214 } 1215 1216 // If we're looking for an XInput controller, match it against any other Xbox controller 1217 if (product_id == USB_PRODUCT_XBOX360_XUSB_CONTROLLER) { 1218 if (device->type == SDL_GAMEPAD_TYPE_XBOX360 || device->type == SDL_GAMEPAD_TYPE_XBOXONE) { 1219 return true; 1220 } 1221 } 1222 } 1223 1224 if (vendor_id == USB_VENDOR_NVIDIA) { 1225 // If we're looking for the NVIDIA SHIELD controller Xbox interface, match it against any NVIDIA SHIELD controller 1226 if (product_id == 0xb400 && 1227 SDL_IsJoystickNVIDIASHIELDController(vendor_id, product_id)) { 1228 return true; 1229 } 1230 } 1231 return false; 1232} 1233 1234static bool HIDAPI_StartUpdatingDevices(void) 1235{ 1236 return SDL_CompareAndSwapAtomicInt(&SDL_HIDAPI_updating_devices, false, true); 1237} 1238 1239static void HIDAPI_FinishUpdatingDevices(void) 1240{ 1241 SDL_SetAtomicInt(&SDL_HIDAPI_updating_devices, false); 1242} 1243 1244bool HIDAPI_IsDeviceTypePresent(SDL_GamepadType type) 1245{ 1246 SDL_HIDAPI_Device *device; 1247 bool result = false; 1248 1249 // Make sure we're initialized, as this could be called from other drivers during startup 1250 if (!HIDAPI_JoystickInit()) { 1251 return false; 1252 } 1253 1254 if (HIDAPI_StartUpdatingDevices()) { 1255 HIDAPI_UpdateDeviceList(); 1256 HIDAPI_FinishUpdatingDevices(); 1257 } 1258 1259 SDL_LockJoysticks(); 1260 for (device = SDL_HIDAPI_devices; device; device = device->next) { 1261 if (device->driver && device->type == type) { 1262 result = true; 1263 break; 1264 } 1265 } 1266 SDL_UnlockJoysticks(); 1267 1268#ifdef DEBUG_HIDAPI 1269 SDL_Log("HIDAPI_IsDeviceTypePresent() returning %s for %d", result ? "true" : "false", type); 1270#endif 1271 return result; 1272} 1273 1274bool HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name) 1275{ 1276 SDL_HIDAPI_Device *device; 1277 bool supported = false; 1278 bool result = false; 1279 1280 // Make sure we're initialized, as this could be called from other drivers during startup 1281 if (!HIDAPI_JoystickInit()) { 1282 return false; 1283 } 1284 1285 /* Only update the device list for devices we know might be supported. 1286 If we did this for every device, it would hit the USB driver too hard and potentially 1287 lock up the system. This won't catch devices that we support but can only detect using 1288 USB interface details, like Xbox controllers, but hopefully the device list update is 1289 responsive enough to catch those. 1290 */ 1291 supported = HIDAPI_IsDeviceSupported(vendor_id, product_id, version, name); 1292#if defined(SDL_JOYSTICK_HIDAPI_XBOX360) || defined(SDL_JOYSTICK_HIDAPI_XBOXONE) 1293 if (!supported && 1294 (SDL_strstr(name, "Xbox") || SDL_strstr(name, "X-Box") || SDL_strstr(name, "XBOX"))) { 1295 supported = true; 1296 } 1297#endif // SDL_JOYSTICK_HIDAPI_XBOX360 || SDL_JOYSTICK_HIDAPI_XBOXONE 1298 if (supported) { 1299 if (HIDAPI_StartUpdatingDevices()) { 1300 HIDAPI_UpdateDeviceList(); 1301 HIDAPI_FinishUpdatingDevices(); 1302 } 1303 } 1304 1305 /* Note that this isn't a perfect check - there may be multiple devices with 0 VID/PID, 1306 or a different name than we have it listed here, etc, but if we support the device 1307 and we have something similar in our device list, mark it as present. 1308 */ 1309 SDL_LockJoysticks(); 1310 for (device = SDL_HIDAPI_devices; device; device = device->next) { 1311 // The HIDAPI functionality will be available when the FlyDigi Space Station app has 1312 // enabled third party controller mapping, so the driver needs to be active to watch 1313 // for that change. Since this is dynamic and we don't have a way to re-trigger device 1314 // changes when that happens, we'll pretend the driver isn't available so the XInput 1315 // interface will always show up (but won't have any input when the controller is in 1316 // enhanced mode) 1317 if (device->vendor_id == USB_VENDOR_FLYDIGI_V2) { 1318 continue; 1319 } 1320 1321 if (device->driver && 1322 HIDAPI_IsEquivalentToDevice(vendor_id, product_id, device)) { 1323 result = true; 1324 break; 1325 } 1326 } 1327 SDL_UnlockJoysticks(); 1328 1329#ifdef DEBUG_HIDAPI 1330 SDL_Log("HIDAPI_IsDevicePresent() returning %s for 0x%.4x / 0x%.4x", result ? "true" : "false", vendor_id, product_id); 1331#endif 1332 return result; 1333} 1334 1335char *HIDAPI_GetDeviceProductName(Uint16 vendor_id, Uint16 product_id) 1336{ 1337 SDL_HIDAPI_Device *device; 1338 char *name = NULL; 1339 1340 SDL_LockJoysticks(); 1341 for (device = SDL_HIDAPI_devices; device; device = device->next) { 1342 if (vendor_id == device->vendor_id && product_id == device->product_id) { 1343 if (device->product_string) { 1344 name = SDL_strdup(device->product_string); 1345 } 1346 break; 1347 } 1348 } 1349 SDL_UnlockJoysticks(); 1350 1351 return name; 1352} 1353 1354char *HIDAPI_GetDeviceManufacturerName(Uint16 vendor_id, Uint16 product_id) 1355{ 1356 SDL_HIDAPI_Device *device; 1357 char *name = NULL; 1358 1359 SDL_LockJoysticks(); 1360 for (device = SDL_HIDAPI_devices; device; device = device->next) { 1361 if (vendor_id == device->vendor_id && product_id == device->product_id) { 1362 if (device->manufacturer_string) { 1363 name = SDL_strdup(device->manufacturer_string); 1364 } 1365 break; 1366 } 1367 } 1368 SDL_UnlockJoysticks(); 1369 1370 return name; 1371} 1372 1373SDL_JoystickType HIDAPI_GetJoystickTypeFromGUID(SDL_GUID guid) 1374{ 1375 SDL_HIDAPI_Device *device; 1376 SDL_JoystickType type = SDL_JOYSTICK_TYPE_UNKNOWN; 1377 1378 SDL_LockJoysticks(); 1379 for (device = SDL_HIDAPI_devices; device; device = device->next) { 1380 if (SDL_memcmp(&guid, &device->guid, sizeof(guid)) == 0) { 1381 type = device->joystick_type; 1382 break; 1383 } 1384 } 1385 SDL_UnlockJoysticks(); 1386 1387 return type; 1388} 1389 1390SDL_GamepadType HIDAPI_GetGamepadTypeFromGUID(SDL_GUID guid) 1391{ 1392 SDL_HIDAPI_Device *device; 1393 SDL_GamepadType type = SDL_GAMEPAD_TYPE_STANDARD; 1394 1395 SDL_LockJoysticks(); 1396 for (device = SDL_HIDAPI_devices; device; device = device->next) { 1397 if (SDL_memcmp(&guid, &device->guid, sizeof(guid)) == 0) { 1398 type = device->type; 1399 break; 1400 } 1401 } 1402 SDL_UnlockJoysticks(); 1403 1404 return type; 1405} 1406 1407static void HIDAPI_JoystickDetect(void) 1408{ 1409 if (HIDAPI_StartUpdatingDevices()) { 1410 Uint32 count = SDL_hid_device_change_count(); 1411 if (SDL_HIDAPI_change_count != count) { 1412 SDL_HIDAPI_change_count = count; 1413 HIDAPI_UpdateDeviceList(); 1414 } 1415 HIDAPI_FinishUpdatingDevices(); 1416 } 1417} 1418 1419void HIDAPI_UpdateDevices(void) 1420{ 1421 SDL_HIDAPI_Device *device; 1422 1423 SDL_AssertJoysticksLocked(); 1424 1425 // Update the devices, which may change connected joysticks and send events 1426 1427 // Prepare the existing device list 1428 if (HIDAPI_StartUpdatingDevices()) { 1429 for (device = SDL_HIDAPI_devices; device; device = device->next) { 1430 if (device->parent) { 1431 continue; 1432 } 1433 if (device->driver) { 1434 if (SDL_TryLockMutex(device->dev_lock)) { 1435 device->updating = true; 1436 device->driver->UpdateDevice(device); 1437 device->updating = false; 1438 SDL_UnlockMutex(device->dev_lock); 1439 } 1440 } 1441 } 1442 HIDAPI_FinishUpdatingDevices(); 1443 } 1444} 1445 1446static const char *HIDAPI_JoystickGetDeviceName(int device_index) 1447{ 1448 SDL_HIDAPI_Device *device; 1449 const char *name = NULL; 1450 1451 device = HIDAPI_GetDeviceByIndex(device_index, NULL); 1452 if (device) { 1453 // FIXME: The device could be freed after this name is returned... 1454 name = device->name; 1455 } 1456 1457 return name; 1458} 1459 1460static const char *HIDAPI_JoystickGetDevicePath(int device_index) 1461{ 1462 SDL_HIDAPI_Device *device; 1463 const char *path = NULL; 1464 1465 device = HIDAPI_GetDeviceByIndex(device_index, NULL); 1466 if (device) { 1467 // FIXME: The device could be freed after this path is returned... 1468 path = device->path; 1469 } 1470 1471 return path; 1472} 1473 1474static int HIDAPI_JoystickGetDeviceSteamVirtualGamepadSlot(int device_index) 1475{ 1476 SDL_HIDAPI_Device *device; 1477 1478 device = HIDAPI_GetDeviceByIndex(device_index, NULL); 1479 if (device) { 1480 return device->steam_virtual_gamepad_slot; 1481 } 1482 return -1; 1483} 1484 1485static int HIDAPI_JoystickGetDevicePlayerIndex(int device_index) 1486{ 1487 SDL_HIDAPI_Device *device; 1488 SDL_JoystickID instance_id; 1489 int player_index = -1; 1490 1491 device = HIDAPI_GetDeviceByIndex(device_index, &instance_id); 1492 if (device) { 1493 player_index = device->driver->GetDevicePlayerIndex(device, instance_id); 1494 } 1495 1496 return player_index; 1497} 1498 1499static void HIDAPI_JoystickSetDevicePlayerIndex(int device_index, int player_index) 1500{ 1501 SDL_HIDAPI_Device *device; 1502 SDL_JoystickID instance_id; 1503 1504 device = HIDAPI_GetDeviceByIndex(device_index, &instance_id); 1505 if (device) { 1506 device->driver->SetDevicePlayerIndex(device, instance_id, player_index); 1507 } 1508} 1509 1510static SDL_GUID HIDAPI_JoystickGetDeviceGUID(int device_index) 1511{ 1512 SDL_HIDAPI_Device *device; 1513 SDL_GUID guid; 1514 1515 device = HIDAPI_GetDeviceByIndex(device_index, NULL); 1516 if (device) { 1517 SDL_memcpy(&guid, &device->guid, sizeof(guid)); 1518 } else { 1519 SDL_zero(guid); 1520 } 1521 1522 return guid; 1523} 1524 1525static SDL_JoystickID HIDAPI_JoystickGetDeviceInstanceID(int device_index) 1526{ 1527 SDL_JoystickID joystickID = 0; 1528 HIDAPI_GetDeviceByIndex(device_index, &joystickID); 1529 return joystickID; 1530} 1531 1532static bool HIDAPI_JoystickOpen(SDL_Joystick *joystick, int device_index) 1533{ 1534 SDL_JoystickID joystickID = 0; 1535 SDL_HIDAPI_Device *device = HIDAPI_GetDeviceByIndex(device_index, &joystickID); 1536 struct joystick_hwdata *hwdata; 1537 1538 SDL_AssertJoysticksLocked(); 1539 1540 if (!device || !device->driver || device->broken) { 1541 // This should never happen - validated before being called 1542 return SDL_SetError("Couldn't find HIDAPI device at index %d", device_index); 1543 } 1544 1545 hwdata = (struct joystick_hwdata *)SDL_calloc(1, sizeof(*hwdata)); 1546 if (!hwdata) { 1547 return false; 1548 } 1549 hwdata->device = device; 1550 1551 // Process any pending reports before opening the device 1552 SDL_LockMutex(device->dev_lock); 1553 device->updating = true; 1554 device->driver->UpdateDevice(device); 1555 device->updating = false; 1556 SDL_UnlockMutex(device->dev_lock); 1557 1558 // UpdateDevice() may have called HIDAPI_JoystickDisconnected() if the device went away 1559 if (device->num_joysticks == 0) { 1560 SDL_free(hwdata); 1561 return SDL_SetError("HIDAPI device disconnected while opening"); 1562 } 1563 1564 // Set the default connection state, can be overridden below 1565 if (device->is_bluetooth) { 1566 joystick->connection_state = SDL_JOYSTICK_CONNECTION_WIRELESS; 1567 } else { 1568 joystick->connection_state = SDL_JOYSTICK_CONNECTION_WIRED; 1569 } 1570 1571 if (!device->driver->OpenJoystick(device, joystick)) { 1572 // The open failed, mark this device as disconnected and update devices 1573 HIDAPI_JoystickDisconnected(device, joystickID); 1574 SDL_free(hwdata); 1575 return false; 1576 } 1577 1578 HIDAPI_UpdateJoystickProperties(device, joystick); 1579 1580 if (device->serial) { 1581 joystick->serial = SDL_strdup(device->serial); 1582 } 1583 1584 joystick->hwdata = hwdata; 1585 return true; 1586} 1587 1588static bool HIDAPI_GetJoystickDevice(SDL_Joystick *joystick, SDL_HIDAPI_Device **device) 1589{ 1590 SDL_AssertJoysticksLocked(); 1591 1592 if (joystick && joystick->hwdata) { 1593 *device = joystick->hwdata->device; 1594 if (SDL_ObjectValid(*device, SDL_OBJECT_TYPE_HIDAPI_JOYSTICK) && (*device)->driver != NULL) { 1595 return true; 1596 } 1597 } 1598 return false; 1599} 1600 1601static bool HIDAPI_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) 1602{ 1603 bool result; 1604 SDL_HIDAPI_Device *device = NULL; 1605 1606 if (HIDAPI_GetJoystickDevice(joystick, &device)) { 1607 result = device->driver->RumbleJoystick(device, joystick, low_frequency_rumble, high_frequency_rumble); 1608 } else { 1609 result = SDL_SetError("Rumble failed, device disconnected"); 1610 } 1611 1612 return result; 1613} 1614 1615static bool HIDAPI_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) 1616{ 1617 bool result; 1618 SDL_HIDAPI_Device *device = NULL; 1619 1620 if (HIDAPI_GetJoystickDevice(joystick, &device)) { 1621 result = device->driver->RumbleJoystickTriggers(device, joystick, left_rumble, right_rumble); 1622 } else { 1623 result = SDL_SetError("Rumble failed, device disconnected"); 1624 } 1625 1626 return result; 1627} 1628 1629static bool HIDAPI_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) 1630{ 1631 bool result; 1632 SDL_HIDAPI_Device *device = NULL; 1633 1634 if (HIDAPI_GetJoystickDevice(joystick, &device)) { 1635 result = device->driver->SetJoystickLED(device, joystick, red, green, blue); 1636 } else { 1637 result = SDL_SetError("SetLED failed, device disconnected"); 1638 } 1639 1640 return result; 1641} 1642 1643static bool HIDAPI_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size) 1644{ 1645 bool result; 1646 SDL_HIDAPI_Device *device = NULL; 1647 1648 if (HIDAPI_GetJoystickDevice(joystick, &device)) { 1649 result = device->driver->SendJoystickEffect(device, joystick, data, size); 1650 } else { 1651 result = SDL_SetError("SendEffect failed, device disconnected"); 1652 } 1653 1654 return result; 1655} 1656 1657static bool HIDAPI_JoystickSetSensorsEnabled(SDL_Joystick *joystick, bool enabled) 1658{ 1659 bool result; 1660 SDL_HIDAPI_Device *device = NULL; 1661 1662 if (HIDAPI_GetJoystickDevice(joystick, &device)) { 1663 result = device->driver->SetJoystickSensorsEnabled(device, joystick, enabled); 1664 } else { 1665 result = SDL_SetError("SetSensorsEnabled failed, device disconnected"); 1666 } 1667 1668 return result; 1669} 1670 1671static void HIDAPI_JoystickUpdate(SDL_Joystick *joystick) 1672{ 1673 // This is handled in SDL_HIDAPI_UpdateDevices() 1674} 1675 1676static void HIDAPI_JoystickClose(SDL_Joystick *joystick) SDL_NO_THREAD_SAFETY_ANALYSIS // We unlock the device lock so rumble can complete 1677{ 1678 SDL_AssertJoysticksLocked(); 1679 1680 if (joystick->hwdata) { 1681 SDL_HIDAPI_Device *device = joystick->hwdata->device; 1682 int i; 1683 1684 // Wait up to 30 ms for pending rumble to complete 1685 if (device->updating) { 1686 // Unlock the device so rumble can complete 1687 SDL_UnlockMutex(device->dev_lock); 1688 } 1689 for (i = 0; i < 3; ++i) { 1690 if (SDL_GetAtomicInt(&device->rumble_pending) > 0) { 1691 SDL_Delay(10); 1692 } 1693 } 1694 if (device->updating) { 1695 // Relock the device 1696 SDL_LockMutex(device->dev_lock); 1697 } 1698 1699 device->driver->CloseJoystick(device, joystick); 1700 1701 SDL_free(joystick->hwdata); 1702 joystick->hwdata = NULL; 1703 } 1704} 1705 1706static void HIDAPI_JoystickQuit(void) 1707{ 1708 int i; 1709 1710 SDL_AssertJoysticksLocked(); 1711 1712 shutting_down = true; 1713 1714 SDL_HIDAPI_QuitRumble(); 1715 1716 while (SDL_HIDAPI_devices) { 1717 SDL_HIDAPI_Device *device = SDL_HIDAPI_devices; 1718 if (device->parent) { 1719 // When a child device goes away, so does the parent 1720 device = device->parent; 1721 for (i = 0; i < device->num_children; ++i) { 1722 HIDAPI_DelDevice(device->children[i]); 1723 } 1724 HIDAPI_DelDevice(device); 1725 } else { 1726 HIDAPI_DelDevice(device); 1727 } 1728 } 1729 1730 // Make sure the drivers cleaned up properly 1731 SDL_assert(SDL_HIDAPI_numjoysticks == 0); 1732 1733 for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) { 1734 SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i]; 1735 driver->UnregisterHints(SDL_HIDAPIDriverHintChanged, driver); 1736 } 1737 SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS, 1738 SDL_HIDAPIDriverHintChanged, NULL); 1739 SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_HIDAPI, 1740 SDL_HIDAPIDriverHintChanged, NULL); 1741 1742 SDL_hid_exit(); 1743 1744 SDL_HIDAPI_change_count = 0; 1745 shutting_down = false; 1746 initialized = false; 1747} 1748 1749static bool HIDAPI_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) 1750{ 1751 return false; 1752} 1753 1754SDL_JoystickDriver SDL_HIDAPI_JoystickDriver = { 1755 HIDAPI_JoystickInit, 1756 HIDAPI_JoystickGetCount, 1757 HIDAPI_JoystickDetect, 1758 HIDAPI_IsDevicePresent, 1759 HIDAPI_JoystickGetDeviceName, 1760 HIDAPI_JoystickGetDevicePath, 1761 HIDAPI_JoystickGetDeviceSteamVirtualGamepadSlot, 1762 HIDAPI_JoystickGetDevicePlayerIndex, 1763 HIDAPI_JoystickSetDevicePlayerIndex, 1764 HIDAPI_JoystickGetDeviceGUID, 1765 HIDAPI_JoystickGetDeviceInstanceID, 1766 HIDAPI_JoystickOpen, 1767 HIDAPI_JoystickRumble, 1768 HIDAPI_JoystickRumbleTriggers, 1769 HIDAPI_JoystickSetLED, 1770 HIDAPI_JoystickSendEffect, 1771 HIDAPI_JoystickSetSensorsEnabled, 1772 HIDAPI_JoystickUpdate, 1773 HIDAPI_JoystickClose, 1774 HIDAPI_JoystickQuit, 1775 HIDAPI_JoystickGetGamepadMapping 1776}; 1777 1778#endif // SDL_JOYSTICK_HIDAPI 1779
[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.