SDL_hidapi.c 55 KB

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