@@ -52,7 +52,6 @@ typedef LONG NTSTATUS;
5252
5353/*#define HIDAPI_USE_DDK*/
5454
55- #include <devpropdef.h>
5655#include "hidapi_cfgmgr32.h"
5756#include "hidapi_hidclass.h"
5857#include "hidapi_hidsdi.h"
@@ -409,6 +408,132 @@ static void* hid_internal_get_device_interface_property(const wchar_t* interface
409408 return property_value ;
410409}
411410
411+ static void hid_internal_towupper (wchar_t * string )
412+ {
413+ for (wchar_t * p = string ; * p ; ++ p ) * p = towupper (* p );
414+ }
415+
416+ static int hid_internal_extract_int_token_value (wchar_t * string , const wchar_t * token )
417+ {
418+ int token_value ;
419+ wchar_t * startptr , * endptr ;
420+
421+ startptr = wcsstr (string , token );
422+ if (!startptr )
423+ return -1 ;
424+
425+ startptr += wcslen (token );
426+ token_value = wcstol (startptr , & endptr , 16 );
427+ if (endptr == startptr )
428+ return -1 ;
429+
430+ return token_value ;
431+ }
432+
433+ static void hid_internal_get_usb_info (struct hid_device_info * dev , DEVINST dev_node )
434+ {
435+ wchar_t * device_id = NULL , * hardware_ids = NULL ;
436+
437+ device_id = hid_internal_get_devnode_property (dev_node , & DEVPKEY_Device_InstanceId , DEVPROP_TYPE_STRING );
438+ if (!device_id )
439+ goto end ;
440+
441+ /* Normalize to upper case */
442+ hid_internal_towupper (device_id );
443+
444+ /* Check for Xbox Common Controller class (XUSB) device.
445+ https://docs.microsoft.com/windows/win32/xinput/directinput-and-xusb-devices
446+ https://docs.microsoft.com/windows/win32/xinput/xinput-and-directinput
447+ */
448+ if (hid_internal_extract_int_token_value (device_id , L"IG_" ) != -1 ) {
449+ /* Get devnode parent to reach out USB device. */
450+ if (CM_Get_Parent (& dev_node , dev_node , 0 ) != CR_SUCCESS )
451+ goto end ;
452+ }
453+
454+ /* Get the hardware ids from devnode */
455+ hardware_ids = hid_internal_get_devnode_property (dev_node , & DEVPKEY_Device_HardwareIds , DEVPROP_TYPE_STRING_LIST );
456+ if (!hardware_ids )
457+ goto end ;
458+
459+ /* Get additional information from USB device's Hardware ID
460+ https://docs.microsoft.com/windows-hardware/drivers/install/standard-usb-identifiers
461+ https://docs.microsoft.com/windows-hardware/drivers/usbcon/enumeration-of-interfaces-not-grouped-in-collections
462+ */
463+ for (wchar_t * hardware_id = hardware_ids ; * hardware_id ; hardware_id += wcslen (hardware_id ) + 1 ) {
464+ /* Normalize to upper case */
465+ hid_internal_towupper (hardware_id );
466+
467+ if (dev -> release_number == 0 ) {
468+ /* USB_DEVICE_DESCRIPTOR.bcdDevice value. */
469+ int release_number = hid_internal_extract_int_token_value (hardware_id , L"REV_" );
470+ if (release_number != -1 ) {
471+ dev -> release_number = (unsigned short )release_number ;
472+ }
473+ }
474+
475+ if (dev -> interface_number == -1 ) {
476+ /* USB_INTERFACE_DESCRIPTOR.bInterfaceNumber value. */
477+ int interface_number = hid_internal_extract_int_token_value (hardware_id , L"MI_" );
478+ if (interface_number != -1 ) {
479+ dev -> interface_number = interface_number ;
480+ }
481+ }
482+ }
483+
484+ /* Try to get USB device manufacturer string if not provided by HidD_GetManufacturerString. */
485+ if (wcslen (dev -> manufacturer_string ) == 0 ) {
486+ wchar_t * manufacturer_string = hid_internal_get_devnode_property (dev_node , & DEVPKEY_Device_Manufacturer , DEVPROP_TYPE_STRING );
487+ if (manufacturer_string ) {
488+ free (dev -> manufacturer_string );
489+ dev -> manufacturer_string = manufacturer_string ;
490+ }
491+ }
492+
493+ /* Try to get USB device serial number if not provided by HidD_GetSerialNumberString. */
494+ if (wcslen (dev -> serial_number ) == 0 ) {
495+ DEVINST usb_dev_node = dev_node ;
496+ if (dev -> interface_number != -1 ) {
497+ /* Get devnode parent to reach out composite parent USB device.
498+ https://docs.microsoft.com/windows-hardware/drivers/usbcon/enumeration-of-the-composite-parent-device
499+ */
500+ if (CM_Get_Parent (& usb_dev_node , dev_node , 0 ) != CR_SUCCESS )
501+ goto end ;
502+ }
503+
504+ /* Get the device id of the USB device. */
505+ free (device_id );
506+ device_id = hid_internal_get_devnode_property (usb_dev_node , & DEVPKEY_Device_InstanceId , DEVPROP_TYPE_STRING );
507+ if (!device_id )
508+ goto end ;
509+
510+ /* Extract substring after last '\\' of Instance ID.
511+ For USB devices it may contain device's serial number.
512+ https://docs.microsoft.com/windows-hardware/drivers/install/instance-ids
513+ */
514+ for (wchar_t * ptr = device_id + wcslen (device_id ); ptr > device_id ; -- ptr ) {
515+ /* Instance ID is unique only within the scope of the bus.
516+ For USB devices it means that serial number is not available. Skip. */
517+ if (* ptr == L'&' )
518+ break ;
519+
520+ if (* ptr == L'\\' ) {
521+ free (dev -> serial_number );
522+ dev -> serial_number = _wcsdup (ptr + 1 );
523+ break ;
524+ }
525+ }
526+ }
527+
528+ /* If we can't get the interface number, it means that there is only one interface. */
529+ if (dev -> interface_number == -1 )
530+ dev -> interface_number = 0 ;
531+
532+ end :
533+ free (device_id );
534+ free (hardware_ids );
535+ }
536+
412537/* HidD_GetProductString/HidD_GetManufacturerString/HidD_GetSerialNumberString is not working for BLE HID devices
413538 Request this info via dev node properties instead.
414539 https://docs.microsoft.com/answers/questions/401236/hidd-getproductstring-with-ble-hid-device.html
@@ -452,34 +577,9 @@ static void hid_internal_get_ble_info(struct hid_device_info* dev, DEVINST dev_n
452577 }
453578}
454579
455- /* USB Device Interface Number.
456- It can be parsed out of the Hardware ID if a USB device is has multiple interfaces (composite device).
457- See https://docs.microsoft.com/windows-hardware/drivers/hid/hidclass-hardware-ids-for-top-level-collections
458- and https://docs.microsoft.com/windows-hardware/drivers/install/standard-usb-identifiers
459-
460- hardware_id is always expected to be uppercase.
461- */
462- static int hid_internal_get_interface_number (const wchar_t * hardware_id )
463- {
464- int interface_number ;
465- wchar_t * startptr , * endptr ;
466- const wchar_t * interface_token = L"&MI_" ;
467-
468- startptr = wcsstr (hardware_id , interface_token );
469- if (!startptr )
470- return -1 ;
471-
472- startptr += wcslen (interface_token );
473- interface_number = wcstol (startptr , & endptr , 16 );
474- if (endptr == startptr )
475- return -1 ;
476-
477- return interface_number ;
478- }
479-
480580static void hid_internal_get_info (const wchar_t * interface_path , struct hid_device_info * dev )
481581{
482- wchar_t * device_id = NULL , * compatible_ids = NULL , * hardware_ids = NULL ;
582+ wchar_t * device_id = NULL , * compatible_ids = NULL ;
483583 CONFIGRET cr ;
484584 DEVINST dev_node ;
485585
@@ -493,22 +593,6 @@ static void hid_internal_get_info(const wchar_t* interface_path, struct hid_devi
493593 if (cr != CR_SUCCESS )
494594 goto end ;
495595
496- /* Get the hardware ids from devnode */
497- hardware_ids = hid_internal_get_devnode_property (dev_node , & DEVPKEY_Device_HardwareIds , DEVPROP_TYPE_STRING_LIST );
498- if (!hardware_ids )
499- goto end ;
500-
501- /* Search for interface number in hardware ids */
502- for (wchar_t * hardware_id = hardware_ids ; * hardware_id ; hardware_id += wcslen (hardware_id ) + 1 ) {
503- /* Normalize to upper case */
504- for (wchar_t * p = hardware_id ; * p ; ++ p ) * p = towupper (* p );
505-
506- dev -> interface_number = hid_internal_get_interface_number (hardware_id );
507-
508- if (dev -> interface_number != -1 )
509- break ;
510- }
511-
512596 /* Get devnode parent */
513597 cr = CM_Get_Parent (& dev_node , dev_node , 0 );
514598 if (cr != CR_SUCCESS )
@@ -522,13 +606,14 @@ static void hid_internal_get_info(const wchar_t* interface_path, struct hid_devi
522606 /* Now we can parse parent's compatible IDs to find out the device bus type */
523607 for (wchar_t * compatible_id = compatible_ids ; * compatible_id ; compatible_id += wcslen (compatible_id ) + 1 ) {
524608 /* Normalize to upper case */
525- for ( wchar_t * p = compatible_id ; * p ; ++ p ) * p = towupper ( * p );
609+ hid_internal_towupper ( compatible_id );
526610
527611 /* USB devices
528612 https://docs.microsoft.com/windows-hardware/drivers/hid/plug-and-play-support
529613 https://docs.microsoft.com/windows-hardware/drivers/install/standard-usb-identifiers */
530614 if (wcsstr (compatible_id , L"USB" ) != NULL ) {
531615 dev -> bus_type = HID_API_BUS_USB ;
616+ hid_internal_get_usb_info (dev , dev_node );
532617 break ;
533618 }
534619
@@ -562,7 +647,6 @@ static void hid_internal_get_info(const wchar_t* interface_path, struct hid_devi
562647 }
563648end :
564649 free (device_id );
565- free (hardware_ids );
566650 free (compatible_ids );
567651}
568652
@@ -607,9 +691,14 @@ static struct hid_device_info *hid_internal_get_device_info(const wchar_t *path,
607691 /* Create the record. */
608692 dev = (struct hid_device_info * )calloc (1 , sizeof (struct hid_device_info ));
609693
694+ if (dev == NULL ) {
695+ return NULL ;
696+ }
697+
610698 /* Fill out the record */
611699 dev -> next = NULL ;
612700 dev -> path = hid_internal_UTF16toUTF8 (path );
701+ dev -> interface_number = -1 ;
613702
614703 attrib .Size = sizeof (HIDD_ATTRIBUTES );
615704 if (HidD_GetAttributes (handle , & attrib )) {
0 commit comments