Simple Directmedia Layer
at main 1728 lines 51 kB view raw
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 30extern "C" { 31#endif 32 33#include "hidapi_winapi.h" 34 35#include <windows.h> 36 37#ifndef _NTDEF_ 38typedef 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 84static 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 96static HidD_GetHidGuid_ HidD_GetHidGuid; 97static HidD_GetAttributes_ HidD_GetAttributes; 98static HidD_GetSerialNumberString_ HidD_GetSerialNumberString; 99static HidD_GetManufacturerString_ HidD_GetManufacturerString; 100static HidD_GetProductString_ HidD_GetProductString; 101static HidD_SetFeature_ HidD_SetFeature; 102static HidD_GetFeature_ HidD_GetFeature; 103static HidD_GetInputReport_ HidD_GetInputReport; 104static HidD_GetIndexedString_ HidD_GetIndexedString; 105static HidD_GetPreparsedData_ HidD_GetPreparsedData; 106static HidD_FreePreparsedData_ HidD_FreePreparsedData; 107static HidP_GetCaps_ HidP_GetCaps; 108static HidD_SetNumInputBuffers_ HidD_SetNumInputBuffers; 109static HidD_SetOutputReport_ HidD_SetOutputReport; 110 111static CM_Locate_DevNodeW_ CM_Locate_DevNodeW = NULL; 112static CM_Get_Parent_ CM_Get_Parent = NULL; 113static CM_Get_DevNode_PropertyW_ CM_Get_DevNode_PropertyW = NULL; 114static CM_Get_Device_Interface_PropertyW_ CM_Get_Device_Interface_PropertyW = NULL; 115static CM_Get_Device_Interface_List_SizeW_ CM_Get_Device_Interface_List_SizeW = NULL; 116static CM_Get_Device_Interface_ListW_ CM_Get_Device_Interface_ListW = NULL; 117 118static HMODULE hid_lib_handle = NULL; 119static HMODULE cfgmgr32_lib_handle = NULL; 120static BOOLEAN hidapi_initialized = FALSE; 121 122static 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 137static 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 177err: 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 188struct 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 205static 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 224static 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 251static 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 265static 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 346static 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 371static void register_winapi_error(hid_device *dev, const WCHAR *op) 372{ 373 register_winapi_error_to_buffer(&dev->last_error_str, op); 374} 375 376static 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 381static wchar_t *last_global_error_str = NULL; 382 383static void register_global_winapi_error(const WCHAR *op) 384{ 385 register_winapi_error_to_buffer(&last_global_error_str, op); 386} 387 388static void register_global_error(const WCHAR *string_error) 389{ 390 register_string_error_to_buffer(&last_global_error_str, string_error); 391} 392 393static 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 410HID_API_EXPORT const struct hid_api_version* HID_API_CALL hid_version(void) 411{ 412 return &api_version; 413} 414 415HID_API_EXPORT const char* HID_API_CALL hid_version_str(void) 416{ 417 return HID_API_VERSION_STR; 418} 419 420int 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 435int 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 445static 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 466static 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 487static void hid_internal_towupper(wchar_t* string) 488{ 489 for (wchar_t* p = string; *p; ++p) *p = towupper(*p); 490} 491 492static 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 509static 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 608end: 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*/ 617static 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 657static 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 } 724end: 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 735typedef 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 741static 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 812end: 813 free(device_id); 814 free(compatible_ids); 815 return result; 816} 817 818static 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 841static 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 856static 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 943static 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 965struct 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 1073cont_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 1085end_of_function: 1086 free(device_interface_list); 1087 1088 return root; 1089} 1090 1091void 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 1106HID_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 1150HID_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 1226end_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 1237static 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 1247int 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 1321end_of_function: 1322 return function_result; 1323} 1324 1325 1326int 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 1404end_of_function: 1405 if (!res) { 1406 return -1; 1407 } 1408 1409 return (int) copy_len; 1410} 1411 1412int 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 1417int 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 1423int 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 1463static 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 1511int 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 1517int 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 1527void 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 1551int 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 1571int 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 1591int 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 1611HID_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 1621int 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 1641int 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 1685end: 1686 free(interface_path); 1687 free(device_id); 1688 1689 return cr == CR_SUCCESS ? 0 : -1; 1690} 1691 1692 1693int 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 1709HID_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