SDL  2.0
SDL_hidapijoystick.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2020 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 #include "../../SDL_internal.h"
22 
23 #ifdef SDL_JOYSTICK_HIDAPI
24 
25 #include "SDL_atomic.h"
26 #include "SDL_endian.h"
27 #include "SDL_hints.h"
28 #include "SDL_thread.h"
29 #include "SDL_timer.h"
30 #include "SDL_joystick.h"
31 #include "../SDL_sysjoystick.h"
32 #include "SDL_hidapijoystick_c.h"
33 #include "SDL_hidapi_rumble.h"
34 #include "../../SDL_hints_c.h"
35 
36 #if defined(__WIN32__)
37 #include "../../core/windows/SDL_windows.h"
38 #include "../windows/SDL_rawinputjoystick_c.h"
39 #endif
40 
41 #if defined(__MACOSX__)
42 #include <CoreFoundation/CoreFoundation.h>
43 #include <mach/mach.h>
44 #include <IOKit/IOKitLib.h>
45 #include <IOKit/hid/IOHIDDevice.h>
46 #include <IOKit/usb/USBSpec.h>
47 #endif
48 
49 #if defined(__LINUX__)
50 #include "../../core/linux/SDL_udev.h"
51 #ifdef SDL_USE_LIBUDEV
52 #include <poll.h>
53 #endif
54 #endif
55 
56 struct joystick_hwdata
57 {
59 };
60 
61 static SDL_HIDAPI_DeviceDriver *SDL_HIDAPI_drivers[] = {
62 #ifdef SDL_JOYSTICK_HIDAPI_PS4
64 #endif
65 #ifdef SDL_JOYSTICK_HIDAPI_PS5
67 #endif
68 #ifdef SDL_JOYSTICK_HIDAPI_STEAM
70 #endif
71 #ifdef SDL_JOYSTICK_HIDAPI_SWITCH
73 #endif
74 #ifdef SDL_JOYSTICK_HIDAPI_XBOX360
77 #endif
78 #ifdef SDL_JOYSTICK_HIDAPI_XBOXONE
80 #endif
81 #ifdef SDL_JOYSTICK_HIDAPI_GAMECUBE
83 #endif
84 };
85 static int SDL_HIDAPI_numdrivers = 0;
86 static SDL_SpinLock SDL_HIDAPI_spinlock;
87 static SDL_HIDAPI_Device *SDL_HIDAPI_devices;
88 static int SDL_HIDAPI_numjoysticks = 0;
89 static SDL_bool initialized = SDL_FALSE;
90 static SDL_bool shutting_down = SDL_FALSE;
91 
92 #if defined(SDL_USE_LIBUDEV)
93 static const SDL_UDEV_Symbols * usyms = NULL;
94 #endif
95 
96 static struct
97 {
98  SDL_bool m_bHaveDevicesChanged;
99  SDL_bool m_bCanGetNotifications;
100  Uint32 m_unLastDetect;
101 
102 #if defined(__WIN32__)
103  SDL_threadID m_nThreadID;
104  WNDCLASSEXA m_wndClass;
105  HWND m_hwndMsg;
106  HDEVNOTIFY m_hNotify;
107  double m_flLastWin32MessageCheck;
108 #endif
109 
110 #if defined(__MACOSX__)
111  IONotificationPortRef m_notificationPort;
112  mach_port_t m_notificationMach;
113 #endif
114 
115 #if defined(SDL_USE_LIBUDEV)
116  struct udev *m_pUdev;
117  struct udev_monitor *m_pUdevMonitor;
118  int m_nUdevFd;
119 #endif
120 } SDL_HIDAPI_discovery;
121 
122 
123 #ifdef __WIN32__
124 struct _DEV_BROADCAST_HDR
125 {
126  DWORD dbch_size;
127  DWORD dbch_devicetype;
128  DWORD dbch_reserved;
129 };
130 
131 typedef 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 
140 typedef 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>
150 DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED);
151 
152 static 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_bHaveDevicesChanged = SDL_TRUE;
161  }
162  break;
163  }
164  return TRUE;
165  }
166 
167  return DefWindowProc(hwnd, message, wParam, lParam);
168 }
169 #endif /* __WIN32__ */
170 
171 
172 #if defined(__MACOSX__)
173 static void CallbackIOServiceFunc(void *context, io_iterator_t portIterator)
174 {
175  /* Must drain the iterator, or we won't receive new notifications */
176  io_object_t entry;
177  while ((entry = IOIteratorNext(portIterator)) != 0) {
178  IOObjectRelease(entry);
180  }
181 }
182 #endif /* __MACOSX__ */
183 
184 static void
185 HIDAPI_InitializeDiscovery()
186 {
187  SDL_HIDAPI_discovery.m_bHaveDevicesChanged = SDL_TRUE;
188  SDL_HIDAPI_discovery.m_bCanGetNotifications = SDL_FALSE;
189  SDL_HIDAPI_discovery.m_unLastDetect = 0;
190 
191 #if defined(__WIN32__)
192  SDL_HIDAPI_discovery.m_nThreadID = SDL_ThreadID();
193 
194  SDL_zero(SDL_HIDAPI_discovery.m_wndClass);
195  SDL_HIDAPI_discovery.m_wndClass.hInstance = GetModuleHandle(NULL);
196  SDL_HIDAPI_discovery.m_wndClass.lpszClassName = "SDL_HIDAPI_DEVICE_DETECTION";
197  SDL_HIDAPI_discovery.m_wndClass.lpfnWndProc = ControllerWndProc; /* This function is called by windows */
198  SDL_HIDAPI_discovery.m_wndClass.cbSize = sizeof(WNDCLASSEX);
199 
200  RegisterClassExA(&SDL_HIDAPI_discovery.m_wndClass);
201  SDL_HIDAPI_discovery.m_hwndMsg = CreateWindowExA(0, "SDL_HIDAPI_DEVICE_DETECTION", NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
202 
203  {
204  DEV_BROADCAST_DEVICEINTERFACE_A devBroadcast;
205 
206  SDL_zero(devBroadcast);
207  devBroadcast.dbcc_size = sizeof( devBroadcast );
208  devBroadcast.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
209  devBroadcast.dbcc_classguid = GUID_DEVINTERFACE_USB_DEVICE;
210 
211  /* DEVICE_NOTIFY_ALL_INTERFACE_CLASSES is important, makes GUID_DEVINTERFACE_USB_DEVICE ignored,
212  * but that seems to be necessary to get a notice after each individual usb input device actually
213  * installs, rather than just as the composite device is seen.
214  */
215  SDL_HIDAPI_discovery.m_hNotify = RegisterDeviceNotification( SDL_HIDAPI_discovery.m_hwndMsg, &devBroadcast, DEVICE_NOTIFY_WINDOW_HANDLE | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES );
216  SDL_HIDAPI_discovery.m_bCanGetNotifications = ( SDL_HIDAPI_discovery.m_hNotify != 0 );
217  }
218 #endif /* __WIN32__ */
219 
220 #if defined(__MACOSX__)
221  SDL_HIDAPI_discovery.m_notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
222  if (SDL_HIDAPI_discovery.m_notificationPort) {
223  {
224  io_iterator_t portIterator = 0;
225  io_object_t entry;
226  IOReturn result = IOServiceAddMatchingNotification(
227  SDL_HIDAPI_discovery.m_notificationPort,
228  kIOFirstMatchNotification,
229  IOServiceMatching(kIOHIDDeviceKey),
230  CallbackIOServiceFunc, &SDL_HIDAPI_discovery.m_bHaveDevicesChanged, &portIterator);
231 
232  if (result == 0) {
233  /* Must drain the existing iterator, or we won't receive new notifications */
234  while ((entry = IOIteratorNext(portIterator)) != 0) {
235  IOObjectRelease(entry);
236  }
237  } else {
238  IONotificationPortDestroy(SDL_HIDAPI_discovery.m_notificationPort);
239  SDL_HIDAPI_discovery.m_notificationPort = nil;
240  }
241  }
242  {
243  io_iterator_t portIterator = 0;
244  io_object_t entry;
245  IOReturn result = IOServiceAddMatchingNotification(
246  SDL_HIDAPI_discovery.m_notificationPort,
247  kIOTerminatedNotification,
248  IOServiceMatching(kIOHIDDeviceKey),
249  CallbackIOServiceFunc, &SDL_HIDAPI_discovery.m_bHaveDevicesChanged, &portIterator);
250 
251  if (result == 0) {
252  /* Must drain the existing iterator, or we won't receive new notifications */
253  while ((entry = IOIteratorNext(portIterator)) != 0) {
254  IOObjectRelease(entry);
255  }
256  } else {
257  IONotificationPortDestroy(SDL_HIDAPI_discovery.m_notificationPort);
258  SDL_HIDAPI_discovery.m_notificationPort = nil;
259  }
260  }
261  }
262 
263  SDL_HIDAPI_discovery.m_notificationMach = MACH_PORT_NULL;
264  if (SDL_HIDAPI_discovery.m_notificationPort) {
265  SDL_HIDAPI_discovery.m_notificationMach = IONotificationPortGetMachPort(SDL_HIDAPI_discovery.m_notificationPort);
266  }
267 
268  SDL_HIDAPI_discovery.m_bCanGetNotifications = (SDL_HIDAPI_discovery.m_notificationMach != MACH_PORT_NULL);
269 
270 #endif // __MACOSX__
271 
272 #if defined(SDL_USE_LIBUDEV)
273  SDL_HIDAPI_discovery.m_pUdev = NULL;
274  SDL_HIDAPI_discovery.m_pUdevMonitor = NULL;
275  SDL_HIDAPI_discovery.m_nUdevFd = -1;
276 
277  usyms = SDL_UDEV_GetUdevSyms();
278  if (usyms) {
279  SDL_HIDAPI_discovery.m_pUdev = usyms->udev_new();
280  }
281  if (SDL_HIDAPI_discovery.m_pUdev) {
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) {
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 = SDL_TRUE;
287  }
288  }
289 
290 #endif /* SDL_USE_LIBUDEV */
291 }
292 
293 static void
294 HIDAPI_UpdateDiscovery()
295 {
296  if (!SDL_HIDAPI_discovery.m_bCanGetNotifications) {
297  const Uint32 SDL_HIDAPI_DETECT_INTERVAL_MS = 3000; /* Update every 3 seconds */
298  Uint32 now = SDL_GetTicks();
299  if (!SDL_HIDAPI_discovery.m_unLastDetect || SDL_TICKS_PASSED(now, SDL_HIDAPI_discovery.m_unLastDetect + SDL_HIDAPI_DETECT_INTERVAL_MS)) {
300  SDL_HIDAPI_discovery.m_bHaveDevicesChanged = SDL_TRUE;
301  SDL_HIDAPI_discovery.m_unLastDetect = now;
302  }
303  return;
304  }
305 
306 #if defined(__WIN32__)
307 #if 0 /* just let the usual SDL_PumpEvents loop dispatch these, fixing bug 4286. --ryan. */
308  /* We'll only get messages on the same thread that created the window */
309  if (SDL_ThreadID() == SDL_HIDAPI_discovery.m_nThreadID) {
310  MSG msg;
311  while (PeekMessage(&msg, SDL_HIDAPI_discovery.m_hwndMsg, 0, 0, PM_NOREMOVE)) {
312  if (GetMessageA(&msg, SDL_HIDAPI_discovery.m_hwndMsg, 0, 0) != 0) {
313  TranslateMessage(&msg);
314  DispatchMessage(&msg);
315  }
316  }
317  }
318 #endif
319 #endif /* __WIN32__ */
320 
321 #if defined(__MACOSX__)
322  if (SDL_HIDAPI_discovery.m_notificationPort) {
323  struct { mach_msg_header_t hdr; char payload[ 4096 ]; } msg;
324  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) {
325  IODispatchCalloutFromMessage(NULL, &msg.hdr, SDL_HIDAPI_discovery.m_notificationPort);
326  }
327  }
328 #endif
329 
330 #if defined(SDL_USE_LIBUDEV)
331  if (SDL_HIDAPI_discovery.m_nUdevFd >= 0) {
332  /* Drain all notification events.
333  * We don't expect a lot of device notifications so just
334  * do a new discovery on any kind or number of notifications.
335  * This could be made more restrictive if necessary.
336  */
337  for (;;) {
338  struct pollfd PollUdev;
339  struct udev_device *pUdevDevice;
340 
341  PollUdev.fd = SDL_HIDAPI_discovery.m_nUdevFd;
342  PollUdev.events = POLLIN;
343  if (poll(&PollUdev, 1, 0) != 1) {
344  break;
345  }
346 
347  SDL_HIDAPI_discovery.m_bHaveDevicesChanged = SDL_TRUE;
348 
349  pUdevDevice = usyms->udev_monitor_receive_device(SDL_HIDAPI_discovery.m_pUdevMonitor);
350  if (pUdevDevice) {
351  usyms->udev_device_unref(pUdevDevice);
352  }
353  }
354  }
355 #endif
356 }
357 
358 static void
359 HIDAPI_ShutdownDiscovery()
360 {
361 #if defined(__WIN32__)
362  if (SDL_HIDAPI_discovery.m_hNotify)
363  UnregisterDeviceNotification(SDL_HIDAPI_discovery.m_hNotify);
364 
365  if (SDL_HIDAPI_discovery.m_hwndMsg) {
366  DestroyWindow(SDL_HIDAPI_discovery.m_hwndMsg);
367  }
368 
369  UnregisterClassA(SDL_HIDAPI_discovery.m_wndClass.lpszClassName, SDL_HIDAPI_discovery.m_wndClass.hInstance);
370 #endif
371 
372 #if defined(__MACOSX__)
373  if (SDL_HIDAPI_discovery.m_notificationPort) {
374  IONotificationPortDestroy(SDL_HIDAPI_discovery.m_notificationPort);
375  }
376 #endif
377 
378 #if defined(SDL_USE_LIBUDEV)
379  if (usyms) {
380  if (SDL_HIDAPI_discovery.m_pUdevMonitor) {
381  usyms->udev_monitor_unref(SDL_HIDAPI_discovery.m_pUdevMonitor);
382  }
383  if (SDL_HIDAPI_discovery.m_pUdev) {
384  usyms->udev_unref(SDL_HIDAPI_discovery.m_pUdev);
385  }
386  SDL_UDEV_ReleaseUdevSyms();
387  usyms = NULL;
388  }
389 #endif
390 }
391 
392 void
393 HIDAPI_DumpPacket(const char *prefix, Uint8 *data, int size)
394 {
395  int i;
396  char *buffer;
397  size_t length = SDL_strlen(prefix) + 11*(USB_PACKET_LENGTH/8) + (5*USB_PACKET_LENGTH*2) + 1 + 1;
398  int start = 0, amount = size;
399 
400  buffer = (char *)SDL_malloc(length);
401  SDL_snprintf(buffer, length, prefix, size);
402  for (i = start; i < start+amount; ++i) {
403  if ((i % 8) == 0) {
405  }
407  }
408  SDL_strlcat(buffer, "\n", length);
409  SDL_Log("%s", buffer);
410  SDL_free(buffer);
411 }
412 
413 static void HIDAPI_JoystickDetect(void);
414 static void HIDAPI_JoystickClose(SDL_Joystick * joystick);
415 
416 static SDL_bool
417 HIDAPI_IsDeviceSupported(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name)
418 {
419  int i;
420  SDL_GameControllerType type = SDL_GetJoystickGameControllerType(name, vendor_id, product_id, -1, 0, 0, 0);
421 
422  for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) {
423  SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i];
424  if (driver->enabled && driver->IsSupportedDevice(name, type, vendor_id, product_id, version, -1, 0, 0, 0)) {
425  return SDL_TRUE;
426  }
427  }
428  return SDL_FALSE;
429 }
430 
432 HIDAPI_GetDeviceDriver(SDL_HIDAPI_Device *device)
433 {
434  const Uint16 USAGE_PAGE_GENERIC_DESKTOP = 0x0001;
435  const Uint16 USAGE_JOYSTICK = 0x0004;
436  const Uint16 USAGE_GAMEPAD = 0x0005;
437  const Uint16 USAGE_MULTIAXISCONTROLLER = 0x0008;
438  int i;
440 
441  if (SDL_ShouldIgnoreJoystick(device->name, device->guid)) {
442  return NULL;
443  }
444 
445  if (device->vendor_id != USB_VENDOR_VALVE) {
446  if (device->usage_page && device->usage_page != USAGE_PAGE_GENERIC_DESKTOP) {
447  return NULL;
448  }
449  if (device->usage && device->usage != USAGE_JOYSTICK && device->usage != USAGE_GAMEPAD && device->usage != USAGE_MULTIAXISCONTROLLER) {
450  return NULL;
451  }
452  }
453 
454  type = SDL_GetJoystickGameControllerType(device->name, device->vendor_id, device->product_id, device->interface_number, device->interface_class, device->interface_subclass, device->interface_protocol);
455  for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) {
456  SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i];
457  if (driver->enabled && driver->IsSupportedDevice(device->name, type, device->vendor_id, device->product_id, device->version, device->interface_number, device->interface_class, device->interface_subclass, device->interface_protocol)) {
458  return driver;
459  }
460  }
461  return NULL;
462 }
463 
464 static SDL_HIDAPI_Device *
465 HIDAPI_GetDeviceByIndex(int device_index, SDL_JoystickID *pJoystickID)
466 {
467  SDL_HIDAPI_Device *device = SDL_HIDAPI_devices;
468  while (device) {
469  if (device->driver) {
470  if (device_index < device->num_joysticks) {
471  if (pJoystickID) {
472  *pJoystickID = device->joysticks[device_index];
473  }
474  return device;
475  }
476  device_index -= device->num_joysticks;
477  }
478  device = device->next;
479  }
480  return NULL;
481 }
482 
483 static SDL_HIDAPI_Device *
484 HIDAPI_GetJoystickByInfo(const char *path, Uint16 vendor_id, Uint16 product_id)
485 {
486  SDL_HIDAPI_Device *device = SDL_HIDAPI_devices;
487  while (device) {
488  if (device->vendor_id == vendor_id && device->product_id == product_id &&
489  SDL_strcmp(device->path, path) == 0) {
490  break;
491  }
492  device = device->next;
493  }
494  return device;
495 }
496 
497 static void
498 HIDAPI_SetupDeviceDriver(SDL_HIDAPI_Device *device)
499 {
500  if (device->driver) {
501  /* Already setup */
502  return;
503  }
504 
505  device->driver = HIDAPI_GetDeviceDriver(device);
506  if (device->driver) {
507  const char *name = device->driver->GetDeviceName(device->vendor_id, device->product_id);
508  if (name) {
509  SDL_free(device->name);
510  device->name = SDL_strdup(name);
511  }
512  }
513 
514  /* Initialize the device, which may cause a connected event */
515  if (device->driver && !device->driver->InitDevice(device)) {
516  device->driver = NULL;
517  }
518 }
519 
520 static void
521 HIDAPI_CleanupDeviceDriver(SDL_HIDAPI_Device *device)
522 {
523  if (!device->driver) {
524  /* Already cleaned up */
525  return;
526  }
527 
528  /* Disconnect any joysticks */
529  while (device->num_joysticks) {
530  HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
531  }
532 
533  device->driver->FreeDevice(device);
534  device->driver = NULL;
535 }
536 
537 static void SDLCALL
538 SDL_HIDAPIDriverHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
539 {
540  int i;
543 
545  for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) {
546  SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i];
547  driver->enabled = SDL_GetHintBoolean(driver->hint, enabled);
548  }
549  } else {
550  for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) {
551  SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i];
552  if (SDL_strcmp(name, driver->hint) == 0) {
553  driver->enabled = enabled;
554  }
555  }
556  }
557 
558  SDL_HIDAPI_numdrivers = 0;
559  for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) {
560  SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i];
561  if (driver->enabled) {
562  ++SDL_HIDAPI_numdrivers;
563  }
564  }
565 
566  /* Update device list if driver availability changes */
568 
569  for (device = SDL_HIDAPI_devices; device; device = device->next) {
570  if (device->driver && !device->driver->enabled) {
571  HIDAPI_CleanupDeviceDriver(device);
572  }
573  HIDAPI_SetupDeviceDriver(device);
574  }
575 
577 }
578 
579 static int
580 HIDAPI_JoystickInit(void)
581 {
582  int i;
583 
584  if (initialized) {
585  return 0;
586  }
587 
588 #if defined(__MACOSX__) || defined(__IPHONEOS__) || defined(__TVOS__)
589  /* The hidapi framwork is weak-linked on Apple platforms */
590  int HID_API_EXPORT HID_API_CALL hid_init(void) __attribute__((weak_import));
591 
592  if (hid_init == NULL) {
593  SDL_SetError("Couldn't initialize hidapi, framework not available");
594  return -1;
595  }
596 #endif /* __MACOSX__ || __IPHONEOS__ || __TVOS__ */
597 
598  if (hid_init() < 0) {
599  SDL_SetError("Couldn't initialize hidapi");
600  return -1;
601  }
602 
603  for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) {
604  SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i];
605  SDL_AddHintCallback(driver->hint, SDL_HIDAPIDriverHintChanged, NULL);
606  }
608  SDL_HIDAPIDriverHintChanged, NULL);
609  HIDAPI_InitializeDiscovery();
610  HIDAPI_JoystickDetect();
612 
613  initialized = SDL_TRUE;
614 
615  return 0;
616 }
617 
618 SDL_bool
620 {
621  SDL_JoystickID joystickID;
622  SDL_JoystickID *joysticks = (SDL_JoystickID *)SDL_realloc(device->joysticks, (device->num_joysticks + 1)*sizeof(*device->joysticks));
623  if (!joysticks) {
624  return SDL_FALSE;
625  }
626 
627  joystickID = SDL_GetNextJoystickInstanceID();
628  device->joysticks = joysticks;
629  device->joysticks[device->num_joysticks++] = joystickID;
630  ++SDL_HIDAPI_numjoysticks;
631 
632  SDL_PrivateJoystickAdded(joystickID);
633 
634  if (pJoystickID) {
635  *pJoystickID = joystickID;
636  }
637  return SDL_TRUE;
638 }
639 
640 void
642 {
643  int i, size;
644 
645  for (i = 0; i < device->num_joysticks; ++i) {
646  if (device->joysticks[i] == joystickID) {
647  SDL_Joystick *joystick = SDL_JoystickFromInstanceID(joystickID);
648  if (joystick) {
649  HIDAPI_JoystickClose(joystick);
650  }
651 
652  size = (device->num_joysticks - i - 1) * sizeof(SDL_JoystickID);
653  SDL_memmove(&device->joysticks[i], &device->joysticks[i+1], size);
654  --device->num_joysticks;
655 
656  --SDL_HIDAPI_numjoysticks;
657  if (device->num_joysticks == 0) {
658  SDL_free(device->joysticks);
659  device->joysticks = NULL;
660  }
661 
662  if (!shutting_down) {
663  SDL_PrivateJoystickRemoved(joystickID);
664  }
665  return;
666  }
667  }
668 }
669 
670 static int
671 HIDAPI_JoystickGetCount(void)
672 {
673  return SDL_HIDAPI_numjoysticks;
674 }
675 
676 static char *
677 HIDAPI_ConvertString(const wchar_t *wide_string)
678 {
679  char *string = NULL;
680 
681  if (wide_string) {
682  string = SDL_iconv_string("UTF-8", "WCHAR_T", (char*)wide_string, (SDL_wcslen(wide_string)+1)*sizeof(wchar_t));
683  if (!string) {
684  if (sizeof(wchar_t) == sizeof(Uint16)) {
685  string = SDL_iconv_string("UTF-8", "UCS-2-INTERNAL", (char*)wide_string, (SDL_wcslen(wide_string)+1)*sizeof(wchar_t));
686  } else if (sizeof(wchar_t) == sizeof(Uint32)) {
687  string = SDL_iconv_string("UTF-8", "UCS-4-INTERNAL", (char*)wide_string, (SDL_wcslen(wide_string)+1)*sizeof(wchar_t));
688  }
689  }
690  }
691  return string;
692 }
693 
694 static void
695 HIDAPI_AddDevice(struct hid_device_info *info)
696 {
698  SDL_HIDAPI_Device *curr, *last = NULL;
699 
700  for (curr = SDL_HIDAPI_devices, last = NULL; curr; last = curr, curr = curr->next) {
701  continue;
702  }
703 
704  device = (SDL_HIDAPI_Device *)SDL_calloc(1, sizeof(*device));
705  if (!device) {
706  return;
707  }
708  device->path = SDL_strdup(info->path);
709  if (!device->path) {
710  SDL_free(device);
711  return;
712  }
713  device->seen = SDL_TRUE;
714  device->vendor_id = info->vendor_id;
715  device->product_id = info->product_id;
716  device->version = info->release_number;
717  device->interface_number = info->interface_number;
718  device->interface_class = info->interface_class;
719  device->interface_subclass = info->interface_subclass;
720  device->interface_protocol = info->interface_protocol;
721  device->usage_page = info->usage_page;
722  device->usage = info->usage;
723  {
724  /* FIXME: Is there any way to tell whether this is a Bluetooth device? */
725  const Uint16 vendor = device->vendor_id;
726  const Uint16 product = device->product_id;
727  const Uint16 version = device->version;
728  Uint16 *guid16 = (Uint16 *)device->guid.data;
729 
730  *guid16++ = SDL_SwapLE16(SDL_HARDWARE_BUS_USB);
731  *guid16++ = 0;
732  *guid16++ = SDL_SwapLE16(vendor);
733  *guid16++ = 0;
734  *guid16++ = SDL_SwapLE16(product);
735  *guid16++ = 0;
736  *guid16++ = SDL_SwapLE16(version);
737  *guid16++ = 0;
738 
739  /* Note that this is a HIDAPI device for special handling elsewhere */
740  device->guid.data[14] = 'h';
741  device->guid.data[15] = 0;
742  }
743  device->dev_lock = SDL_CreateMutex();
744 
745  /* Need the device name before getting the driver to know whether to ignore this device */
746  {
747  char *manufacturer_string = HIDAPI_ConvertString(info->manufacturer_string);
748  char *product_string = HIDAPI_ConvertString(info->product_string);
749  char *serial_number = HIDAPI_ConvertString(info->serial_number);
750 
751  device->name = SDL_CreateJoystickName(device->vendor_id, device->product_id, manufacturer_string, product_string);
752  if (SDL_strncmp(device->name, "0x", 2) == 0) {
753  /* Couldn't find a controller name, try to give it one based on device type */
754  const char *name = NULL;
755 
756  switch (SDL_GetJoystickGameControllerType(NULL, device->vendor_id, device->product_id, device->interface_number, device->interface_class, device->interface_subclass, device->interface_protocol)) {
758  name = "Xbox 360 Controller";
759  break;
761  name = "Xbox One Controller";
762  break;
764  name = "PS3 Controller";
765  break;
767  name = "PS4 Controller";
768  break;
770  name = "PS5 Controller";
771  break;
773  name = "Nintendo Switch Pro Controller";
774  break;
775  default:
776  break;
777  }
778 
779  if (name) {
780  SDL_free(device->name);
781  device->name = SDL_strdup(name);
782  }
783  }
784 
785  if (manufacturer_string) {
786  SDL_free(manufacturer_string);
787  }
788  if (product_string) {
789  SDL_free(product_string);
790  }
791 
792  if (serial_number && *serial_number) {
793  device->serial = serial_number;
794  } else {
795  SDL_free(serial_number);
796  }
797 
798  if (!device->name) {
799  SDL_free(device->serial);
800  SDL_free(device->path);
801  SDL_free(device);
802  return;
803  }
804  }
805 
806  /* Add it to the list */
807  if (last) {
808  last->next = device;
809  } else {
810  SDL_HIDAPI_devices = device;
811  }
812 
813  HIDAPI_SetupDeviceDriver(device);
814 
815 #ifdef DEBUG_HIDAPI
816  SDL_Log("Added HIDAPI device '%s' VID 0x%.4x, PID 0x%.4x, version %d, serial %s, interface %d, interface_class %d, interface_subclass %d, interface_protocol %d, usage page 0x%.4x, usage 0x%.4x, path = %s, driver = %s (%s)\n", device->name, device->vendor_id, device->product_id, device->version, device->serial ? device->serial : "NONE", device->interface_number, device->interface_class, device->interface_subclass, device->interface_protocol, device->usage_page, device->usage, device->path, device->driver ? device->driver->hint : "NONE", device->driver && device->driver->enabled ? "ENABLED" : "DISABLED");
817 #endif
818 }
819 
820 
821 static void
822 HIDAPI_DelDevice(SDL_HIDAPI_Device *device)
823 {
824  SDL_HIDAPI_Device *curr, *last;
825 
826 #ifdef DEBUG_HIDAPI
827  SDL_Log("Removing HIDAPI device '%s' VID 0x%.4x, PID 0x%.4x, version %d, serial %s, interface %d, interface_class %d, interface_subclass %d, interface_protocol %d, usage page 0x%.4x, usage 0x%.4x, path = %s, driver = %s (%s)\n", device->name, device->vendor_id, device->product_id, device->version, device->serial ? device->serial : "NONE", device->interface_number, device->interface_class, device->interface_subclass, device->interface_protocol, device->usage_page, device->usage, device->path, device->driver ? device->driver->hint : "NONE", device->driver && device->driver->enabled ? "ENABLED" : "DISABLED");
828 #endif
829 
830  for (curr = SDL_HIDAPI_devices, last = NULL; curr; last = curr, curr = curr->next) {
831  if (curr == device) {
832  if (last) {
833  last->next = curr->next;
834  } else {
835  SDL_HIDAPI_devices = curr->next;
836  }
837 
838  HIDAPI_CleanupDeviceDriver(device);
839 
840  /* Make sure the rumble thread is done with this device */
841  while (SDL_AtomicGet(&device->rumble_pending) > 0) {
842  SDL_Delay(10);
843  }
844 
845  SDL_DestroyMutex(device->dev_lock);
846  SDL_free(device->serial);
847  SDL_free(device->name);
848  SDL_free(device->path);
849  SDL_free(device);
850  return;
851  }
852  }
853 }
854 
855 static void
856 HIDAPI_UpdateDeviceList(void)
857 {
859  struct hid_device_info *devs, *info;
860 
862 
863  /* Prepare the existing device list */
864  device = SDL_HIDAPI_devices;
865  while (device) {
866  device->seen = SDL_FALSE;
867  device = device->next;
868  }
869 
870  /* Enumerate the devices */
871  if (SDL_HIDAPI_numdrivers > 0) {
872  devs = hid_enumerate(0, 0);
873  if (devs) {
874  for (info = devs; info; info = info->next) {
875  device = HIDAPI_GetJoystickByInfo(info->path, info->vendor_id, info->product_id);
876  if (device) {
877  device->seen = SDL_TRUE;
878  } else {
879  HIDAPI_AddDevice(info);
880  }
881  }
882  hid_free_enumeration(devs);
883  }
884  }
885 
886  /* Remove any devices that weren't seen */
887  device = SDL_HIDAPI_devices;
888  while (device) {
889  SDL_HIDAPI_Device *next = device->next;
890 
891  if (!device->seen) {
892  HIDAPI_DelDevice(device);
893  }
894  device = next;
895  }
896 
898 }
899 
900 static SDL_bool
901 HIDAPI_IsEquivalentToDevice(Uint16 vendor_id, Uint16 product_id, SDL_HIDAPI_Device *device)
902 {
903  if (vendor_id == device->vendor_id && product_id == device->product_id) {
904  return SDL_TRUE;
905  }
906 
908  /* If we're looking for the wireless XBox 360 controller, also look for the dongle */
909  if (product_id == 0x02a1 && device->product_id == 0x0719) {
910  return SDL_TRUE;
911  }
912 
913  /* If we're looking for the raw input Xbox One controller, match it against any other Xbox One controller */
915  SDL_GetJoystickGameControllerType(device->name, device->vendor_id, device->product_id, device->interface_number, device->interface_class, device->interface_subclass, device->interface_protocol) == SDL_CONTROLLER_TYPE_XBOXONE) {
916  return SDL_TRUE;
917  }
918 
919  /* If we're looking for an XInput controller, match it against any other Xbox controller */
921  SDL_GameControllerType type = SDL_GetJoystickGameControllerType(device->name, device->vendor_id, device->product_id, device->interface_number, device->interface_class, device->interface_subclass, device->interface_protocol);
923  return SDL_TRUE;
924  }
925  }
926  }
927  return SDL_FALSE;
928 }
929 
930 SDL_bool
932 {
934  SDL_bool supported = SDL_FALSE;
936 
937  /* Make sure we're initialized, as this could be called from other drivers during startup */
938  if (HIDAPI_JoystickInit() < 0) {
939  return SDL_FALSE;
940  }
941 
942  /* Only update the device list for devices we know might be supported.
943  If we did this for every device, it would hit the USB driver too hard and potentially
944  lock up the system. This won't catch devices that we support but can only detect using
945  USB interface details, like Xbox controllers, but hopefully the device list update is
946  responsive enough to catch those.
947  */
948  supported = HIDAPI_IsDeviceSupported(vendor_id, product_id, version, name);
949 #if defined(SDL_JOYSTICK_HIDAPI_XBOX360) || defined(SDL_JOYSTICK_HIDAPI_XBOXONE)
950  if (!supported &&
951  (SDL_strstr(name, "Xbox") || SDL_strstr(name, "X-Box") || SDL_strstr(name, "XBOX"))) {
952  supported = SDL_TRUE;
953  }
954 #endif /* SDL_JOYSTICK_HIDAPI_XBOX360 || SDL_JOYSTICK_HIDAPI_XBOXONE */
955  if (supported) {
956  if (SDL_AtomicTryLock(&SDL_HIDAPI_spinlock)) {
957  HIDAPI_UpdateDeviceList();
958  SDL_AtomicUnlock(&SDL_HIDAPI_spinlock);
959  }
960  }
961 
962  /* Note that this isn't a perfect check - there may be multiple devices with 0 VID/PID,
963  or a different name than we have it listed here, etc, but if we support the device
964  and we have something similar in our device list, mark it as present.
965  */
967  device = SDL_HIDAPI_devices;
968  while (device) {
969  if (device->driver &&
970  HIDAPI_IsEquivalentToDevice(vendor_id, product_id, device)) {
971  result = SDL_TRUE;
972  }
973  device = device->next;
974  }
976 
977 #ifdef DEBUG_HIDAPI
978  SDL_Log("HIDAPI_IsDevicePresent() returning %s for 0x%.4x / 0x%.4x\n", result ? "true" : "false", vendor_id, product_id);
979 #endif
980  return result;
981 }
982 
983 static void
984 HIDAPI_JoystickDetect(void)
985 {
986  if (SDL_AtomicTryLock(&SDL_HIDAPI_spinlock)) {
987  HIDAPI_UpdateDiscovery();
988  if (SDL_HIDAPI_discovery.m_bHaveDevicesChanged) {
989  /* FIXME: We probably need to schedule an update in a few seconds as well */
990  HIDAPI_UpdateDeviceList();
991  SDL_HIDAPI_discovery.m_bHaveDevicesChanged = SDL_FALSE;
992  }
993  SDL_AtomicUnlock(&SDL_HIDAPI_spinlock);
994  }
995 }
996 
997 void
999 {
1001 
1002  /* Update the devices, which may change connected joysticks and send events */
1003 
1004  /* Prepare the existing device list */
1005  if (SDL_AtomicTryLock(&SDL_HIDAPI_spinlock)) {
1006  device = SDL_HIDAPI_devices;
1007  while (device) {
1008  if (device->driver) {
1009  if (SDL_TryLockMutex(device->dev_lock) == 0) {
1010  device->updating = SDL_TRUE;
1011  device->driver->UpdateDevice(device);
1012  device->updating = SDL_FALSE;
1013  SDL_UnlockMutex(device->dev_lock);
1014  }
1015  }
1016  device = device->next;
1017  }
1018  SDL_AtomicUnlock(&SDL_HIDAPI_spinlock);
1019  }
1020 }
1021 
1022 static const char *
1023 HIDAPI_JoystickGetDeviceName(int device_index)
1024 {
1026  const char *name = NULL;
1027 
1028  device = HIDAPI_GetDeviceByIndex(device_index, NULL);
1029  if (device) {
1030  /* FIXME: The device could be freed after this name is returned... */
1031  name = device->name;
1032  }
1033 
1034  return name;
1035 }
1036 
1037 static int
1038 HIDAPI_JoystickGetDevicePlayerIndex(int device_index)
1039 {
1041  SDL_JoystickID instance_id;
1042  int player_index = -1;
1043 
1044  device = HIDAPI_GetDeviceByIndex(device_index, &instance_id);
1045  if (device) {
1046  player_index = device->driver->GetDevicePlayerIndex(device, instance_id);
1047  }
1048 
1049  return player_index;
1050 }
1051 
1052 static void
1053 HIDAPI_JoystickSetDevicePlayerIndex(int device_index, int player_index)
1054 {
1056  SDL_JoystickID instance_id;
1057 
1058  device = HIDAPI_GetDeviceByIndex(device_index, &instance_id);
1059  if (device) {
1060  device->driver->SetDevicePlayerIndex(device, instance_id, player_index);
1061  }
1062 }
1063 
1064 static SDL_JoystickGUID
1065 HIDAPI_JoystickGetDeviceGUID(int device_index)
1066 {
1068  SDL_JoystickGUID guid;
1069 
1070  device = HIDAPI_GetDeviceByIndex(device_index, NULL);
1071  if (device) {
1072  SDL_memcpy(&guid, &device->guid, sizeof(guid));
1073  } else {
1074  SDL_zero(guid);
1075  }
1076 
1077  return guid;
1078 }
1079 
1080 static SDL_JoystickID
1081 HIDAPI_JoystickGetDeviceInstanceID(int device_index)
1082 {
1083  SDL_JoystickID joystickID = -1;
1084  HIDAPI_GetDeviceByIndex(device_index, &joystickID);
1085  return joystickID;
1086 }
1087 
1088 static int
1089 HIDAPI_JoystickOpen(SDL_Joystick * joystick, int device_index)
1090 {
1091  SDL_JoystickID joystickID;
1092  SDL_HIDAPI_Device *device = HIDAPI_GetDeviceByIndex(device_index, &joystickID);
1093  struct joystick_hwdata *hwdata;
1094 
1095  hwdata = (struct joystick_hwdata *)SDL_calloc(1, sizeof(*hwdata));
1096  if (!hwdata) {
1097  return SDL_OutOfMemory();
1098  }
1099  hwdata->device = device;
1100 
1101  if (!device->driver->OpenJoystick(device, joystick)) {
1102  SDL_free(hwdata);
1103  return -1;
1104  }
1105 
1106  if (!joystick->serial && device->serial) {
1107  joystick->serial = SDL_strdup(device->serial);
1108  }
1109 
1110  joystick->hwdata = hwdata;
1111  return 0;
1112 }
1113 
1114 static int
1115 HIDAPI_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
1116 {
1117  int result;
1118 
1119  if (joystick->hwdata) {
1120  SDL_HIDAPI_Device *device = joystick->hwdata->device;
1121 
1122  result = device->driver->RumbleJoystick(device, joystick, low_frequency_rumble, high_frequency_rumble);
1123  } else {
1124  SDL_SetError("Rumble failed, device disconnected");
1125  result = -1;
1126  }
1127 
1128  return result;
1129 }
1130 
1131 static int
1132 HIDAPI_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 right_rumble)
1133 {
1134  int result;
1135 
1136  if (joystick->hwdata) {
1137  SDL_HIDAPI_Device *device = joystick->hwdata->device;
1138 
1139  result = device->driver->RumbleJoystickTriggers(device, joystick, left_rumble, right_rumble);
1140  } else {
1141  SDL_SetError("Rumble failed, device disconnected");
1142  result = -1;
1143  }
1144 
1145  return result;
1146 }
1147 
1148 static SDL_bool
1149 HIDAPI_JoystickHasLED(SDL_Joystick * joystick)
1150 {
1152 
1153  if (joystick->hwdata) {
1154  SDL_HIDAPI_Device *device = joystick->hwdata->device;
1155 
1156  result = device->driver->HasJoystickLED(device, joystick);
1157  }
1158 
1159  return result;
1160 }
1161 
1162 static int
1163 HIDAPI_JoystickSetLED(SDL_Joystick * joystick, Uint8 red, Uint8 green, Uint8 blue)
1164 {
1165  int result;
1166 
1167  if (joystick->hwdata) {
1168  SDL_HIDAPI_Device *device = joystick->hwdata->device;
1169 
1170  result = device->driver->SetJoystickLED(device, joystick, red, green, blue);
1171  } else {
1172  SDL_SetError("SetLED failed, device disconnected");
1173  result = -1;
1174  }
1175 
1176  return result;
1177 }
1178 
1179 static int
1180 HIDAPI_JoystickSetSensorsEnabled(SDL_Joystick * joystick, SDL_bool enabled)
1181 {
1182  int result;
1183 
1184  if (joystick->hwdata) {
1185  SDL_HIDAPI_Device *device = joystick->hwdata->device;
1186 
1187  result = device->driver->SetJoystickSensorsEnabled(device, joystick, enabled);
1188  } else {
1189  SDL_SetError("SetSensorsEnabled failed, device disconnected");
1190  result = -1;
1191  }
1192 
1193  return result;
1194 }
1195 
1196 static void
1197 HIDAPI_JoystickUpdate(SDL_Joystick * joystick)
1198 {
1199  /* This is handled in SDL_HIDAPI_UpdateDevices() */
1200 }
1201 
1202 static void
1203 HIDAPI_JoystickClose(SDL_Joystick * joystick)
1204 {
1205  if (joystick->hwdata) {
1206  SDL_HIDAPI_Device *device = joystick->hwdata->device;
1207  int i;
1208 
1209  /* Wait up to 30 ms for pending rumble to complete */
1210  if (device->updating) {
1211  /* Unlock the device so rumble can complete */
1212  SDL_UnlockMutex(device->dev_lock);
1213  }
1214  for (i = 0; i < 3; ++i) {
1215  if (SDL_AtomicGet(&device->rumble_pending) > 0) {
1216  SDL_Delay(10);
1217  }
1218  }
1219  if (device->updating) {
1220  /* Relock the device */
1221  SDL_LockMutex(device->dev_lock);
1222  }
1223 
1224  device->driver->CloseJoystick(device, joystick);
1225 
1226  SDL_free(joystick->hwdata);
1227  joystick->hwdata = NULL;
1228  }
1229 }
1230 
1231 static void
1232 HIDAPI_JoystickQuit(void)
1233 {
1234  int i;
1235 
1236  shutting_down = SDL_TRUE;
1237 
1238  HIDAPI_ShutdownDiscovery();
1239 
1240  SDL_HIDAPI_QuitRumble();
1241 
1242  while (SDL_HIDAPI_devices) {
1243  HIDAPI_DelDevice(SDL_HIDAPI_devices);
1244  }
1245 
1246  /* Make sure the drivers cleaned up properly */
1247  SDL_assert(SDL_HIDAPI_numjoysticks == 0);
1248 
1249  for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) {
1250  SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i];
1251  SDL_DelHintCallback(driver->hint, SDL_HIDAPIDriverHintChanged, NULL);
1252  }
1254  SDL_HIDAPIDriverHintChanged, NULL);
1255 
1256  hid_exit();
1257 
1258  shutting_down = SDL_FALSE;
1259  initialized = SDL_FALSE;
1260 }
1261 
1262 static SDL_bool
1263 HIDAPI_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
1264 {
1265  return SDL_FALSE;
1266 }
1267 
1269 {
1270  HIDAPI_JoystickInit,
1271  HIDAPI_JoystickGetCount,
1272  HIDAPI_JoystickDetect,
1273  HIDAPI_JoystickGetDeviceName,
1274  HIDAPI_JoystickGetDevicePlayerIndex,
1275  HIDAPI_JoystickSetDevicePlayerIndex,
1276  HIDAPI_JoystickGetDeviceGUID,
1277  HIDAPI_JoystickGetDeviceInstanceID,
1278  HIDAPI_JoystickOpen,
1279  HIDAPI_JoystickRumble,
1280  HIDAPI_JoystickRumbleTriggers,
1281  HIDAPI_JoystickHasLED,
1282  HIDAPI_JoystickSetLED,
1283  HIDAPI_JoystickSetSensorsEnabled,
1284  HIDAPI_JoystickUpdate,
1285  HIDAPI_JoystickClose,
1286  HIDAPI_JoystickQuit,
1287  HIDAPI_JoystickGetGamepadMapping
1288 };
1289 
1290 #endif /* SDL_JOYSTICK_HIDAPI */
1291 
1292 /* vi: set ts=4 sw=4 expandtab: */
#define SDL_assert(condition)
Definition: SDL_assert.h:171
int SDL_SpinLock
Definition: SDL_atomic.h:89
#define SDL_SetError
#define SDL_LockJoysticks
#define SDL_DelHintCallback
#define SDL_strncmp
#define SDL_TryLockMutex
#define SDL_AtomicTryLock
#define SDL_strlcat
#define SDL_wcslen
#define SDL_LockMutex
#define SDL_malloc
#define SDL_strlen
#define SDL_ThreadID
#define SDL_realloc
#define SDL_CreateMutex
#define SDL_JoystickFromInstanceID
#define SDL_AtomicUnlock
#define SDL_free
#define SDL_strdup
#define SDL_strcmp
#define SDL_iconv_string
#define SDL_Delay
#define SDL_strstr
#define SDL_UnlockJoysticks
#define SDL_GetHintBoolean
#define SDL_AtomicGet
#define SDL_memcpy
#define SDL_DestroyMutex
#define SDL_AddHintCallback
#define SDL_Log
#define SDL_snprintf
#define SDL_memmove
#define SDL_calloc
#define SDL_UnlockMutex
#define SDL_SwapLE16(X)
Definition: SDL_endian.h:235
#define SDL_OutOfMemory()
Definition: SDL_error.h:88
SDL_GameControllerType
@ SDL_CONTROLLER_TYPE_XBOX360
@ SDL_CONTROLLER_TYPE_PS4
@ SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO
@ SDL_CONTROLLER_TYPE_PS3
@ SDL_CONTROLLER_TYPE_PS5
@ SDL_CONTROLLER_TYPE_XBOXONE
const GLubyte GLuint red
Definition: SDL_glfuncs.h:80
#define USB_PACKET_LENGTH
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS4
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSteam
void HIDAPI_UpdateDevices(void)
void HIDAPI_DumpPacket(const char *prefix, Uint8 *data, int size)
SDL_bool HIDAPI_JoystickConnected(SDL_HIDAPI_Device *device, SDL_JoystickID *pJoystickID)
void HIDAPI_JoystickDisconnected(SDL_HIDAPI_Device *device, SDL_JoystickID joystickID)
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverGameCube
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360
SDL_bool HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name)
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSwitch
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS5
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360W
SDL_bool SDL_GetStringBoolean(const char *value, SDL_bool default_value)
Definition: SDL_hints.c:123
#define SDL_HINT_JOYSTICK_HIDAPI
A variable controlling whether the HIDAPI joystick drivers should be used.
Definition: SDL_hints.h:594
#define SDLCALL
Definition: SDL_internal.h:49
void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance)
SDL_bool SDL_ShouldIgnoreJoystick(const char *name, SDL_JoystickGUID guid)
void SDL_PrivateJoystickAdded(SDL_JoystickID device_instance)
SDL_GameControllerType SDL_GetJoystickGameControllerType(const char *name, Uint16 vendor, Uint16 product, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
SDL_JoystickID SDL_GetNextJoystickInstanceID()
Definition: SDL_joystick.c:262
char * SDL_CreateJoystickName(Uint16 vendor, Uint16 product, const char *vendor_name, const char *product_name)
Sint32 SDL_JoystickID
Definition: SDL_joystick.h:81
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
GLuint start
Definition: SDL_opengl.h:1571
GLuint GLuint GLsizei GLenum type
Definition: SDL_opengl.h:1571
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLbyte GLbyte blue
GLuint64EXT * result
GLuint GLsizei const GLchar * message
GLuint buffer
GLuint const GLchar * name
GLsizeiptr size
GLsizei const GLchar *const * path
GLuint GLsizei GLsizei * length
GLbyte green
GLsizei const GLchar *const * string
uint16_t Uint16
Definition: SDL_stdinc.h:197
#define SDL_zero(x)
Definition: SDL_stdinc.h:426
SDL_bool
Definition: SDL_stdinc.h:168
@ SDL_TRUE
Definition: SDL_stdinc.h:170
@ SDL_FALSE
Definition: SDL_stdinc.h:169
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:121
uint8_t Uint8
Definition: SDL_stdinc.h:185
uint32_t Uint32
Definition: SDL_stdinc.h:209
#define SDL_HARDWARE_BUS_USB
SDL_JoystickDriver SDL_HIDAPI_JoystickDriver
unsigned long SDL_threadID
Definition: SDL_thread.h:49
Uint32 SDL_GetTicks(void)
Get the number of milliseconds since the SDL library initialization.
#define SDL_TICKS_PASSED(A, B)
Compare SDL ticks values, and return true if A has passed B.
Definition: SDL_timer.h:56
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:163
#define TRUE
Definition: edid-parse.c:33
struct hid_device_info HID_API_EXPORT *HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id)
Enumerate the HID Devices.
int HID_API_EXPORT HID_API_CALL hid_init(void)
Initialize the HIDAPI library.
#define HID_API_EXPORT
Definition: hidapi.h:37
int HID_API_EXPORT HID_API_CALL hid_exit(void)
Finalize the HIDAPI library.
#define HID_API_CALL
Definition: hidapi.h:40
void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs)
Free an enumeration Linked List.
static SDL_AudioDeviceID device
Definition: loopwave.c:37
SDL_bool(* IsSupportedDevice)(const char *name, SDL_GameControllerType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
struct _SDL_HIDAPI_Device * next
unsigned short product_id
Definition: hidapi.h:63
struct hid_device_info * next
Definition: hidapi.h:92
unsigned short usage
Definition: hidapi.h:78
wchar_t * manufacturer_string
Definition: hidapi.h:70
unsigned short vendor_id
Definition: hidapi.h:61
int interface_class
Definition: hidapi.h:87
char * path
Definition: hidapi.h:59
unsigned short release_number
Definition: hidapi.h:68
wchar_t * serial_number
Definition: hidapi.h:65
int interface_number
Definition: hidapi.h:83
unsigned short usage_page
Definition: hidapi.h:75
int interface_protocol
Definition: hidapi.h:89
wchar_t * product_string
Definition: hidapi.h:72
int interface_subclass
Definition: hidapi.h:88
static SDL_Joystick * joystick
Definition: testjoystick.c:37
#define USB_VENDOR_VALVE
Definition: usb_ids.h:36
#define USB_VENDOR_MICROSOFT
Definition: usb_ids.h:29
#define USB_PRODUCT_XBOX_ONE_XINPUT_CONTROLLER
Definition: usb_ids.h:56
#define USB_PRODUCT_XBOX_ONE_RAW_INPUT_CONTROLLER
Definition: usb_ids.h:55
static screen_context_t context
Definition: video.c:25