Simple Directmedia Layer
at main 63 kB view raw
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org> 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 22/* Original hybrid wrapper for Linux by Valve Software. Their original notes: 23 * 24 * The libusb version doesn't support Bluetooth, but not all Linux 25 * distributions allow access to /dev/hidraw* 26 * 27 * This merges the two, at a small performance cost, until distributions 28 * have granted access to /dev/hidraw* 29 */ 30 31#include "SDL_internal.h" 32 33#include "SDL_hidapi_c.h" 34#include "../joystick/usb_ids.h" 35#include "../SDL_hints_c.h" 36 37// Initial type declarations 38#define HID_API_NO_EXPORT_DEFINE // do not export hidapi procedures 39#include "hidapi/hidapi.h" 40 41#ifndef SDL_HIDAPI_DISABLED 42 43#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK) 44#include "../core/windows/SDL_windows.h" 45#endif 46 47#ifdef SDL_PLATFORM_MACOS 48#include <CoreFoundation/CoreFoundation.h> 49#include <mach/mach.h> 50#include <IOKit/IOKitLib.h> 51#include <IOKit/hid/IOHIDDevice.h> 52#include <IOKit/usb/USBSpec.h> 53#include <AvailabilityMacros.h> 54// Things named "Master" were renamed to "Main" in macOS 12.0's SDK. 55#if MAC_OS_X_VERSION_MIN_REQUIRED < 120000 56#define kIOMainPortDefault kIOMasterPortDefault 57#endif 58#endif 59 60#include "../core/linux/SDL_udev.h" 61#ifdef SDL_USE_LIBUDEV 62#include <poll.h> 63#endif 64 65#ifdef HAVE_INOTIFY 66#include <string.h> // strerror 67#include <errno.h> // errno 68#include <fcntl.h> 69#include <limits.h> // For the definition of NAME_MAX 70#include <sys/inotify.h> 71#endif 72 73#if defined(SDL_USE_LIBUDEV) || defined(HAVE_INOTIFY) 74#include <unistd.h> 75#endif 76 77#ifdef SDL_USE_LIBUDEV 78typedef enum 79{ 80 ENUMERATION_UNSET, 81 ENUMERATION_LIBUDEV, 82 ENUMERATION_FALLBACK 83} LinuxEnumerationMethod; 84 85static LinuxEnumerationMethod linux_enumeration_method = ENUMERATION_UNSET; 86#endif 87 88#ifdef HAVE_INOTIFY 89static int inotify_fd = -1; 90#endif 91 92#ifdef SDL_USE_LIBUDEV 93static const SDL_UDEV_Symbols *usyms = NULL; 94#endif 95 96static struct 97{ 98 bool m_bInitialized; 99 Uint32 m_unDeviceChangeCounter; 100 bool m_bCanGetNotifications; 101 Uint64 m_unLastDetect; 102 103#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK) 104 SDL_ThreadID m_nThreadID; 105 WNDCLASSEXA m_wndClass; 106 HWND m_hwndMsg; 107 HDEVNOTIFY m_hNotify; 108 double m_flLastWin32MessageCheck; 109#endif 110 111#ifdef SDL_PLATFORM_MACOS 112 IONotificationPortRef m_notificationPort; 113 mach_port_t m_notificationMach; 114#endif 115 116#ifdef SDL_USE_LIBUDEV 117 struct udev *m_pUdev; 118 struct udev_monitor *m_pUdevMonitor; 119 int m_nUdevFd; 120#endif 121} SDL_HIDAPI_discovery; 122 123#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK) 124struct _DEV_BROADCAST_HDR 125{ 126 DWORD dbch_size; 127 DWORD dbch_devicetype; 128 DWORD dbch_reserved; 129}; 130 131typedef struct _DEV_BROADCAST_DEVICEINTERFACE_A 132{ 133 DWORD dbcc_size; 134 DWORD dbcc_devicetype; 135 DWORD dbcc_reserved; 136 GUID dbcc_classguid; 137 char dbcc_name[1]; 138} DEV_BROADCAST_DEVICEINTERFACE_A, *PDEV_BROADCAST_DEVICEINTERFACE_A; 139 140typedef struct _DEV_BROADCAST_HDR DEV_BROADCAST_HDR; 141#define DBT_DEVICEARRIVAL 0x8000 // system detected a new device 142#define DBT_DEVICEREMOVECOMPLETE 0x8004 // device was removed from the system 143#define DBT_DEVTYP_DEVICEINTERFACE 0x00000005 // device interface class 144#define DBT_DEVNODES_CHANGED 0x0007 145#define DBT_CONFIGCHANGED 0x0018 146#define DBT_DEVICETYPESPECIFIC 0x8005 // type specific event 147#define DBT_DEVINSTSTARTED 0x8008 // device installed and started 148 149#include <initguid.h> 150DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED); 151 152static LRESULT CALLBACK ControllerWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 153{ 154 switch (message) { 155 case WM_DEVICECHANGE: 156 switch (wParam) { 157 case DBT_DEVICEARRIVAL: 158 case DBT_DEVICEREMOVECOMPLETE: 159 if (((DEV_BROADCAST_HDR *)lParam)->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) { 160 ++SDL_HIDAPI_discovery.m_unDeviceChangeCounter; 161 } 162 break; 163 } 164 return TRUE; 165 } 166 167 return DefWindowProc(hwnd, message, wParam, lParam); 168} 169#endif // defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK) 170 171#ifdef SDL_PLATFORM_MACOS 172static void CallbackIOServiceFunc(void *context, io_iterator_t portIterator) 173{ 174 // Must drain the iterator, or we won't receive new notifications 175 io_object_t entry; 176 while ((entry = IOIteratorNext(portIterator)) != 0) { 177 IOObjectRelease(entry); 178 ++SDL_HIDAPI_discovery.m_unDeviceChangeCounter; 179 } 180} 181#endif // SDL_PLATFORM_MACOS 182 183#ifdef HAVE_INOTIFY 184#ifdef HAVE_INOTIFY_INIT1 185static int SDL_inotify_init1(void) 186{ 187 return inotify_init1(IN_NONBLOCK | IN_CLOEXEC); 188} 189#else 190static int SDL_inotify_init1(void) 191{ 192 int fd = inotify_init(); 193 if (fd < 0) { 194 return -1; 195 } 196 fcntl(fd, F_SETFL, O_NONBLOCK); 197 fcntl(fd, F_SETFD, FD_CLOEXEC); 198 return fd; 199} 200#endif 201 202static int StrHasPrefix(const char *string, const char *prefix) 203{ 204 return SDL_strncmp(string, prefix, SDL_strlen(prefix)) == 0; 205} 206 207static int StrIsInteger(const char *string) 208{ 209 const char *p; 210 211 if (*string == '\0') { 212 return 0; 213 } 214 215 for (p = string; *p != '\0'; p++) { 216 if (*p < '0' || *p > '9') { 217 return 0; 218 } 219 } 220 221 return 1; 222} 223#endif // HAVE_INOTIFY 224 225static void HIDAPI_InitializeDiscovery(void) 226{ 227 SDL_HIDAPI_discovery.m_bInitialized = true; 228 SDL_HIDAPI_discovery.m_unDeviceChangeCounter = 1; 229 SDL_HIDAPI_discovery.m_bCanGetNotifications = false; 230 SDL_HIDAPI_discovery.m_unLastDetect = 0; 231 232#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK) 233 SDL_HIDAPI_discovery.m_nThreadID = SDL_GetCurrentThreadID(); 234 235 SDL_zero(SDL_HIDAPI_discovery.m_wndClass); 236 SDL_HIDAPI_discovery.m_wndClass.hInstance = GetModuleHandle(NULL); 237 SDL_HIDAPI_discovery.m_wndClass.lpszClassName = "SDL_HIDAPI_DEVICE_DETECTION"; 238 SDL_HIDAPI_discovery.m_wndClass.lpfnWndProc = ControllerWndProc; // This function is called by windows 239 SDL_HIDAPI_discovery.m_wndClass.cbSize = sizeof(WNDCLASSEX); 240 241 RegisterClassExA(&SDL_HIDAPI_discovery.m_wndClass); 242 SDL_HIDAPI_discovery.m_hwndMsg = CreateWindowExA(0, "SDL_HIDAPI_DEVICE_DETECTION", NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL); 243 244 { 245 DEV_BROADCAST_DEVICEINTERFACE_A devBroadcast; 246 247 SDL_zero(devBroadcast); 248 devBroadcast.dbcc_size = sizeof(devBroadcast); 249 devBroadcast.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; 250 devBroadcast.dbcc_classguid = GUID_DEVINTERFACE_USB_DEVICE; 251 252 /* DEVICE_NOTIFY_ALL_INTERFACE_CLASSES is important, makes GUID_DEVINTERFACE_USB_DEVICE ignored, 253 * but that seems to be necessary to get a notice after each individual usb input device actually 254 * installs, rather than just as the composite device is seen. 255 */ 256 SDL_HIDAPI_discovery.m_hNotify = RegisterDeviceNotification(SDL_HIDAPI_discovery.m_hwndMsg, &devBroadcast, DEVICE_NOTIFY_WINDOW_HANDLE | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES); 257 SDL_HIDAPI_discovery.m_bCanGetNotifications = (SDL_HIDAPI_discovery.m_hNotify != 0); 258 } 259#endif // defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK) 260 261#ifdef SDL_PLATFORM_MACOS 262 SDL_HIDAPI_discovery.m_notificationPort = IONotificationPortCreate(kIOMainPortDefault); 263 if (SDL_HIDAPI_discovery.m_notificationPort) { 264 { 265 io_iterator_t portIterator = 0; 266 io_object_t entry; 267 IOReturn result = IOServiceAddMatchingNotification( 268 SDL_HIDAPI_discovery.m_notificationPort, 269 kIOFirstMatchNotification, 270 IOServiceMatching(kIOHIDDeviceKey), 271 CallbackIOServiceFunc, NULL, &portIterator); 272 273 if (result == 0) { 274 // Must drain the existing iterator, or we won't receive new notifications 275 while ((entry = IOIteratorNext(portIterator)) != 0) { 276 IOObjectRelease(entry); 277 } 278 } else { 279 IONotificationPortDestroy(SDL_HIDAPI_discovery.m_notificationPort); 280 SDL_HIDAPI_discovery.m_notificationPort = nil; 281 } 282 } 283 { 284 io_iterator_t portIterator = 0; 285 io_object_t entry; 286 IOReturn result = IOServiceAddMatchingNotification( 287 SDL_HIDAPI_discovery.m_notificationPort, 288 kIOTerminatedNotification, 289 IOServiceMatching(kIOHIDDeviceKey), 290 CallbackIOServiceFunc, NULL, &portIterator); 291 292 if (result == 0) { 293 // Must drain the existing iterator, or we won't receive new notifications 294 while ((entry = IOIteratorNext(portIterator)) != 0) { 295 IOObjectRelease(entry); 296 } 297 } else { 298 IONotificationPortDestroy(SDL_HIDAPI_discovery.m_notificationPort); 299 SDL_HIDAPI_discovery.m_notificationPort = nil; 300 } 301 } 302 } 303 304 SDL_HIDAPI_discovery.m_notificationMach = MACH_PORT_NULL; 305 if (SDL_HIDAPI_discovery.m_notificationPort) { 306 SDL_HIDAPI_discovery.m_notificationMach = IONotificationPortGetMachPort(SDL_HIDAPI_discovery.m_notificationPort); 307 } 308 309 SDL_HIDAPI_discovery.m_bCanGetNotifications = (SDL_HIDAPI_discovery.m_notificationMach != MACH_PORT_NULL); 310 311#endif // SDL_PLATFORM_MACOS 312 313#ifdef SDL_USE_LIBUDEV 314 if (linux_enumeration_method == ENUMERATION_LIBUDEV) { 315 SDL_HIDAPI_discovery.m_pUdev = NULL; 316 SDL_HIDAPI_discovery.m_pUdevMonitor = NULL; 317 SDL_HIDAPI_discovery.m_nUdevFd = -1; 318 319 usyms = SDL_UDEV_GetUdevSyms(); 320 if (usyms != NULL) { 321 SDL_HIDAPI_discovery.m_pUdev = usyms->udev_new(); 322 if (SDL_HIDAPI_discovery.m_pUdev != NULL) { 323 SDL_HIDAPI_discovery.m_pUdevMonitor = usyms->udev_monitor_new_from_netlink(SDL_HIDAPI_discovery.m_pUdev, "udev"); 324 if (SDL_HIDAPI_discovery.m_pUdevMonitor != NULL) { 325 usyms->udev_monitor_enable_receiving(SDL_HIDAPI_discovery.m_pUdevMonitor); 326 SDL_HIDAPI_discovery.m_nUdevFd = usyms->udev_monitor_get_fd(SDL_HIDAPI_discovery.m_pUdevMonitor); 327 SDL_HIDAPI_discovery.m_bCanGetNotifications = true; 328 } 329 } 330 } 331 } else 332#endif // SDL_USE_LIBUDEV 333 { 334#ifdef HAVE_INOTIFY 335 inotify_fd = SDL_inotify_init1(); 336 337 if (inotify_fd < 0) { 338 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, 339 "Unable to initialize inotify, falling back to polling: %s", 340 strerror(errno)); 341 return; 342 } 343 344 /* We need to watch for attribute changes in addition to 345 * creation, because when a device is first created, it has 346 * permissions that we can't read. When udev chmods it to 347 * something that we maybe *can* read, we'll get an 348 * IN_ATTRIB event to tell us. */ 349 if (inotify_add_watch(inotify_fd, "/dev", 350 IN_CREATE | IN_DELETE | IN_MOVE | IN_ATTRIB) < 0) { 351 close(inotify_fd); 352 inotify_fd = -1; 353 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, 354 "Unable to add inotify watch, falling back to polling: %s", 355 strerror(errno)); 356 return; 357 } 358 359 SDL_HIDAPI_discovery.m_bCanGetNotifications = true; 360#endif // HAVE_INOTIFY 361 } 362} 363 364static void HIDAPI_UpdateDiscovery(void) 365{ 366 if (!SDL_HIDAPI_discovery.m_bInitialized) { 367 HIDAPI_InitializeDiscovery(); 368 } 369 370 if (!SDL_HIDAPI_discovery.m_bCanGetNotifications) { 371 const Uint32 SDL_HIDAPI_DETECT_INTERVAL_MS = 3000; // Update every 3 seconds 372 Uint64 now = SDL_GetTicks(); 373 if (!SDL_HIDAPI_discovery.m_unLastDetect || now >= (SDL_HIDAPI_discovery.m_unLastDetect + SDL_HIDAPI_DETECT_INTERVAL_MS)) { 374 ++SDL_HIDAPI_discovery.m_unDeviceChangeCounter; 375 SDL_HIDAPI_discovery.m_unLastDetect = now; 376 } 377 return; 378 } 379 380#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK) 381#if 0 // just let the usual SDL_PumpEvents loop dispatch these, fixing bug 4286. --ryan. 382 // We'll only get messages on the same thread that created the window 383 if (SDL_GetCurrentThreadID() == SDL_HIDAPI_discovery.m_nThreadID) { 384 MSG msg; 385 while (PeekMessage(&msg, SDL_HIDAPI_discovery.m_hwndMsg, 0, 0, PM_NOREMOVE)) { 386 if (GetMessageA(&msg, SDL_HIDAPI_discovery.m_hwndMsg, 0, 0) != 0) { 387 TranslateMessage(&msg); 388 DispatchMessage(&msg); 389 } 390 } 391 } 392#endif 393#endif // defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK) 394 395#ifdef SDL_PLATFORM_MACOS 396 if (SDL_HIDAPI_discovery.m_notificationPort) { 397 struct 398 { 399 mach_msg_header_t hdr; 400 char payload[4096]; 401 } msg; 402 while (mach_msg(&msg.hdr, MACH_RCV_MSG | MACH_RCV_TIMEOUT, 0, sizeof(msg), SDL_HIDAPI_discovery.m_notificationMach, 0, MACH_PORT_NULL) == KERN_SUCCESS) { 403 IODispatchCalloutFromMessage(NULL, &msg.hdr, SDL_HIDAPI_discovery.m_notificationPort); 404 } 405 } 406#endif 407 408#ifdef SDL_USE_LIBUDEV 409 if (linux_enumeration_method == ENUMERATION_LIBUDEV) { 410 if (SDL_HIDAPI_discovery.m_nUdevFd >= 0) { 411 /* Drain all notification events. 412 * We don't expect a lot of device notifications so just 413 * do a new discovery on any kind or number of notifications. 414 * This could be made more restrictive if necessary. 415 */ 416 for (;;) { 417 struct pollfd PollUdev; 418 struct udev_device *pUdevDevice; 419 420 PollUdev.fd = SDL_HIDAPI_discovery.m_nUdevFd; 421 PollUdev.events = POLLIN; 422 if (poll(&PollUdev, 1, 0) != 1) { 423 break; 424 } 425 426 pUdevDevice = usyms->udev_monitor_receive_device(SDL_HIDAPI_discovery.m_pUdevMonitor); 427 if (pUdevDevice) { 428 const char *action = NULL; 429 action = usyms->udev_device_get_action(pUdevDevice); 430 if (action == NULL || SDL_strcmp(action, "add") == 0 || SDL_strcmp(action, "remove") == 0) { 431 ++SDL_HIDAPI_discovery.m_unDeviceChangeCounter; 432 } 433 usyms->udev_device_unref(pUdevDevice); 434 } 435 } 436 } 437 } else 438#endif // SDL_USE_LIBUDEV 439 { 440#ifdef HAVE_INOTIFY 441 if (inotify_fd >= 0) { 442 union 443 { 444 struct inotify_event event; 445 char storage[4096]; 446 char enough_for_inotify[sizeof(struct inotify_event) + NAME_MAX + 1]; 447 } buf; 448 ssize_t bytes; 449 size_t remain = 0; 450 size_t len; 451 452 bytes = read(inotify_fd, &buf, sizeof(buf)); 453 454 if (bytes > 0) { 455 remain = (size_t)bytes; 456 } 457 458 while (remain > 0) { 459 if (buf.event.len > 0) { 460 if (StrHasPrefix(buf.event.name, "hidraw") && 461 StrIsInteger(buf.event.name + SDL_strlen("hidraw"))) { 462 ++SDL_HIDAPI_discovery.m_unDeviceChangeCounter; 463 /* We found an hidraw change. We still continue to 464 * drain the inotify fd to avoid leaving old 465 * notifications in the queue. */ 466 } 467 } 468 469 len = sizeof(struct inotify_event) + buf.event.len; 470 remain -= len; 471 472 if (remain != 0) { 473 SDL_memmove(&buf.storage[0], &buf.storage[len], remain); 474 } 475 } 476 } 477#endif // HAVE_INOTIFY 478 } 479} 480 481static void HIDAPI_ShutdownDiscovery(void) 482{ 483 if (!SDL_HIDAPI_discovery.m_bInitialized) { 484 return; 485 } 486 487#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK) 488 if (SDL_HIDAPI_discovery.m_hNotify) { 489 UnregisterDeviceNotification(SDL_HIDAPI_discovery.m_hNotify); 490 } 491 492 if (SDL_HIDAPI_discovery.m_hwndMsg) { 493 DestroyWindow(SDL_HIDAPI_discovery.m_hwndMsg); 494 } 495 496 UnregisterClassA(SDL_HIDAPI_discovery.m_wndClass.lpszClassName, SDL_HIDAPI_discovery.m_wndClass.hInstance); 497#endif 498 499#ifdef SDL_PLATFORM_MACOS 500 if (SDL_HIDAPI_discovery.m_notificationPort) { 501 IONotificationPortDestroy(SDL_HIDAPI_discovery.m_notificationPort); 502 } 503#endif 504 505#ifdef SDL_USE_LIBUDEV 506 if (linux_enumeration_method == ENUMERATION_LIBUDEV) { 507 if (usyms) { 508 if (SDL_HIDAPI_discovery.m_pUdevMonitor) { 509 usyms->udev_monitor_unref(SDL_HIDAPI_discovery.m_pUdevMonitor); 510 } 511 if (SDL_HIDAPI_discovery.m_pUdev) { 512 usyms->udev_unref(SDL_HIDAPI_discovery.m_pUdev); 513 } 514 SDL_UDEV_ReleaseUdevSyms(); 515 usyms = NULL; 516 } 517 } else 518#endif // SDL_USE_LIBUDEV 519 { 520#ifdef HAVE_INOTIFY 521 if (inotify_fd >= 0) { 522 close(inotify_fd); 523 inotify_fd = -1; 524 } 525#endif 526 } 527 528 SDL_HIDAPI_discovery.m_bInitialized = false; 529} 530 531// Platform HIDAPI Implementation 532 533#define HIDAPI_USING_SDL_RUNTIME 534#define HIDAPI_IGNORE_DEVICE(BUS, VID, PID, USAGE_PAGE, USAGE) \ 535 SDL_HIDAPI_ShouldIgnoreDevice(BUS, VID, PID, USAGE_PAGE, USAGE) 536 537struct PLATFORM_hid_device_; 538typedef struct PLATFORM_hid_device_ PLATFORM_hid_device; 539 540#define api_version PLATFORM_api_version 541#define create_device_info_for_device PLATFORM_create_device_info_for_device 542#define free_hid_device PLATFORM_free_hid_device 543#define hid_close PLATFORM_hid_close 544#define hid_device PLATFORM_hid_device 545#define hid_device_ PLATFORM_hid_device_ 546#define hid_enumerate PLATFORM_hid_enumerate 547#define hid_error PLATFORM_hid_error 548#define hid_exit PLATFORM_hid_exit 549#define hid_free_enumeration PLATFORM_hid_free_enumeration 550#define hid_get_device_info PLATFORM_hid_get_device_info 551#define hid_get_feature_report PLATFORM_hid_get_feature_report 552#define hid_get_indexed_string PLATFORM_hid_get_indexed_string 553#define hid_get_input_report PLATFORM_hid_get_input_report 554#define hid_get_manufacturer_string PLATFORM_hid_get_manufacturer_string 555#define hid_get_product_string PLATFORM_hid_get_product_string 556#define hid_get_report_descriptor PLATFORM_hid_get_report_descriptor 557#define hid_get_serial_number_string PLATFORM_hid_get_serial_number_string 558#define hid_init PLATFORM_hid_init 559#define hid_open_path PLATFORM_hid_open_path 560#define hid_open PLATFORM_hid_open 561#define hid_read PLATFORM_hid_read 562#define hid_read_timeout PLATFORM_hid_read_timeout 563#define hid_send_feature_report PLATFORM_hid_send_feature_report 564#define hid_set_nonblocking PLATFORM_hid_set_nonblocking 565#define hid_version PLATFORM_hid_version 566#define hid_version_str PLATFORM_hid_version_str 567#define hid_write PLATFORM_hid_write 568#define input_report PLATFORM_input_report 569#define make_path PLATFORM_make_path 570#define new_hid_device PLATFORM_new_hid_device 571#define read_thread PLATFORM_read_thread 572#define return_data PLATFORM_return_data 573 574#ifdef SDL_PLATFORM_LINUX 575#include "SDL_hidapi_linux.h" 576#elif defined(SDL_PLATFORM_NETBSD) 577#include "SDL_hidapi_netbsd.h" 578#elif defined(SDL_PLATFORM_MACOS) 579#include "SDL_hidapi_mac.h" 580#elif defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK) 581#include "SDL_hidapi_windows.h" 582#elif defined(SDL_PLATFORM_ANDROID) 583#include "SDL_hidapi_android.h" 584#elif defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_TVOS) 585#include "SDL_hidapi_ios.h" 586#endif 587 588#undef api_version 589#undef create_device_info_for_device 590#undef free_hid_device 591#undef hid_close 592#undef hid_device 593#undef hid_device_ 594#undef hid_enumerate 595#undef hid_error 596#undef hid_exit 597#undef hid_free_enumeration 598#undef hid_get_device_info 599#undef hid_get_feature_report 600#undef hid_get_indexed_string 601#undef hid_get_input_report 602#undef hid_get_manufacturer_string 603#undef hid_get_product_string 604#undef hid_get_report_descriptor 605#undef hid_get_serial_number_string 606#undef hid_init 607#undef hid_open 608#undef hid_open_path 609#undef hid_read 610#undef hid_read_timeout 611#undef hid_send_feature_report 612#undef hid_set_nonblocking 613#undef hid_version 614#undef hid_version_str 615#undef hid_write 616#undef input_report 617#undef make_path 618#undef new_hid_device 619#undef read_thread 620#undef return_data 621 622#ifdef SDL_JOYSTICK_HIDAPI_STEAMXBOX 623#define HAVE_DRIVER_BACKEND 1 624#endif 625 626#ifdef HAVE_DRIVER_BACKEND 627 628// DRIVER HIDAPI Implementation 629 630struct DRIVER_hid_device_; 631typedef struct DRIVER_hid_device_ DRIVER_hid_device; 632 633#define hid_close DRIVER_hid_close 634#define hid_device DRIVER_hid_device 635#define hid_device_ DRIVER_hid_device_ 636#define hid_enumerate DRIVER_hid_enumerate 637#define hid_error DRIVER_hid_error 638#define hid_exit DRIVER_hid_exit 639#define hid_free_enumeration DRIVER_hid_free_enumeration 640#define hid_get_device_info DRIVER_hid_get_device_info 641#define hid_get_feature_report DRIVER_hid_get_feature_report 642#define hid_get_indexed_string DRIVER_hid_get_indexed_string 643#define hid_get_input_report DRIVER_hid_get_input_report 644#define hid_get_manufacturer_string DRIVER_hid_get_manufacturer_string 645#define hid_get_product_string DRIVER_hid_get_product_string 646#define hid_get_report_descriptor DRIVER_hid_get_report_descriptor 647#define hid_get_serial_number_string DRIVER_hid_get_serial_number_string 648#define hid_init DRIVER_hid_init 649#define hid_open DRIVER_hid_open 650#define hid_open_path DRIVER_hid_open_path 651#define hid_read DRIVER_hid_read 652#define hid_read_timeout DRIVER_hid_read_timeout 653#define hid_send_feature_report DRIVER_hid_send_feature_report 654#define hid_set_nonblocking DRIVER_hid_set_nonblocking 655#define hid_write DRIVER_hid_write 656 657#ifdef SDL_JOYSTICK_HIDAPI_STEAMXBOX 658#include "SDL_hidapi_steamxbox.h" 659#else 660#error Need a driver hid.c for this platform! 661#endif 662 663#undef hid_close 664#undef hid_device 665#undef hid_device_ 666#undef hid_enumerate 667#undef hid_error 668#undef hid_exit 669#undef hid_free_enumeration 670#undef hid_get_device_info 671#undef hid_get_feature_report 672#undef hid_get_indexed_string 673#undef hid_get_input_report 674#undef hid_get_manufacturer_string 675#undef hid_get_product_string 676#undef hid_get_report_descriptor 677#undef hid_get_serial_number_string 678#undef hid_init 679#undef hid_open 680#undef hid_open_path 681#undef hid_read 682#undef hid_read_timeout 683#undef hid_send_feature_report 684#undef hid_set_nonblocking 685#undef hid_write 686 687#endif // HAVE_DRIVER_BACKEND 688 689#ifdef HAVE_LIBUSB 690// libusb HIDAPI Implementation 691 692// Include this now, for our dynamically-loaded libusb context 693#include <libusb.h> 694 695static struct 696{ 697 SDL_SharedObject *libhandle; 698 699 /* *INDENT-OFF* */ // clang-format off 700 int (LIBUSB_CALL *init)(libusb_context **ctx); 701 void (LIBUSB_CALL *exit)(libusb_context *ctx); 702 ssize_t (LIBUSB_CALL *get_device_list)(libusb_context *ctx, libusb_device ***list); 703 void (LIBUSB_CALL *free_device_list)(libusb_device **list, int unref_devices); 704 int (LIBUSB_CALL *get_device_descriptor)(libusb_device *dev, struct libusb_device_descriptor *desc); 705 int (LIBUSB_CALL *get_active_config_descriptor)(libusb_device *dev, struct libusb_config_descriptor **config); 706 int (LIBUSB_CALL *get_config_descriptor)( 707 libusb_device *dev, 708 uint8_t config_index, 709 struct libusb_config_descriptor **config 710 ); 711 void (LIBUSB_CALL *free_config_descriptor)(struct libusb_config_descriptor *config); 712 uint8_t (LIBUSB_CALL *get_bus_number)(libusb_device *dev); 713 int (LIBUSB_CALL *get_port_numbers)(libusb_device *dev, uint8_t *port_numbers, int port_numbers_len); 714 uint8_t (LIBUSB_CALL *get_device_address)(libusb_device *dev); 715 int (LIBUSB_CALL *open)(libusb_device *dev, libusb_device_handle **dev_handle); 716 void (LIBUSB_CALL *close)(libusb_device_handle *dev_handle); 717 libusb_device *(LIBUSB_CALL *get_device)(libusb_device_handle *dev_handle); 718 int (LIBUSB_CALL *claim_interface)(libusb_device_handle *dev_handle, int interface_number); 719 int (LIBUSB_CALL *release_interface)(libusb_device_handle *dev_handle, int interface_number); 720 int (LIBUSB_CALL *kernel_driver_active)(libusb_device_handle *dev_handle, int interface_number); 721 int (LIBUSB_CALL *detach_kernel_driver)(libusb_device_handle *dev_handle, int interface_number); 722 int (LIBUSB_CALL *attach_kernel_driver)(libusb_device_handle *dev_handle, int interface_number); 723 int (LIBUSB_CALL *set_interface_alt_setting)(libusb_device_handle *dev, int interface_number, int alternate_setting); 724 struct libusb_transfer * (LIBUSB_CALL *alloc_transfer)(int iso_packets); 725 int (LIBUSB_CALL *submit_transfer)(struct libusb_transfer *transfer); 726 int (LIBUSB_CALL *cancel_transfer)(struct libusb_transfer *transfer); 727 void (LIBUSB_CALL *free_transfer)(struct libusb_transfer *transfer); 728 int (LIBUSB_CALL *control_transfer)( 729 libusb_device_handle *dev_handle, 730 uint8_t request_type, 731 uint8_t bRequest, 732 uint16_t wValue, 733 uint16_t wIndex, 734 unsigned char *data, 735 uint16_t wLength, 736 unsigned int timeout 737 ); 738 int (LIBUSB_CALL *interrupt_transfer)( 739 libusb_device_handle *dev_handle, 740 unsigned char endpoint, 741 unsigned char *data, 742 int length, 743 int *actual_length, 744 unsigned int timeout 745 ); 746 int (LIBUSB_CALL *handle_events)(libusb_context *ctx); 747 int (LIBUSB_CALL *handle_events_completed)(libusb_context *ctx, int *completed); 748 const char * (LIBUSB_CALL *error_name)(int errcode); 749/* *INDENT-ON* */ // clang-format on 750 751} libusb_ctx; 752 753#define libusb_init libusb_ctx.init 754#define libusb_exit libusb_ctx.exit 755#define libusb_get_device_list libusb_ctx.get_device_list 756#define libusb_free_device_list libusb_ctx.free_device_list 757#define libusb_get_device_descriptor libusb_ctx.get_device_descriptor 758#define libusb_get_active_config_descriptor libusb_ctx.get_active_config_descriptor 759#define libusb_get_config_descriptor libusb_ctx.get_config_descriptor 760#define libusb_free_config_descriptor libusb_ctx.free_config_descriptor 761#define libusb_get_bus_number libusb_ctx.get_bus_number 762#define libusb_get_port_numbers libusb_ctx.get_port_numbers 763#define libusb_get_device_address libusb_ctx.get_device_address 764#define libusb_open libusb_ctx.open 765#define libusb_close libusb_ctx.close 766#define libusb_get_device libusb_ctx.get_device 767#define libusb_claim_interface libusb_ctx.claim_interface 768#define libusb_release_interface libusb_ctx.release_interface 769#define libusb_kernel_driver_active libusb_ctx.kernel_driver_active 770#define libusb_detach_kernel_driver libusb_ctx.detach_kernel_driver 771#define libusb_attach_kernel_driver libusb_ctx.attach_kernel_driver 772#define libusb_set_interface_alt_setting libusb_ctx.set_interface_alt_setting 773#define libusb_alloc_transfer libusb_ctx.alloc_transfer 774#define libusb_submit_transfer libusb_ctx.submit_transfer 775#define libusb_cancel_transfer libusb_ctx.cancel_transfer 776#define libusb_free_transfer libusb_ctx.free_transfer 777#define libusb_control_transfer libusb_ctx.control_transfer 778#define libusb_interrupt_transfer libusb_ctx.interrupt_transfer 779#define libusb_handle_events libusb_ctx.handle_events 780#define libusb_handle_events_completed libusb_ctx.handle_events_completed 781#define libusb_error_name libusb_ctx.error_name 782 783struct LIBUSB_hid_device_; 784typedef struct LIBUSB_hid_device_ LIBUSB_hid_device; 785 786#define free_hid_device LIBUSB_free_hid_device 787#define hid_close LIBUSB_hid_close 788#define hid_device LIBUSB_hid_device 789#define hid_device_ LIBUSB_hid_device_ 790#define hid_enumerate LIBUSB_hid_enumerate 791#define hid_error LIBUSB_hid_error 792#define hid_exit LIBUSB_hid_exit 793#define hid_free_enumeration LIBUSB_hid_free_enumeration 794#define hid_get_device_info LIBUSB_hid_get_device_info 795#define hid_get_feature_report LIBUSB_hid_get_feature_report 796#define hid_get_indexed_string LIBUSB_hid_get_indexed_string 797#define hid_get_input_report LIBUSB_hid_get_input_report 798#define hid_get_manufacturer_string LIBUSB_hid_get_manufacturer_string 799#define hid_get_product_string LIBUSB_hid_get_product_string 800#define hid_get_report_descriptor LIBUSB_hid_get_report_descriptor 801#define hid_get_serial_number_string LIBUSB_hid_get_serial_number_string 802#define hid_init LIBUSB_hid_init 803#define hid_open LIBUSB_hid_open 804#define hid_open_path LIBUSB_hid_open_path 805#define hid_read LIBUSB_hid_read 806#define hid_read_timeout LIBUSB_hid_read_timeout 807#define hid_send_feature_report LIBUSB_hid_send_feature_report 808#define hid_set_nonblocking LIBUSB_hid_set_nonblocking 809#define hid_write LIBUSB_hid_write 810#define input_report LIBUSB_input_report 811#define make_path LIBUSB_make_path 812#define new_hid_device LIBUSB_new_hid_device 813#define read_thread LIBUSB_read_thread 814#define return_data LIBUSB_return_data 815 816#include "SDL_hidapi_libusb.h" 817 818#undef libusb_init 819#undef libusb_exit 820#undef libusb_get_device_list 821#undef libusb_free_device_list 822#undef libusb_get_device_descriptor 823#undef libusb_get_active_config_descriptor 824#undef libusb_get_config_descriptor 825#undef libusb_free_config_descriptor 826#undef libusb_get_bus_number 827#undef libusb_get_port_numbers 828#undef libusb_get_device_address 829#undef libusb_open 830#undef libusb_close 831#undef libusb_get_device 832#undef libusb_claim_interface 833#undef libusb_release_interface 834#undef libusb_kernel_driver_active 835#undef libusb_detach_kernel_driver 836#undef libusb_attach_kernel_driver 837#undef libusb_set_interface_alt_setting 838#undef libusb_alloc_transfer 839#undef libusb_submit_transfer 840#undef libusb_cancel_transfer 841#undef libusb_free_transfer 842#undef libusb_control_transfer 843#undef libusb_interrupt_transfer 844#undef libusb_handle_events 845#undef libusb_handle_events_completed 846#undef libusb_error_name 847 848#undef free_hid_device 849#undef hid_close 850#undef hid_device 851#undef hid_device_ 852#undef hid_enumerate 853#undef hid_error 854#undef hid_exit 855#undef hid_free_enumeration 856#undef hid_get_device_info 857#undef hid_get_feature_report 858#undef hid_get_indexed_string 859#undef hid_get_input_report 860#undef hid_get_manufacturer_string 861#undef hid_get_product_string 862#undef hid_get_report_descriptor 863#undef hid_get_serial_number_string 864#undef hid_init 865#undef hid_open 866#undef hid_open_path 867#undef hid_read 868#undef hid_read_timeout 869#undef hid_send_feature_report 870#undef hid_set_nonblocking 871#undef hid_write 872#undef input_report 873#undef make_path 874#undef new_hid_device 875#undef read_thread 876#undef return_data 877 878/* If the platform has any backend other than libusb, try to avoid using 879 * libusb as the main backend for devices, since it detaches drivers and 880 * therefore makes devices inaccessible to the rest of the OS. 881 * 882 * We do this by whitelisting devices we know to be accessible _exclusively_ 883 * via libusb; these are typically devices that look like HIDs but have a 884 * quirk that requires direct access to the hardware. 885 */ 886static const struct { 887 Uint16 vendor; 888 Uint16 product; 889} SDL_libusb_whitelist[] = { 890 { 0x057e, 0x0337 } // Nintendo WUP-028, Wii U/Switch GameCube Adapter 891}; 892 893static bool IsInWhitelist(Uint16 vendor, Uint16 product) 894{ 895 int i; 896 for (i = 0; i < SDL_arraysize(SDL_libusb_whitelist); i += 1) { 897 if (vendor == SDL_libusb_whitelist[i].vendor && 898 product == SDL_libusb_whitelist[i].product) { 899 return true; 900 } 901 } 902 return false; 903} 904 905#endif // HAVE_LIBUSB 906 907#endif // !SDL_HIDAPI_DISABLED 908 909#if defined(HAVE_PLATFORM_BACKEND) || defined(HAVE_DRIVER_BACKEND) 910// We have another way to get HID devices, so use the whitelist to get devices where libusb is preferred 911#define SDL_HINT_HIDAPI_LIBUSB_WHITELIST_DEFAULT true 912#else 913// libusb is the only way to get HID devices, so don't use the whitelist, get them all 914#define SDL_HINT_HIDAPI_LIBUSB_WHITELIST_DEFAULT false 915#endif // HAVE_PLATFORM_BACKEND || HAVE_DRIVER_BACKEND 916 917static bool use_libusb_whitelist = SDL_HINT_HIDAPI_LIBUSB_WHITELIST_DEFAULT; 918 919// Shared HIDAPI Implementation 920 921struct hidapi_backend 922{ 923 int (*hid_write)(void *device, const unsigned char *data, size_t length); 924 int (*hid_read_timeout)(void *device, unsigned char *data, size_t length, int milliseconds); 925 int (*hid_read)(void *device, unsigned char *data, size_t length); 926 int (*hid_set_nonblocking)(void *device, int nonblock); 927 int (*hid_send_feature_report)(void *device, const unsigned char *data, size_t length); 928 int (*hid_get_feature_report)(void *device, unsigned char *data, size_t length); 929 int (*hid_get_input_report)(void *device, unsigned char *data, size_t length); 930 void (*hid_close)(void *device); 931 int (*hid_get_manufacturer_string)(void *device, wchar_t *string, size_t maxlen); 932 int (*hid_get_product_string)(void *device, wchar_t *string, size_t maxlen); 933 int (*hid_get_serial_number_string)(void *device, wchar_t *string, size_t maxlen); 934 int (*hid_get_indexed_string)(void *device, int string_index, wchar_t *string, size_t maxlen); 935 struct hid_device_info *(*hid_get_device_info)(void *device); 936 int (*hid_get_report_descriptor)(void *device, unsigned char *buf, size_t buf_size); 937 const wchar_t *(*hid_error)(void *device); 938}; 939 940#ifdef HAVE_PLATFORM_BACKEND 941static const struct hidapi_backend PLATFORM_Backend = { 942 (void *)PLATFORM_hid_write, 943 (void *)PLATFORM_hid_read_timeout, 944 (void *)PLATFORM_hid_read, 945 (void *)PLATFORM_hid_set_nonblocking, 946 (void *)PLATFORM_hid_send_feature_report, 947 (void *)PLATFORM_hid_get_feature_report, 948 (void *)PLATFORM_hid_get_input_report, 949 (void *)PLATFORM_hid_close, 950 (void *)PLATFORM_hid_get_manufacturer_string, 951 (void *)PLATFORM_hid_get_product_string, 952 (void *)PLATFORM_hid_get_serial_number_string, 953 (void *)PLATFORM_hid_get_indexed_string, 954 (void *)PLATFORM_hid_get_device_info, 955 (void *)PLATFORM_hid_get_report_descriptor, 956 (void *)PLATFORM_hid_error 957}; 958#endif // HAVE_PLATFORM_BACKEND 959 960#ifdef HAVE_DRIVER_BACKEND 961static const struct hidapi_backend DRIVER_Backend = { 962 (void *)DRIVER_hid_write, 963 (void *)DRIVER_hid_read_timeout, 964 (void *)DRIVER_hid_read, 965 (void *)DRIVER_hid_set_nonblocking, 966 (void *)DRIVER_hid_send_feature_report, 967 (void *)DRIVER_hid_get_feature_report, 968 (void *)DRIVER_hid_get_input_report, 969 (void *)DRIVER_hid_close, 970 (void *)DRIVER_hid_get_manufacturer_string, 971 (void *)DRIVER_hid_get_product_string, 972 (void *)DRIVER_hid_get_serial_number_string, 973 (void *)DRIVER_hid_get_indexed_string, 974 (void *)DRIVER_hid_get_device_info, 975 (void *)DRIVER_hid_get_report_descriptor, 976 (void *)DRIVER_hid_error 977}; 978#endif // HAVE_DRIVER_BACKEND 979 980#ifdef HAVE_LIBUSB 981static const struct hidapi_backend LIBUSB_Backend = { 982 (void *)LIBUSB_hid_write, 983 (void *)LIBUSB_hid_read_timeout, 984 (void *)LIBUSB_hid_read, 985 (void *)LIBUSB_hid_set_nonblocking, 986 (void *)LIBUSB_hid_send_feature_report, 987 (void *)LIBUSB_hid_get_feature_report, 988 (void *)LIBUSB_hid_get_input_report, 989 (void *)LIBUSB_hid_close, 990 (void *)LIBUSB_hid_get_manufacturer_string, 991 (void *)LIBUSB_hid_get_product_string, 992 (void *)LIBUSB_hid_get_serial_number_string, 993 (void *)LIBUSB_hid_get_indexed_string, 994 (void *)LIBUSB_hid_get_device_info, 995 (void *)LIBUSB_hid_get_report_descriptor, 996 (void *)LIBUSB_hid_error 997}; 998#endif // HAVE_LIBUSB 999 1000struct SDL_hid_device 1001{ 1002 void *device; 1003 const struct hidapi_backend *backend; 1004 SDL_hid_device_info info; 1005}; 1006 1007#if defined(HAVE_PLATFORM_BACKEND) || defined(HAVE_DRIVER_BACKEND) || defined(HAVE_LIBUSB) 1008 1009static SDL_hid_device *CreateHIDDeviceWrapper(void *device, const struct hidapi_backend *backend) 1010{ 1011 SDL_hid_device *wrapper = (SDL_hid_device *)SDL_malloc(sizeof(*wrapper)); 1012 SDL_SetObjectValid(wrapper, SDL_OBJECT_TYPE_HIDAPI_DEVICE, true); 1013 wrapper->device = device; 1014 wrapper->backend = backend; 1015 SDL_zero(wrapper->info); 1016 return wrapper; 1017} 1018 1019#endif // HAVE_PLATFORM_BACKEND || HAVE_DRIVER_BACKEND || HAVE_LIBUSB 1020 1021static void DeleteHIDDeviceWrapper(SDL_hid_device *wrapper) 1022{ 1023 SDL_SetObjectValid(wrapper, SDL_OBJECT_TYPE_HIDAPI_DEVICE, false); 1024 SDL_free(wrapper->info.path); 1025 SDL_free(wrapper->info.serial_number); 1026 SDL_free(wrapper->info.manufacturer_string); 1027 SDL_free(wrapper->info.product_string); 1028 SDL_free(wrapper); 1029} 1030 1031#define CHECK_DEVICE_MAGIC(device, result) \ 1032 if (!SDL_ObjectValid(device, SDL_OBJECT_TYPE_HIDAPI_DEVICE)) { \ 1033 SDL_SetError("Invalid device"); \ 1034 return result; \ 1035 } 1036 1037#define COPY_IF_EXISTS(var) \ 1038 if (pSrc->var != NULL) { \ 1039 pDst->var = SDL_strdup(pSrc->var); \ 1040 } else { \ 1041 pDst->var = NULL; \ 1042 } 1043#define WCOPY_IF_EXISTS(var) \ 1044 if (pSrc->var != NULL) { \ 1045 pDst->var = SDL_wcsdup(pSrc->var); \ 1046 } else { \ 1047 pDst->var = NULL; \ 1048 } 1049 1050static void CopyHIDDeviceInfo(struct hid_device_info *pSrc, struct SDL_hid_device_info *pDst) 1051{ 1052 COPY_IF_EXISTS(path) 1053 pDst->vendor_id = pSrc->vendor_id; 1054 pDst->product_id = pSrc->product_id; 1055 WCOPY_IF_EXISTS(serial_number) 1056 pDst->release_number = pSrc->release_number; 1057 WCOPY_IF_EXISTS(manufacturer_string) 1058 WCOPY_IF_EXISTS(product_string) 1059 pDst->usage_page = pSrc->usage_page; 1060 pDst->usage = pSrc->usage; 1061 pDst->interface_number = pSrc->interface_number; 1062 pDst->interface_class = pSrc->interface_class; 1063 pDst->interface_subclass = pSrc->interface_subclass; 1064 pDst->interface_protocol = pSrc->interface_protocol; 1065 pDst->bus_type = (SDL_hid_bus_type)pSrc->bus_type; 1066 pDst->next = NULL; 1067} 1068 1069#undef COPY_IF_EXISTS 1070#undef WCOPY_IF_EXISTS 1071 1072static int SDL_hidapi_refcount = 0; 1073static bool SDL_hidapi_only_controllers; 1074static char *SDL_hidapi_ignored_devices = NULL; 1075 1076static void SDLCALL OnlyControllersChanged(void *userdata, const char *name, const char *oldValue, const char *hint) 1077{ 1078 SDL_hidapi_only_controllers = SDL_GetStringBoolean(hint, true); 1079} 1080 1081static void SDLCALL IgnoredDevicesChanged(void *userdata, const char *name, const char *oldValue, const char *hint) 1082{ 1083 if (SDL_hidapi_ignored_devices) { 1084 SDL_free(SDL_hidapi_ignored_devices); 1085 } 1086 if (hint && *hint) { 1087 SDL_hidapi_ignored_devices = SDL_strdup(hint); 1088 } else { 1089 SDL_hidapi_ignored_devices = NULL; 1090 } 1091} 1092 1093bool SDL_HIDAPI_ShouldIgnoreDevice(int bus, Uint16 vendor_id, Uint16 product_id, Uint16 usage_page, Uint16 usage) 1094{ 1095 // See if there are any devices we should skip in enumeration 1096 if (SDL_hidapi_only_controllers && usage_page) { 1097 if (vendor_id == USB_VENDOR_VALVE) { 1098 // Ignore the mouse/keyboard interface on Steam Controllers 1099 if ( 1100#ifdef SDL_PLATFORM_WIN32 1101 // Check the usage page and usage on both USB and Bluetooth 1102#else 1103 // Only check the usage page and usage on USB 1104 bus == HID_API_BUS_USB && 1105#endif 1106 usage_page == USB_USAGEPAGE_GENERIC_DESKTOP && 1107 (usage == USB_USAGE_GENERIC_KEYBOARD || usage == USB_USAGE_GENERIC_MOUSE)) { 1108 return true; 1109 } 1110 } else if (usage_page == USB_USAGEPAGE_GENERIC_DESKTOP && 1111 (usage == USB_USAGE_GENERIC_JOYSTICK || usage == USB_USAGE_GENERIC_GAMEPAD || usage == USB_USAGE_GENERIC_MULTIAXISCONTROLLER)) { 1112 // This is a controller 1113 } else { 1114 return true; 1115 } 1116 } 1117 if (SDL_hidapi_ignored_devices) { 1118 char vendor_match[16], product_match[16]; 1119 SDL_snprintf(vendor_match, sizeof(vendor_match), "0x%.4x/0x0000", vendor_id); 1120 SDL_snprintf(product_match, sizeof(product_match), "0x%.4x/0x%.4x", vendor_id, product_id); 1121 if (SDL_strcasestr(SDL_hidapi_ignored_devices, vendor_match) || 1122 SDL_strcasestr(SDL_hidapi_ignored_devices, product_match)) { 1123 return true; 1124 } 1125 } 1126 return false; 1127} 1128 1129int SDL_hid_init(void) 1130{ 1131 int attempts = 0, success = 0; 1132 1133 if (SDL_hidapi_refcount > 0) { 1134 ++SDL_hidapi_refcount; 1135 return 0; 1136 } 1137 1138 SDL_AddHintCallback(SDL_HINT_HIDAPI_ENUMERATE_ONLY_CONTROLLERS, OnlyControllersChanged, NULL); 1139 SDL_AddHintCallback(SDL_HINT_HIDAPI_IGNORE_DEVICES, IgnoredDevicesChanged, NULL); 1140 1141#ifdef SDL_USE_LIBUDEV 1142 if (!SDL_GetHintBoolean(SDL_HINT_HIDAPI_UDEV, true)) { 1143 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, 1144 "udev disabled by SDL_HINT_HIDAPI_UDEV"); 1145 linux_enumeration_method = ENUMERATION_FALLBACK; 1146 } else if (SDL_GetSandbox() != SDL_SANDBOX_NONE) { 1147 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, 1148 "Container detected, disabling HIDAPI udev integration"); 1149 linux_enumeration_method = ENUMERATION_FALLBACK; 1150 } else { 1151 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, 1152 "Using udev for HIDAPI joystick device discovery"); 1153 linux_enumeration_method = ENUMERATION_LIBUDEV; 1154 } 1155#endif 1156 1157 use_libusb_whitelist = SDL_GetHintBoolean(SDL_HINT_HIDAPI_LIBUSB_WHITELIST, 1158 SDL_HINT_HIDAPI_LIBUSB_WHITELIST_DEFAULT); 1159#ifdef HAVE_LIBUSB 1160 if (!SDL_GetHintBoolean(SDL_HINT_HIDAPI_LIBUSB, true)) { 1161 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, 1162 "libusb disabled with SDL_HINT_HIDAPI_LIBUSB"); 1163 libusb_ctx.libhandle = NULL; 1164 } else { 1165 ++attempts; 1166#ifdef SDL_LIBUSB_DYNAMIC 1167 libusb_ctx.libhandle = SDL_LoadObject(SDL_LIBUSB_DYNAMIC); 1168#else 1169 libusb_ctx.libhandle = (void *)1; 1170#endif 1171 if (libusb_ctx.libhandle != NULL) { 1172 bool loaded = true; 1173#ifdef SDL_LIBUSB_DYNAMIC 1174#define LOAD_LIBUSB_SYMBOL(type, func) \ 1175 if (!(libusb_ctx.func = (type)SDL_LoadFunction(libusb_ctx.libhandle, "libusb_" #func))) { \ 1176 loaded = false; \ 1177 } 1178#else 1179#define LOAD_LIBUSB_SYMBOL(type, func) \ 1180 libusb_ctx.func = libusb_##func; 1181#endif 1182 LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_context **), init) 1183 LOAD_LIBUSB_SYMBOL(void (LIBUSB_CALL *)(libusb_context *), exit) 1184 LOAD_LIBUSB_SYMBOL(ssize_t (LIBUSB_CALL *)(libusb_context *, libusb_device ***), get_device_list) 1185 LOAD_LIBUSB_SYMBOL(void (LIBUSB_CALL *)(libusb_device **, int), free_device_list) 1186 LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_device *, struct libusb_device_descriptor *), get_device_descriptor) 1187 LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_device *, struct libusb_config_descriptor **), get_active_config_descriptor) 1188 LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_device *, uint8_t, struct libusb_config_descriptor **), get_config_descriptor) 1189 LOAD_LIBUSB_SYMBOL(void (LIBUSB_CALL *)(struct libusb_config_descriptor *), free_config_descriptor) 1190 LOAD_LIBUSB_SYMBOL(uint8_t (LIBUSB_CALL *)(libusb_device *), get_bus_number) 1191 LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_device *dev, uint8_t *port_numbers, int port_numbers_len), get_port_numbers) 1192 LOAD_LIBUSB_SYMBOL(uint8_t (LIBUSB_CALL *)(libusb_device *), get_device_address) 1193 LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_device *, libusb_device_handle **), open) 1194 LOAD_LIBUSB_SYMBOL(void (LIBUSB_CALL *)(libusb_device_handle *), close) 1195 LOAD_LIBUSB_SYMBOL(libusb_device * (LIBUSB_CALL *)(libusb_device_handle *dev_handle), get_device) 1196 LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_device_handle *, int), claim_interface) 1197 LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_device_handle *, int), release_interface) 1198 LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_device_handle *, int), kernel_driver_active) 1199 LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_device_handle *, int), detach_kernel_driver) 1200 LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_device_handle *, int), attach_kernel_driver) 1201 LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_device_handle *, int, int), set_interface_alt_setting) 1202 LOAD_LIBUSB_SYMBOL(struct libusb_transfer * (LIBUSB_CALL *)(int), alloc_transfer) 1203 LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(struct libusb_transfer *), submit_transfer) 1204 LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(struct libusb_transfer *), cancel_transfer) 1205 LOAD_LIBUSB_SYMBOL(void (LIBUSB_CALL *)(struct libusb_transfer *), free_transfer) 1206 LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_device_handle *, uint8_t, uint8_t, uint16_t, uint16_t, unsigned char *, uint16_t, unsigned int), control_transfer) 1207 LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_device_handle *, unsigned char, unsigned char *, int, int *, unsigned int), interrupt_transfer) 1208 LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_context *), handle_events) 1209 LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_context *, int *), handle_events_completed) 1210 LOAD_LIBUSB_SYMBOL(const char * (LIBUSB_CALL *)(int), error_name) 1211#undef LOAD_LIBUSB_SYMBOL 1212 1213 if (!loaded) { 1214#ifdef SDL_LIBUSB_DYNAMIC 1215 SDL_UnloadObject(libusb_ctx.libhandle); 1216#endif 1217 libusb_ctx.libhandle = NULL; 1218 // SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, SDL_LIBUSB_DYNAMIC " found but could not load function"); 1219 } else if (LIBUSB_hid_init() < 0) { 1220#ifdef SDL_LIBUSB_DYNAMIC 1221 SDL_UnloadObject(libusb_ctx.libhandle); 1222#endif 1223 libusb_ctx.libhandle = NULL; 1224 } else { 1225 ++success; 1226 } 1227 } 1228 } 1229#endif // HAVE_LIBUSB 1230 1231#ifdef HAVE_PLATFORM_BACKEND 1232 ++attempts; 1233#ifdef SDL_PLATFORM_LINUX 1234 udev_ctx = SDL_UDEV_GetUdevSyms(); 1235#endif // __LINUX __ 1236 if (udev_ctx && PLATFORM_hid_init() == 0) { 1237 ++success; 1238 } 1239#endif // HAVE_PLATFORM_BACKEND 1240 1241 if (attempts > 0 && success == 0) { 1242 return -1; 1243 } 1244 1245#if defined(SDL_PLATFORM_MACOS) && !defined(SDL_HIDAPI_DISABLED) 1246 hid_darwin_set_open_exclusive(0); 1247#endif 1248 1249 ++SDL_hidapi_refcount; 1250 return 0; 1251} 1252 1253int SDL_hid_exit(void) 1254{ 1255 int result = 0; 1256 1257 if (SDL_hidapi_refcount == 0) { 1258 return 0; 1259 } 1260 --SDL_hidapi_refcount; 1261 if (SDL_hidapi_refcount > 0) { 1262 return 0; 1263 } 1264 SDL_hidapi_refcount = 0; 1265 1266#ifndef SDL_HIDAPI_DISABLED 1267 HIDAPI_ShutdownDiscovery(); 1268#endif 1269 1270#ifdef HAVE_PLATFORM_BACKEND 1271 if (udev_ctx) { 1272 result |= PLATFORM_hid_exit(); 1273 } 1274#ifdef SDL_PLATFORM_LINUX 1275 SDL_UDEV_ReleaseUdevSyms(); 1276#endif // __LINUX __ 1277#endif // HAVE_PLATFORM_BACKEND 1278 1279#ifdef HAVE_LIBUSB 1280 if (libusb_ctx.libhandle) { 1281 result |= LIBUSB_hid_exit(); 1282#ifdef SDL_LIBUSB_DYNAMIC 1283 SDL_UnloadObject(libusb_ctx.libhandle); 1284#endif 1285 libusb_ctx.libhandle = NULL; 1286 } 1287#endif // HAVE_LIBUSB 1288 1289 SDL_RemoveHintCallback(SDL_HINT_HIDAPI_ENUMERATE_ONLY_CONTROLLERS, OnlyControllersChanged, NULL); 1290 SDL_RemoveHintCallback(SDL_HINT_HIDAPI_IGNORE_DEVICES, IgnoredDevicesChanged, NULL); 1291 1292 if (SDL_hidapi_ignored_devices) { 1293 SDL_free(SDL_hidapi_ignored_devices); 1294 SDL_hidapi_ignored_devices = NULL; 1295 } 1296 1297 return result; 1298} 1299 1300Uint32 SDL_hid_device_change_count(void) 1301{ 1302 Uint32 counter = 0; 1303 1304#ifndef SDL_HIDAPI_DISABLED 1305 if (SDL_hidapi_refcount == 0 && SDL_hid_init() < 0) { 1306 return 0; 1307 } 1308 1309 HIDAPI_UpdateDiscovery(); 1310 1311 if (SDL_HIDAPI_discovery.m_unDeviceChangeCounter == 0) { 1312 // Counter wrapped! 1313 ++SDL_HIDAPI_discovery.m_unDeviceChangeCounter; 1314 } 1315 counter = SDL_HIDAPI_discovery.m_unDeviceChangeCounter; 1316 1317#endif // !SDL_HIDAPI_DISABLED 1318 1319 return counter; 1320} 1321 1322static void AddDeviceToEnumeration(const char *driver_name, struct hid_device_info *dev, struct SDL_hid_device_info **devs, struct SDL_hid_device_info **last) 1323{ 1324 struct SDL_hid_device_info *new_dev; 1325 1326#ifdef DEBUG_HIDAPI 1327 SDL_Log("Adding %s device to enumeration: %ls %ls 0x%.4hx/0x%.4hx/%d", 1328 driver_name, dev->manufacturer_string, dev->product_string, dev->vendor_id, dev->product_id, dev->interface_number); 1329#else 1330 (void)driver_name; 1331#endif 1332 1333 new_dev = (struct SDL_hid_device_info *)SDL_malloc(sizeof(struct SDL_hid_device_info)); 1334 if (new_dev == NULL) { 1335 // Don't bother returning an error, get as many devices as possible 1336 return; 1337 } 1338 CopyHIDDeviceInfo(dev, new_dev); 1339 1340 if ((*last) != NULL) { 1341 (*last)->next = new_dev; 1342 } else { 1343 *devs = new_dev; 1344 } 1345 *last = new_dev; 1346} 1347 1348#if defined(HAVE_LIBUSB) || defined(HAVE_PLATFORM_BACKEND) 1349static void RemoveDeviceFromEnumeration(const char *driver_name, struct hid_device_info *dev, struct hid_device_info **devs, void (*free_device_info)(struct hid_device_info *)) 1350{ 1351 struct hid_device_info *last = NULL, *curr, *next; 1352 1353 for (curr = *devs; curr; curr = next) { 1354 next = curr->next; 1355 1356 if (dev->vendor_id == curr->vendor_id && 1357 dev->product_id == curr->product_id && 1358 (dev->interface_number < 0 || curr->interface_number < 0 || dev->interface_number == curr->interface_number)) { 1359#ifdef DEBUG_HIDAPI 1360 SDL_Log("Skipping %s device: %ls %ls 0x%.4hx/0x%.4hx/%d", 1361 driver_name, curr->manufacturer_string, curr->product_string, curr->vendor_id, curr->product_id, curr->interface_number); 1362#else 1363 (void)driver_name; 1364#endif 1365 if (last) { 1366 last->next = next; 1367 } else { 1368 *devs = next; 1369 } 1370 1371 curr->next = NULL; 1372 free_device_info(curr); 1373 continue; 1374 } 1375 last = curr; 1376 } 1377} 1378#endif // HAVE_LIBUSB || HAVE_PLATFORM_BACKEND 1379 1380#ifdef HAVE_LIBUSB 1381static void RemoveNonWhitelistedDevicesFromEnumeration(struct hid_device_info **devs, void (*free_device_info)(struct hid_device_info *)) 1382{ 1383 struct hid_device_info *last = NULL, *curr, *next; 1384 1385 for (curr = *devs; curr; curr = next) { 1386 next = curr->next; 1387 1388 if (!IsInWhitelist(curr->vendor_id, curr->product_id)) { 1389#ifdef DEBUG_HIDAPI 1390 SDL_Log("Device was not in libusb whitelist, skipping: %ls %ls 0x%.4hx/0x%.4hx/%d", 1391 curr->manufacturer_string, curr->product_string, curr->vendor_id, curr->product_id, curr->interface_number); 1392#endif 1393 if (last) { 1394 last->next = next; 1395 } else { 1396 *devs = next; 1397 } 1398 1399 curr->next = NULL; 1400 free_device_info(curr); 1401 continue; 1402 } 1403 last = curr; 1404 } 1405} 1406#endif // HAVE_LIBUSB 1407 1408struct SDL_hid_device_info *SDL_hid_enumerate(unsigned short vendor_id, unsigned short product_id) 1409{ 1410 struct hid_device_info *driver_devs = NULL; 1411 struct hid_device_info *usb_devs = NULL; 1412 struct hid_device_info *raw_devs = NULL; 1413 struct hid_device_info *dev; 1414 struct SDL_hid_device_info *devs = NULL, *last = NULL; 1415 1416 if (SDL_hidapi_refcount == 0 && SDL_hid_init() < 0) { 1417 return NULL; 1418 } 1419 1420 // Collect the available devices 1421#ifdef HAVE_DRIVER_BACKEND 1422 driver_devs = DRIVER_hid_enumerate(vendor_id, product_id); 1423#endif 1424 1425#ifdef HAVE_LIBUSB 1426 if (libusb_ctx.libhandle) { 1427 usb_devs = LIBUSB_hid_enumerate(vendor_id, product_id); 1428 1429 if (use_libusb_whitelist) { 1430 RemoveNonWhitelistedDevicesFromEnumeration(&usb_devs, LIBUSB_hid_free_enumeration); 1431 } 1432 } 1433#endif // HAVE_LIBUSB 1434 1435#ifdef HAVE_PLATFORM_BACKEND 1436 if (udev_ctx) { 1437 raw_devs = PLATFORM_hid_enumerate(vendor_id, product_id); 1438 } 1439#endif 1440 1441 // Highest priority are custom driver devices 1442 for (dev = driver_devs; dev; dev = dev->next) { 1443 AddDeviceToEnumeration("driver", dev, &devs, &last); 1444#ifdef HAVE_LIBUSB 1445 RemoveDeviceFromEnumeration("libusb", dev, &usb_devs, LIBUSB_hid_free_enumeration); 1446#endif 1447#ifdef HAVE_PLATFORM_BACKEND 1448 RemoveDeviceFromEnumeration("raw", dev, &raw_devs, PLATFORM_hid_free_enumeration); 1449#endif 1450 } 1451 1452 // If whitelist is in effect, libusb has priority, otherwise raw devices do 1453 if (use_libusb_whitelist) { 1454 for (dev = usb_devs; dev; dev = dev->next) { 1455 AddDeviceToEnumeration("libusb", dev, &devs, &last); 1456#ifdef HAVE_PLATFORM_BACKEND 1457 RemoveDeviceFromEnumeration("raw", dev, &raw_devs, PLATFORM_hid_free_enumeration); 1458#endif 1459 } 1460 for (dev = raw_devs; dev; dev = dev->next) { 1461 AddDeviceToEnumeration("platform", dev, &devs, &last); 1462 } 1463 } else { 1464 for (dev = raw_devs; dev; dev = dev->next) { 1465 AddDeviceToEnumeration("raw", dev, &devs, &last); 1466#ifdef HAVE_LIBUSB 1467 RemoveDeviceFromEnumeration("libusb", dev, &usb_devs, LIBUSB_hid_free_enumeration); 1468#endif 1469 } 1470 for (dev = usb_devs; dev; dev = dev->next) { 1471 AddDeviceToEnumeration("libusb", dev, &devs, &last); 1472 } 1473 } 1474 1475#ifdef HAVE_DRIVER_BACKEND 1476 DRIVER_hid_free_enumeration(driver_devs); 1477#endif 1478#ifdef HAVE_LIBUSB 1479 LIBUSB_hid_free_enumeration(usb_devs); 1480#endif 1481#ifdef HAVE_PLATFORM_BACKEND 1482 PLATFORM_hid_free_enumeration(raw_devs); 1483#endif 1484 1485 return devs; 1486} 1487 1488void SDL_hid_free_enumeration(struct SDL_hid_device_info *devs) 1489{ 1490 while (devs) { 1491 struct SDL_hid_device_info *next = devs->next; 1492 SDL_free(devs->path); 1493 SDL_free(devs->serial_number); 1494 SDL_free(devs->manufacturer_string); 1495 SDL_free(devs->product_string); 1496 SDL_free(devs); 1497 devs = next; 1498 } 1499} 1500 1501SDL_hid_device *SDL_hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number) 1502{ 1503#if defined(HAVE_PLATFORM_BACKEND) || defined(HAVE_DRIVER_BACKEND) || defined(HAVE_LIBUSB) 1504 void *pDevice = NULL; 1505 1506 if (SDL_hidapi_refcount == 0 && SDL_hid_init() < 0) { 1507 return NULL; 1508 } 1509 1510#ifdef HAVE_PLATFORM_BACKEND 1511 if (udev_ctx) { 1512 pDevice = PLATFORM_hid_open(vendor_id, product_id, serial_number); 1513 if (pDevice != NULL) { 1514 return CreateHIDDeviceWrapper(pDevice, &PLATFORM_Backend); 1515 } 1516 } 1517#endif // HAVE_PLATFORM_BACKEND 1518 1519#ifdef HAVE_DRIVER_BACKEND 1520 pDevice = DRIVER_hid_open(vendor_id, product_id, serial_number); 1521 if (pDevice != NULL) { 1522 return CreateHIDDeviceWrapper(pDevice, &DRIVER_Backend); 1523 } 1524#endif // HAVE_DRIVER_BACKEND 1525 1526#ifdef HAVE_LIBUSB 1527 if (libusb_ctx.libhandle != NULL) { 1528 pDevice = LIBUSB_hid_open(vendor_id, product_id, serial_number); 1529 if (pDevice != NULL) { 1530 return CreateHIDDeviceWrapper(pDevice, &LIBUSB_Backend); 1531 } 1532 } 1533#endif // HAVE_LIBUSB 1534 1535#endif // HAVE_PLATFORM_BACKEND || HAVE_DRIVER_BACKEND || HAVE_LIBUSB 1536 1537 return NULL; 1538} 1539 1540SDL_hid_device *SDL_hid_open_path(const char *path) 1541{ 1542#if defined(HAVE_PLATFORM_BACKEND) || defined(HAVE_DRIVER_BACKEND) || defined(HAVE_LIBUSB) 1543 void *pDevice = NULL; 1544 1545 if (SDL_hidapi_refcount == 0 && SDL_hid_init() < 0) { 1546 return NULL; 1547 } 1548 1549#ifdef HAVE_PLATFORM_BACKEND 1550 if (udev_ctx) { 1551 pDevice = PLATFORM_hid_open_path(path); 1552 if (pDevice != NULL) { 1553 return CreateHIDDeviceWrapper(pDevice, &PLATFORM_Backend); 1554 } 1555 } 1556#endif // HAVE_PLATFORM_BACKEND 1557 1558#ifdef HAVE_DRIVER_BACKEND 1559 pDevice = DRIVER_hid_open_path(path); 1560 if (pDevice != NULL) { 1561 return CreateHIDDeviceWrapper(pDevice, &DRIVER_Backend); 1562 } 1563#endif // HAVE_DRIVER_BACKEND 1564 1565#ifdef HAVE_LIBUSB 1566 if (libusb_ctx.libhandle != NULL) { 1567 pDevice = LIBUSB_hid_open_path(path); 1568 if (pDevice != NULL) { 1569 return CreateHIDDeviceWrapper(pDevice, &LIBUSB_Backend); 1570 } 1571 } 1572#endif // HAVE_LIBUSB 1573 1574#endif // HAVE_PLATFORM_BACKEND || HAVE_DRIVER_BACKEND || HAVE_LIBUSB 1575 1576 return NULL; 1577} 1578 1579int SDL_hid_write(SDL_hid_device *device, const unsigned char *data, size_t length) 1580{ 1581 CHECK_DEVICE_MAGIC(device, -1); 1582 1583 return device->backend->hid_write(device->device, data, length); 1584} 1585 1586int SDL_hid_read_timeout(SDL_hid_device *device, unsigned char *data, size_t length, int milliseconds) 1587{ 1588 CHECK_DEVICE_MAGIC(device, -1); 1589 1590 return device->backend->hid_read_timeout(device->device, data, length, milliseconds); 1591} 1592 1593int SDL_hid_read(SDL_hid_device *device, unsigned char *data, size_t length) 1594{ 1595 CHECK_DEVICE_MAGIC(device, -1); 1596 1597 return device->backend->hid_read(device->device, data, length); 1598} 1599 1600int SDL_hid_set_nonblocking(SDL_hid_device *device, int nonblock) 1601{ 1602 CHECK_DEVICE_MAGIC(device, -1); 1603 1604 return device->backend->hid_set_nonblocking(device->device, nonblock); 1605} 1606 1607int SDL_hid_send_feature_report(SDL_hid_device *device, const unsigned char *data, size_t length) 1608{ 1609 CHECK_DEVICE_MAGIC(device, -1); 1610 1611 return device->backend->hid_send_feature_report(device->device, data, length); 1612} 1613 1614int SDL_hid_get_feature_report(SDL_hid_device *device, unsigned char *data, size_t length) 1615{ 1616 CHECK_DEVICE_MAGIC(device, -1); 1617 1618 return device->backend->hid_get_feature_report(device->device, data, length); 1619} 1620 1621int SDL_hid_get_input_report(SDL_hid_device *device, unsigned char *data, size_t length) 1622{ 1623 CHECK_DEVICE_MAGIC(device, -1); 1624 1625 return device->backend->hid_get_input_report(device->device, data, length); 1626} 1627 1628int SDL_hid_close(SDL_hid_device *device) 1629{ 1630 CHECK_DEVICE_MAGIC(device, -1); 1631 1632 device->backend->hid_close(device->device); 1633 DeleteHIDDeviceWrapper(device); 1634 return 0; 1635} 1636 1637int SDL_hid_get_manufacturer_string(SDL_hid_device *device, wchar_t *string, size_t maxlen) 1638{ 1639 CHECK_DEVICE_MAGIC(device, -1); 1640 1641 return device->backend->hid_get_manufacturer_string(device->device, string, maxlen); 1642} 1643 1644int SDL_hid_get_product_string(SDL_hid_device *device, wchar_t *string, size_t maxlen) 1645{ 1646 CHECK_DEVICE_MAGIC(device, -1); 1647 1648 return device->backend->hid_get_product_string(device->device, string, maxlen); 1649} 1650 1651int SDL_hid_get_serial_number_string(SDL_hid_device *device, wchar_t *string, size_t maxlen) 1652{ 1653 CHECK_DEVICE_MAGIC(device, -1); 1654 1655 return device->backend->hid_get_serial_number_string(device->device, string, maxlen); 1656} 1657 1658int SDL_hid_get_indexed_string(SDL_hid_device *device, int string_index, wchar_t *string, size_t maxlen) 1659{ 1660 CHECK_DEVICE_MAGIC(device, -1); 1661 1662 return device->backend->hid_get_indexed_string(device->device, string_index, string, maxlen); 1663} 1664 1665SDL_hid_device_info *SDL_hid_get_device_info(SDL_hid_device *device) 1666{ 1667 struct hid_device_info *info; 1668 1669 CHECK_DEVICE_MAGIC(device, NULL); 1670 1671 info = device->backend->hid_get_device_info(device->device); 1672 if (info) { 1673 CopyHIDDeviceInfo(info, &device->info); 1674 return &device->info; 1675 } else { 1676 return NULL; 1677 } 1678} 1679 1680int SDL_hid_get_report_descriptor(SDL_hid_device *device, unsigned char *buf, size_t buf_size) 1681{ 1682 CHECK_DEVICE_MAGIC(device, -1); 1683 1684 return device->backend->hid_get_report_descriptor(device->device, buf, buf_size); 1685} 1686 1687void SDL_hid_ble_scan(bool active) 1688{ 1689#if !defined(SDL_HIDAPI_DISABLED) && (defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_TVOS)) 1690 extern void hid_ble_scan(int bStart); 1691 hid_ble_scan(active); 1692#endif 1693} 1694 1695#ifdef HAVE_ENABLE_GAMECUBE_ADAPTORS 1696// This is needed to enable input for Nyko and EVORETRO GameCube adaptors 1697void SDL_EnableGameCubeAdaptors(void) 1698{ 1699#ifdef HAVE_LIBUSB 1700 libusb_context *context = NULL; 1701 libusb_device **devs = NULL; 1702 libusb_device_handle *handle = NULL; 1703 struct libusb_device_descriptor desc; 1704 ssize_t i, num_devs; 1705 int kernel_detached = 0; 1706 1707 if (libusb_ctx.libhandle == NULL) { 1708 return; 1709 } 1710 1711 if (libusb_ctx.init(&context) == 0) { 1712 num_devs = libusb_ctx.get_device_list(context, &devs); 1713 for (i = 0; i < num_devs; ++i) { 1714 if (libusb_ctx.get_device_descriptor(devs[i], &desc) != 0) { 1715 continue; 1716 } 1717 1718 if (desc.idVendor != 0x057e || desc.idProduct != 0x0337) { 1719 continue; 1720 } 1721 1722 if (libusb_ctx.open(devs[i], &handle) != 0) { 1723 continue; 1724 } 1725 1726 if (libusb_ctx.kernel_driver_active(handle, 0)) { 1727 if (libusb_ctx.detach_kernel_driver(handle, 0) == 0) { 1728 kernel_detached = 1; 1729 } 1730 } 1731 1732 if (libusb_ctx.claim_interface(handle, 0) == 0) { 1733 libusb_ctx.control_transfer(handle, 0x21, 11, 0x0001, 0, NULL, 0, 1000); 1734 libusb_ctx.release_interface(handle, 0); 1735 } 1736 1737 if (kernel_detached) { 1738 libusb_ctx.attach_kernel_driver(handle, 0); 1739 } 1740 1741 libusb_ctx.close(handle); 1742 } 1743 1744 libusb_ctx.free_device_list(devs, 1); 1745 1746 libusb_ctx.exit(context); 1747 } 1748#endif // HAVE_LIBUSB 1749} 1750#endif // HAVE_ENABLE_GAMECUBE_ADAPTORS