Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/sdl/hidapi/windows/hid.c
9917 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
{ 0x1B1C, 0x1B3D }, /* Corsair Gaming keyboard - causes deadlock asking for device details */
953
{ 0x1CCF, 0x0000 } /* All Konami Amusement Devices - causes deadlock asking for device details */
954
};
955
956
for (i = 0; i < (sizeof(known_bad)/sizeof(known_bad[0])); i++) {
957
if ((vendor_id == known_bad[i].vid) && (product_id == known_bad[i].pid || known_bad[i].pid == 0x0000)) {
958
return 1;
959
}
960
}
961
962
return 0;
963
}
964
965
struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id)
966
{
967
struct hid_device_info *root = NULL; /* return object */
968
struct hid_device_info *cur_dev = NULL;
969
GUID interface_class_guid;
970
CONFIGRET cr;
971
wchar_t* device_interface_list = NULL;
972
DWORD len;
973
974
if (hid_init() < 0) {
975
/* register_global_error: global error is reset by hid_init */
976
return NULL;
977
}
978
979
/* Retrieve HID Interface Class GUID
980
https://docs.microsoft.com/windows-hardware/drivers/install/guid-devinterface-hid */
981
HidD_GetHidGuid(&interface_class_guid);
982
983
/* Get the list of all device interfaces belonging to the HID class. */
984
/* Retry in case of list was changed between calls to
985
CM_Get_Device_Interface_List_SizeW and CM_Get_Device_Interface_ListW */
986
do {
987
cr = CM_Get_Device_Interface_List_SizeW(&len, &interface_class_guid, NULL, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
988
if (cr != CR_SUCCESS) {
989
register_global_error(L"Failed to get size of HID device interface list");
990
break;
991
}
992
993
if (device_interface_list != NULL) {
994
free(device_interface_list);
995
}
996
997
device_interface_list = (wchar_t*)calloc(len, sizeof(wchar_t));
998
if (device_interface_list == NULL) {
999
register_global_error(L"Failed to allocate memory for HID device interface list");
1000
return NULL;
1001
}
1002
cr = CM_Get_Device_Interface_ListW(&interface_class_guid, NULL, device_interface_list, len, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
1003
if (cr != CR_SUCCESS && cr != CR_BUFFER_SMALL) {
1004
register_global_error(L"Failed to get HID device interface list");
1005
}
1006
} while (cr == CR_BUFFER_SMALL);
1007
1008
if (cr != CR_SUCCESS) {
1009
goto end_of_function;
1010
}
1011
1012
/* Iterate over each device interface in the HID class, looking for the right one. */
1013
for (wchar_t* device_interface = device_interface_list; *device_interface; device_interface += wcslen(device_interface) + 1) {
1014
HANDLE device_handle = INVALID_HANDLE_VALUE;
1015
HIDD_ATTRIBUTES attrib;
1016
1017
/* XInput devices don't get real HID reports and are better handled by the raw input driver */
1018
if (wcsstr(device_interface, L"&IG_") != NULL) {
1019
continue;
1020
}
1021
1022
/* Open read-only handle to the device */
1023
device_handle = open_device(device_interface, FALSE);
1024
1025
/* Check validity of device_handle. */
1026
if (device_handle == INVALID_HANDLE_VALUE) {
1027
/* Unable to open the device. */
1028
continue;
1029
}
1030
1031
/* Get the Vendor ID and Product ID for this device. */
1032
attrib.Size = sizeof(HIDD_ATTRIBUTES);
1033
if (!HidD_GetAttributes(device_handle, &attrib)) {
1034
goto cont_close;
1035
}
1036
1037
#ifdef HIDAPI_IGNORE_DEVICE
1038
/* See if there are any devices we should skip in enumeration */
1039
hid_bus_type bus_type = get_bus_type(device_interface);
1040
PHIDP_PREPARSED_DATA pp_data = NULL;
1041
HIDP_CAPS caps = { 0 };
1042
if (HidD_GetPreparsedData(device_handle, &pp_data)) {
1043
HidP_GetCaps(pp_data, &caps);
1044
HidD_FreePreparsedData(pp_data);
1045
}
1046
if (HIDAPI_IGNORE_DEVICE(bus_type, attrib.VendorID, attrib.ProductID, caps.UsagePage, caps.Usage)) {
1047
goto cont_close;
1048
}
1049
#endif
1050
1051
/* Check the VID/PID to see if we should add this
1052
device to the enumeration list. */
1053
if ((vendor_id == 0x0 || attrib.VendorID == vendor_id) &&
1054
(product_id == 0x0 || attrib.ProductID == product_id) &&
1055
!hid_blacklist(attrib.VendorID, attrib.ProductID)) {
1056
1057
/* VID/PID match. Create the record. */
1058
struct hid_device_info *tmp = hid_internal_get_device_info(device_interface, device_handle);
1059
1060
if (tmp == NULL) {
1061
goto cont_close;
1062
}
1063
1064
if (cur_dev) {
1065
cur_dev->next = tmp;
1066
}
1067
else {
1068
root = tmp;
1069
}
1070
cur_dev = tmp;
1071
}
1072
1073
cont_close:
1074
CloseHandle(device_handle);
1075
}
1076
1077
if (root == NULL) {
1078
if (vendor_id == 0 && product_id == 0) {
1079
register_global_error(L"No HID devices found in the system.");
1080
} else {
1081
register_global_error(L"No HID devices with requested VID/PID found in the system.");
1082
}
1083
}
1084
1085
end_of_function:
1086
free(device_interface_list);
1087
1088
return root;
1089
}
1090
1091
void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs)
1092
{
1093
/* TODO: Merge this with the Linux version. This function is platform-independent. */
1094
struct hid_device_info *d = devs;
1095
while (d) {
1096
struct hid_device_info *next = d->next;
1097
free(d->path);
1098
free(d->serial_number);
1099
free(d->manufacturer_string);
1100
free(d->product_string);
1101
free(d);
1102
d = next;
1103
}
1104
}
1105
1106
HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
1107
{
1108
/* TODO: Merge this functions with the Linux version. This function should be platform independent. */
1109
struct hid_device_info *devs, *cur_dev;
1110
const char *path_to_open = NULL;
1111
hid_device *handle = NULL;
1112
1113
/* register_global_error: global error is reset by hid_enumerate/hid_init */
1114
devs = hid_enumerate(vendor_id, product_id);
1115
if (!devs) {
1116
/* register_global_error: global error is already set by hid_enumerate */
1117
return NULL;
1118
}
1119
1120
cur_dev = devs;
1121
while (cur_dev) {
1122
if (cur_dev->vendor_id == vendor_id &&
1123
cur_dev->product_id == product_id) {
1124
if (serial_number) {
1125
if (cur_dev->serial_number && wcscmp(serial_number, cur_dev->serial_number) == 0) {
1126
path_to_open = cur_dev->path;
1127
break;
1128
}
1129
}
1130
else {
1131
path_to_open = cur_dev->path;
1132
break;
1133
}
1134
}
1135
cur_dev = cur_dev->next;
1136
}
1137
1138
if (path_to_open) {
1139
/* Open the device */
1140
handle = hid_open_path(path_to_open);
1141
} else {
1142
register_global_error(L"Device with requested VID/PID/(SerialNumber) not found");
1143
}
1144
1145
hid_free_enumeration(devs);
1146
1147
return handle;
1148
}
1149
1150
HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path)
1151
{
1152
hid_device *dev = NULL;
1153
wchar_t* interface_path = NULL;
1154
HANDLE device_handle = INVALID_HANDLE_VALUE;
1155
PHIDP_PREPARSED_DATA pp_data = NULL;
1156
HIDP_CAPS caps;
1157
1158
if (hid_init() < 0) {
1159
/* register_global_error: global error is reset by hid_init */
1160
goto end_of_function;
1161
}
1162
1163
interface_path = hid_internal_UTF8toUTF16(path);
1164
if (!interface_path) {
1165
register_global_error(L"Path conversion failure");
1166
goto end_of_function;
1167
}
1168
1169
/* Open a handle to the device */
1170
device_handle = open_device(interface_path, TRUE);
1171
1172
/* Check validity of write_handle. */
1173
if (device_handle == INVALID_HANDLE_VALUE) {
1174
/* System devices, such as keyboards and mice, cannot be opened in
1175
read-write mode, because the system takes exclusive control over
1176
them. This is to prevent keyloggers. However, feature reports
1177
can still be sent and received. Retry opening the device, but
1178
without read/write access. */
1179
device_handle = open_device(interface_path, FALSE);
1180
1181
/* Check the validity of the limited device_handle. */
1182
if (device_handle == INVALID_HANDLE_VALUE) {
1183
register_global_winapi_error(L"open_device");
1184
goto end_of_function;
1185
}
1186
}
1187
1188
/* Set the Input Report buffer size to 64 reports. */
1189
if (!HidD_SetNumInputBuffers(device_handle, 64)) {
1190
register_global_winapi_error(L"set input buffers");
1191
goto end_of_function;
1192
}
1193
1194
/* Get the Input Report length for the device. */
1195
if (!HidD_GetPreparsedData(device_handle, &pp_data)) {
1196
register_global_winapi_error(L"get preparsed data");
1197
goto end_of_function;
1198
}
1199
1200
if (HidP_GetCaps(pp_data, &caps) != HIDP_STATUS_SUCCESS) {
1201
register_global_error(L"HidP_GetCaps");
1202
goto end_of_function;
1203
}
1204
1205
dev = new_hid_device();
1206
1207
if (dev == NULL) {
1208
register_global_error(L"hid_device allocation error");
1209
goto end_of_function;
1210
}
1211
1212
dev->device_handle = device_handle;
1213
device_handle = INVALID_HANDLE_VALUE;
1214
1215
dev->output_report_length = caps.OutputReportByteLength;
1216
dev->input_report_length = caps.InputReportByteLength;
1217
dev->feature_report_length = caps.FeatureReportByteLength;
1218
dev->read_buf = (char*) malloc(dev->input_report_length);
1219
dev->device_info = hid_internal_get_device_info(interface_path, dev->device_handle);
1220
1221
/* On Windows 7, we need to use hid_write_output_report() over Bluetooth */
1222
if (dev->output_report_length > 512) {
1223
dev->use_hid_write_output_report = !IsWindowsVersionOrGreater( HIBYTE( _WIN32_WINNT_WIN8 ), LOBYTE( _WIN32_WINNT_WIN8 ), 0 );
1224
}
1225
1226
end_of_function:
1227
free(interface_path);
1228
CloseHandle(device_handle);
1229
1230
if (pp_data) {
1231
HidD_FreePreparsedData(pp_data);
1232
}
1233
1234
return dev;
1235
}
1236
1237
static int hid_write_output_report(hid_device *dev, const unsigned char *data, size_t length)
1238
{
1239
BOOL res;
1240
res = HidD_SetOutputReport(dev->device_handle, (void *)data, (ULONG)length);
1241
if (res)
1242
return (int)length;
1243
else
1244
return -1;
1245
}
1246
1247
int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length)
1248
{
1249
DWORD bytes_written = 0;
1250
int function_result = -1;
1251
BOOL res;
1252
BOOL overlapped = FALSE;
1253
1254
unsigned char *buf;
1255
1256
if (!data || !length) {
1257
register_string_error(dev, L"Zero buffer/length");
1258
return function_result;
1259
}
1260
1261
register_string_error(dev, NULL);
1262
1263
if (dev->use_hid_write_output_report) {
1264
return hid_write_output_report(dev, data, length);
1265
}
1266
1267
/* Make sure the right number of bytes are passed to WriteFile. Windows
1268
expects the number of bytes which are in the _longest_ report (plus
1269
one for the report number) bytes even if the data is a report
1270
which is shorter than that. Windows gives us this value in
1271
caps.OutputReportByteLength. If a user passes in fewer bytes than this,
1272
use cached temporary buffer which is the proper size. */
1273
if (length >= dev->output_report_length) {
1274
/* The user passed the right number of bytes. Use the buffer as-is. */
1275
buf = (unsigned char *) data;
1276
} else {
1277
if (dev->write_buf == NULL)
1278
dev->write_buf = (unsigned char *) malloc(dev->output_report_length);
1279
buf = dev->write_buf;
1280
memcpy(buf, data, length);
1281
memset(buf + length, 0, dev->output_report_length - length);
1282
length = dev->output_report_length;
1283
}
1284
1285
res = WriteFile(dev->device_handle, buf, (DWORD) length, &bytes_written, &dev->write_ol);
1286
1287
if (!res) {
1288
if (GetLastError() != ERROR_IO_PENDING) {
1289
/* WriteFile() failed. Return error. */
1290
register_winapi_error(dev, L"WriteFile");
1291
goto end_of_function;
1292
}
1293
overlapped = TRUE;
1294
} else {
1295
/* WriteFile() succeeded synchronously. */
1296
function_result = bytes_written;
1297
}
1298
1299
if (overlapped) {
1300
/* Wait for the transaction to complete. This makes
1301
hid_write() synchronous. */
1302
res = WaitForSingleObject(dev->write_ol.hEvent, 1000);
1303
if (res != WAIT_OBJECT_0) {
1304
/* There was a Timeout. */
1305
register_winapi_error(dev, L"hid_write/WaitForSingleObject");
1306
goto end_of_function;
1307
}
1308
1309
/* Get the result. */
1310
res = GetOverlappedResult(dev->device_handle, &dev->write_ol, &bytes_written, FALSE/*wait*/);
1311
if (res) {
1312
function_result = bytes_written;
1313
}
1314
else {
1315
/* The Write operation failed. */
1316
register_winapi_error(dev, L"hid_write/GetOverlappedResult");
1317
goto end_of_function;
1318
}
1319
}
1320
1321
end_of_function:
1322
return function_result;
1323
}
1324
1325
1326
int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
1327
{
1328
DWORD bytes_read = 0;
1329
size_t copy_len = 0;
1330
BOOL res = FALSE;
1331
BOOL overlapped = FALSE;
1332
1333
if (!data || !length) {
1334
register_string_error(dev, L"Zero buffer/length");
1335
return -1;
1336
}
1337
1338
register_string_error(dev, NULL);
1339
1340
/* Copy the handle for convenience. */
1341
HANDLE ev = dev->ol.hEvent;
1342
1343
if (!dev->read_pending) {
1344
/* Start an Overlapped I/O read. */
1345
dev->read_pending = TRUE;
1346
memset(dev->read_buf, 0, dev->input_report_length);
1347
ResetEvent(ev);
1348
res = ReadFile(dev->device_handle, dev->read_buf, (DWORD) dev->input_report_length, &bytes_read, &dev->ol);
1349
1350
if (!res) {
1351
if (GetLastError() != ERROR_IO_PENDING) {
1352
/* ReadFile() has failed.
1353
Clean up and return error. */
1354
register_winapi_error(dev, L"ReadFile");
1355
CancelIo(dev->device_handle);
1356
dev->read_pending = FALSE;
1357
goto end_of_function;
1358
}
1359
overlapped = TRUE;
1360
}
1361
}
1362
else {
1363
overlapped = TRUE;
1364
}
1365
1366
if (overlapped) {
1367
/* See if there is any data yet. */
1368
res = WaitForSingleObject(ev, milliseconds >= 0 ? (DWORD)milliseconds : INFINITE);
1369
if (res != WAIT_OBJECT_0) {
1370
/* There was no data this time. Return zero bytes available,
1371
but leave the Overlapped I/O running. */
1372
return 0;
1373
}
1374
1375
/* Get the number of bytes read. The actual data has been copied to the data[]
1376
array which was passed to ReadFile(). We must not wait here because we've
1377
already waited on our event above, and since it's auto-reset, it will have
1378
been reset back to unsignalled by now. */
1379
res = GetOverlappedResult(dev->device_handle, &dev->ol, &bytes_read, FALSE/*don't wait now - already did on the prev step*/);
1380
}
1381
/* Set pending back to false, even if GetOverlappedResult() returned error. */
1382
dev->read_pending = FALSE;
1383
1384
if (res && bytes_read > 0) {
1385
if (dev->read_buf[0] == 0x0) {
1386
/* If report numbers aren't being used, but Windows sticks a report
1387
number (0x0) on the beginning of the report anyway. To make this
1388
work like the other platforms, and to make it work more like the
1389
HID spec, we'll skip over this byte. */
1390
bytes_read--;
1391
copy_len = length > bytes_read ? bytes_read : length;
1392
memcpy(data, dev->read_buf+1, copy_len);
1393
}
1394
else {
1395
/* Copy the whole buffer, report number and all. */
1396
copy_len = length > bytes_read ? bytes_read : length;
1397
memcpy(data, dev->read_buf, copy_len);
1398
}
1399
}
1400
if (!res) {
1401
register_winapi_error(dev, L"hid_read_timeout/GetOverlappedResult");
1402
}
1403
1404
end_of_function:
1405
if (!res) {
1406
return -1;
1407
}
1408
1409
return (int) copy_len;
1410
}
1411
1412
int HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, size_t length)
1413
{
1414
return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0);
1415
}
1416
1417
int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *dev, int nonblock)
1418
{
1419
dev->blocking = !nonblock;
1420
return 0; /* Success */
1421
}
1422
1423
int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)
1424
{
1425
BOOL res = FALSE;
1426
unsigned char *buf;
1427
size_t length_to_send;
1428
1429
if (!data || !length) {
1430
register_string_error(dev, L"Zero buffer/length");
1431
return -1;
1432
}
1433
1434
register_string_error(dev, NULL);
1435
1436
/* Windows expects at least caps.FeatureReportByteLength bytes passed
1437
to HidD_SetFeature(), even if the report is shorter. Any less sent and
1438
the function fails with error ERROR_INVALID_PARAMETER set. Any more
1439
and HidD_SetFeature() silently truncates the data sent in the report
1440
to caps.FeatureReportByteLength. */
1441
if (length >= dev->feature_report_length) {
1442
buf = (unsigned char *) data;
1443
length_to_send = length;
1444
} else {
1445
if (dev->feature_buf == NULL)
1446
dev->feature_buf = (unsigned char *) malloc(dev->feature_report_length);
1447
buf = dev->feature_buf;
1448
memcpy(buf, data, length);
1449
memset(buf + length, 0, dev->feature_report_length - length);
1450
length_to_send = dev->feature_report_length;
1451
}
1452
1453
res = HidD_SetFeature(dev->device_handle, (PVOID)buf, (DWORD) length_to_send);
1454
1455
if (!res) {
1456
register_winapi_error(dev, L"HidD_SetFeature");
1457
return -1;
1458
}
1459
1460
return (int) length;
1461
}
1462
1463
static int hid_get_report(hid_device *dev, DWORD report_type, unsigned char *data, size_t length)
1464
{
1465
BOOL res;
1466
DWORD bytes_returned = 0;
1467
1468
OVERLAPPED ol;
1469
memset(&ol, 0, sizeof(ol));
1470
1471
if (!data || !length) {
1472
register_string_error(dev, L"Zero buffer/length");
1473
return -1;
1474
}
1475
1476
register_string_error(dev, NULL);
1477
1478
res = DeviceIoControl(dev->device_handle,
1479
report_type,
1480
data, (DWORD) length,
1481
data, (DWORD) length,
1482
&bytes_returned, &ol);
1483
1484
if (!res) {
1485
if (GetLastError() != ERROR_IO_PENDING) {
1486
/* DeviceIoControl() failed. Return error. */
1487
register_winapi_error(dev, L"Get Input/Feature Report DeviceIoControl");
1488
return -1;
1489
}
1490
}
1491
1492
/* Wait here until the write is done. This makes
1493
hid_get_feature_report() synchronous. */
1494
res = GetOverlappedResult(dev->device_handle, &ol, &bytes_returned, TRUE/*wait*/);
1495
if (!res) {
1496
/* The operation failed. */
1497
register_winapi_error(dev, L"Get Input/Feature Report GetOverLappedResult");
1498
return -1;
1499
}
1500
1501
/* When numbered reports aren't used,
1502
bytes_returned seem to include only what is actually received from the device
1503
(not including the first byte with 0, as an indication "no numbered reports"). */
1504
if (data[0] == 0x0) {
1505
bytes_returned++;
1506
}
1507
1508
return bytes_returned;
1509
}
1510
1511
int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
1512
{
1513
/* We could use HidD_GetFeature() instead, but it doesn't give us an actual length, unfortunately */
1514
return hid_get_report(dev, IOCTL_HID_GET_FEATURE, data, length);
1515
}
1516
1517
int HID_API_EXPORT HID_API_CALL hid_get_input_report(hid_device *dev, unsigned char *data, size_t length)
1518
{
1519
/* We could use HidD_GetInputReport() instead, but it doesn't give us an actual length, unfortunately */
1520
return hid_get_report(dev, IOCTL_HID_GET_INPUT_REPORT, data, length);
1521
}
1522
1523
#if defined(__GNUC__) && __GNUC__ >= 8
1524
# pragma GCC diagnostic push
1525
# pragma GCC diagnostic ignored "-Wcast-function-type"
1526
#endif
1527
void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev)
1528
{
1529
typedef BOOL (WINAPI *CancelIoEx_t)(HANDLE hFile, LPOVERLAPPED lpOverlapped);
1530
CancelIoEx_t CancelIoExFunc = (CancelIoEx_t)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "CancelIoEx");
1531
1532
if (!dev)
1533
return;
1534
1535
if (CancelIoExFunc) {
1536
CancelIoExFunc(dev->device_handle, NULL);
1537
} else {
1538
/* Windows XP, this will only cancel I/O on the current thread */
1539
CancelIo(dev->device_handle);
1540
}
1541
if (dev->read_pending) {
1542
DWORD bytes_read = 0;
1543
GetOverlappedResult(dev->device_handle, &dev->ol, &bytes_read, TRUE/*wait*/);
1544
}
1545
free_hid_device(dev);
1546
}
1547
#if defined(__GNUC__) && __GNUC__ >= 8
1548
# pragma GCC diagnostic pop
1549
#endif
1550
1551
int HID_API_EXPORT_CALL HID_API_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)
1552
{
1553
if (!string || !maxlen) {
1554
register_string_error(dev, L"Zero buffer/length");
1555
return -1;
1556
}
1557
1558
if (!dev->device_info) {
1559
register_string_error(dev, L"NULL device info");
1560
return -1;
1561
}
1562
1563
wcsncpy(string, dev->device_info->manufacturer_string, maxlen);
1564
string[maxlen - 1] = L'\0';
1565
1566
register_string_error(dev, NULL);
1567
1568
return 0;
1569
}
1570
1571
int HID_API_EXPORT_CALL HID_API_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)
1572
{
1573
if (!string || !maxlen) {
1574
register_string_error(dev, L"Zero buffer/length");
1575
return -1;
1576
}
1577
1578
if (!dev->device_info) {
1579
register_string_error(dev, L"NULL device info");
1580
return -1;
1581
}
1582
1583
wcsncpy(string, dev->device_info->product_string, maxlen);
1584
string[maxlen - 1] = L'\0';
1585
1586
register_string_error(dev, NULL);
1587
1588
return 0;
1589
}
1590
1591
int HID_API_EXPORT_CALL HID_API_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)
1592
{
1593
if (!string || !maxlen) {
1594
register_string_error(dev, L"Zero buffer/length");
1595
return -1;
1596
}
1597
1598
if (!dev->device_info) {
1599
register_string_error(dev, L"NULL device info");
1600
return -1;
1601
}
1602
1603
wcsncpy(string, dev->device_info->serial_number, maxlen);
1604
string[maxlen - 1] = L'\0';
1605
1606
register_string_error(dev, NULL);
1607
1608
return 0;
1609
}
1610
1611
HID_API_EXPORT struct hid_device_info * HID_API_CALL hid_get_device_info(hid_device *dev) {
1612
if (!dev->device_info)
1613
{
1614
register_string_error(dev, L"NULL device info");
1615
return NULL;
1616
}
1617
1618
return dev->device_info;
1619
}
1620
1621
int HID_API_EXPORT_CALL HID_API_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)
1622
{
1623
BOOL res;
1624
1625
if (dev->device_info && dev->device_info->bus_type == HID_API_BUS_USB && maxlen > MAX_STRING_WCHARS_USB) {
1626
string[MAX_STRING_WCHARS_USB] = L'\0';
1627
maxlen = MAX_STRING_WCHARS_USB;
1628
}
1629
1630
res = HidD_GetIndexedString(dev->device_handle, string_index, string, (ULONG)maxlen * sizeof(wchar_t));
1631
if (!res) {
1632
register_winapi_error(dev, L"HidD_GetIndexedString");
1633
return -1;
1634
}
1635
1636
register_string_error(dev, NULL);
1637
1638
return 0;
1639
}
1640
1641
int HID_API_EXPORT_CALL hid_winapi_get_container_id(hid_device *dev, GUID *container_id)
1642
{
1643
wchar_t *interface_path = NULL, *device_id = NULL;
1644
CONFIGRET cr = CR_FAILURE;
1645
DEVINST dev_node;
1646
DEVPROPTYPE property_type;
1647
ULONG len;
1648
1649
if (!container_id) {
1650
register_string_error(dev, L"Invalid Container ID");
1651
return -1;
1652
}
1653
1654
register_string_error(dev, NULL);
1655
1656
interface_path = hid_internal_UTF8toUTF16(dev->device_info->path);
1657
if (!interface_path) {
1658
register_string_error(dev, L"Path conversion failure");
1659
goto end;
1660
}
1661
1662
/* Get the device id from interface path */
1663
device_id = hid_internal_get_device_interface_property(interface_path, &DEVPKEY_Device_InstanceId, DEVPROP_TYPE_STRING);
1664
if (!device_id) {
1665
register_string_error(dev, L"Failed to get device interface property InstanceId");
1666
goto end;
1667
}
1668
1669
/* Open devnode from device id */
1670
cr = CM_Locate_DevNodeW(&dev_node, (DEVINSTID_W)device_id, CM_LOCATE_DEVNODE_NORMAL);
1671
if (cr != CR_SUCCESS) {
1672
register_string_error(dev, L"Failed to locate device node");
1673
goto end;
1674
}
1675
1676
/* Get the container id from devnode */
1677
len = sizeof(*container_id);
1678
cr = CM_Get_DevNode_PropertyW(dev_node, &DEVPKEY_Device_ContainerId, &property_type, (PBYTE)container_id, &len, 0);
1679
if (cr == CR_SUCCESS && property_type != DEVPROP_TYPE_GUID)
1680
cr = CR_FAILURE;
1681
1682
if (cr != CR_SUCCESS)
1683
register_string_error(dev, L"Failed to read ContainerId property from device node");
1684
1685
end:
1686
free(interface_path);
1687
free(device_id);
1688
1689
return cr == CR_SUCCESS ? 0 : -1;
1690
}
1691
1692
1693
int HID_API_EXPORT_CALL hid_get_report_descriptor(hid_device *dev, unsigned char *buf, size_t buf_size)
1694
{
1695
PHIDP_PREPARSED_DATA pp_data = NULL;
1696
1697
if (!HidD_GetPreparsedData(dev->device_handle, &pp_data) || pp_data == NULL) {
1698
register_string_error(dev, L"HidD_GetPreparsedData");
1699
return -1;
1700
}
1701
1702
int res = hid_winapi_descriptor_reconstruct_pp_data(pp_data, buf, buf_size);
1703
1704
HidD_FreePreparsedData(pp_data);
1705
1706
return res;
1707
}
1708
1709
HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev)
1710
{
1711
if (dev) {
1712
if (dev->last_error_str == NULL)
1713
return L"Success";
1714
return (wchar_t*)dev->last_error_str;
1715
}
1716
1717
if (last_global_error_str == NULL)
1718
return L"Success";
1719
return last_global_error_str;
1720
}
1721
1722
#ifndef hidapi_winapi_EXPORTS
1723
#include "hidapi_descriptor_reconstruct.c"
1724
#endif
1725
1726
#ifdef __cplusplus
1727
} /* extern "C" */
1728
#endif
1729
1730