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