@@ -46,6 +46,7 @@ typedef LONG NTSTATUS;
4646extern "C" {
4747#endif
4848 #include <setupapi.h>
49+ #include <cfgmgr32.h>
4950 #include <winioctl.h>
5051 #ifdef HIDAPI_USE_DDK
5152 #include <hidsdi.h>
@@ -507,6 +508,9 @@ struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned shor
507508
508509 //wprintf(L"HandleName: %s\n", device_interface_detail_data->DevicePath);
509510
511+ /* Normalize the path */
512+ for (char * p = device_interface_detail_data -> DevicePath ; * p ; ++ p ) * p = tolower (* p );
513+
510514 /* Open read-only handle to the device */
511515 read_handle = open_device (device_interface_detail_data -> DevicePath , FALSE);
512516
@@ -573,6 +577,198 @@ void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *d
573577 }
574578}
575579
580+ struct hid_notify {
581+ unsigned short vendor_id ;
582+ unsigned short product_id ;
583+ void * context ;
584+ hid_device_callback callback ;
585+
586+ /** Pointer to the next notification */
587+ struct hid_notify * next ;
588+ };
589+
590+ static struct notify_context {
591+ HCMNOTIFICATION notify_handle ;
592+ struct hid_notify * notifys ;
593+ struct hid_device_info * devs ;
594+ } notify_context = {
595+ .notify_handle = NULL ,
596+ .notifys = NULL ,
597+ .devs = NULL
598+ };
599+
600+ DWORD WINAPI interface_notify_callback (HCMNOTIFICATION notify , PVOID context , CM_NOTIFY_ACTION action , PCM_NOTIFY_EVENT_DATA event_data , DWORD event_data_size )
601+ {
602+ switch (action ) {
603+ case CM_NOTIFY_ACTION_DEVICEINTERFACEARRIVAL :
604+ case CM_NOTIFY_ACTION_DEVICEINTERFACEREMOVAL :
605+ {
606+ char * path ;
607+ size_t len ;
608+ struct hid_device_info * dev = NULL ;
609+ int is_connected = (action == CM_NOTIFY_ACTION_DEVICEINTERFACEARRIVAL ) ? TRUE : FALSE;
610+
611+ len = wcslen (event_data -> u .DeviceInterface .SymbolicLink );
612+ path = (char * )calloc (len + 1 , sizeof (char ));
613+
614+ if (wcstombs (path , event_data -> u .DeviceInterface .SymbolicLink , len ) == (size_t )-1 )
615+ goto close ;
616+
617+ /* Normalize the path */
618+ for (char * p = path ; * p ; ++ p ) * p = tolower (* p );
619+
620+ if (is_connected ) {
621+ dev = hid_get_device_info (path );
622+
623+ /* Append to the end of the device list */
624+ if (notify_context .devs ) {
625+ struct hid_device_info * last = notify_context .devs ;
626+ while (last -> next ) {
627+ last = last -> next ;
628+ }
629+ last -> next = dev ;
630+ }
631+ else {
632+ notify_context .devs = dev ;
633+ }
634+ }
635+ else {
636+ /* Remove this device from the device list */
637+ for (struct hid_device_info * * current = & notify_context .devs ; * current ; current = & (* current )-> next ) {
638+ if (strcmp ((* current )-> path , path ) == 0 ) {
639+ struct hid_device_info * next = (* current )-> next ;
640+ dev = * current ;
641+ * current = next ;
642+ break ;
643+ }
644+ }
645+ }
646+
647+ if (dev ) {
648+ /* Call the notifications for this device */
649+ struct hid_notify * notify = notify_context .notifys ;
650+ while (notify ) {
651+ if ((notify -> vendor_id == 0x0 || notify -> vendor_id == dev -> vendor_id ) &&
652+ (notify -> product_id == 0x0 || notify -> product_id == dev -> product_id )) {
653+ /* Call notification callback */
654+ (* notify -> callback )((hid_callback_token * )notify , notify -> context , dev , is_connected );
655+ }
656+ notify = notify -> next ;
657+ }
658+
659+ /* Clean removed device info */
660+ if (!is_connected )
661+ free (dev );
662+ }
663+
664+ close :
665+ free (path );
666+ }
667+ break ;
668+ }
669+
670+ return ERROR_SUCCESS ;
671+ }
672+
673+ HID_API_EXPORT hid_callback_token * HID_API_CALL hid_register_callback (unsigned short vendor_id , unsigned short product_id , void * context , hid_device_callback callback )
674+ {
675+ /* Create the record. */
676+ struct hid_notify * notify = (struct hid_notify * )calloc (1 , sizeof (struct hid_notify ));
677+
678+ /* Fill out the record */
679+ notify -> next = NULL ;
680+ notify -> vendor_id = vendor_id ;
681+ notify -> product_id = product_id ;
682+ notify -> context = context ;
683+ notify -> callback = callback ;
684+
685+ /* Append to the end */
686+ if (notify_context .notifys ) {
687+ struct hid_notify * last = notify_context .notifys ;
688+ while (last -> next ) {
689+ last = last -> next ;
690+ }
691+ last -> next = notify ;
692+ }
693+ else {
694+ struct hid_device_info * dev ;
695+
696+ /* Register device connection notification after adding first callback */
697+ if (notify_context .notify_handle == NULL ) {
698+ GUID interface_class_guid ;
699+ CONFIGRET cr = CR_SUCCESS ;
700+ CM_NOTIFY_FILTER notify_filter = { 0 };
701+
702+ HidD_GetHidGuid (& interface_class_guid );
703+
704+ notify_filter .cbSize = sizeof (notify_filter );
705+ notify_filter .FilterType = CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE ;
706+ notify_filter .u .DeviceInterface .ClassGuid = interface_class_guid ;
707+ cr = CM_Register_Notification (& notify_filter , NULL , interface_notify_callback , & notify_context .notify_handle );
708+ if (cr != CR_SUCCESS ) {
709+ return NULL ;
710+ }
711+ }
712+
713+ notify_context .notifys = notify ;
714+
715+ /* Fill already connected devices */
716+ dev = hid_enumerate (0 , 0 );
717+ notify_context .devs = dev ;
718+
719+ /* Notify about already connected devices */
720+ while (dev ) {
721+ if ((notify -> vendor_id == 0x0 || notify -> vendor_id == dev -> vendor_id ) &&
722+ (notify -> product_id == 0x0 || notify -> product_id == dev -> product_id )) {
723+ (* notify -> callback )((hid_callback_token * )notify , notify -> callback , dev , TRUE);
724+ }
725+ dev = dev -> next ;
726+ }
727+ }
728+
729+ return (hid_callback_token * )notify ;
730+ }
731+
732+ int HID_API_EXPORT HID_API_CALL hid_unregister_callback (hid_callback_token * token )
733+ {
734+ struct hid_notify * notify = NULL ;
735+
736+ if (token <= 0 || notify_context .notifys == NULL )
737+ return 1 ;
738+
739+ /* Remove this notification */
740+ for (struct hid_notify * * current = & notify_context .notifys ; * current ; current = & (* current )-> next ) {
741+ if (* current == (struct hid_notify * )token ) {
742+ struct hid_notify * next = (* current )-> next ;
743+ notify = * current ;
744+ * current = next ;
745+ break ;
746+ }
747+ }
748+
749+ if (!notify )
750+ return 1 ;
751+
752+ free (notify );
753+
754+ /* Unregister device connection notification on removing last callback */
755+ if (notify_context .notifys == NULL ) {
756+ /* Cleanup connected device list */
757+ hid_free_enumeration (notify_context .devs );
758+ notify_context .devs = NULL ;
759+
760+ if (notify_context .notify_handle != NULL ) {
761+ CONFIGRET cr = CM_Unregister_Notification (notify_context .notify_handle );
762+ notify_context .notify_handle = NULL ;
763+ if (cr != CR_SUCCESS ) {
764+ return 1 ;
765+ }
766+ }
767+ }
768+
769+ return 0 ;
770+ }
771+
576772
577773HID_API_EXPORT hid_device * HID_API_CALL hid_open (unsigned short vendor_id , unsigned short product_id , const wchar_t * serial_number )
578774{
0 commit comments