Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/sdl/hidapi/windows/hid.c
21345 views
1
/*******************************************************
2
HIDAPI - Multi-Platform library for
3
communication with HID devices.
4
5
Alan Ott
6
Signal 11 Software
7
8
libusb/hidapi Team
9
10
Copyright 2022, All Rights Reserved.
11
12
At the discretion of the user of this library,
13
this software may be licensed under the terms of the
14
GNU General Public License v3, a BSD-Style license, or the
15
original HIDAPI license as outlined in the LICENSE.txt,
16
LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
17
files located at the root of the source distribution.
18
These files may also be found in the public source
19
code repository located at:
20
https://github.com/libusb/hidapi .
21
********************************************************/
22
23
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
24
/* Do not warn about wcsncpy usage.
25
https://docs.microsoft.com/cpp/c-runtime-library/security-features-in-the-crt */
26
#define _CRT_SECURE_NO_WARNINGS
27
#endif
28
29
#ifdef __cplusplus
30
extern "C" {
31
#endif
32
33
#include "hidapi_winapi.h"
34
35
#include <windows.h>
36
37
#ifndef _NTDEF_
38
typedef LONG NTSTATUS;
39
#endif
40
41
#ifndef WC_ERR_INVALID_CHARS
42
#define WC_ERR_INVALID_CHARS 0x00000080
43
#endif
44
#ifndef _WIN32_WINNT_WIN8
45
#define _WIN32_WINNT_WIN8 0x0602
46
#endif
47
48
#ifdef __CYGWIN__
49
#include <ntdef.h>
50
#include <wctype.h>
51
#define _wcsdup wcsdup
52
#endif
53
54
/*#define HIDAPI_USE_DDK*/
55
56
#include "hidapi_cfgmgr32.h"
57
#include "hidapi_hidclass.h"
58
#include "hidapi_hidsdi.h"
59
60
#ifndef HIDAPI_USING_SDL_RUNTIME
61
#include <stdio.h>
62
#include <stdlib.h>
63
#include <string.h>
64
#endif
65
66
#ifdef MIN
67
#undef MIN
68
#endif
69
#define MIN(x,y) ((x) < (y)? (x): (y))
70
71
/* MAXIMUM_USB_STRING_LENGTH from usbspec.h is 255 */
72
/* BLUETOOTH_DEVICE_NAME_SIZE from bluetoothapis.h is 256 */
73
#define MAX_STRING_WCHARS 256
74
75
/* For certain USB devices, using a buffer larger or equal to 127 wchars results
76
in successful completion of HID API functions, but a broken string is stored
77
in the output buffer. This behaviour persists even if HID API is bypassed and
78
HID IOCTLs are passed to the HID driver directly. Therefore, for USB devices,
79
the buffer MUST NOT exceed 126 WCHARs.
80
*/
81
82
#define MAX_STRING_WCHARS_USB 126
83
84
static struct hid_api_version api_version = {
85
.major = HID_API_VERSION_MAJOR,
86
.minor = HID_API_VERSION_MINOR,
87
.patch = HID_API_VERSION_PATCH
88
};
89
90
#ifndef HIDAPI_USE_DDK
91
/* Since we're not building with the DDK, and the HID header
92
files aren't part of the Windows SDK, we define what we need ourselves.
93
In lookup_functions(), the function pointers
94
defined below are set. */
95
96
static HidD_GetHidGuid_ HidD_GetHidGuid;
97
static HidD_GetAttributes_ HidD_GetAttributes;
98
static HidD_GetSerialNumberString_ HidD_GetSerialNumberString;
99
static HidD_GetManufacturerString_ HidD_GetManufacturerString;
100
static HidD_GetProductString_ HidD_GetProductString;
101
static HidD_SetFeature_ HidD_SetFeature;
102
static HidD_GetFeature_ HidD_GetFeature;
103
static HidD_GetInputReport_ HidD_GetInputReport;
104
static HidD_GetIndexedString_ HidD_GetIndexedString;
105
static HidD_GetPreparsedData_ HidD_GetPreparsedData;
106
static HidD_FreePreparsedData_ HidD_FreePreparsedData;
107
static HidP_GetCaps_ HidP_GetCaps;
108
static HidD_SetNumInputBuffers_ HidD_SetNumInputBuffers;
109
static HidD_SetOutputReport_ HidD_SetOutputReport;
110
111
static CM_Locate_DevNodeW_ CM_Locate_DevNodeW = NULL;
112
static CM_Get_Parent_ CM_Get_Parent = NULL;
113
static CM_Get_DevNode_PropertyW_ CM_Get_DevNode_PropertyW = NULL;
114
static CM_Get_Device_Interface_PropertyW_ CM_Get_Device_Interface_PropertyW = NULL;
115
static CM_Get_Device_Interface_List_SizeW_ CM_Get_Device_Interface_List_SizeW = NULL;
116
static CM_Get_Device_Interface_ListW_ CM_Get_Device_Interface_ListW = NULL;
117
118
static HMODULE hid_lib_handle = NULL;
119
static HMODULE cfgmgr32_lib_handle = NULL;
120
static BOOLEAN hidapi_initialized = FALSE;
121
122
static void free_library_handles(void)
123
{
124
if (hid_lib_handle)
125
FreeLibrary(hid_lib_handle);
126
hid_lib_handle = NULL;
127
if (cfgmgr32_lib_handle)
128
FreeLibrary(cfgmgr32_lib_handle);
129
cfgmgr32_lib_handle = NULL;
130
}
131
132
#if defined(__GNUC__) && __GNUC__ >= 8
133
# pragma GCC diagnostic push
134
# pragma GCC diagnostic ignored "-Wcast-function-type"
135
#endif
136
137
static int lookup_functions(void)
138
{
139
hid_lib_handle = LoadLibraryW(L"hid.dll");
140
if (hid_lib_handle == NULL) {
141
goto err;
142
}
143
144
cfgmgr32_lib_handle = LoadLibraryW(L"cfgmgr32.dll");
145
if (cfgmgr32_lib_handle == NULL) {
146
goto err;
147
}
148
149
#define RESOLVE(lib_handle, x) x = (x##_)GetProcAddress(lib_handle, #x); if (!x) goto err;
150
151
RESOLVE(hid_lib_handle, HidD_GetHidGuid);
152
RESOLVE(hid_lib_handle, HidD_GetAttributes);
153
RESOLVE(hid_lib_handle, HidD_GetSerialNumberString);
154
RESOLVE(hid_lib_handle, HidD_GetManufacturerString);
155
RESOLVE(hid_lib_handle, HidD_GetProductString);
156
RESOLVE(hid_lib_handle, HidD_SetFeature);
157
RESOLVE(hid_lib_handle, HidD_GetFeature);
158
RESOLVE(hid_lib_handle, HidD_GetInputReport);
159
RESOLVE(hid_lib_handle, HidD_GetIndexedString);
160
RESOLVE(hid_lib_handle, HidD_GetPreparsedData);
161
RESOLVE(hid_lib_handle, HidD_FreePreparsedData);
162
RESOLVE(hid_lib_handle, HidP_GetCaps);
163
RESOLVE(hid_lib_handle, HidD_SetNumInputBuffers);
164
RESOLVE(hid_lib_handle, HidD_SetOutputReport);
165
166
RESOLVE(cfgmgr32_lib_handle, CM_Locate_DevNodeW);
167
RESOLVE(cfgmgr32_lib_handle, CM_Get_Parent);
168
RESOLVE(cfgmgr32_lib_handle, CM_Get_DevNode_PropertyW);
169
RESOLVE(cfgmgr32_lib_handle, CM_Get_Device_Interface_PropertyW);
170
RESOLVE(cfgmgr32_lib_handle, CM_Get_Device_Interface_List_SizeW);
171
RESOLVE(cfgmgr32_lib_handle, CM_Get_Device_Interface_ListW);
172
173
#undef RESOLVE
174
175
return 0;
176
177
err:
178
free_library_handles();
179
return -1;
180
}
181
182
#if defined(__GNUC__) && __GNUC__ >= 8
183
# pragma GCC diagnostic pop
184
#endif
185
186
#endif /* HIDAPI_USE_DDK */
187
188
struct hid_device_ {
189
HANDLE device_handle;
190
BOOL blocking;
191
USHORT output_report_length;
192
unsigned char *write_buf;
193
size_t input_report_length;
194
USHORT feature_report_length;
195
unsigned char *feature_buf;
196
wchar_t *last_error_str;
197
BOOL read_pending;
198
char *read_buf;
199
OVERLAPPED ol;
200
OVERLAPPED write_ol;
201
struct hid_device_info* device_info;
202
BOOL use_hid_write_output_report;
203
};
204
205
static BOOL IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor)
206
{
207
OSVERSIONINFOEXW osvi;
208
DWORDLONG const dwlConditionMask = VerSetConditionMask(
209
VerSetConditionMask(
210
VerSetConditionMask(
211
0, VER_MAJORVERSION, VER_GREATER_EQUAL ),
212
VER_MINORVERSION, VER_GREATER_EQUAL ),
213
VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL );
214
215
memset(&osvi, 0, sizeof(osvi));
216
osvi.dwOSVersionInfoSize = sizeof( osvi );
217
osvi.dwMajorVersion = wMajorVersion;
218
osvi.dwMinorVersion = wMinorVersion;
219
osvi.wServicePackMajor = wServicePackMajor;
220
221
return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE;
222
}
223
224
static hid_device *new_hid_device(void)
225
{
226
hid_device *dev = (hid_device*) calloc(1, sizeof(hid_device));
227
228
if (dev == NULL) {
229
return NULL;
230
}
231
232
dev->device_handle = INVALID_HANDLE_VALUE;
233
dev->blocking = TRUE;
234
dev->output_report_length = 0;
235
dev->write_buf = NULL;
236
dev->input_report_length = 0;
237
dev->feature_report_length = 0;
238
dev->feature_buf = NULL;
239
dev->last_error_str = NULL;
240
dev->read_pending = FALSE;
241
dev->read_buf = NULL;
242
memset(&dev->ol, 0, sizeof(dev->ol));
243
dev->ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*initial state f=nonsignaled*/, NULL);
244
memset(&dev->write_ol, 0, sizeof(dev->write_ol));
245
dev->write_ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*initial state f=nonsignaled*/, NULL);
246
dev->device_info = NULL;
247
248
return dev;
249
}
250
251
static void free_hid_device(hid_device *dev)
252
{
253
CloseHandle(dev->ol.hEvent);
254
CloseHandle(dev->write_ol.hEvent);
255
CloseHandle(dev->device_handle);
256
free(dev->last_error_str);
257
dev->last_error_str = NULL;
258
free(dev->write_buf);
259
free(dev->feature_buf);
260
free(dev->read_buf);
261
hid_free_enumeration(dev->device_info);
262
free(dev);
263
}
264
265
static void register_winapi_error_to_buffer(wchar_t **error_buffer, const WCHAR *op)
266
{
267
WCHAR system_err_buf[1024];
268
DWORD error_code = GetLastError();
269
270
free(*error_buffer);
271
*error_buffer = NULL;
272
273
#ifdef HIDAPI_USING_SDL_RUNTIME
274
/* Thread-safe error handling */
275
SDL_ClearError();
276
#endif
277
278
/* Only clear out error messages if NULL is passed into op */
279
if (!op) {
280
return;
281
}
282
283
DWORD system_err_len = FormatMessageW(
284
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
285
NULL,
286
error_code,
287
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
288
system_err_buf, ARRAYSIZE(system_err_buf),
289
NULL);
290
291
DWORD op_len = (DWORD)wcslen(op);
292
293
DWORD op_prefix_len =
294
op_len
295
+ 15 /*: (0x00000000) */
296
;
297
DWORD msg_len =
298
+ op_prefix_len
299
+ system_err_len
300
;
301
302
WCHAR *msg = (WCHAR *)calloc(msg_len + 1, sizeof (WCHAR));
303
304
if (!msg)
305
return;
306
307
int printf_written = swprintf(msg, msg_len + 1, L"%.*ls: (0x%08X) %.*ls", (int)op_len, op, error_code, (int)system_err_len, system_err_buf);
308
309
if (printf_written < 0)
310
{
311
/* Highly unlikely */
312
msg[0] = L'\0';
313
return;
314
}
315
316
/* Get rid of the CR and LF that FormatMessage() sticks at the
317
end of the message. Thanks Microsoft! */
318
while(msg[msg_len-1] == L'\r' || msg[msg_len-1] == L'\n' || msg[msg_len-1] == L' ')
319
{
320
msg[msg_len-1] = L'\0';
321
msg_len--;
322
}
323
324
#ifdef HIDAPI_USING_SDL_RUNTIME
325
/* Thread-safe error handling */
326
char *error_utf8 = SDL_iconv_wchar_utf8(msg);
327
if (error_utf8) {
328
SDL_SetError("%s", error_utf8);
329
SDL_free(error_utf8);
330
}
331
free(msg);
332
#else
333
*error_buffer = msg;
334
#endif
335
}
336
337
#if defined(__GNUC__) && (__GNUC__ + (__GNUC_MINOR__ >= 6) > 4)
338
# pragma GCC diagnostic push
339
# pragma GCC diagnostic ignored "-Warray-bounds"
340
#endif
341
/* A bug in GCC/mingw gives:
342
* error: array subscript 0 is outside array bounds of 'wchar_t *[0]' {aka 'short unsigned int *[]'} [-Werror=array-bounds]
343
* | free(*error_buffer);
344
* Which doesn't make sense in this context. */
345
346
static void register_string_error_to_buffer(wchar_t **error_buffer, const WCHAR *string_error)
347
{
348
free(*error_buffer);
349
*error_buffer = NULL;
350
351
#ifdef HIDAPI_USING_SDL_RUNTIME
352
/* Thread-safe error handling */
353
char *error_utf8 = string_error ? SDL_iconv_wchar_utf8(string_error) : NULL;
354
if (error_utf8) {
355
SDL_SetError("%s", error_utf8);
356
SDL_free(error_utf8);
357
} else {
358
SDL_ClearError();
359
}
360
#else
361
if (string_error) {
362
*error_buffer = _wcsdup(string_error);
363
}
364
#endif /* HIDAPI_USING_SDL_RUNTIME */
365
}
366
367
#if defined(__GNUC__) && (__GNUC__ + (__GNUC_MINOR__ >= 6) > 4)
368
# pragma GCC diagnostic pop
369
#endif
370
371
static void register_winapi_error(hid_device *dev, const WCHAR *op)
372
{
373
register_winapi_error_to_buffer(&dev->last_error_str, op);
374
}
375
376
static void register_string_error(hid_device *dev, const WCHAR *string_error)
377
{
378
register_string_error_to_buffer(&dev->last_error_str, string_error);
379
}
380
381
static wchar_t *last_global_error_str = NULL;
382
383
static void register_global_winapi_error(const WCHAR *op)
384
{
385
register_winapi_error_to_buffer(&last_global_error_str, op);
386
}
387
388
static void register_global_error(const WCHAR *string_error)
389
{
390
register_string_error_to_buffer(&last_global_error_str, string_error);
391
}
392
393
static HANDLE open_device(const wchar_t *path, BOOL open_rw)
394
{
395
HANDLE handle;
396
DWORD desired_access = (open_rw)? (GENERIC_WRITE | GENERIC_READ): 0;
397
DWORD share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
398
399
handle = CreateFileW(path,
400
desired_access,
401
share_mode,
402
NULL,
403
OPEN_EXISTING,
404
FILE_FLAG_OVERLAPPED,/*FILE_ATTRIBUTE_NORMAL,*/
405
0);
406
407
return handle;
408
}
409
410
HID_API_EXPORT const struct hid_api_version* HID_API_CALL hid_version(void)
411
{
412
return &api_version;
413
}
414
415
HID_API_EXPORT const char* HID_API_CALL hid_version_str(void)
416
{
417
return HID_API_VERSION_STR;
418
}
419
420
int HID_API_EXPORT hid_init(void)
421
{
422
register_global_error(NULL);
423
#ifndef HIDAPI_USE_DDK
424
if (!hidapi_initialized) {
425
if (lookup_functions() < 0) {
426
register_global_winapi_error(L"resolve DLL functions");
427
return -1;
428
}
429
hidapi_initialized = TRUE;
430
}
431
#endif
432
return 0;
433
}
434
435
int HID_API_EXPORT hid_exit(void)
436
{
437
#ifndef HIDAPI_USE_DDK
438
free_library_handles();
439
hidapi_initialized = FALSE;
440
#endif
441
register_global_error(NULL);
442
return 0;
443
}
444
445
static void* hid_internal_get_devnode_property(DEVINST dev_node, const DEVPROPKEY* property_key, DEVPROPTYPE expected_property_type)
446
{
447
ULONG len = 0;
448
CONFIGRET cr;
449
DEVPROPTYPE property_type;
450
PBYTE property_value = NULL;
451
452
cr = CM_Get_DevNode_PropertyW(dev_node, property_key, &property_type, NULL, &len, 0);
453
if (cr != CR_BUFFER_SMALL || property_type != expected_property_type)
454
return NULL;
455
456
property_value = (PBYTE)calloc(len, sizeof(BYTE));
457
cr = CM_Get_DevNode_PropertyW(dev_node, property_key, &property_type, property_value, &len, 0);
458
if (cr != CR_SUCCESS) {
459
free(property_value);
460
return NULL;
461
}
462
463
return property_value;
464
}
465
466
static void* hid_internal_get_device_interface_property(const wchar_t* interface_path, const DEVPROPKEY* property_key, DEVPROPTYPE expected_property_type)
467
{
468
ULONG len = 0;
469
CONFIGRET cr;
470
DEVPROPTYPE property_type;
471
PBYTE property_value = NULL;
472
473
cr = CM_Get_Device_Interface_PropertyW(interface_path, property_key, &property_type, NULL, &len, 0);
474
if (cr != CR_BUFFER_SMALL || property_type != expected_property_type)
475
return NULL;
476
477
property_value = (PBYTE)calloc(len, sizeof(BYTE));
478
cr = CM_Get_Device_Interface_PropertyW(interface_path, property_key, &property_type, property_value, &len, 0);
479
if (cr != CR_SUCCESS) {
480
free(property_value);
481
return NULL;
482
}
483
484
return property_value;
485
}
486
487
static void hid_internal_towupper(wchar_t* string)
488
{
489
for (wchar_t* p = string; *p; ++p) *p = towupper(*p);
490
}
491
492
static int hid_internal_extract_int_token_value(wchar_t* string, const wchar_t* token)
493
{
494
int token_value;
495
wchar_t* startptr, * endptr;
496
497
startptr = wcsstr(string, token);
498
if (!startptr)
499
return -1;
500
501
startptr += wcslen(token);
502
token_value = wcstol(startptr, &endptr, 16);
503
if (endptr == startptr)
504
return -1;
505
506
return token_value;
507
}
508
509
static void hid_internal_get_usb_info(struct hid_device_info* dev, DEVINST dev_node)
510
{
511
wchar_t *device_id = NULL, *hardware_ids = NULL;
512
513
device_id = hid_internal_get_devnode_property(dev_node, &DEVPKEY_Device_InstanceId, DEVPROP_TYPE_STRING);
514
if (!device_id)
515
goto end;
516
517
/* Normalize to upper case */
518
hid_internal_towupper(device_id);
519
520
/* Check for Xbox Common Controller class (XUSB) device.
521
https://docs.microsoft.com/windows/win32/xinput/directinput-and-xusb-devices
522
https://docs.microsoft.com/windows/win32/xinput/xinput-and-directinput
523
*/
524
if (hid_internal_extract_int_token_value(device_id, L"IG_") != -1) {
525
/* Get devnode parent to reach out USB device. */
526
if (CM_Get_Parent(&dev_node, dev_node, 0) != CR_SUCCESS)
527
goto end;
528
}
529
530
/* Get the hardware ids from devnode */
531
hardware_ids = hid_internal_get_devnode_property(dev_node, &DEVPKEY_Device_HardwareIds, DEVPROP_TYPE_STRING_LIST);
532
if (!hardware_ids)
533
goto end;
534
535
/* Get additional information from USB device's Hardware ID
536
https://docs.microsoft.com/windows-hardware/drivers/install/standard-usb-identifiers
537
https://docs.microsoft.com/windows-hardware/drivers/usbcon/enumeration-of-interfaces-not-grouped-in-collections
538
*/
539
for (wchar_t* hardware_id = hardware_ids; *hardware_id; hardware_id += wcslen(hardware_id) + 1) {
540
/* Normalize to upper case */
541
hid_internal_towupper(hardware_id);
542
543
if (dev->release_number == 0) {
544
/* USB_DEVICE_DESCRIPTOR.bcdDevice value. */
545
int release_number = hid_internal_extract_int_token_value(hardware_id, L"REV_");
546
if (release_number != -1) {
547
dev->release_number = (unsigned short)release_number;
548
}
549
}
550
551
if (dev->interface_number == -1) {
552
/* USB_INTERFACE_DESCRIPTOR.bInterfaceNumber value. */
553
int interface_number = hid_internal_extract_int_token_value(hardware_id, L"MI_");
554
if (interface_number != -1) {
555
dev->interface_number = interface_number;
556
}
557
}
558
}
559
560
/* Try to get USB device manufacturer string if not provided by HidD_GetManufacturerString. */
561
if (wcslen(dev->manufacturer_string) == 0) {
562
wchar_t* manufacturer_string = hid_internal_get_devnode_property(dev_node, &DEVPKEY_Device_Manufacturer, DEVPROP_TYPE_STRING);
563
if (manufacturer_string) {
564
free(dev->manufacturer_string);
565
dev->manufacturer_string = manufacturer_string;
566
}
567
}
568
569
/* Try to get USB device serial number if not provided by HidD_GetSerialNumberString. */
570
if (wcslen(dev->serial_number) == 0) {
571
DEVINST usb_dev_node = dev_node;
572
if (dev->interface_number != -1) {
573
/* Get devnode parent to reach out composite parent USB device.
574
https://docs.microsoft.com/windows-hardware/drivers/usbcon/enumeration-of-the-composite-parent-device
575
*/
576
if (CM_Get_Parent(&usb_dev_node, dev_node, 0) != CR_SUCCESS)
577
goto end;
578
}
579
580
/* Get the device id of the USB device. */
581
free(device_id);
582
device_id = hid_internal_get_devnode_property(usb_dev_node, &DEVPKEY_Device_InstanceId, DEVPROP_TYPE_STRING);
583
if (!device_id)
584
goto end;
585
586
/* Extract substring after last '\\' of Instance ID.
587
For USB devices it may contain device's serial number.
588
https://docs.microsoft.com/windows-hardware/drivers/install/instance-ids
589
*/
590
for (wchar_t *ptr = device_id + wcslen(device_id); ptr > device_id; --ptr) {
591
/* Instance ID is unique only within the scope of the bus.
592
For USB devices it means that serial number is not available. Skip. */
593
if (*ptr == L'&')
594
break;
595
596
if (*ptr == L'\\') {
597
free(dev->serial_number);
598
dev->serial_number = _wcsdup(ptr + 1);
599
break;
600
}
601
}
602
}
603
604
/* If we can't get the interface number, it means that there is only one interface. */
605
if (dev->interface_number == -1)
606
dev->interface_number = 0;
607
608
end:
609
free(device_id);
610
free(hardware_ids);
611
}
612
613
/* HidD_GetProductString/HidD_GetManufacturerString/HidD_GetSerialNumberString is not working for BLE HID devices
614
Request this info via dev node properties instead.
615
https://docs.microsoft.com/answers/questions/401236/hidd-getproductstring-with-ble-hid-device.html
616
*/
617
static void hid_internal_get_ble_info(struct hid_device_info* dev, DEVINST dev_node)
618
{
619
if (wcslen(dev->manufacturer_string) == 0) {
620
/* Manufacturer Name String (UUID: 0x2A29) */
621
wchar_t* manufacturer_string = hid_internal_get_devnode_property(dev_node, (const DEVPROPKEY*)&PKEY_DeviceInterface_Bluetooth_Manufacturer, DEVPROP_TYPE_STRING);
622
if (manufacturer_string) {
623
free(dev->manufacturer_string);
624
dev->manufacturer_string = manufacturer_string;
625
}
626
}
627
628
if (wcslen(dev->serial_number) == 0) {
629
/* Serial Number String (UUID: 0x2A25) */
630
wchar_t* serial_number = hid_internal_get_devnode_property(dev_node, (const DEVPROPKEY*)&PKEY_DeviceInterface_Bluetooth_DeviceAddress, DEVPROP_TYPE_STRING);
631
if (serial_number) {
632
free(dev->serial_number);
633
dev->serial_number = serial_number;
634
}
635
}
636
637
if (wcslen(dev->product_string) == 0) {
638
/* Model Number String (UUID: 0x2A24) */
639
wchar_t* product_string = hid_internal_get_devnode_property(dev_node, (const DEVPROPKEY*)&PKEY_DeviceInterface_Bluetooth_ModelNumber, DEVPROP_TYPE_STRING);
640
if (!product_string) {
641
DEVINST parent_dev_node = 0;
642
/* Fallback: Get devnode grandparent to reach out Bluetooth LE device node */
643
if (CM_Get_Parent(&parent_dev_node, dev_node, 0) == CR_SUCCESS) {
644
/* Device Name (UUID: 0x2A00) */
645
product_string = hid_internal_get_devnode_property(parent_dev_node, &DEVPKEY_NAME, DEVPROP_TYPE_STRING);
646
}
647
}
648
649
if (product_string) {
650
free(dev->product_string);
651
dev->product_string = product_string;
652
}
653
}
654
}
655
656
#ifdef HIDAPI_IGNORE_DEVICE
657
static hid_bus_type get_bus_type(const wchar_t* interface_path)
658
{
659
wchar_t *device_id = NULL, *compatible_ids = NULL;
660
CONFIGRET cr;
661
DEVINST dev_node;
662
hid_bus_type bus_type = HID_API_BUS_UNKNOWN;
663
664
/* Get the device id from interface path */
665
device_id = hid_internal_get_device_interface_property(interface_path, &DEVPKEY_Device_InstanceId, DEVPROP_TYPE_STRING);
666
if (!device_id)
667
goto end;
668
669
/* Open devnode from device id */
670
cr = CM_Locate_DevNodeW(&dev_node, (DEVINSTID_W)device_id, CM_LOCATE_DEVNODE_NORMAL);
671
if (cr != CR_SUCCESS)
672
goto end;
673
674
/* Get devnode parent */
675
cr = CM_Get_Parent(&dev_node, dev_node, 0);
676
if (cr != CR_SUCCESS)
677
goto end;
678
679
/* Get the compatible ids from parent devnode */
680
compatible_ids = hid_internal_get_devnode_property(dev_node, &DEVPKEY_Device_CompatibleIds, DEVPROP_TYPE_STRING_LIST);
681
if (!compatible_ids)
682
goto end;
683
684
/* Now we can parse parent's compatible IDs to find out the device bus type */
685
for (wchar_t* compatible_id = compatible_ids; *compatible_id; compatible_id += wcslen(compatible_id) + 1) {
686
/* Normalize to upper case */
687
hid_internal_towupper(compatible_id);
688
689
/* USB devices
690
https://docs.microsoft.com/windows-hardware/drivers/hid/plug-and-play-support
691
https://docs.microsoft.com/windows-hardware/drivers/install/standard-usb-identifiers */
692
if (wcsstr(compatible_id, L"USB") != NULL) {
693
bus_type = HID_API_BUS_USB;
694
break;
695
}
696
697
/* Bluetooth devices
698
https://docs.microsoft.com/windows-hardware/drivers/bluetooth/installing-a-bluetooth-device */
699
if (wcsstr(compatible_id, L"BTHENUM") != NULL) {
700
bus_type = HID_API_BUS_BLUETOOTH;
701
break;
702
}
703
704
/* Bluetooth LE devices */
705
if (wcsstr(compatible_id, L"BTHLEDEVICE") != NULL) {
706
bus_type = HID_API_BUS_BLUETOOTH;
707
break;
708
}
709
710
/* I2C devices
711
https://docs.microsoft.com/windows-hardware/drivers/hid/plug-and-play-support-and-power-management */
712
if (wcsstr(compatible_id, L"PNP0C50") != NULL) {
713
bus_type = HID_API_BUS_I2C;
714
break;
715
}
716
717
/* SPI devices
718
https://docs.microsoft.com/windows-hardware/drivers/hid/plug-and-play-for-spi */
719
if (wcsstr(compatible_id, L"PNP0C51") != NULL) {
720
bus_type = HID_API_BUS_SPI;
721
break;
722
}
723
}
724
end:
725
free(device_id);
726
free(compatible_ids);
727
return bus_type;
728
}
729
#endif /* HIDAPI_IGNORE_DEVICE */
730
731
/* Unfortunately, HID_API_BUS_xxx constants alone aren't enough to distinguish between BLUETOOTH and BLE */
732
733
#define HID_API_BUS_FLAG_BLE 0x01
734
735
typedef struct hid_internal_detect_bus_type_result_ {
736
DEVINST dev_node;
737
hid_bus_type bus_type;
738
unsigned int bus_flags;
739
} hid_internal_detect_bus_type_result;
740
741
static hid_internal_detect_bus_type_result hid_internal_detect_bus_type(const wchar_t* interface_path)
742
{
743
wchar_t *device_id = NULL, *compatible_ids = NULL;
744
CONFIGRET cr;
745
DEVINST dev_node;
746
hid_internal_detect_bus_type_result result = { 0 };
747
748
/* Get the device id from interface path */
749
device_id = hid_internal_get_device_interface_property(interface_path, &DEVPKEY_Device_InstanceId, DEVPROP_TYPE_STRING);
750
if (!device_id)
751
goto end;
752
753
/* Open devnode from device id */
754
cr = CM_Locate_DevNodeW(&dev_node, (DEVINSTID_W)device_id, CM_LOCATE_DEVNODE_NORMAL);
755
if (cr != CR_SUCCESS)
756
goto end;
757
758
/* Get devnode parent */
759
cr = CM_Get_Parent(&dev_node, dev_node, 0);
760
if (cr != CR_SUCCESS)
761
goto end;
762
763
/* Get the compatible ids from parent devnode */
764
compatible_ids = hid_internal_get_devnode_property(dev_node, &DEVPKEY_Device_CompatibleIds, DEVPROP_TYPE_STRING_LIST);
765
if (!compatible_ids)
766
goto end;
767
768
/* Now we can parse parent's compatible IDs to find out the device bus type */
769
for (wchar_t* compatible_id = compatible_ids; *compatible_id; compatible_id += wcslen(compatible_id) + 1) {
770
/* Normalize to upper case */
771
hid_internal_towupper(compatible_id);
772
773
/* USB devices
774
https://docs.microsoft.com/windows-hardware/drivers/hid/plug-and-play-support
775
https://docs.microsoft.com/windows-hardware/drivers/install/standard-usb-identifiers */
776
if (wcsstr(compatible_id, L"USB") != NULL) {
777
result.bus_type = HID_API_BUS_USB;
778
break;
779
}
780
781
/* Bluetooth devices
782
https://docs.microsoft.com/windows-hardware/drivers/bluetooth/installing-a-bluetooth-device */
783
if (wcsstr(compatible_id, L"BTHENUM") != NULL) {
784
result.bus_type = HID_API_BUS_BLUETOOTH;
785
break;
786
}
787
788
/* Bluetooth LE devices */
789
if (wcsstr(compatible_id, L"BTHLEDEVICE") != NULL) {
790
result.bus_type = HID_API_BUS_BLUETOOTH;
791
result.bus_flags |= HID_API_BUS_FLAG_BLE;
792
break;
793
}
794
795
/* I2C devices
796
https://docs.microsoft.com/windows-hardware/drivers/hid/plug-and-play-support-and-power-management */
797
if (wcsstr(compatible_id, L"PNP0C50") != NULL) {
798
result.bus_type = HID_API_BUS_I2C;
799
break;
800
}
801
802
/* SPI devices
803
https://docs.microsoft.com/windows-hardware/drivers/hid/plug-and-play-for-spi */
804
if (wcsstr(compatible_id, L"PNP0C51") != NULL) {
805
result.bus_type = HID_API_BUS_SPI;
806
break;
807
}
808
}
809
810
result.dev_node = dev_node;
811
812
end:
813
free(device_id);
814
free(compatible_ids);
815
return result;
816
}
817
818
static char *hid_internal_UTF16toUTF8(const wchar_t *src)
819
{
820
char *dst = NULL;
821
#ifdef HIDAPI_USING_SDL_RUNTIME
822
int len = WIN_WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, src, -1, NULL, 0, NULL, NULL);
823
#else
824
int len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, src, -1, NULL, 0, NULL, NULL);
825
#endif
826
if (len) {
827
dst = (char*)calloc(len, sizeof(char));
828
if (dst == NULL) {
829
return NULL;
830
}
831
#ifdef HIDAPI_USING_SDL_RUNTIME
832
WIN_WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, src, -1, dst, len, NULL, NULL);
833
#else
834
WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, src, -1, dst, len, NULL, NULL);
835
#endif
836
}
837
838
return dst;
839
}
840
841
static wchar_t *hid_internal_UTF8toUTF16(const char *src)
842
{
843
wchar_t *dst = NULL;
844
int len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src, -1, NULL, 0);
845
if (len) {
846
dst = (wchar_t*)calloc(len, sizeof(wchar_t));
847
if (dst == NULL) {
848
return NULL;
849
}
850
MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src, -1, dst, len);
851
}
852
853
return dst;
854
}
855
856
static struct hid_device_info *hid_internal_get_device_info(const wchar_t *path, HANDLE handle)
857
{
858
struct hid_device_info *dev = NULL; /* return object */
859
HIDD_ATTRIBUTES attrib;
860
PHIDP_PREPARSED_DATA pp_data = NULL;
861
HIDP_CAPS caps;
862
wchar_t string[MAX_STRING_WCHARS + 1];
863
ULONG len;
864
ULONG size;
865
hid_internal_detect_bus_type_result detect_bus_type_result;
866
867
/* Create the record. */
868
dev = (struct hid_device_info*)calloc(1, sizeof(struct hid_device_info));
869
870
if (dev == NULL) {
871
return NULL;
872
}
873
874
/* Fill out the record */
875
dev->next = NULL;
876
dev->path = hid_internal_UTF16toUTF8(path);
877
dev->interface_number = -1;
878
879
attrib.Size = sizeof(HIDD_ATTRIBUTES);
880
if (HidD_GetAttributes(handle, &attrib)) {
881
/* VID/PID */
882
dev->vendor_id = attrib.VendorID;
883
dev->product_id = attrib.ProductID;
884
885
/* Release Number */
886
dev->release_number = attrib.VersionNumber;
887
}
888
889
/* Get the Usage Page and Usage for this device. */
890
if (HidD_GetPreparsedData(handle, &pp_data)) {
891
if (HidP_GetCaps(pp_data, &caps) == HIDP_STATUS_SUCCESS) {
892
dev->usage_page = caps.UsagePage;
893
dev->usage = caps.Usage;
894
}
895
896
HidD_FreePreparsedData(pp_data);
897
}
898
899
/* detect bus type before reading string descriptors */
900
detect_bus_type_result = hid_internal_detect_bus_type(path);
901
dev->bus_type = detect_bus_type_result.bus_type;
902
903
len = dev->bus_type == HID_API_BUS_USB ? MAX_STRING_WCHARS_USB : MAX_STRING_WCHARS;
904
string[len] = L'\0';
905
size = len * sizeof(wchar_t);
906
907
/* Serial Number */
908
string[0] = L'\0';
909
HidD_GetSerialNumberString(handle, string, size);
910
dev->serial_number = _wcsdup(string);
911
912
/* Manufacturer String */
913
string[0] = L'\0';
914
HidD_GetManufacturerString(handle, string, size);
915
dev->manufacturer_string = _wcsdup(string);
916
917
/* Product String */
918
string[0] = L'\0';
919
HidD_GetProductString(handle, string, size);
920
dev->product_string = _wcsdup(string);
921
922
/* now, the portion that depends on string descriptors */
923
switch (dev->bus_type) {
924
case HID_API_BUS_USB:
925
hid_internal_get_usb_info(dev, detect_bus_type_result.dev_node);
926
break;
927
928
case HID_API_BUS_BLUETOOTH:
929
if (detect_bus_type_result.bus_flags & HID_API_BUS_FLAG_BLE)
930
hid_internal_get_ble_info(dev, detect_bus_type_result.dev_node);
931
break;
932
933
case HID_API_BUS_UNKNOWN:
934
case HID_API_BUS_SPI:
935
case HID_API_BUS_I2C:
936
/* shut down -Wswitch */
937
break;
938
}
939
940
return dev;
941
}
942
943
static int hid_blacklist(unsigned short vendor_id, unsigned short product_id)
944
{
945
size_t i;
946
static const struct { unsigned short vid; unsigned short pid; } known_bad[] = {
947
{ 0x045E, 0x0822 }, /* Microsoft Precision Mouse - causes deadlock asking for device details */
948
{ 0x0738, 0x2217 }, /* SPEEDLINK COMPETITION PRO - turns into an Android controller when enumerated */
949
{ 0x0D8C, 0x0014 }, /* Sharkoon Skiller SGH2 headset - causes deadlock asking for device details */
950
{ 0x1532, 0x0109 }, /* Razer Lycosa Gaming keyboard - causes deadlock asking for device details */
951
{ 0x1532, 0x010B }, /* Razer Arctosa Gaming keyboard - causes deadlock asking for device details */
952
{ 0x1532, 0x0227 }, /* Razer Huntsman Gaming keyboard - long delay asking for device details */
953
{ 0x1B1C, 0x1B3D }, /* Corsair Gaming keyboard - causes deadlock asking for device details */
954
{ 0x1CCF, 0x0000 } /* All Konami Amusement Devices - causes deadlock asking for device details */
955
};
956
957
for (i = 0; i < (sizeof(known_bad)/sizeof(known_bad[0])); i++) {
958
if ((vendor_id == known_bad[i].vid) && (product_id == known_bad[i].pid || known_bad[i].pid == 0x0000)) {
959
return 1;
960
}
961
}
962
963
return 0;
964
}
965
966
struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id)
967
{
968
struct hid_device_info *root = NULL; /* return object */
969
struct hid_device_info *cur_dev = NULL;
970
GUID interface_class_guid;
971
CONFIGRET cr;
972
wchar_t* device_interface_list = NULL;
973
DWORD len;
974
975
if (hid_init() < 0) {
976
/* register_global_error: global error is reset by hid_init */
977
return NULL;
978
}
979
980
/* Retrieve HID Interface Class GUID
981
https://docs.microsoft.com/windows-hardware/drivers/install/guid-devinterface-hid */
982
HidD_GetHidGuid(&interface_class_guid);
983
984
/* Get the list of all device interfaces belonging to the HID class. */
985
/* Retry in case of list was changed between calls to
986
CM_Get_Device_Interface_List_SizeW and CM_Get_Device_Interface_ListW */
987
do {
988
cr = CM_Get_Device_Interface_List_SizeW(&len, &interface_class_guid, NULL, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
989
if (cr != CR_SUCCESS) {
990
register_global_error(L"Failed to get size of HID device interface list");
991
break;
992
}
993
994
if (device_interface_list != NULL) {
995
free(device_interface_list);
996
}
997
998
device_interface_list = (wchar_t*)calloc(len, sizeof(wchar_t));
999
if (device_interface_list == NULL) {
1000
register_global_error(L"Failed to allocate memory for HID device interface list");
1001
return NULL;
1002
}
1003
cr = CM_Get_Device_Interface_ListW(&interface_class_guid, NULL, device_interface_list, len, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
1004
if (cr != CR_SUCCESS && cr != CR_BUFFER_SMALL) {
1005
register_global_error(L"Failed to get HID device interface list");
1006
}
1007
} while (cr == CR_BUFFER_SMALL);
1008
1009
if (cr != CR_SUCCESS) {
1010
goto end_of_function;
1011
}
1012
1013
/* Iterate over each device interface in the HID class, looking for the right one. */
1014
for (wchar_t* device_interface = device_interface_list; *device_interface; device_interface += wcslen(device_interface) + 1) {
1015
HANDLE device_handle = INVALID_HANDLE_VALUE;
1016
HIDD_ATTRIBUTES attrib;
1017
1018
/* XInput devices don't get real HID reports and are better handled by the raw input driver */
1019
if (wcsstr(device_interface, L"&IG_") != NULL) {
1020
continue;
1021
}
1022
1023
/* Open read-only handle to the device */
1024
device_handle = open_device(device_interface, FALSE);
1025
1026
/* Check validity of device_handle. */
1027
if (device_handle == INVALID_HANDLE_VALUE) {
1028
/* Unable to open the device. */
1029
continue;
1030
}
1031
1032
/* Get the Vendor ID and Product ID for this device. */
1033
attrib.Size = sizeof(HIDD_ATTRIBUTES);
1034
if (!HidD_GetAttributes(device_handle, &attrib)) {
1035
goto cont_close;
1036
}
1037
1038
#ifdef HIDAPI_IGNORE_DEVICE
1039
/* See if there are any devices we should skip in enumeration */
1040
hid_bus_type bus_type = get_bus_type(device_interface);
1041
PHIDP_PREPARSED_DATA pp_data = NULL;
1042
HIDP_CAPS caps = { 0 };
1043
if (HidD_GetPreparsedData(device_handle, &pp_data)) {
1044
HidP_GetCaps(pp_data, &caps);
1045
HidD_FreePreparsedData(pp_data);
1046
}
1047
if (HIDAPI_IGNORE_DEVICE(bus_type, attrib.VendorID, attrib.ProductID, caps.UsagePage, caps.Usage)) {
1048
goto cont_close;
1049
}
1050
#endif
1051
1052
/* Check the VID/PID to see if we should add this
1053
device to the enumeration list. */
1054
if ((vendor_id == 0x0 || attrib.VendorID == vendor_id) &&
1055
(product_id == 0x0 || attrib.ProductID == product_id) &&
1056
!hid_blacklist(attrib.VendorID, attrib.ProductID)) {
1057
1058
/* VID/PID match. Create the record. */
1059
struct hid_device_info *tmp = hid_internal_get_device_info(device_interface, device_handle);
1060
1061
if (tmp == NULL) {
1062
goto cont_close;
1063
}
1064
1065
if (cur_dev) {
1066
cur_dev->next = tmp;
1067
}
1068
else {
1069
root = tmp;
1070
}
1071
cur_dev = tmp;
1072
}
1073
1074
cont_close:
1075
CloseHandle(device_handle);
1076
}
1077
1078
if (root == NULL) {
1079
if (vendor_id == 0 && product_id == 0) {
1080
register_global_error(L"No HID devices found in the system.");
1081
} else {
1082
register_global_error(L"No HID devices with requested VID/PID found in the system.");
1083
}
1084
}
1085
1086
end_of_function:
1087
free(device_interface_list);
1088
1089
return root;
1090
}
1091
1092
void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs)
1093
{
1094
/* TODO: Merge this with the Linux version. This function is platform-independent. */
1095
struct hid_device_info *d = devs;
1096
while (d) {
1097
struct hid_device_info *next = d->next;
1098
free(d->path);
1099
free(d->serial_number);
1100
free(d->manufacturer_string);
1101
free(d->product_string);
1102
free(d);
1103
d = next;
1104
}
1105
}
1106
1107
HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
1108
{
1109
/* TODO: Merge this functions with the Linux version. This function should be platform independent. */
1110
struct hid_device_info *devs, *cur_dev;
1111
const char *path_to_open = NULL;
1112
hid_device *handle = NULL;
1113
1114
/* register_global_error: global error is reset by hid_enumerate/hid_init */
1115
devs = hid_enumerate(vendor_id, product_id);
1116
if (!devs) {
1117
/* register_global_error: global error is already set by hid_enumerate */
1118
return NULL;
1119
}
1120
1121
cur_dev = devs;
1122
while (cur_dev) {
1123
if (cur_dev->vendor_id == vendor_id &&
1124
cur_dev->product_id == product_id) {
1125
if (serial_number) {
1126
if (cur_dev->serial_number && wcscmp(serial_number, cur_dev->serial_number) == 0) {
1127
path_to_open = cur_dev->path;
1128
break;
1129
}
1130
}
1131
else {
1132
path_to_open = cur_dev->path;
1133
break;
1134
}
1135
}
1136
cur_dev = cur_dev->next;
1137
}
1138
1139
if (path_to_open) {
1140
/* Open the device */
1141
handle = hid_open_path(path_to_open);
1142
} else {
1143
register_global_error(L"Device with requested VID/PID/(SerialNumber) not found");
1144
}
1145
1146
hid_free_enumeration(devs);
1147
1148
return handle;
1149
}
1150
1151
HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path)
1152
{
1153
hid_device *dev = NULL;
1154
wchar_t* interface_path = NULL;
1155
HANDLE device_handle = INVALID_HANDLE_VALUE;
1156
PHIDP_PREPARSED_DATA pp_data = NULL;
1157
HIDP_CAPS caps;
1158
1159
if (hid_init() < 0) {
1160
/* register_global_error: global error is reset by hid_init */
1161
goto end_of_function;
1162
}
1163
1164
interface_path = hid_internal_UTF8toUTF16(path);
1165
if (!interface_path) {
1166
register_global_error(L"Path conversion failure");
1167
goto end_of_function;
1168
}
1169
1170
/* Open a handle to the device */
1171
device_handle = open_device(interface_path, TRUE);
1172
1173
/* Check validity of write_handle. */
1174
if (device_handle == INVALID_HANDLE_VALUE) {
1175
/* System devices, such as keyboards and mice, cannot be opened in
1176
read-write mode, because the system takes exclusive control over
1177
them. This is to prevent keyloggers. However, feature reports
1178
can still be sent and received. Retry opening the device, but
1179
without read/write access. */
1180
device_handle = open_device(interface_path, FALSE);
1181
1182
/* Check the validity of the limited device_handle. */
1183
if (device_handle == INVALID_HANDLE_VALUE) {
1184
register_global_winapi_error(L"open_device");
1185
goto end_of_function;
1186
}
1187
}
1188
1189
/* Set the Input Report buffer size to 64 reports. */
1190
if (!HidD_SetNumInputBuffers(device_handle, 64)) {
1191
register_global_winapi_error(L"set input buffers");
1192
goto end_of_function;
1193
}
1194
1195
/* Get the Input Report length for the device. */
1196
if (!HidD_GetPreparsedData(device_handle, &pp_data)) {
1197
register_global_winapi_error(L"get preparsed data");
1198
goto end_of_function;
1199
}
1200
1201
if (HidP_GetCaps(pp_data, &caps) != HIDP_STATUS_SUCCESS) {
1202
register_global_error(L"HidP_GetCaps");
1203
goto end_of_function;
1204
}
1205
1206
dev = new_hid_device();
1207
1208
if (dev == NULL) {
1209
register_global_error(L"hid_device allocation error");
1210
goto end_of_function;
1211
}
1212
1213
dev->device_handle = device_handle;
1214
device_handle = INVALID_HANDLE_VALUE;
1215
1216
dev->output_report_length = caps.OutputReportByteLength;
1217
dev->input_report_length = caps.InputReportByteLength;
1218
dev->feature_report_length = caps.FeatureReportByteLength;
1219
dev->read_buf = (char*) malloc(dev->input_report_length);
1220
dev->device_info = hid_internal_get_device_info(interface_path, dev->device_handle);
1221
1222
/* On Windows 7, we need to use hid_write_output_report() over Bluetooth */
1223
if (dev->output_report_length > 512) {
1224
dev->use_hid_write_output_report = !IsWindowsVersionOrGreater( HIBYTE( _WIN32_WINNT_WIN8 ), LOBYTE( _WIN32_WINNT_WIN8 ), 0 );
1225
}
1226
1227
end_of_function:
1228
free(interface_path);
1229
CloseHandle(device_handle);
1230
1231
if (pp_data) {
1232
HidD_FreePreparsedData(pp_data);
1233
}
1234
1235
return dev;
1236
}
1237
1238
static int hid_write_output_report(hid_device *dev, const unsigned char *data, size_t length)
1239
{
1240
BOOL res;
1241
res = HidD_SetOutputReport(dev->device_handle, (void *)data, (ULONG)length);
1242
if (res)
1243
return (int)length;
1244
else
1245
return -1;
1246
}
1247
1248
int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length)
1249
{
1250
DWORD bytes_written = 0;
1251
int function_result = -1;
1252
BOOL res;
1253
BOOL overlapped = FALSE;
1254
1255
unsigned char *buf;
1256
1257
if (!data || !length) {
1258
register_string_error(dev, L"Zero buffer/length");
1259
return function_result;
1260
}
1261
1262
register_string_error(dev, NULL);
1263
1264
if (dev->use_hid_write_output_report) {
1265
return hid_write_output_report(dev, data, length);
1266
}
1267
1268
/* Make sure the right number of bytes are passed to WriteFile. Windows
1269
expects the number of bytes which are in the _longest_ report (plus
1270
one for the report number) bytes even if the data is a report
1271
which is shorter than that. Windows gives us this value in
1272
caps.OutputReportByteLength. If a user passes in fewer bytes than this,
1273
use cached temporary buffer which is the proper size. */
1274
if (length >= dev->output_report_length) {
1275
/* The user passed the right number of bytes. Use the buffer as-is. */
1276
buf = (unsigned char *) data;
1277
} else {
1278
if (dev->write_buf == NULL)
1279
dev->write_buf = (unsigned char *) malloc(dev->output_report_length);
1280
buf = dev->write_buf;
1281
memcpy(buf, data, length);
1282
memset(buf + length, 0, dev->output_report_length - length);
1283
length = dev->output_report_length;
1284
}
1285
1286
res = WriteFile(dev->device_handle, buf, (DWORD) length, &bytes_written, &dev->write_ol);
1287
1288
if (!res) {
1289
if (GetLastError() != ERROR_IO_PENDING) {
1290
/* WriteFile() failed. Return error. */
1291
register_winapi_error(dev, L"WriteFile");
1292
goto end_of_function;
1293
}
1294
overlapped = TRUE;
1295
} else {
1296
/* WriteFile() succeeded synchronously. */
1297
function_result = bytes_written;
1298
}
1299
1300
if (overlapped) {
1301
/* Wait for the transaction to complete. This makes
1302
hid_write() synchronous. */
1303
res = WaitForSingleObject(dev->write_ol.hEvent, 1000);
1304
if (res != WAIT_OBJECT_0) {
1305
/* There was a Timeout. */
1306
register_winapi_error(dev, L"hid_write/WaitForSingleObject");
1307
goto end_of_function;
1308
}
1309
1310
/* Get the result. */
1311
res = GetOverlappedResult(dev->device_handle, &dev->write_ol, &bytes_written, FALSE/*wait*/);
1312
if (res) {
1313
function_result = bytes_written;
1314
}
1315
else {
1316
/* The Write operation failed. */
1317
register_winapi_error(dev, L"hid_write/GetOverlappedResult");
1318
goto end_of_function;
1319
}
1320
}
1321
1322
end_of_function:
1323
return function_result;
1324
}
1325
1326
1327
int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
1328
{
1329
DWORD bytes_read = 0;
1330
size_t copy_len = 0;
1331
BOOL res = FALSE;
1332
BOOL overlapped = FALSE;
1333
1334
if (!data || !length) {
1335
register_string_error(dev, L"Zero buffer/length");
1336
return -1;
1337
}
1338
1339
register_string_error(dev, NULL);
1340
1341
/* Copy the handle for convenience. */
1342
HANDLE ev = dev->ol.hEvent;
1343
1344
if (!dev->read_pending) {
1345
/* Start an Overlapped I/O read. */
1346
dev->read_pending = TRUE;
1347
memset(dev->read_buf, 0, dev->input_report_length);
1348
ResetEvent(ev);
1349
res = ReadFile(dev->device_handle, dev->read_buf, (DWORD) dev->input_report_length, &bytes_read, &dev->ol);
1350
1351
if (!res) {
1352
if (GetLastError() != ERROR_IO_PENDING) {
1353
/* ReadFile() has failed.
1354
Clean up and return error. */
1355
register_winapi_error(dev, L"ReadFile");
1356
CancelIo(dev->device_handle);
1357
dev->read_pending = FALSE;
1358
goto end_of_function;
1359
}
1360
overlapped = TRUE;
1361
}
1362
}
1363
else {
1364
overlapped = TRUE;
1365
}
1366
1367
if (overlapped) {
1368
/* See if there is any data yet. */
1369
res = WaitForSingleObject(ev, milliseconds >= 0 ? (DWORD)milliseconds : INFINITE);
1370
if (res != WAIT_OBJECT_0) {
1371
/* There was no data this time. Return zero bytes available,
1372
but leave the Overlapped I/O running. */
1373
return 0;
1374
}
1375
1376
/* Get the number of bytes read. The actual data has been copied to the data[]
1377
array which was passed to ReadFile(). We must not wait here because we've
1378
already waited on our event above, and since it's auto-reset, it will have
1379
been reset back to unsignalled by now. */
1380
res = GetOverlappedResult(dev->device_handle, &dev->ol, &bytes_read, FALSE/*don't wait now - already did on the prev step*/);
1381
}
1382
/* Set pending back to false, even if GetOverlappedResult() returned error. */
1383
dev->read_pending = FALSE;
1384
1385
if (res && bytes_read > 0) {
1386
if (dev->read_buf[0] == 0x0) {
1387
/* If report numbers aren't being used, but Windows sticks a report
1388
number (0x0) on the beginning of the report anyway. To make this
1389
work like the other platforms, and to make it work more like the
1390
HID spec, we'll skip over this byte. */
1391
bytes_read--;
1392
copy_len = length > bytes_read ? bytes_read : length;
1393
memcpy(data, dev->read_buf+1, copy_len);
1394
}
1395
else {
1396
/* Copy the whole buffer, report number and all. */
1397
copy_len = length > bytes_read ? bytes_read : length;
1398
memcpy(data, dev->read_buf, copy_len);
1399
}
1400
}
1401
if (!res) {
1402
if (GetLastError() == ERROR_OPERATION_ABORTED) {
1403
/* The read request was issued on another thread.
1404
This is harmless, so just ignore it. */
1405
return 0;
1406
}
1407
register_winapi_error(dev, L"hid_read_timeout/GetOverlappedResult");
1408
}
1409
1410
end_of_function:
1411
if (!res) {
1412
return -1;
1413
}
1414
1415
return (int) copy_len;
1416
}
1417
1418
int HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, size_t length)
1419
{
1420
return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0);
1421
}
1422
1423
int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *dev, int nonblock)
1424
{
1425
dev->blocking = !nonblock;
1426
return 0; /* Success */
1427
}
1428
1429
int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)
1430
{
1431
BOOL res = FALSE;
1432
unsigned char *buf;
1433
size_t length_to_send;
1434
1435
if (!data || !length) {
1436
register_string_error(dev, L"Zero buffer/length");
1437
return -1;
1438
}
1439
1440
register_string_error(dev, NULL);
1441
1442
/* Windows expects at least caps.FeatureReportByteLength bytes passed
1443
to HidD_SetFeature(), even if the report is shorter. Any less sent and
1444
the function fails with error ERROR_INVALID_PARAMETER set. Any more
1445
and HidD_SetFeature() silently truncates the data sent in the report
1446
to caps.FeatureReportByteLength. */
1447
if (length >= dev->feature_report_length) {
1448
buf = (unsigned char *) data;
1449
length_to_send = length;
1450
} else {
1451
if (dev->feature_buf == NULL)
1452
dev->feature_buf = (unsigned char *) malloc(dev->feature_report_length);
1453
buf = dev->feature_buf;
1454
memcpy(buf, data, length);
1455
memset(buf + length, 0, dev->feature_report_length - length);
1456
length_to_send = dev->feature_report_length;
1457
}
1458
1459
res = HidD_SetFeature(dev->device_handle, (PVOID)buf, (DWORD) length_to_send);
1460
1461
if (!res) {
1462
register_winapi_error(dev, L"HidD_SetFeature");
1463
return -1;
1464
}
1465
1466
return (int) length;
1467
}
1468
1469
static int hid_get_report(hid_device *dev, DWORD report_type, unsigned char *data, size_t length)
1470
{
1471
BOOL res;
1472
DWORD bytes_returned = 0;
1473
1474
OVERLAPPED ol;
1475
memset(&ol, 0, sizeof(ol));
1476
1477
if (!data || !length) {
1478
register_string_error(dev, L"Zero buffer/length");
1479
return -1;
1480
}
1481
1482
register_string_error(dev, NULL);
1483
1484
res = DeviceIoControl(dev->device_handle,
1485
report_type,
1486
data, (DWORD) length,
1487
data, (DWORD) length,
1488
&bytes_returned, &ol);
1489
1490
if (!res) {
1491
if (GetLastError() != ERROR_IO_PENDING) {
1492
/* DeviceIoControl() failed. Return error. */
1493
register_winapi_error(dev, L"Get Input/Feature Report DeviceIoControl");
1494
return -1;
1495
}
1496
}
1497
1498
/* Wait here until the write is done. This makes
1499
hid_get_feature_report() synchronous. */
1500
res = GetOverlappedResult(dev->device_handle, &ol, &bytes_returned, TRUE/*wait*/);
1501
if (!res) {
1502
/* The operation failed. */
1503
register_winapi_error(dev, L"Get Input/Feature Report GetOverLappedResult");
1504
return -1;
1505
}
1506
1507
/* When numbered reports aren't used,
1508
bytes_returned seem to include only what is actually received from the device
1509
(not including the first byte with 0, as an indication "no numbered reports"). */
1510
if (data[0] == 0x0) {
1511
bytes_returned++;
1512
}
1513
1514
return bytes_returned;
1515
}
1516
1517
int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
1518
{
1519
/* We could use HidD_GetFeature() instead, but it doesn't give us an actual length, unfortunately */
1520
return hid_get_report(dev, IOCTL_HID_GET_FEATURE, data, length);
1521
}
1522
1523
int HID_API_EXPORT HID_API_CALL hid_get_input_report(hid_device *dev, unsigned char *data, size_t length)
1524
{
1525
/* We could use HidD_GetInputReport() instead, but it doesn't give us an actual length, unfortunately */
1526
return hid_get_report(dev, IOCTL_HID_GET_INPUT_REPORT, data, length);
1527
}
1528
1529
#if defined(__GNUC__) && __GNUC__ >= 8
1530
# pragma GCC diagnostic push
1531
# pragma GCC diagnostic ignored "-Wcast-function-type"
1532
#endif
1533
void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev)
1534
{
1535
typedef BOOL (WINAPI *CancelIoEx_t)(HANDLE hFile, LPOVERLAPPED lpOverlapped);
1536
CancelIoEx_t CancelIoExFunc = (CancelIoEx_t)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "CancelIoEx");
1537
1538
if (!dev)
1539
return;
1540
1541
if (CancelIoExFunc) {
1542
CancelIoExFunc(dev->device_handle, NULL);
1543
} else {
1544
/* Windows XP, this will only cancel I/O on the current thread */
1545
CancelIo(dev->device_handle);
1546
}
1547
if (dev->read_pending) {
1548
DWORD bytes_read = 0;
1549
GetOverlappedResult(dev->device_handle, &dev->ol, &bytes_read, TRUE/*wait*/);
1550
}
1551
free_hid_device(dev);
1552
}
1553
#if defined(__GNUC__) && __GNUC__ >= 8
1554
# pragma GCC diagnostic pop
1555
#endif
1556
1557
int HID_API_EXPORT_CALL HID_API_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)
1558
{
1559
if (!string || !maxlen) {
1560
register_string_error(dev, L"Zero buffer/length");
1561
return -1;
1562
}
1563
1564
if (!dev->device_info) {
1565
register_string_error(dev, L"NULL device info");
1566
return -1;
1567
}
1568
1569
wcsncpy(string, dev->device_info->manufacturer_string, maxlen);
1570
string[maxlen - 1] = L'\0';
1571
1572
register_string_error(dev, NULL);
1573
1574
return 0;
1575
}
1576
1577
int HID_API_EXPORT_CALL HID_API_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)
1578
{
1579
if (!string || !maxlen) {
1580
register_string_error(dev, L"Zero buffer/length");
1581
return -1;
1582
}
1583
1584
if (!dev->device_info) {
1585
register_string_error(dev, L"NULL device info");
1586
return -1;
1587
}
1588
1589
wcsncpy(string, dev->device_info->product_string, maxlen);
1590
string[maxlen - 1] = L'\0';
1591
1592
register_string_error(dev, NULL);
1593
1594
return 0;
1595
}
1596
1597
int HID_API_EXPORT_CALL HID_API_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)
1598
{
1599
if (!string || !maxlen) {
1600
register_string_error(dev, L"Zero buffer/length");
1601
return -1;
1602
}
1603
1604
if (!dev->device_info) {
1605
register_string_error(dev, L"NULL device info");
1606
return -1;
1607
}
1608
1609
wcsncpy(string, dev->device_info->serial_number, maxlen);
1610
string[maxlen - 1] = L'\0';
1611
1612
register_string_error(dev, NULL);
1613
1614
return 0;
1615
}
1616
1617
HID_API_EXPORT struct hid_device_info * HID_API_CALL hid_get_device_info(hid_device *dev) {
1618
if (!dev->device_info)
1619
{
1620
register_string_error(dev, L"NULL device info");
1621
return NULL;
1622
}
1623
1624
return dev->device_info;
1625
}
1626
1627
int HID_API_EXPORT_CALL HID_API_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)
1628
{
1629
BOOL res;
1630
1631
if (dev->device_info && dev->device_info->bus_type == HID_API_BUS_USB && maxlen > MAX_STRING_WCHARS_USB) {
1632
string[MAX_STRING_WCHARS_USB] = L'\0';
1633
maxlen = MAX_STRING_WCHARS_USB;
1634
}
1635
1636
res = HidD_GetIndexedString(dev->device_handle, string_index, string, (ULONG)maxlen * sizeof(wchar_t));
1637
if (!res) {
1638
register_winapi_error(dev, L"HidD_GetIndexedString");
1639
return -1;
1640
}
1641
1642
register_string_error(dev, NULL);
1643
1644
return 0;
1645
}
1646
1647
int HID_API_EXPORT_CALL hid_winapi_get_container_id(hid_device *dev, GUID *container_id)
1648
{
1649
wchar_t *interface_path = NULL, *device_id = NULL;
1650
CONFIGRET cr = CR_FAILURE;
1651
DEVINST dev_node;
1652
DEVPROPTYPE property_type;
1653
ULONG len;
1654
1655
if (!container_id) {
1656
register_string_error(dev, L"Invalid Container ID");
1657
return -1;
1658
}
1659
1660
register_string_error(dev, NULL);
1661
1662
interface_path = hid_internal_UTF8toUTF16(dev->device_info->path);
1663
if (!interface_path) {
1664
register_string_error(dev, L"Path conversion failure");
1665
goto end;
1666
}
1667
1668
/* Get the device id from interface path */
1669
device_id = hid_internal_get_device_interface_property(interface_path, &DEVPKEY_Device_InstanceId, DEVPROP_TYPE_STRING);
1670
if (!device_id) {
1671
register_string_error(dev, L"Failed to get device interface property InstanceId");
1672
goto end;
1673
}
1674
1675
/* Open devnode from device id */
1676
cr = CM_Locate_DevNodeW(&dev_node, (DEVINSTID_W)device_id, CM_LOCATE_DEVNODE_NORMAL);
1677
if (cr != CR_SUCCESS) {
1678
register_string_error(dev, L"Failed to locate device node");
1679
goto end;
1680
}
1681
1682
/* Get the container id from devnode */
1683
len = sizeof(*container_id);
1684
cr = CM_Get_DevNode_PropertyW(dev_node, &DEVPKEY_Device_ContainerId, &property_type, (PBYTE)container_id, &len, 0);
1685
if (cr == CR_SUCCESS && property_type != DEVPROP_TYPE_GUID)
1686
cr = CR_FAILURE;
1687
1688
if (cr != CR_SUCCESS)
1689
register_string_error(dev, L"Failed to read ContainerId property from device node");
1690
1691
end:
1692
free(interface_path);
1693
free(device_id);
1694
1695
return cr == CR_SUCCESS ? 0 : -1;
1696
}
1697
1698
1699
int HID_API_EXPORT_CALL hid_get_report_descriptor(hid_device *dev, unsigned char *buf, size_t buf_size)
1700
{
1701
PHIDP_PREPARSED_DATA pp_data = NULL;
1702
1703
if (!HidD_GetPreparsedData(dev->device_handle, &pp_data) || pp_data == NULL) {
1704
register_string_error(dev, L"HidD_GetPreparsedData");
1705
return -1;
1706
}
1707
1708
int res = hid_winapi_descriptor_reconstruct_pp_data(pp_data, buf, buf_size);
1709
1710
HidD_FreePreparsedData(pp_data);
1711
1712
return res;
1713
}
1714
1715
HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev)
1716
{
1717
if (dev) {
1718
if (dev->last_error_str == NULL)
1719
return L"Success";
1720
return (wchar_t*)dev->last_error_str;
1721
}
1722
1723
if (last_global_error_str == NULL)
1724
return L"Success";
1725
return last_global_error_str;
1726
}
1727
1728
#ifndef hidapi_winapi_EXPORTS
1729
#include "hidapi_descriptor_reconstruct.c"
1730
#endif
1731
1732
#ifdef __cplusplus
1733
} /* extern "C" */
1734
#endif
1735
1736