From df0137c2b04d273c1b0f2ea7c27a7ecb122c9fa7 Mon Sep 17 00:00:00 2001 From: Adam Honse Date: Wed, 1 Jul 2026 17:49:07 -0500 Subject: [PATCH] Add network request for requesting list of HID devices in local client mode --- NetworkClient.cpp | 78 +++++++++++- NetworkClient.h | 2 + NetworkProtocol.h | 1 + NetworkServer.cpp | 112 ++++++++++++++++++ NetworkServer.h | 1 + ResourceManager.cpp | 44 +++++++ ResourceManager.h | 15 +++ .../OpenRGBHardwareIDsDialog.cpp | 20 +--- 8 files changed, 257 insertions(+), 16 deletions(-) diff --git a/NetworkClient.cpp b/NetworkClient.cpp index eb243c320..4974e888d 100644 --- a/NetworkClient.cpp +++ b/NetworkClient.cpp @@ -387,6 +387,81 @@ void NetworkClient::RegisterNetworkClientCallback(NetworkClientCallback new_call /*---------------------------------------------------------*\ | Device Info Functions | \*---------------------------------------------------------*/ +std::vector NetworkClient::GetHIDDeviceInfo() +{ + /*-----------------------------------------------------*\ + | Send request | + \*-----------------------------------------------------*/ + std::vector device_info; + NetPacketHeader reply_hdr; + + InitNetPacketHeader(&reply_hdr, 0, NET_PACKET_ID_GET_HID_DEVICE_INFO, 0); + + send_in_progress.lock(); + send(client_sock, (char *)&reply_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); + send_in_progress.unlock(); + + /*-----------------------------------------------------*\ + | Wait for response | + \*-----------------------------------------------------*/ + std::unique_lock wait_lock(waiting_on_response_mutex); + waiting_on_response_cv.wait(wait_lock); + + /*-----------------------------------------------------*\ + | Parse response into device list | + \*-----------------------------------------------------*/ + if(response_header.pkt_id == NET_PACKET_ID_GET_HID_DEVICE_INFO && response_data_ptr != NULL) + { + unsigned int device_count = 0; + unsigned char* data_ptr = response_data_ptr; + unsigned int& data_size = response_header.pkt_size; + unsigned int data_size_pkt; + + COPY_DATA_FIELD(data_ptr, response_data_ptr, data_size_pkt); + + if(data_size_pkt == data_size) + { + COPY_DATA_FIELD(data_ptr, response_data_ptr, device_count); + + for(unsigned int device_idx = 0; device_idx < device_count; device_idx++) + { + HIDDeviceInfo device; + + COPY_DATA_FIELD(data_ptr, response_data_ptr, device.vendor_id); + COPY_DATA_FIELD(data_ptr, response_data_ptr, device.product_id); + COPY_DATA_FIELD(data_ptr, response_data_ptr, device.release_number); + COPY_DATA_FIELD(data_ptr, response_data_ptr, device.usage_page); + COPY_DATA_FIELD(data_ptr, response_data_ptr, device.usage); + COPY_DATA_FIELD(data_ptr, response_data_ptr, device.interface_number); + + unsigned short serial_number_size; + COPY_DATA_FIELD(data_ptr, response_data_ptr, serial_number_size); + COPY_STRING_FIELD(data_ptr, response_data_ptr, serial_number_size, device.serial_number); + + unsigned short manufacturer_string_size; + COPY_DATA_FIELD(data_ptr, response_data_ptr, manufacturer_string_size); + COPY_STRING_FIELD(data_ptr, response_data_ptr, manufacturer_string_size, device.manufacturer_string); + + unsigned short product_string_size; + COPY_DATA_FIELD(data_ptr, response_data_ptr, product_string_size); + COPY_STRING_FIELD(data_ptr, response_data_ptr, product_string_size, device.product_string); + + unsigned short path_size; + COPY_DATA_FIELD(data_ptr, response_data_ptr, path_size); + COPY_STRING_FIELD(data_ptr, response_data_ptr, path_size, device.path); + + device_info.push_back(device); + } + } + + COPY_DATA_ERROR: + delete[] response_data_ptr; + response_data_ptr = NULL; + } + + return(device_info); +} + std::vector NetworkClient::GetI2CBusInfo() { /*-----------------------------------------------------*\ @@ -425,7 +500,7 @@ std::vector NetworkClient::GetI2CBusInfo() for(unsigned int bus_idx = 0; bus_idx < bus_count; bus_idx++) { - i2c_smbus_info bus; + i2c_smbus_info bus; COPY_DATA_FIELD(data_ptr, response_data_ptr, bus); @@ -1512,6 +1587,7 @@ void NetworkClient::ListenThreadFunction() break; case NET_PACKET_ID_GET_I2C_BUS_INFO: + case NET_PACKET_ID_GET_HID_DEVICE_INFO: case NET_PACKET_ID_LOGMANAGER_GET_LOG_LEVEL: case NET_PACKET_ID_PROFILEMANAGER_DOWNLOAD_PROFILE: case NET_PACKET_ID_PROFILEMANAGER_GET_ACTIVE_PROFILE: diff --git a/NetworkClient.h b/NetworkClient.h index d3624d0e7..c63f134ec 100644 --- a/NetworkClient.h +++ b/NetworkClient.h @@ -17,6 +17,7 @@ #include #include #include "i2c_smbus.h" +#include "ResourceManager.h" #include "RGBController.h" #include "NetworkProtocol.h" #include "net_port.h" @@ -109,6 +110,7 @@ public: /*-----------------------------------------------------*\ | Device Info Functions | \*-----------------------------------------------------*/ + std::vector GetHIDDeviceInfo(); std::vector GetI2CBusInfo(); /*-----------------------------------------------------*\ diff --git a/NetworkProtocol.h b/NetworkProtocol.h index 9cbecfbed..5182d78b3 100644 --- a/NetworkProtocol.h +++ b/NetworkProtocol.h @@ -117,6 +117,7 @@ enum NET_PACKET_ID_DETECTION_COMPLETE = 103, /* Indicate to clients that detection completed */ NET_PACKET_ID_GET_I2C_BUS_INFO = 120, /* Request list of I2C bus info */ + NET_PACKET_ID_GET_HID_DEVICE_INFO = 121, /* Request list of HID device info */ NET_PACKET_ID_REQUEST_RESCAN_DEVICES = 140, /* Request rescan of devices */ diff --git a/NetworkServer.cpp b/NetworkServer.cpp index 582536476..4f62ffa74 100644 --- a/NetworkServer.cpp +++ b/NetworkServer.cpp @@ -1287,6 +1287,10 @@ void NetworkServer::ListenThreadFunction(NetworkClientInfo* client_info) status = ProcessRequest_GetI2CBusInfo(client_info); break; + case NET_PACKET_ID_GET_HID_DEVICE_INFO: + status = ProcessRequest_GetHIDDeviceInfo(client_info); + break; + /*-------------------------------------------------*\ | LogManager functions | \*-------------------------------------------------*/ @@ -1616,6 +1620,114 @@ NetPacketStatus NetworkServer::ProcessRequest_RescanDevices() return(NET_PACKET_STATUS_OK); } +NetPacketStatus NetworkServer::ProcessRequest_GetHIDDeviceInfo(NetworkClientInfo* client_info) +{ + /*-----------------------------------------------------*\ + | Require local client for this packet | + \*-----------------------------------------------------*/ + if(!client_info->client_is_local_client) + { + return(NET_PACKET_STATUS_ERROR_NOT_ALLOWED); + } + + std::vector device_info = ResourceManager::get()->GetHIDDeviceInfo(); + + unsigned int data_size = 0; + unsigned int device_count = (unsigned int)device_info.size(); + + /*-----------------------------------------------------*\ + | Calculate data size | + \*-----------------------------------------------------*/ + data_size += sizeof(data_size); + data_size += sizeof(device_count); + + for(unsigned int device_idx = 0; device_idx < device_count; device_idx++) + { + data_size += sizeof(device_info[device_idx].vendor_id); + data_size += sizeof(device_info[device_idx].product_id); + data_size += sizeof(device_info[device_idx].release_number); + data_size += sizeof(device_info[device_idx].usage_page); + data_size += sizeof(device_info[device_idx].usage); + data_size += sizeof(device_info[device_idx].interface_number); + data_size += sizeof(unsigned short); + data_size += (unsigned int)strlen(device_info[device_idx].serial_number.c_str()) + 1; + data_size += sizeof(unsigned short); + data_size += (unsigned int)strlen(device_info[device_idx].manufacturer_string.c_str()) + 1; + data_size += sizeof(unsigned short); + data_size += (unsigned int)strlen(device_info[device_idx].product_string.c_str()) + 1; + data_size += sizeof(unsigned short); + data_size += (unsigned int)strlen(device_info[device_idx].path.c_str()) + 1; + } + + /*-----------------------------------------------------*\ + | Copy in data | + \*-----------------------------------------------------*/ + unsigned char* data_buf = new unsigned char[data_size]; + unsigned char* data_ptr = data_buf; + + memcpy(data_ptr, &data_size, sizeof(data_size)); + data_ptr += sizeof(data_size); + + memcpy(data_ptr, &device_count, sizeof(device_count)); + data_ptr += sizeof(device_count); + + for(unsigned int device_idx = 0; device_idx < device_count; device_idx++) + { + memcpy(data_ptr, &device_info[device_idx].vendor_id, sizeof(device_info[device_idx].vendor_id)); + data_ptr += sizeof(device_info[device_idx].vendor_id); + + memcpy(data_ptr, &device_info[device_idx].product_id, sizeof(device_info[device_idx].product_id)); + data_ptr += sizeof(device_info[device_idx].product_id); + + memcpy(data_ptr, &device_info[device_idx].release_number, sizeof(device_info[device_idx].release_number)); + data_ptr += sizeof(device_info[device_idx].release_number); + + memcpy(data_ptr, &device_info[device_idx].usage_page, sizeof(device_info[device_idx].usage_page)); + data_ptr += sizeof(device_info[device_idx].usage_page); + + memcpy(data_ptr, &device_info[device_idx].usage, sizeof(device_info[device_idx].usage)); + data_ptr += sizeof(device_info[device_idx].usage); + + memcpy(data_ptr, &device_info[device_idx].interface_number, sizeof(device_info[device_idx].interface_number)); + data_ptr += sizeof(device_info[device_idx].interface_number); + + unsigned short serial_number_size = (unsigned short)strlen(device_info[device_idx].serial_number.c_str()) + 1; + memcpy(data_ptr, &serial_number_size, sizeof(serial_number_size)); + data_ptr += sizeof(serial_number_size); + memcpy(data_ptr, device_info[device_idx].serial_number.c_str(), serial_number_size); + data_ptr += serial_number_size; + + unsigned short manufacturer_string_size = (unsigned short)strlen(device_info[device_idx].manufacturer_string.c_str()) + 1; + memcpy(data_ptr, &manufacturer_string_size, sizeof(manufacturer_string_size)); + data_ptr += sizeof(manufacturer_string_size); + memcpy(data_ptr, device_info[device_idx].manufacturer_string.c_str(), manufacturer_string_size); + data_ptr += manufacturer_string_size; + + unsigned short product_string_size = (unsigned short)strlen(device_info[device_idx].product_string.c_str()) + 1; + memcpy(data_ptr, &product_string_size, sizeof(product_string_size)); + data_ptr += sizeof(product_string_size); + memcpy(data_ptr, device_info[device_idx].product_string.c_str(), product_string_size); + data_ptr += product_string_size; + + unsigned short path_size = (unsigned short)strlen(device_info[device_idx].path.c_str()) + 1; + memcpy(data_ptr, &path_size, sizeof(path_size)); + data_ptr += sizeof(path_size); + memcpy(data_ptr, device_info[device_idx].path.c_str(), path_size); + data_ptr += path_size; + } + + NetPacketHeader reply_hdr; + + InitNetPacketHeader(&reply_hdr, 0, NET_PACKET_ID_GET_HID_DEVICE_INFO, data_size); + + send_in_progress.lock(); + send(client_info->client_sock, (char *)&reply_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); + send(client_info->client_sock, (char *)data_buf, reply_hdr.pkt_size, MSG_NOSIGNAL); + send_in_progress.unlock(); + + return(NET_PACKET_STATUS_OK); +} + NetPacketStatus NetworkServer::ProcessRequest_GetI2CBusInfo(NetworkClientInfo* client_info) { /*-----------------------------------------------------*\ diff --git a/NetworkServer.h b/NetworkServer.h index 91b762068..3725c766f 100644 --- a/NetworkServer.h +++ b/NetworkServer.h @@ -230,6 +230,7 @@ private: NetPacketStatus ProcessRequest_ClientString(NetworkClientInfo* client_info, unsigned int data_size, unsigned char* data_ptr); NetPacketStatus ProcessRequest_RescanDevices(); + NetPacketStatus ProcessRequest_GetHIDDeviceInfo(NetworkClientInfo* client_info); NetPacketStatus ProcessRequest_GetI2CBusInfo(NetworkClientInfo* client_info); NetPacketStatus ProcessRequest_LogManager_ClearLogBuffer(NetworkClientInfo* client_info); diff --git a/ResourceManager.cpp b/ResourceManager.cpp index ffcd990c8..5c893f5d1 100644 --- a/ResourceManager.cpp +++ b/ResourceManager.cpp @@ -24,10 +24,17 @@ #include "ProfileManager.h" #include "LogManager.h" #include "SettingsManager.h" +#include "StringUtils.h" #include "NetworkClient.h" #include "NetworkServer.h" #include "filesystem.h" +/*---------------------------------------------------------*\ +| Put these last to avoid some include order issues | +\*---------------------------------------------------------*/ +#include +#include + #ifdef __linux__ #include #endif @@ -308,6 +315,43 @@ unsigned short ResourceManager::GetDefaultServerPort() return(default_server_port); } +std::vector ResourceManager::GetHIDDeviceInfo() +{ + if(IsLocalClient()) + { + return(GetLocalClient()->GetHIDDeviceInfo()); + } + else + { + hid_device_info* hid_devices; + std::vector hid_info; + + hid_devices = hid_enumerate(0,0); + + while(hid_devices) + { + HIDDeviceInfo hid_device_info; + + hid_device_info.vendor_id = hid_devices->vendor_id; + hid_device_info.product_id = hid_devices->product_id; + hid_device_info.release_number = hid_devices->release_number; + hid_device_info.usage_page = hid_devices->usage_page; + hid_device_info.usage = hid_devices->usage; + hid_device_info.interface_number = hid_devices->interface_number; + hid_device_info.serial_number = StringUtils::wchar_to_string(hid_devices->serial_number); + hid_device_info.manufacturer_string = StringUtils::wchar_to_string(hid_devices->manufacturer_string); + hid_device_info.product_string = StringUtils::wchar_to_string(hid_devices->product_string); + hid_device_info.path = hid_devices->path; + + hid_info.push_back(hid_device_info); + + hid_devices = hid_devices->next; + } + + return(hid_info); + } +} + std::vector & ResourceManager::GetI2CBuses() { return DetectionManager::get()->GetI2CBuses(); diff --git a/ResourceManager.h b/ResourceManager.h index 6fb80ea0c..1cb409c53 100644 --- a/ResourceManager.h +++ b/ResourceManager.h @@ -36,6 +36,20 @@ class ProfileManager; class RGBController; class SettingsManager; +typedef struct +{ + unsigned short vendor_id; + unsigned short product_id; + unsigned short release_number; + unsigned short usage_page; + unsigned short usage; + int interface_number; + std::string serial_number; + std::string manufacturer_string; + std::string product_string; + std::string path; +} HIDDeviceInfo; + class ResourceManager { public: @@ -55,6 +69,7 @@ public: std::string GetDefaultServerHost(); unsigned short GetDefaultServerPort(); LogManager* GetLogManager(); + std::vector GetHIDDeviceInfo(); std::vector& GetI2CBuses(); std::vector GetI2CBusInfo(); PluginManagerInterface* GetPluginManager(); diff --git a/qt/OpenRGBHardwareIDsDialog/OpenRGBHardwareIDsDialog.cpp b/qt/OpenRGBHardwareIDsDialog/OpenRGBHardwareIDsDialog.cpp index 911a02559..f3a2426e4 100644 --- a/qt/OpenRGBHardwareIDsDialog/OpenRGBHardwareIDsDialog.cpp +++ b/qt/OpenRGBHardwareIDsDialog/OpenRGBHardwareIDsDialog.cpp @@ -55,30 +55,20 @@ int OpenRGBHardwareIDsDialog::show() /*-----------------------------------------------------*\ | Add HID Devices | \*-----------------------------------------------------*/ - hid_device_info* hid_devices = NULL; - hid_devices = hid_enumerate(0,0); - - hid_device_info* current_hid_device; - current_hid_device = hid_devices; - + std::vector hid_device_info = ResourceManager::get()->GetHIDDeviceInfo(); QTreeWidgetItem* hid_top = new QTreeWidgetItem(ui->HardwareIdsList, {"HID Devices"}); strings.push_back("\n[ HID Devices ]"); - while(current_hid_device) + for(HIDDeviceInfo device_info : hid_device_info) { - const char* manu_name = StringUtils::wchar_to_char(current_hid_device->manufacturer_string); - const char* prod_name = StringUtils::wchar_to_char(current_hid_device->product_string); - char line[550]; - snprintf(line, 550, "[%04X:%04X U=%04X P=0x%04X I=%d]", current_hid_device->vendor_id, current_hid_device->product_id, current_hid_device->usage, current_hid_device->usage_page, current_hid_device->interface_number); - new QTreeWidgetItem(hid_top, {line, prod_name, manu_name}); + snprintf(line, 550, "[%04X:%04X U=%04X P=0x%04X I=%d]", device_info.vendor_id, device_info.product_id, device_info.usage, device_info.usage_page, device_info.interface_number); + new QTreeWidgetItem(hid_top, {line, QString::fromStdString(device_info.product_string), QString::fromStdString(device_info.manufacturer_string)}); - snprintf(line, 550, "[%04X:%04X U=%04X P=0x%04X I=%d] %s - %s", current_hid_device->vendor_id, current_hid_device->product_id, current_hid_device->usage, current_hid_device->usage_page, current_hid_device->interface_number, manu_name, prod_name); + snprintf(line, 550, "[%04X:%04X U=%04X P=0x%04X I=%d] %s - %s", device_info.vendor_id, device_info.product_id, device_info.usage, device_info.usage_page, device_info.interface_number, device_info.manufacturer_string.c_str(), device_info.product_string.c_str()); strings.push_back(line); - - current_hid_device = current_hid_device->next; } /*-----------------------------------------------------*\