Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions proto/config.proto
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,22 @@ message GamepadOptions
optional uint32 usbVendorID = 31;
optional uint32 miniMenuGamepadInput = 32;
optional InputModeDeviceType inputDeviceType = 33;
// Separate XInput USB descriptor overrides
optional bool hidDescOverride = 34;
optional string hidDescProduct = 35 [(nanopb).max_length = 32];
optional string hidDescManufacturer = 36 [(nanopb).max_length = 32];
optional string hidDescVersion = 37 [(nanopb).max_length = 8];
optional bool hidOverrideID = 38;
optional uint32 hidProductID = 39;
optional uint32 hidVendorID = 40;
// Separate USB-HID (non-XInput) USB descriptor overrides
optional bool xinputDescOverride = 41;
optional string xinputDescProduct = 42 [(nanopb).max_length = 32];
optional string xinputDescManufacturer = 43 [(nanopb).max_length = 32];
optional string xinputDescVersion = 44 [(nanopb).max_length = 8];
optional bool xinputOverrideID = 45;
optional uint32 xinputProductID = 46;
optional uint32 xinputVendorID = 47;
}

message KeyboardMapping
Expand Down
16 changes: 16 additions & 0 deletions src/config_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,22 @@ void ConfigUtils::initUnsetPropertiesWithDefaults(Config& config)
INIT_UNSET_PROPERTY(config.gamepadOptions, usbOverrideID, DEFAULT_USB_ID_OVERRIDE);
INIT_UNSET_PROPERTY(config.gamepadOptions, usbVendorID, DEFAULT_USB_VENDOR_ID);
INIT_UNSET_PROPERTY(config.gamepadOptions, usbProductID, DEFAULT_USB_PRODUCT_ID);
// HID specific USB descriptor overrides
INIT_UNSET_PROPERTY(config.gamepadOptions, hidDescOverride, DEFAULT_USB_DESC_OVERRIDE);
INIT_UNSET_PROPERTY_STR(config.gamepadOptions, hidDescProduct, DEFAULT_USB_DESC_PRODUCT);
INIT_UNSET_PROPERTY_STR(config.gamepadOptions, hidDescManufacturer, DEFAULT_USB_DESC_MANUFACTURER);
INIT_UNSET_PROPERTY_STR(config.gamepadOptions, hidDescVersion, DEFAULT_USB_DESC_VERSION);
INIT_UNSET_PROPERTY(config.gamepadOptions, hidOverrideID, DEFAULT_USB_ID_OVERRIDE);
INIT_UNSET_PROPERTY(config.gamepadOptions, hidVendorID, DEFAULT_USB_VENDOR_ID);
INIT_UNSET_PROPERTY(config.gamepadOptions, hidProductID, DEFAULT_USB_PRODUCT_ID);
// XInput specific USB descriptor overrides
INIT_UNSET_PROPERTY(config.gamepadOptions, xinputDescOverride, DEFAULT_USB_DESC_OVERRIDE);
INIT_UNSET_PROPERTY_STR(config.gamepadOptions, xinputDescProduct, DEFAULT_USB_DESC_PRODUCT);
INIT_UNSET_PROPERTY_STR(config.gamepadOptions, xinputDescManufacturer, DEFAULT_USB_DESC_MANUFACTURER);
INIT_UNSET_PROPERTY_STR(config.gamepadOptions, xinputDescVersion, DEFAULT_USB_DESC_VERSION);
INIT_UNSET_PROPERTY(config.gamepadOptions, xinputOverrideID, DEFAULT_USB_ID_OVERRIDE);
INIT_UNSET_PROPERTY(config.gamepadOptions, xinputVendorID, DEFAULT_USB_VENDOR_ID);
INIT_UNSET_PROPERTY(config.gamepadOptions, xinputProductID, DEFAULT_USB_PRODUCT_ID);
INIT_UNSET_PROPERTY(config.gamepadOptions, miniMenuGamepadInput, MINI_MENU_GAMEPAD_INPUT);

// hotkeyOptions
Expand Down
22 changes: 13 additions & 9 deletions src/drivers/hid/HIDDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,18 +135,20 @@ bool HIDDriver::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_contr

const uint16_t * HIDDriver::get_descriptor_string_cb(uint8_t index, uint16_t langid) {
char *value;
// Check for override settings
// Check for override settings - use HID-specific overrides if available
GamepadOptions & gamepadOptions = Storage::getInstance().getGamepadOptions();
if ( gamepadOptions.usbDescOverride == true ) {
// Check for HID-specific overrides first, fall back to legacy shared settings
bool useOverride = gamepadOptions.hidDescOverride;
if ( useOverride == true ) {
switch(index) {
case 1:
value = gamepadOptions.usbDescManufacturer;
value = gamepadOptions.hidDescManufacturer;
break;
case 2:
value = gamepadOptions.usbDescProduct;
value = gamepadOptions.hidDescProduct;
break;
case 3:
value = gamepadOptions.usbDescVersion;
value = gamepadOptions.hidDescVersion;
default:
value = (char *)hid_string_descriptors[index];
break;
Expand All @@ -159,13 +161,15 @@ const uint16_t * HIDDriver::get_descriptor_string_cb(uint8_t index, uint16_t lan
}

const uint8_t * HIDDriver::get_descriptor_device_cb() {
// Check for override settings
// Check for override settings - use HID-specific overrides if available
GamepadOptions & gamepadOptions = Storage::getInstance().getGamepadOptions();
if ( gamepadOptions.usbOverrideID == true ) {
// Check for HID-specific overrides first, fall back to legacy shared settings
bool useOverride = gamepadOptions.hidOverrideID;
if ( useOverride == true ) {
static uint8_t modified_device_descriptor[18];
memcpy(modified_device_descriptor, hid_device_descriptor, sizeof(hid_device_descriptor));
memcpy(&modified_device_descriptor[8], (uint8_t*)&gamepadOptions.usbVendorID, sizeof(uint16_t)); // Vendor ID
memcpy(&modified_device_descriptor[10], (uint8_t*)&gamepadOptions.usbProductID, sizeof(uint16_t)); // Product ID
memcpy(&modified_device_descriptor[8], (uint8_t*)&gamepadOptions.hidVendorID, sizeof(uint16_t)); // Vendor ID
memcpy(&modified_device_descriptor[10], (uint8_t*)&gamepadOptions.hidProductID, sizeof(uint16_t)); // Product ID
return (const uint8_t*)modified_device_descriptor;
}

Expand Down
22 changes: 13 additions & 9 deletions src/drivers/xinput/XInputDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -488,18 +488,20 @@ bool XInputDriver::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_co

const uint16_t * XInputDriver::get_descriptor_string_cb(uint8_t index, uint16_t langid) {
char *value;
// Check for override settings
// Check for override settings - use XInput-specific overrides if available
GamepadOptions & gamepadOptions = Storage::getInstance().getGamepadOptions();
if ( gamepadOptions.usbDescOverride == true ) {
// Check for XInput-specific overrides first, fall back to legacy shared settings
bool useOverride = gamepadOptions.xinputDescOverride;
if ( useOverride == true ) {
switch(index) {
case 1:
value = gamepadOptions.usbDescManufacturer;
value = gamepadOptions.xinputDescManufacturer;
break;
case 2:
value = gamepadOptions.usbDescProduct;
value = gamepadOptions.xinputDescProduct;
break;
case 3:
value = gamepadOptions.usbDescVersion;
value = gamepadOptions.xinputDescVersion;
default:
value = (char *)xinput_get_string_descriptor(index);
break;
Expand All @@ -511,13 +513,15 @@ const uint16_t * XInputDriver::get_descriptor_string_cb(uint8_t index, uint16_t
}

const uint8_t * XInputDriver::get_descriptor_device_cb() {
// Check for override settings
// Check for override settings - use XInput-specific overrides if available
GamepadOptions & gamepadOptions = Storage::getInstance().getGamepadOptions();
if ( gamepadOptions.usbOverrideID == true ) {
// Check for XInput-specific overrides first, fall back to legacy shared settings
bool useOverride = gamepadOptions.xinputOverrideID;
if ( useOverride == true ) {
static uint8_t modified_device_descriptor[18];
memcpy(modified_device_descriptor, xinput_device_descriptor, sizeof(xinput_device_descriptor));
memcpy(&modified_device_descriptor[8], (uint8_t*)&gamepadOptions.usbVendorID, sizeof(uint16_t)); // Vendor ID
memcpy(&modified_device_descriptor[10], (uint8_t*)&gamepadOptions.usbProductID, sizeof(uint16_t)); // Product ID
memcpy(&modified_device_descriptor[8], (uint8_t*)&gamepadOptions.xinputVendorID, sizeof(uint16_t)); // Vendor ID
memcpy(&modified_device_descriptor[10], (uint8_t*)&gamepadOptions.xinputProductID, sizeof(uint16_t)); // Product ID
return (const uint8_t*)modified_device_descriptor;
}
return xinput_device_descriptor;
Expand Down
80 changes: 76 additions & 4 deletions src/webconfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -679,7 +679,7 @@ std::string setGamepadOptions()
readDoc(gamepadOptions.ps4ControllerIDMode, doc, "ps4ControllerIDMode");
readDoc(gamepadOptions.usbDescOverride, doc, "usbDescOverride");
readDoc(gamepadOptions.miniMenuGamepadInput, doc, "miniMenuGamepadInput");
// Copy USB descriptor strings
// Copy USB descriptor strings (legacy shared settings for backward compatibility)
size_t strSize = sizeof(gamepadOptions.usbDescManufacturer);
strncpy(gamepadOptions.usbDescManufacturer, doc["usbDescManufacturer"], strSize - 1);
gamepadOptions.usbDescManufacturer[strSize - 1] = '\0';
Expand All @@ -690,8 +690,53 @@ std::string setGamepadOptions()
strncpy(gamepadOptions.usbDescVersion, doc["usbDescVersion"], strSize - 1);
gamepadOptions.usbDescVersion[strSize - 1] = '\0';
readDoc(gamepadOptions.usbOverrideID, doc, "usbOverrideID");
readDoc(gamepadOptions.usbVendorID, doc, "usbVendorID");
readDoc(gamepadOptions.usbProductID, doc, "usbProductID");
// Parse USB VID/PID as hex strings
if (doc.containsKey("usbVendorID")) {
gamepadOptions.usbVendorID = strtoul(doc["usbVendorID"], nullptr, 16);
}
if (doc.containsKey("usbProductID")) {
gamepadOptions.usbProductID = strtoul(doc["usbProductID"], nullptr, 16);
}

// HID (USB-HID) specific overrides
readDoc(gamepadOptions.hidDescOverride, doc, "hidDescOverride");
strSize = sizeof(gamepadOptions.hidDescManufacturer);
strncpy(gamepadOptions.hidDescManufacturer, doc["hidDescManufacturer"], strSize - 1);
gamepadOptions.hidDescManufacturer[strSize - 1] = '\0';
strSize = sizeof(gamepadOptions.hidDescProduct);
strncpy(gamepadOptions.hidDescProduct, doc["hidDescProduct"], strSize - 1);
gamepadOptions.hidDescProduct[strSize - 1] = '\0';
strSize = sizeof(gamepadOptions.hidDescVersion);
strncpy(gamepadOptions.hidDescVersion, doc["hidDescVersion"], strSize - 1);
gamepadOptions.hidDescVersion[strSize - 1] = '\0';
readDoc(gamepadOptions.hidOverrideID, doc, "hidOverrideID");
// Parse HID VID/PID as hex strings
if (doc.containsKey("hidVendorID")) {
gamepadOptions.hidVendorID = strtoul(doc["hidVendorID"], nullptr, 16);
}
if (doc.containsKey("hidProductID")) {
gamepadOptions.hidProductID = strtoul(doc["hidProductID"], nullptr, 16);
}

// XInput specific overrides
readDoc(gamepadOptions.xinputDescOverride, doc, "xinputDescOverride");
strSize = sizeof(gamepadOptions.xinputDescManufacturer);
strncpy(gamepadOptions.xinputDescManufacturer, doc["xinputDescManufacturer"], strSize - 1);
gamepadOptions.xinputDescManufacturer[strSize - 1] = '\0';
strSize = sizeof(gamepadOptions.xinputDescProduct);
strncpy(gamepadOptions.xinputDescProduct, doc["xinputDescProduct"], strSize - 1);
gamepadOptions.xinputDescProduct[strSize - 1] = '\0';
strSize = sizeof(gamepadOptions.xinputDescVersion);
strncpy(gamepadOptions.xinputDescVersion, doc["xinputDescVersion"], strSize - 1);
gamepadOptions.xinputDescVersion[strSize - 1] = '\0';
readDoc(gamepadOptions.xinputOverrideID, doc, "xinputOverrideID");
// Parse XInput VID/PID as hex strings
if (doc.containsKey("xinputVendorID")) {
gamepadOptions.xinputVendorID = strtoul(doc["xinputVendorID"], nullptr, 16);
}
if (doc.containsKey("xinputProductID")) {
gamepadOptions.xinputProductID = strtoul(doc["xinputProductID"], nullptr, 16);
}


HotkeyOptions& hotkeyOptions = Storage::getInstance().getHotkeyOptions();
Expand Down Expand Up @@ -753,13 +798,40 @@ std::string getGamepadOptions()
writeDoc(doc, "usbDescVersion", gamepadOptions.usbDescVersion);
writeDoc(doc, "usbOverrideID", gamepadOptions.usbOverrideID);
writeDoc(doc, "miniMenuGamepadInput", gamepadOptions.miniMenuGamepadInput);
// Write USB Vendor ID and Product ID as 4 character hex strings with 0 padding
// Write USB Vendor ID and Product ID as 4 character hex strings with 0 padding (legacy)
char usbVendorStr[5];
snprintf(usbVendorStr, 5, "%04X", gamepadOptions.usbVendorID);
writeDoc(doc, "usbVendorID", usbVendorStr);
char usbProductStr[5];
snprintf(usbProductStr, 5, "%04X", gamepadOptions.usbProductID);
writeDoc(doc, "usbProductID", usbProductStr);

// HID (USB-HID) specific overrides
writeDoc(doc, "hidDescOverride", gamepadOptions.hidDescOverride);
writeDoc(doc, "hidDescManufacturer", gamepadOptions.hidDescManufacturer);
writeDoc(doc, "hidDescProduct", gamepadOptions.hidDescProduct);
writeDoc(doc, "hidDescVersion", gamepadOptions.hidDescVersion);
writeDoc(doc, "hidOverrideID", gamepadOptions.hidOverrideID);
char hidVendorStr[5];
snprintf(hidVendorStr, 5, "%04X", gamepadOptions.hidVendorID);
writeDoc(doc, "hidVendorID", hidVendorStr);
char hidProductStr[5];
snprintf(hidProductStr, 5, "%04X", gamepadOptions.hidProductID);
writeDoc(doc, "hidProductID", hidProductStr);

// XInput specific overrides
writeDoc(doc, "xinputDescOverride", gamepadOptions.xinputDescOverride);
writeDoc(doc, "xinputDescManufacturer", gamepadOptions.xinputDescManufacturer);
writeDoc(doc, "xinputDescProduct", gamepadOptions.xinputDescProduct);
writeDoc(doc, "xinputDescVersion", gamepadOptions.xinputDescVersion);
writeDoc(doc, "xinputOverrideID", gamepadOptions.xinputOverrideID);
char xinputVendorStr[5];
snprintf(xinputVendorStr, 5, "%04X", gamepadOptions.xinputVendorID);
writeDoc(doc, "xinputVendorID", xinputVendorStr);
char xinputProductStr[5];
snprintf(xinputProductStr, 5, "%04X", gamepadOptions.xinputProductID);
writeDoc(doc, "xinputProductID", xinputProductStr);

writeDoc(doc, "fnButtonPin", -1);
GpioMappingInfo* gpioMappings = Storage::getInstance().getGpioMappings().pins;
for (unsigned int pin = 0; pin < NUM_BANK0_GPIOS; pin++) {
Expand Down
Loading