From 4d4cb534cdc0726e4e946ace13586ca5f123f7ec Mon Sep 17 00:00:00 2001 From: Adam Honse Date: Wed, 14 Jan 2026 19:33:18 -0600 Subject: [PATCH] [WIP] Add optional HID device hotplug support (requires hidapi hotplug support) --- .../HyperXMicrophoneController.cpp | 2 +- .../HyperXMicrophoneV2Controller.cpp | 2 +- .../WushiController/WushiL50USBController.cpp | 4 +- DetectionManager.cpp | 238 +++++++++++++++--- DetectionManager.h | 43 ++++ OpenRGB.pro | 36 +-- hidapi_wrapper/hidapi_wrapper.h | 57 +++-- 7 files changed, 308 insertions(+), 74 deletions(-) diff --git a/Controllers/HyperXMicrophoneController/HyperXMicrophoneController.cpp b/Controllers/HyperXMicrophoneController/HyperXMicrophoneController.cpp index 458d3e5b6..b501e3240 100644 --- a/Controllers/HyperXMicrophoneController/HyperXMicrophoneController.cpp +++ b/Controllers/HyperXMicrophoneController/HyperXMicrophoneController.cpp @@ -37,7 +37,7 @@ HyperXMicrophoneController::~HyperXMicrophoneController() std::string HyperXMicrophoneController::GetDeviceLocation() { - return(location); + return("HID: " + location); } std::string HyperXMicrophoneController::GetNameString() diff --git a/Controllers/HyperXMicrophoneV2Controller/HyperXMicrophoneV2Controller.cpp b/Controllers/HyperXMicrophoneV2Controller/HyperXMicrophoneV2Controller.cpp index 9f93a2bc6..d88d4bc87 100644 --- a/Controllers/HyperXMicrophoneV2Controller/HyperXMicrophoneV2Controller.cpp +++ b/Controllers/HyperXMicrophoneV2Controller/HyperXMicrophoneV2Controller.cpp @@ -37,7 +37,7 @@ HyperXMicrophoneV2Controller::~HyperXMicrophoneV2Controller() std::string HyperXMicrophoneV2Controller::GetDeviceLocation() { - return(location); + return("HID: " + location); } std::string HyperXMicrophoneV2Controller::GetNameString() diff --git a/Controllers/WushiController/WushiL50USBController.cpp b/Controllers/WushiController/WushiL50USBController.cpp index 45949a27f..6f017d1b1 100644 --- a/Controllers/WushiController/WushiL50USBController.cpp +++ b/Controllers/WushiController/WushiL50USBController.cpp @@ -26,12 +26,12 @@ WushiL50USBController::~WushiL50USBController() std::string WushiL50USBController::getName() { - return name; + return(name); } std::string WushiL50USBController::getLocation() { - return location; + return("HID: " + location); } std::string WushiL50USBController::GetSerialString() diff --git a/DetectionManager.cpp b/DetectionManager.cpp index b6803b886..b6c56f6c3 100644 --- a/DetectionManager.cpp +++ b/DetectionManager.cpp @@ -76,14 +76,18 @@ const char* UDEV_MUTLI = QT_TRANSLATE_NOOP("DetectionManager", const hidapi_wrapper default_hidapi_wrapper = { NULL, - (hidapi_wrapper_send_feature_report) hid_send_feature_report, - (hidapi_wrapper_get_feature_report) hid_get_feature_report, - (hidapi_wrapper_get_serial_number_string) hid_get_serial_number_string, - (hidapi_wrapper_open_path) hid_open_path, - (hidapi_wrapper_enumerate) hid_enumerate, - (hidapi_wrapper_free_enumeration) hid_free_enumeration, - (hidapi_wrapper_close) hid_close, - (hidapi_wrapper_error) hid_error + (hidapi_wrapper_send_feature_report) hid_send_feature_report, + (hidapi_wrapper_get_feature_report) hid_get_feature_report, + (hidapi_wrapper_get_serial_number_string) hid_get_serial_number_string, + (hidapi_wrapper_open_path) hid_open_path, + (hidapi_wrapper_enumerate) hid_enumerate, + (hidapi_wrapper_free_enumeration) hid_free_enumeration, + (hidapi_wrapper_close) hid_close, + (hidapi_wrapper_error) hid_error, +#if(HID_HOTPLUG_ENABLED) + (hidapi_wrapper_hotplug_register_callback) hid_hotplug_register_callback, + (hidapi_wrapper_hotplug_deregister_callback) hid_hotplug_deregister_callback, +#endif }; /*---------------------------------------------------------*\ @@ -143,6 +147,12 @@ DetectionManager::DetectionManager() dynamic_detectors_processed = false; initial_detection = true; +#ifdef __linux__ +#ifdef __GLIBC__ + hidapi_libusb_handle = nullptr; +#endif +#endif + /*-----------------------------------------------------*\ | Start the background thread | \*-----------------------------------------------------*/ @@ -711,7 +721,12 @@ void DetectionManager::BackgroundDetectDevices() } else { +#if(HID_HOTPLUG_ENABLED) + StopHIDHotplug(); + StartHIDHotplug(); +#else BackgroundDetectHIDDevices(hid_devices, detector_settings); +#endif } /*-----------------------------------------------------*\ @@ -1141,31 +1156,12 @@ void DetectionManager::BackgroundDetectHIDDevicesWrapped(hid_device_info* hid_de LOG_INFO("| Detecting libusb HID devices |"); LOG_INFO("------------------------------------------------------"); - void * dyn_handle = NULL; - hidapi_wrapper wrapper; - /*-----------------------------------------------------*\ | Load the libhidapi-libusb library | \*-----------------------------------------------------*/ - if((dyn_handle = dlopen("libhidapi-libusb.so", RTLD_NOW | RTLD_NODELETE | RTLD_DEEPBIND))) + if(hidapi_libusb_handle) { - /*-------------------------------------------------*\ - | Create a wrapper with the libusb functions | - \*-------------------------------------------------*/ - wrapper = - { - .dyn_handle = dyn_handle, - .hid_send_feature_report = (hidapi_wrapper_send_feature_report) dlsym(dyn_handle,"hid_send_feature_report"), - .hid_get_feature_report = (hidapi_wrapper_get_feature_report) dlsym(dyn_handle,"hid_get_feature_report"), - .hid_get_serial_number_string = (hidapi_wrapper_get_serial_number_string) dlsym(dyn_handle,"hid_get_serial_number_string"), - .hid_open_path = (hidapi_wrapper_open_path) dlsym(dyn_handle,"hid_open_path"), - .hid_enumerate = (hidapi_wrapper_enumerate) dlsym(dyn_handle,"hid_enumerate"), - .hid_free_enumeration = (hidapi_wrapper_free_enumeration) dlsym(dyn_handle,"hid_free_enumeration"), - .hid_close = (hidapi_wrapper_close) dlsym(dyn_handle,"hid_close"), - .hid_error = (hidapi_wrapper_error) dlsym(dyn_handle,"hid_free_enumeration") - }; - - hid_devices = wrapper.hid_enumerate(0, 0); + hid_devices = hidapi_libusb_wrapper.hid_enumerate(0, 0); hid_device_info* current_hid_device = hid_devices; @@ -1177,7 +1173,7 @@ void DetectionManager::BackgroundDetectHIDDevicesWrapped(hid_device_info* hid_de while(current_hid_device) { - RunHIDWrappedDetector(&wrapper, current_hid_device, detector_settings); + RunHIDWrappedDetector(&hidapi_libusb_wrapper, current_hid_device, detector_settings); /*---------------------------------------------*\ | Update detection percent | @@ -1195,7 +1191,7 @@ void DetectionManager::BackgroundDetectHIDDevicesWrapped(hid_device_info* hid_de /*-------------------------------------------------*\ | Done using the device list, free it | \*-------------------------------------------------*/ - wrapper.hid_free_enumeration(hid_devices); + hidapi_libusb_wrapper.hid_free_enumeration(hid_devices); } } #endif @@ -1268,6 +1264,42 @@ void DetectionManager::BackgroundHIDInit() int hid_status = hid_init(); LOG_DEBUG("[%s] Initializing HID interfaces: %s", DETECTIONMANAGER, ((hid_status == 0) ? "Success" : "Failed")); + +#ifdef __linux__ +#ifdef __GLIBC__ + /*-----------------------------------------------------*\ + | Load the libhidapi-libusb library | + \*-----------------------------------------------------*/ +#if(HID_HOTPLUG_ENABLED) + hidapi_libusb_handle = dlopen("libhidapi-hotplug-libusb.so", RTLD_NOW | RTLD_NODELETE | RTLD_DEEPBIND); +#else + hidapi_libusb_handle = dlopen("libhidapi-libusb.so", RTLD_NOW | RTLD_NODELETE | RTLD_DEEPBIND); +#endif + + if(hidapi_libusb_handle) + { + /*-------------------------------------------------*\ + | Create a wrapper with the libusb functions | + \*-------------------------------------------------*/ + hidapi_libusb_wrapper = + { + .dyn_handle = hidapi_libusb_handle, + .hid_send_feature_report = (hidapi_wrapper_send_feature_report) dlsym(hidapi_libusb_handle,"hid_send_feature_report"), + .hid_get_feature_report = (hidapi_wrapper_get_feature_report) dlsym(hidapi_libusb_handle,"hid_get_feature_report"), + .hid_get_serial_number_string = (hidapi_wrapper_get_serial_number_string) dlsym(hidapi_libusb_handle,"hid_get_serial_number_string"), + .hid_open_path = (hidapi_wrapper_open_path) dlsym(hidapi_libusb_handle,"hid_open_path"), + .hid_enumerate = (hidapi_wrapper_enumerate) dlsym(hidapi_libusb_handle,"hid_enumerate"), + .hid_free_enumeration = (hidapi_wrapper_free_enumeration) dlsym(hidapi_libusb_handle,"hid_free_enumeration"), + .hid_close = (hidapi_wrapper_close) dlsym(hidapi_libusb_handle,"hid_close"), + .hid_error = (hidapi_wrapper_error) dlsym(hidapi_libusb_handle,"hid_free_enumeration"), +#if(HID_HOTPLUG_ENABLED) + .hid_hotplug_register_callback = (hidapi_wrapper_hotplug_register_callback) dlsym(hidapi_libusb_handle,"hid_hotplug_register_callback"), + .hid_hotplug_deregister_callback = (hidapi_wrapper_hotplug_deregister_callback) dlsym(hidapi_libusb_handle,"hid_hotplug_deregister_callback"), +#endif + }; + } +#endif +#endif } /*---------------------------------------------------------*\ @@ -1320,6 +1352,10 @@ void DetectionManager::RunHIDDetector(hid_device_info* current_hid_device, json for(std::size_t detected_controller_idx = 0; detected_controller_idx < detected_controllers.size(); detected_controller_idx++) { +#if(HID_HOTPLUG_ENABLED) + int handle; + hid_hotplug_register_callback(current_hid_device->vendor_id, current_hid_device->product_id, HID_API_HOTPLUG_EVENT_DEVICE_LEFT, 0, &DetectionManager::UnplugCallbackFunction, detected_controllers[detected_controller_idx], &handle); +#endif RegisterRGBController(detected_controllers[detected_controller_idx]); } } @@ -1376,6 +1412,10 @@ void DetectionManager::RunHIDWrappedDetector(const hidapi_wrapper* wrapper, hid_ for(std::size_t detected_controller_idx = 0; detected_controller_idx < detected_controllers.size(); detected_controller_idx++) { +#if(HID_HOTPLUG_ENABLED) + int handle; + wrapper->hid_hotplug_register_callback(current_hid_device->vendor_id, current_hid_device->product_id, HID_API_HOTPLUG_EVENT_DEVICE_LEFT, 0, &DetectionManager::WrappedUnplugCallbackFunction, detected_controllers[detected_controller_idx], &handle); +#endif RegisterRGBController(detected_controllers[detected_controller_idx]); } } @@ -1392,6 +1432,10 @@ void DetectionManager::ProcessCleanup() { WaitForDetection(); +#if(HID_HOTPLUG_ENABLED) + StopHIDHotplug(); +#endif + /*-----------------------------------------------------*\ | Make a copy of the list so that the controllers can | | be deleted after the list is cleared | @@ -1619,6 +1663,138 @@ void DetectionManager::UpdateDetectorSettings() } } +#if(HID_HOTPLUG_ENABLED) +/*---------------------------------------------------------*\ +| HID hotplug management functions | +\*---------------------------------------------------------*/ +void DetectionManager::StartHIDHotplug() +{ + hid_hotplug_register_callback(0, 0, HID_API_HOTPLUG_EVENT_DEVICE_ARRIVED, HID_API_HOTPLUG_ENUMERATE, &DetectionManager::HotplugCallbackFunction, nullptr, &hotplug_callback_handle); + +#ifdef __linux__ +#ifdef __GLIBC__ + if(hidapi_libusb_handle != nullptr) + { + hidapi_libusb_wrapper.hid_hotplug_register_callback(0, 0, HID_API_HOTPLUG_EVENT_DEVICE_ARRIVED, HID_API_HOTPLUG_ENUMERATE, &DetectionManager::WrappedHotplugCallbackFunction, nullptr, &libusb_hotplug_callback_handle); + } +#endif +#endif +} + +void DetectionManager::StopHIDHotplug() +{ + hid_hotplug_deregister_callback(hotplug_callback_handle); + +#ifdef __linux__ +#ifdef __GLIBC__ + if(hidapi_libusb_handle != nullptr) + { + hidapi_libusb_wrapper.hid_hotplug_deregister_callback(libusb_hotplug_callback_handle); + } +#endif +#endif +} + +/*---------------------------------------------------------*\ +| HID hotplug callback functions | +\*---------------------------------------------------------*/ +int DetectionManager::HotplugCallbackFunction(hid_hotplug_callback_handle callback_handle, hid_device_info *device, hid_hotplug_event event, void *user_data) +{ + /*-----------------------------------------------------*\ + | Open device disable list and read in disabled | + | device strings | + \*-----------------------------------------------------*/ + json detector_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("Detectors"); + DetectionManager* dm = DetectionManager::get(); + + if(event == HID_API_HOTPLUG_EVENT_DEVICE_ARRIVED) + { + LOG_INFO("[%s] HID device connected: [%04x:%04x]", DETECTIONMANAGER, device->vendor_id, device->product_id); + + dm->RunHIDDetector(device, detector_settings); + dm->RunHIDWrappedDetector(&default_hidapi_wrapper, device, detector_settings); + } + + return 0; +} + +int DetectionManager::UnplugCallbackFunction(hid_hotplug_callback_handle callback_handle, hid_device_info *device, hid_hotplug_event event, void *user_data) +{ + DetectionManager* dm = DetectionManager::get(); + + if(event == HID_API_HOTPLUG_EVENT_DEVICE_LEFT) + { + LOG_INFO("[%s] HID device disconnected: [%04x:%04x]", DETECTIONMANAGER, device->vendor_id, device->product_id); + + std::string location = "HID: "; + location.append(device->path); + + // User data is the pointer to the controller being removed + RGBController* controller = (RGBController*)(user_data); + + LOG_DEBUG("Checking device location:\"%s\":\"%s\"", location.c_str(), controller->location.c_str()); + + if(controller && controller->location == location) + { + dm->UnregisterRGBController(controller); + delete controller; + return 1; + } + } + return 0; +} + +#ifdef __linux__ +#ifdef __GLIBC__ +int DetectionManager::WrappedHotplugCallbackFunction(hid_hotplug_callback_handle callback_handle, hid_device_info *device, hid_hotplug_event event, void *user_data) +{ + /*-----------------------------------------------------*\ + | Open device disable list and read in disabled | + | device strings | + \*-----------------------------------------------------*/ + json detector_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("Detectors"); + DetectionManager* dm = DetectionManager::get(); + + if(event == HID_API_HOTPLUG_EVENT_DEVICE_ARRIVED) + { + LOG_INFO("[%s] libusb HID device connected: [%04x:%04x]", DETECTIONMANAGER, device->vendor_id, device->product_id); + + dm->RunHIDDetector(device, detector_settings); + dm->RunHIDWrappedDetector(&DetectionManager::get()->hidapi_libusb_wrapper, device, detector_settings); + } + + return 0; +} + +int DetectionManager::WrappedUnplugCallbackFunction(hid_hotplug_callback_handle callback_handle, hid_device_info *device, hid_hotplug_event event, void *user_data) +{ + DetectionManager* dm = DetectionManager::get(); + + if(event == HID_API_HOTPLUG_EVENT_DEVICE_LEFT) + { + LOG_INFO("[%s] libusb HID device disconnected: [%04x:%04x]", DETECTIONMANAGER, device->vendor_id, device->product_id); + + std::string location = "HID: "; + location.append(device->path); + + // User data is the pointer to the controller being removed + RGBController* controller = (RGBController*)(user_data); + + LOG_DEBUG("Checking device location:\"%s\":\"%s\"", location.c_str(), controller->location.c_str()); + + if(controller && controller->location == location) + { + dm->UnregisterRGBController(controller); + delete controller; + return 1; + } + } + return 0; +} +#endif +#endif +#endif + /*---------------------------------------------------------*\ | Function for signalling DetectionManager updates to | | registered callbacks | diff --git a/DetectionManager.h b/DetectionManager.h index 49358bfec..32471606c 100644 --- a/DetectionManager.h +++ b/DetectionManager.h @@ -228,6 +228,28 @@ private: std::vector dynamic_detector_strings; std::vector pre_detection_hooks; +#ifdef __linux__ +#ifdef __GLIBC__ + /*-----------------------------------------------------*\ + | Wrapped libusb hidapi handles | + \*-----------------------------------------------------*/ + void * hidapi_libusb_handle; + hidapi_wrapper hidapi_libusb_wrapper; +#endif +#endif + + /*-----------------------------------------------------*\ + | HID Hotplug handles | + \*-----------------------------------------------------*/ +#if(HID_HOTPLUG_ENABLED) + hid_hotplug_callback_handle hotplug_callback_handle; +#ifdef __linux__ +#ifdef __GLIBC__ + hid_hotplug_callback_handle libusb_hotplug_callback_handle; +#endif +#endif +#endif + /*-----------------------------------------------------*\ | Detection Callbacks | \*-----------------------------------------------------*/ @@ -303,6 +325,27 @@ private: void ProcessPreDetectionHooks(); void UpdateDetectorSettings(); +#if(HID_HOTPLUG_ENABLED) + /*-----------------------------------------------------*\ + | HID hotplug management functions | + \*-----------------------------------------------------*/ + void StartHIDHotplug(); + void StopHIDHotplug(); + + /*-----------------------------------------------------*\ + | HID hotplug callback functions | + \*-----------------------------------------------------*/ + static int HotplugCallbackFunction(hid_hotplug_callback_handle callback_handle, hid_device_info *device, hid_hotplug_event event, void *user_data); + static int UnplugCallbackFunction(hid_hotplug_callback_handle callback_handle, hid_device_info *device, hid_hotplug_event event, void *user_data); + +#ifdef __linux__ +#ifdef __GLIBC__ + static int WrappedHotplugCallbackFunction(hid_hotplug_callback_handle callback_handle, hid_device_info *device, hid_hotplug_event event, void *user_data); + static int WrappedUnplugCallbackFunction(hid_hotplug_callback_handle callback_handle, hid_device_info *device, hid_hotplug_event event, void *user_data); +#endif +#endif +#endif + /*-----------------------------------------------------*\ | Function for signalling DetectionManager updates to | | registered callbacks | diff --git a/OpenRGB.pro b/OpenRGB.pro index b4792725d..d9e769632 100644 --- a/OpenRGB.pro +++ b/OpenRGB.pro @@ -501,22 +501,28 @@ contains(QMAKE_PLATFORM, linux) { # Determine which hidapi to use based on availability # # Prefer hidraw backend, then libusb # #-------------------------------------------------------------------------------------------# - packagesExist(hidapi-hidraw) { - PKGCONFIG += hidapi-hidraw - - #---------------------------------------------------------------------------------------# - # hidapi-hidraw >= 0.10.1 supports USAGE/USAGE_PAGE # - # Define USE_HID_USAGE if hidapi-hidraw supports it # - #---------------------------------------------------------------------------------------# - HIDAPI_HIDRAW_VERSION = $$system($$PKG_CONFIG --modversion hidapi-hidraw) - if(versionAtLeast(HIDAPI_HIDRAW_VERSION, "0.10.1")) { - DEFINES += USE_HID_USAGE - } + packagesExist(hidapi-hotplug-hidraw) { + PKGCONFIG += hidapi-hotplug-hidraw + DEFINES += USE_HID_USAGE=1 \ + HID_HOTPLUG_ENABLED=1 } else { - packagesExist(hidapi-libusb) { - PKGCONFIG += hidapi-libusb + packagesExist(hidapi-hidraw) { + PKGCONFIG += hidapi-hidraw + + #-----------------------------------------------------------------------------------# + # hidapi-hidraw >= 0.10.1 supports USAGE/USAGE_PAGE # + # Define USE_HID_USAGE if hidapi-hidraw supports it # + #-----------------------------------------------------------------------------------# + HIDAPI_HIDRAW_VERSION = $$system($$PKG_CONFIG --modversion hidapi-hidraw) + if(versionAtLeast(HIDAPI_HIDRAW_VERSION, "0.10.1")) { + DEFINES += USE_HID_USAGE + } } else { - PKGCONFIG += hidapi + packagesExist(hidapi-libusb) { + PKGCONFIG += hidapi-libusb + } else { + PKGCONFIG += hidapi + } } } @@ -713,7 +719,7 @@ macx { hidapi DEFINES += \ - USE_HID_USAGE \ + cUSAGE \ QMAKE_CXXFLAGS += \ -Wno-narrowing \ diff --git a/hidapi_wrapper/hidapi_wrapper.h b/hidapi_wrapper/hidapi_wrapper.h index b04246e05..d7d1b2d59 100644 --- a/hidapi_wrapper/hidapi_wrapper.h +++ b/hidapi_wrapper/hidapi_wrapper.h @@ -19,31 +19,40 @@ #include #endif -/*-----------------------------------------------------*\ -| Type definitions for libhidapi function pointers | -\*-----------------------------------------------------*/ -typedef int (*hidapi_wrapper_send_feature_report) (hid_device*, const unsigned char*, size_t); -typedef int (*hidapi_wrapper_get_feature_report) (hid_device*, unsigned char*, size_t); -typedef int (*hidapi_wrapper_get_serial_number_string) (hid_device*, wchar_t*, size_t); -typedef hid_device* (*hidapi_wrapper_open_path) (const char*); -typedef hid_device_info* (*hidapi_wrapper_enumerate) (unsigned short, unsigned short); -typedef void (*hidapi_wrapper_free_enumeration) (hid_device_info*); -typedef void (*hidapi_wrapper_close) (hid_device*); -typedef const wchar_t* (*hidapi_wrapper_error) (hid_device*); +/*---------------------------------------------------------*\ +| Type definitions for libhidapi function pointers | +\*---------------------------------------------------------*/ +typedef int (*hidapi_wrapper_send_feature_report) (hid_device*, const unsigned char*, size_t); +typedef int (*hidapi_wrapper_get_feature_report) (hid_device*, unsigned char*, size_t); +typedef int (*hidapi_wrapper_get_serial_number_string) (hid_device*, wchar_t*, size_t); +typedef hid_device* (*hidapi_wrapper_open_path) (const char*); +typedef hid_device_info* (*hidapi_wrapper_enumerate) (unsigned short, unsigned short); +typedef void (*hidapi_wrapper_free_enumeration) (hid_device_info*); +typedef void (*hidapi_wrapper_close) (hid_device*); +typedef const wchar_t* (*hidapi_wrapper_error) (hid_device*); -/*-----------------------------------------------------*\ -| See comment at top of HyperXQuadcastSDetect.cpp for | -| details about the hidapi wrapper for this device | -\*-----------------------------------------------------*/ +#if(HID_HOTPLUG_ENABLED) +typedef int (*hidapi_wrapper_hotplug_register_callback) (unsigned short vendor_id, unsigned short product_id, int events, int flags, hid_hotplug_callback_fn callback, void* user_data, hid_hotplug_callback_handle* callback_handle); +typedef int (*hidapi_wrapper_hotplug_deregister_callback) (hid_hotplug_callback_handle callback_handle); +#endif + +/*---------------------------------------------------------*\ +| See comment at top of HyperXQuadcastSDetect.cpp for | +| details about the hidapi wrapper for this device | +\*---------------------------------------------------------*/ struct hidapi_wrapper { - void* dyn_handle; - hidapi_wrapper_send_feature_report hid_send_feature_report; - hidapi_wrapper_get_feature_report hid_get_feature_report; - hidapi_wrapper_get_serial_number_string hid_get_serial_number_string; - hidapi_wrapper_open_path hid_open_path; - hidapi_wrapper_enumerate hid_enumerate; - hidapi_wrapper_free_enumeration hid_free_enumeration; - hidapi_wrapper_close hid_close; - hidapi_wrapper_error hid_error; + void* dyn_handle; + hidapi_wrapper_send_feature_report hid_send_feature_report; + hidapi_wrapper_get_feature_report hid_get_feature_report; + hidapi_wrapper_get_serial_number_string hid_get_serial_number_string; + hidapi_wrapper_open_path hid_open_path; + hidapi_wrapper_enumerate hid_enumerate; + hidapi_wrapper_free_enumeration hid_free_enumeration; + hidapi_wrapper_close hid_close; + hidapi_wrapper_error hid_error; +#if(HID_HOTPLUG_ENABLED) + hidapi_wrapper_hotplug_register_callback hid_hotplug_register_callback; + hidapi_wrapper_hotplug_deregister_callback hid_hotplug_deregister_callback; +#endif };