Tijdelijke checkin, issues met opslaan van gamepad sensitivty
This commit is contained in:
+3
-3
@@ -48,7 +48,7 @@ public:
|
||||
void setMouseSensitivity(float sensitivity);
|
||||
void setGamepadSensitivityValue(float sensitivity);
|
||||
void setGamepadDeadzoneValue(float deadzone);
|
||||
void setGamepadInvertY(bool invert) { settings.gamepad_invert_y = invert; }
|
||||
void setGamepadInvertY(bool invert);
|
||||
|
||||
// Keyboard functions (spell to key mapping)
|
||||
void sendKeyPress(uint8_t keycode, uint8_t modifiers = 0);
|
||||
@@ -97,7 +97,7 @@ public:
|
||||
const uint8_t *getSpellKeycodes() const { return settings.spell_keycodes; }
|
||||
const uint8_t *getSpellGamepadButtons() const { return settings.spell_gamepad_buttons; }
|
||||
bool getInvertMouseY() const { return settings.invert_mouse_y; }
|
||||
void setInvertMouseY(bool invert) { settings.invert_mouse_y = invert; }
|
||||
void setInvertMouseY(bool invert);
|
||||
|
||||
private:
|
||||
bool initialized;
|
||||
@@ -120,6 +120,6 @@ private:
|
||||
// Helper functions
|
||||
void sendMouseReport(int8_t x, int8_t y, int8_t wheel, uint8_t buttons);
|
||||
void sendKeyboardReport(uint8_t modifiers, uint8_t keycode);
|
||||
void sendGamepadReport(int8_t lx, int8_t ly, int8_t rx, int8_t ry, uint16_t buttons, uint8_t hat);
|
||||
void sendGamepadReport(int8_t lx, int8_t ly, int8_t rx, int8_t ry, uint8_t lt, uint8_t rt, uint16_t buttons, uint8_t hat);
|
||||
uint8_t getKeycodeForSpell(const char *spell_name);
|
||||
};
|
||||
|
||||
+58
-4
@@ -1054,15 +1054,48 @@ void WandBLEClient::updateAHRS(const IMUSample &sample)
|
||||
{
|
||||
float dx = pos.x - last_mouse_pos.x;
|
||||
float dy = pos.y - last_mouse_pos.y;
|
||||
float original_dy = dy; // Store original for logging
|
||||
#if USE_USB_HID_DEVICE
|
||||
HIDMode current_mode = usbHID.getHidMode();
|
||||
if (current_mode == HID_MODE_MOUSE)
|
||||
{
|
||||
dy = usbHID.getInvertMouseY() ? -dy : dy;
|
||||
bool invert = usbHID.getInvertMouseY();
|
||||
dy = invert ? -dy : dy;
|
||||
|
||||
// Log occasionally to debug axis inversion (every 100 samples)
|
||||
static int debug_counter = 0;
|
||||
if (++debug_counter >= 100)
|
||||
{
|
||||
debug_counter = 0;
|
||||
ESP_LOGI(TAG, "🖱️ MOUSE mode | Y: original=%.3f, invert=%s, final=%.3f (up wand should give original=%s)",
|
||||
original_dy, invert ? "INVERTED" : "NORMAL", dy,
|
||||
original_dy > 0 ? "POSITIVE" : original_dy < 0 ? "NEGATIVE"
|
||||
: "ZERO");
|
||||
}
|
||||
}
|
||||
else if (current_mode == HID_MODE_GAMEPAD)
|
||||
{
|
||||
dy = usbHID.getGamepadInvertY() ? -dy : dy;
|
||||
bool invert = usbHID.getGamepadInvertY();
|
||||
dy = invert ? -dy : dy;
|
||||
|
||||
// Log occasionally to debug axis inversion (every 100 samples)
|
||||
static int gpad_debug_counter = 0;
|
||||
if (++gpad_debug_counter >= 100)
|
||||
{
|
||||
gpad_debug_counter = 0;
|
||||
ESP_LOGI(TAG, "🎮 GAMEPAD mode | Y: original=%.3f, invert=%s, final=%.3f",
|
||||
original_dy, invert ? "INVERTED" : "NORMAL", dy);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// KEYBOARD or DISABLED mode - still process for WebSocket
|
||||
static int other_debug_counter = 0;
|
||||
if (++other_debug_counter >= 100)
|
||||
{
|
||||
other_debug_counter = 0;
|
||||
ESP_LOGI(TAG, "⌨️ OTHER mode (%d) | No axis inversion applied", current_mode);
|
||||
}
|
||||
}
|
||||
#else
|
||||
dy = -dy; // Default: inverted
|
||||
@@ -1113,15 +1146,36 @@ void WandBLEClient::updateAHRS(const IMUSample &sample)
|
||||
{
|
||||
float dx = pos.x - last_mouse_pos.x;
|
||||
float dy = pos.y - last_mouse_pos.y;
|
||||
float original_dy = dy; // Store original for logging
|
||||
#if USE_USB_HID_DEVICE
|
||||
HIDMode current_mode = usbHID.getHidMode();
|
||||
if (current_mode == HID_MODE_MOUSE)
|
||||
{
|
||||
dy = usbHID.getInvertMouseY() ? -dy : dy;
|
||||
bool invert = usbHID.getInvertMouseY();
|
||||
dy = invert ? -dy : dy;
|
||||
|
||||
// Log occasionally to debug axis inversion (every 200 samples for websocket path)
|
||||
static int ws_debug_counter = 0;
|
||||
if (++ws_debug_counter >= 200)
|
||||
{
|
||||
ws_debug_counter = 0;
|
||||
ESP_LOGI(TAG, "🖱️ Mouse Y (WS): original=%.3f, invert=%s, final=%.3f",
|
||||
original_dy, invert ? "true" : "false", dy);
|
||||
}
|
||||
}
|
||||
else if (current_mode == HID_MODE_GAMEPAD)
|
||||
{
|
||||
dy = usbHID.getGamepadInvertY() ? -dy : dy;
|
||||
bool invert = usbHID.getGamepadInvertY();
|
||||
dy = invert ? -dy : dy;
|
||||
|
||||
// Log occasionally to debug axis inversion (every 200 samples for websocket path)
|
||||
static int ws_gpad_debug_counter = 0;
|
||||
if (++ws_gpad_debug_counter >= 200)
|
||||
{
|
||||
ws_gpad_debug_counter = 0;
|
||||
ESP_LOGI(TAG, "🎮 Gamepad Y (WS): original=%.3f, invert=%s, final=%.3f",
|
||||
original_dy, invert ? "true" : "false", dy);
|
||||
}
|
||||
}
|
||||
#else
|
||||
dy = -dy; // Default: inverted
|
||||
|
||||
+255
-90
@@ -76,32 +76,57 @@ static const uint8_t hid_report_descriptor[] = {
|
||||
0x81, 0x00, // Input (Data, Array) - Key array
|
||||
0xC0, // End Collection (Application)
|
||||
|
||||
// Gamepad Report (Report ID 3)
|
||||
0x05, 0x01, // Usage Page (Generic Desktop)
|
||||
0x09, 0x05, // Usage (Gamepad)
|
||||
0xA1, 0x01, // Collection (Application)
|
||||
0x85, 0x03, // Report ID (3)
|
||||
0x05, 0x01, // Usage Page (Generic Desktop)
|
||||
0x09, 0x30, // Usage (X)
|
||||
0x09, 0x31, // Usage (Y)
|
||||
0x09, 0x33, // Usage (Rx)
|
||||
0x09, 0x34, // Usage (Ry)
|
||||
0x15, 0x81, // Logical Minimum (-127)
|
||||
0x25, 0x7F, // Logical Maximum (127)
|
||||
0x75, 0x08, // Report Size (8)
|
||||
0x95, 0x04, // Report Count (4)
|
||||
0x81, 0x02, // Input (Data, Variable, Absolute)
|
||||
0x05, 0x09, // Usage Page (Buttons)
|
||||
0x19, 0x01, // Usage Minimum (Button 1)
|
||||
0x29, 0x0A, // Usage Maximum (Button 10)
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
0x25, 0x01, // Logical Maximum (1)
|
||||
0x75, 0x01, // Report Size (1)
|
||||
0x95, 0x0A, // Report Count (10)
|
||||
0x81, 0x02, // Input (Data, Variable, Absolute)
|
||||
0x75, 0x01, // Report Size (1)
|
||||
0x95, 0x06, // Report Count (6)
|
||||
0x81, 0x01, // Input (Constant) - padding
|
||||
// Gamepad Report (Report ID 3) - Full Xbox-Compatible Controller
|
||||
// Compatible with games like Hogwarts Legacy that require complete gamepad support
|
||||
0x05, 0x01, // Usage Page (Generic Desktop)
|
||||
0x09, 0x05, // Usage (Gamepad)
|
||||
0xA1, 0x01, // Collection (Application)
|
||||
0x85, 0x03, // Report ID (3)
|
||||
|
||||
// Left Stick (X, Y)
|
||||
0x05, 0x01, // Usage Page (Generic Desktop)
|
||||
0x09, 0x30, // Usage (X)
|
||||
0x09, 0x31, // Usage (Y)
|
||||
0x15, 0x81, // Logical Minimum (-127)
|
||||
0x25, 0x7F, // Logical Maximum (127)
|
||||
0x75, 0x08, // Report Size (8)
|
||||
0x95, 0x02, // Report Count (2)
|
||||
0x81, 0x02, // Input (Data, Variable, Absolute)
|
||||
|
||||
// Right Stick (Rx, Ry)
|
||||
0x09, 0x33, // Usage (Rx)
|
||||
0x09, 0x34, // Usage (Ry)
|
||||
0x15, 0x81, // Logical Minimum (-127)
|
||||
0x25, 0x7F, // Logical Maximum (127)
|
||||
0x75, 0x08, // Report Size (8)
|
||||
0x95, 0x02, // Report Count (2)
|
||||
0x81, 0x02, // Input (Data, Variable, Absolute)
|
||||
|
||||
// Triggers (LT, RT) - Z axis
|
||||
0x09, 0x32, // Usage (Z) - Left Trigger
|
||||
0x09, 0x35, // Usage (Rz) - Right Trigger
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
0x25, 0xFF, // Logical Maximum (255)
|
||||
0x75, 0x08, // Report Size (8)
|
||||
0x95, 0x02, // Report Count (2)
|
||||
0x81, 0x02, // Input (Data, Variable, Absolute)
|
||||
|
||||
// Buttons (14 buttons: A, B, X, Y, LB, RB, Back, Start, LS, RS, + 4 extra)
|
||||
0x05, 0x09, // Usage Page (Buttons)
|
||||
0x19, 0x01, // Usage Minimum (Button 1)
|
||||
0x29, 0x0E, // Usage Maximum (Button 14)
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
0x25, 0x01, // Logical Maximum (1)
|
||||
0x75, 0x01, // Report Size (1)
|
||||
0x95, 0x0E, // Report Count (14)
|
||||
0x81, 0x02, // Input (Data, Variable, Absolute)
|
||||
|
||||
// Padding (2 bits to make 16 bits = 2 bytes)
|
||||
0x75, 0x01, // Report Size (1)
|
||||
0x95, 0x02, // Report Count (2)
|
||||
0x81, 0x01, // Input (Constant)
|
||||
|
||||
// D-Pad (Hat Switch)
|
||||
0x05, 0x01, // Usage Page (Generic Desktop)
|
||||
0x09, 0x39, // Usage (Hat switch)
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
@@ -112,10 +137,13 @@ static const uint8_t hid_report_descriptor[] = {
|
||||
0x75, 0x04, // Report Size (4)
|
||||
0x95, 0x01, // Report Count (1)
|
||||
0x81, 0x42, // Input (Data, Variable, Absolute, Null State)
|
||||
0x75, 0x04, // Report Size (4)
|
||||
0x95, 0x01, // Report Count (1)
|
||||
0x81, 0x01, // Input (Constant) - padding
|
||||
0xC0 // End Collection (Application)
|
||||
|
||||
// Padding (4 bits to complete the byte)
|
||||
0x75, 0x04, // Report Size (4)
|
||||
0x95, 0x01, // Report Count (1)
|
||||
0x81, 0x01, // Input (Constant)
|
||||
|
||||
0xC0 // End Collection (Application)
|
||||
};
|
||||
|
||||
// USB Descriptors for Composite HID + CDC
|
||||
@@ -331,13 +359,13 @@ USBHIDManager::USBHIDManager()
|
||||
{
|
||||
// Initialize default settings
|
||||
settings.mouse_sensitivity = 1.0f;
|
||||
settings.invert_mouse_y = true; // Default: inverted (typical UI behavior)
|
||||
settings.invert_mouse_y = false; // Default: natural (wand UP = cursor UP, since IMU gives negative for up)
|
||||
settings.mouse_enabled = true; // Default: enabled
|
||||
settings.keyboard_enabled = true; // Default: enabled
|
||||
settings.hid_mode = HID_MODE_MOUSE;
|
||||
settings.gamepad_sensitivity = 1.0f;
|
||||
settings.gamepad_deadzone = 0.05f;
|
||||
settings.gamepad_invert_y = true;
|
||||
settings.gamepad_invert_y = false; // Default: natural (wand UP = stick UP)
|
||||
// Initialize all spell keycodes to 0 (disabled)
|
||||
memset(settings.spell_keycodes, 0, sizeof(settings.spell_keycodes));
|
||||
memset(settings.spell_gamepad_buttons, 0, sizeof(settings.spell_gamepad_buttons));
|
||||
@@ -387,6 +415,16 @@ bool USBHIDManager::begin()
|
||||
#endif
|
||||
|
||||
initialized = true;
|
||||
|
||||
// Log final loaded settings for verification
|
||||
ESP_LOGI(TAG, "📋 Final settings after initialization:");
|
||||
ESP_LOGI(TAG, " Mouse: sensitivity=%.2f, invert_y=%s",
|
||||
settings.mouse_sensitivity, settings.invert_mouse_y ? "true" : "false");
|
||||
ESP_LOGI(TAG, " Gamepad: sensitivity=%.2f, deadzone=%.2f, invert_y=%s",
|
||||
settings.gamepad_sensitivity, settings.gamepad_deadzone, settings.gamepad_invert_y ? "true" : "false");
|
||||
ESP_LOGI(TAG, " HID mode=%u, mouse_enabled=%d, keyboard_enabled=%d",
|
||||
settings.hid_mode, settings.mouse_enabled, settings.keyboard_enabled);
|
||||
|
||||
ESP_LOGI(TAG, "USB HID initialized successfully");
|
||||
return true;
|
||||
#else
|
||||
@@ -460,11 +498,8 @@ void USBHIDManager::updateGamepadFromGesture(float delta_x, float delta_y)
|
||||
|
||||
float scale = settings.gamepad_sensitivity;
|
||||
|
||||
// Apply invert Y-axis setting
|
||||
if (settings.gamepad_invert_y)
|
||||
{
|
||||
delta_y = -delta_y;
|
||||
}
|
||||
// Note: Inversion is already applied in ble_client.cpp before calling this function
|
||||
// Do NOT apply inversion here again to avoid double-inversion
|
||||
|
||||
int16_t temp_x = (int16_t)(delta_x * scale);
|
||||
int16_t temp_y = (int16_t)(delta_y * scale);
|
||||
@@ -484,19 +519,19 @@ void USBHIDManager::updateGamepadFromGesture(float delta_x, float delta_y)
|
||||
if (gamepad_ly > -deadzone && gamepad_ly < deadzone)
|
||||
gamepad_ly = 0;
|
||||
|
||||
// Use left stick only; right stick centered, hat neutral.
|
||||
sendGamepadReport(gamepad_lx, gamepad_ly, gamepad_rx, gamepad_ry, gamepad_buttons, 0x0F);
|
||||
// Use left stick only; right stick centered, triggers off, hat neutral.
|
||||
sendGamepadReport(gamepad_lx, gamepad_ly, gamepad_rx, gamepad_ry, 0, 0, gamepad_buttons, 0x0F);
|
||||
#endif
|
||||
}
|
||||
|
||||
void USBHIDManager::setGamepadButtons(uint16_t buttons)
|
||||
{
|
||||
gamepad_buttons = buttons & 0x03FF; // 10 buttons max
|
||||
gamepad_buttons = buttons & 0x3FFF; // 14 buttons max
|
||||
|
||||
#if USE_USB_HID_DEVICE
|
||||
if (initialized && getHidMode() == HID_MODE_GAMEPAD)
|
||||
{
|
||||
sendGamepadReport(gamepad_lx, gamepad_ly, gamepad_rx, gamepad_ry, gamepad_buttons, 0x0F);
|
||||
sendGamepadReport(gamepad_lx, gamepad_ly, gamepad_rx, gamepad_ry, 0, 0, gamepad_buttons, 0x0F);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -526,8 +561,13 @@ void USBHIDManager::setMouseSensitivity(float sensitivity)
|
||||
void USBHIDManager::sendKeyPress(uint8_t keycode, uint8_t modifiers)
|
||||
{
|
||||
#if USE_USB_HID_DEVICE
|
||||
if (!initialized || !keyboard_enabled || getHidMode() != HID_MODE_KEYBOARD)
|
||||
// Allow keyboard input in both MOUSE and KEYBOARD modes (for spell hotkeys + mouse movement)
|
||||
if (!initialized || !keyboard_enabled || (getHidMode() != HID_MODE_KEYBOARD && getHidMode() != HID_MODE_MOUSE))
|
||||
{
|
||||
ESP_LOGW(TAG, "⚠️ sendKeyPress blocked: init=%d, kbd_en=%d, mode=%d",
|
||||
initialized, keyboard_enabled, getHidMode());
|
||||
return;
|
||||
}
|
||||
|
||||
sendKeyboardReport(modifiers, keycode);
|
||||
#endif
|
||||
@@ -536,7 +576,8 @@ void USBHIDManager::sendKeyPress(uint8_t keycode, uint8_t modifiers)
|
||||
void USBHIDManager::sendKeyRelease()
|
||||
{
|
||||
#if USE_USB_HID_DEVICE
|
||||
if (!initialized || !keyboard_enabled || getHidMode() != HID_MODE_KEYBOARD)
|
||||
// Allow keyboard input in both MOUSE and KEYBOARD modes (for spell hotkeys + mouse movement)
|
||||
if (!initialized || !keyboard_enabled || (getHidMode() != HID_MODE_KEYBOARD && getHidMode() != HID_MODE_MOUSE))
|
||||
return;
|
||||
|
||||
sendKeyboardReport(0, 0);
|
||||
@@ -627,7 +668,7 @@ void USBHIDManager::setHidMode(HIDMode mode)
|
||||
{
|
||||
case HID_MODE_MOUSE:
|
||||
mouse_enabled = true;
|
||||
keyboard_enabled = false;
|
||||
keyboard_enabled = true; // Enable keyboard for spell hotkeys in mouse mode
|
||||
break;
|
||||
case HID_MODE_KEYBOARD:
|
||||
mouse_enabled = false;
|
||||
@@ -645,7 +686,7 @@ void USBHIDManager::setHidMode(HIDMode mode)
|
||||
}
|
||||
settings.mouse_enabled = mouse_enabled;
|
||||
settings.keyboard_enabled = keyboard_enabled;
|
||||
ESP_LOGI(TAG, "HID mode set to %u", settings.hid_mode);
|
||||
ESP_LOGI(TAG, "HID mode set to %u (mouse=%d, keyboard=%d)", settings.hid_mode, mouse_enabled, keyboard_enabled);
|
||||
}
|
||||
|
||||
void USBHIDManager::sendMouseReport(int8_t x, int8_t y, int8_t wheel, uint8_t buttons)
|
||||
@@ -664,20 +705,24 @@ void USBHIDManager::sendMouseReport(int8_t x, int8_t y, int8_t wheel, uint8_t bu
|
||||
#endif
|
||||
}
|
||||
|
||||
void USBHIDManager::sendGamepadReport(int8_t lx, int8_t ly, int8_t rx, int8_t ry, uint16_t buttons, uint8_t hat)
|
||||
void USBHIDManager::sendGamepadReport(int8_t lx, int8_t ly, int8_t rx, int8_t ry, uint8_t lt, uint8_t rt, uint16_t buttons, uint8_t hat)
|
||||
{
|
||||
#if USE_USB_HID_DEVICE
|
||||
if (!tud_hid_ready())
|
||||
return;
|
||||
|
||||
uint8_t report[7];
|
||||
report[0] = (uint8_t)lx;
|
||||
report[1] = (uint8_t)ly;
|
||||
report[2] = (uint8_t)rx;
|
||||
report[3] = (uint8_t)ry;
|
||||
report[4] = (uint8_t)(buttons & 0xFF);
|
||||
report[5] = (uint8_t)((buttons >> 8) & 0x03);
|
||||
report[6] = (uint8_t)(hat & 0x0F);
|
||||
// Full Xbox-compatible gamepad: 9 bytes total (per HID descriptor)
|
||||
// Left stick (2), right stick (2), triggers (2), buttons (2), hat (1)
|
||||
uint8_t report[9];
|
||||
report[0] = (uint8_t)lx; // Left stick X
|
||||
report[1] = (uint8_t)ly; // Left stick Y
|
||||
report[2] = (uint8_t)rx; // Right stick X
|
||||
report[3] = (uint8_t)ry; // Right stick Y
|
||||
report[4] = lt; // Left trigger (Z axis)
|
||||
report[5] = rt; // Right trigger (Rz axis)
|
||||
report[6] = (uint8_t)(buttons & 0xFF); // Buttons 1-8
|
||||
report[7] = (uint8_t)((buttons >> 8) & 0x3F); // Buttons 9-14 (6 bits) + 2 bits padding
|
||||
report[8] = (uint8_t)(hat & 0x0F); // D-pad hat (4 bits) + 4 bits padding
|
||||
|
||||
tud_hid_report(3, report, sizeof(report)); // Report ID 3 = Gamepad
|
||||
#endif
|
||||
@@ -796,6 +841,7 @@ uint8_t USBHIDManager::getSpellKeycode(const char *spell_name) const
|
||||
|
||||
bool USBHIDManager::loadSettings()
|
||||
{
|
||||
ESP_LOGI(TAG, "📂 Loading settings from NVS...");
|
||||
nvs_handle_t nvs_handle;
|
||||
esp_err_t err = nvs_open("usb_hid", NVS_READONLY, &nvs_handle);
|
||||
if (err != ESP_OK)
|
||||
@@ -810,10 +856,12 @@ bool USBHIDManager::loadSettings()
|
||||
if (err == ESP_OK)
|
||||
{
|
||||
settings.mouse_sensitivity = (float)sens_10x / 10.0f;
|
||||
ESP_LOGI(TAG, "✓ Loaded mouse_sensitivity from NVS: %.2f (raw: %d)", settings.mouse_sensitivity, sens_10x);
|
||||
}
|
||||
else
|
||||
{
|
||||
settings.mouse_sensitivity = 1.0f;
|
||||
ESP_LOGI(TAG, "⚠ Mouse sensitivity not found in NVS, using default: 1.0");
|
||||
}
|
||||
|
||||
// Load gamepad sensitivity (stored as uint8_t: value * 10)
|
||||
@@ -822,10 +870,12 @@ bool USBHIDManager::loadSettings()
|
||||
if (err == ESP_OK)
|
||||
{
|
||||
settings.gamepad_sensitivity = (float)gpad_sens_10x / 10.0f;
|
||||
ESP_LOGI(TAG, "✓ Loaded gamepad_sensitivity from NVS: %.2f (raw: %d)", settings.gamepad_sensitivity, gpad_sens_10x);
|
||||
}
|
||||
else
|
||||
{
|
||||
settings.gamepad_sensitivity = 1.0f;
|
||||
ESP_LOGI(TAG, "⚠ Gamepad sensitivity not found in NVS, using default: 1.0");
|
||||
}
|
||||
|
||||
// Load gamepad deadzone (stored as uint8_t: value * 100)
|
||||
@@ -834,21 +884,46 @@ bool USBHIDManager::loadSettings()
|
||||
if (err == ESP_OK)
|
||||
{
|
||||
settings.gamepad_deadzone = (float)gpad_deadzone_100 / 100.0f;
|
||||
ESP_LOGI(TAG, "✓ Loaded gamepad_deadzone from NVS: %.2f (raw: %d)", settings.gamepad_deadzone, gpad_deadzone_100);
|
||||
}
|
||||
else
|
||||
{
|
||||
settings.gamepad_deadzone = 0.05f;
|
||||
ESP_LOGI(TAG, "⚠ Gamepad deadzone not found in NVS, using default: 0.05");
|
||||
}
|
||||
|
||||
// Load gamepad invert_y
|
||||
uint8_t gpad_invert_y = 1; // Default: inverted
|
||||
uint8_t gpad_invert_y = 0; // Default: natural (non-inverted)
|
||||
err = nvs_get_u8(nvs_handle, "gamepad_invert_y", &gpad_invert_y);
|
||||
settings.gamepad_invert_y = (gpad_invert_y != 0);
|
||||
if (err == ESP_OK)
|
||||
{
|
||||
settings.gamepad_invert_y = (gpad_invert_y != 0);
|
||||
ESP_LOGI(TAG, "✓ Loaded gamepad_invert_y from NVS: %s", settings.gamepad_invert_y ? "true" : "false");
|
||||
}
|
||||
else
|
||||
{
|
||||
settings.gamepad_invert_y = false;
|
||||
ESP_LOGI(TAG, "⚠ Gamepad invert_y not found in NVS, using default: false (natural)");
|
||||
}
|
||||
|
||||
// Load invert_mouse_y setting
|
||||
uint8_t invert_y = 1; // Default: inverted (typical UI behavior)
|
||||
uint8_t invert_y = 0; // Default: natural (non-inverted)
|
||||
err = nvs_get_u8(nvs_handle, "invert_mouse_y", &invert_y);
|
||||
settings.invert_mouse_y = (invert_y != 0);
|
||||
if (err == ESP_OK)
|
||||
{
|
||||
settings.invert_mouse_y = (invert_y != 0);
|
||||
ESP_LOGI(TAG, "✓ Loaded invert_mouse_y from NVS: %s", settings.invert_mouse_y ? "true" : "false");
|
||||
}
|
||||
else
|
||||
{
|
||||
settings.invert_mouse_y = false;
|
||||
ESP_LOGI(TAG, "⚠ Invert_mouse_y not found in NVS, using default: false (natural)");
|
||||
}
|
||||
|
||||
// Log current state for debugging
|
||||
ESP_LOGI(TAG, "🎯 Current axis inversion settings: mouse_y=%s, gamepad_y=%s",
|
||||
settings.invert_mouse_y ? "INVERTED" : "NORMAL",
|
||||
settings.gamepad_invert_y ? "INVERTED" : "NORMAL");
|
||||
|
||||
// Load mouse_enabled
|
||||
uint8_t mouse_en = 1; // Default: enabled
|
||||
@@ -885,30 +960,56 @@ bool USBHIDManager::loadSettings()
|
||||
setHidMode(static_cast<HIDMode>(hid_mode));
|
||||
|
||||
// Load spell keycodes (73 spells)
|
||||
ESP_LOGI(TAG, "Loading spell keycodes from NVS...");
|
||||
int non_zero_count = 0;
|
||||
for (int i = 0; i < 73; i++)
|
||||
{
|
||||
char key[16];
|
||||
snprintf(key, sizeof(key), "spell%d", i);
|
||||
uint8_t old_value = settings.spell_keycodes[i];
|
||||
nvs_get_u8(nvs_handle, key, &settings.spell_keycodes[i]);
|
||||
// If not found, spell_keycodes[i] remains 0 (disabled)
|
||||
}
|
||||
|
||||
// Load spell gamepad button mappings (73 spells)
|
||||
for (int i = 0; i < 73; i++)
|
||||
{
|
||||
char key[20];
|
||||
snprintf(key, sizeof(key), "gpad_spell%d", i);
|
||||
nvs_get_u8(nvs_handle, key, &settings.spell_gamepad_buttons[i]);
|
||||
// If not found, spell_gamepad_buttons[i] remains 0 (disabled)
|
||||
if (settings.spell_keycodes[i] != 0)
|
||||
{
|
||||
non_zero_count++;
|
||||
if (settings.spell_keycodes[i] != old_value)
|
||||
{
|
||||
extern const char *SPELL_NAMES[73];
|
||||
ESP_LOGI(TAG, " Spell[%d]='%s' loaded: 0x%02X (%d)",
|
||||
i, SPELL_NAMES[i], settings.spell_keycodes[i], settings.spell_keycodes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
ESP_LOGI(TAG, "Loaded %d non-zero spell mappings", non_zero_count);
|
||||
|
||||
nvs_close(nvs_handle);
|
||||
|
||||
// Open gamepad namespace for gamepad spell mappings
|
||||
err = nvs_open("gamepad", NVS_READONLY, &nvs_handle);
|
||||
if (err == ESP_OK)
|
||||
{
|
||||
// Load spell gamepad button mappings (73 spells)
|
||||
for (int i = 0; i < 73; i++)
|
||||
{
|
||||
char key[20];
|
||||
snprintf(key, sizeof(key), "gpad_spell%d", i);
|
||||
nvs_get_u8(nvs_handle, key, &settings.spell_gamepad_buttons[i]);
|
||||
// If not found, spell_gamepad_buttons[i] remains 0 (disabled)
|
||||
}
|
||||
nvs_close(nvs_handle);
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "USB HID settings loaded from NVS");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool USBHIDManager::saveSettings()
|
||||
{
|
||||
ESP_LOGI(TAG, "🔍 saveSettings() called - checking current settings struct values:");
|
||||
ESP_LOGI(TAG, " gamepad_sensitivity=%.2f, gamepad_deadzone=%.2f, gamepad_invert_y=%s",
|
||||
settings.gamepad_sensitivity, settings.gamepad_deadzone, settings.gamepad_invert_y ? "true" : "false");
|
||||
ESP_LOGI(TAG, " mouse_sensitivity=%.2f, invert_mouse_y=%s",
|
||||
settings.mouse_sensitivity, settings.invert_mouse_y ? "true" : "false");
|
||||
|
||||
nvs_handle_t nvs_handle;
|
||||
esp_err_t err = nvs_open("usb_hid", NVS_READWRITE, &nvs_handle);
|
||||
if (err != ESP_OK)
|
||||
@@ -921,19 +1022,9 @@ bool USBHIDManager::saveSettings()
|
||||
uint8_t sens_10x = (uint8_t)(settings.mouse_sensitivity * 10.0f);
|
||||
nvs_set_u8(nvs_handle, "mouse_sens_10x", sens_10x);
|
||||
|
||||
// Save gamepad sensitivity (as 10x value to store as uint8)
|
||||
uint8_t gpad_sens_10x = (uint8_t)(settings.gamepad_sensitivity * 10.0f);
|
||||
nvs_set_u8(nvs_handle, "gamepad_sens_10x", gpad_sens_10x);
|
||||
|
||||
// Save gamepad deadzone (as 100x value to store as uint8)
|
||||
uint8_t gpad_deadzone_100 = (uint8_t)(settings.gamepad_deadzone * 100.0f);
|
||||
nvs_set_u8(nvs_handle, "gamepad_deadzone_100", gpad_deadzone_100);
|
||||
|
||||
// Save gamepad invert_y
|
||||
nvs_set_u8(nvs_handle, "gamepad_invert_y", settings.gamepad_invert_y ? 1 : 0);
|
||||
|
||||
// Save invert_mouse_y setting
|
||||
nvs_set_u8(nvs_handle, "invert_mouse_y", settings.invert_mouse_y ? 1 : 0);
|
||||
ESP_LOGI(TAG, "💾 Saved invert_mouse_y to NVS: %s", settings.invert_mouse_y ? "true" : "false");
|
||||
|
||||
// Save mouse_enabled
|
||||
nvs_set_u8(nvs_handle, "mouse_enabled", settings.mouse_enabled ? 1 : 0);
|
||||
@@ -945,14 +1036,58 @@ bool USBHIDManager::saveSettings()
|
||||
nvs_set_u8(nvs_handle, "hid_mode", settings.hid_mode);
|
||||
|
||||
// Save spell keycodes (73 spells)
|
||||
ESP_LOGI(TAG, "Saving spell keycodes to NVS...");
|
||||
int saved_count = 0;
|
||||
for (int i = 0; i < 73; i++)
|
||||
{
|
||||
char key[16];
|
||||
if (settings.spell_keycodes[i] != 0)
|
||||
{
|
||||
extern const char *SPELL_NAMES[73];
|
||||
ESP_LOGI(TAG, " Saving spell[%d]='%s' = 0x%02X (%d)",
|
||||
i, SPELL_NAMES[i], settings.spell_keycodes[i], settings.spell_keycodes[i]);
|
||||
saved_count++;
|
||||
}
|
||||
snprintf(key, sizeof(key), "spell%d", i);
|
||||
nvs_set_u8(nvs_handle, key, settings.spell_keycodes[i]);
|
||||
}
|
||||
ESP_LOGI(TAG, "Saved %d non-zero spell mappings to NVS", saved_count);
|
||||
|
||||
// Commit usb_hid namespace
|
||||
err = nvs_commit(nvs_handle);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to commit usb_hid NVS settings");
|
||||
nvs_close(nvs_handle);
|
||||
return false;
|
||||
}
|
||||
nvs_close(nvs_handle);
|
||||
ESP_LOGI(TAG, "✅ Saved usb_hid settings to NVS");
|
||||
|
||||
// Open gamepad namespace for gamepad-specific settings
|
||||
err = nvs_open("gamepad", NVS_READWRITE, &nvs_handle);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to open NVS namespace 'gamepad'");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Save gamepad sensitivity (as 10x value to store as uint8)
|
||||
uint8_t gpad_sens_10x = (uint8_t)(settings.gamepad_sensitivity * 10.0f);
|
||||
nvs_set_u8(nvs_handle, "gamepad_sens_10x", gpad_sens_10x);
|
||||
ESP_LOGI(TAG, "💾 Saved gamepad_sensitivity to NVS: %.2f (raw: %d)", settings.gamepad_sensitivity, gpad_sens_10x);
|
||||
|
||||
// Save gamepad deadzone (as 100x value to store as uint8)
|
||||
uint8_t gpad_deadzone_100 = (uint8_t)(settings.gamepad_deadzone * 100.0f);
|
||||
nvs_set_u8(nvs_handle, "gamepad_deadzone_100", gpad_deadzone_100);
|
||||
ESP_LOGI(TAG, "💾 Saved gamepad_deadzone to NVS: %.2f (raw: %d)", settings.gamepad_deadzone, gpad_deadzone_100);
|
||||
|
||||
// Save gamepad invert_y
|
||||
nvs_set_u8(nvs_handle, "gamepad_invert_y", settings.gamepad_invert_y ? 1 : 0);
|
||||
ESP_LOGI(TAG, "💾 Saved gamepad_invert_y to NVS: %s", settings.gamepad_invert_y ? "true" : "false");
|
||||
|
||||
// Save spell gamepad button mappings (73 spells)
|
||||
ESP_LOGI(TAG, "Saving gamepad spell button mappings to NVS...");
|
||||
for (int i = 0; i < 73; i++)
|
||||
{
|
||||
char key[20];
|
||||
@@ -960,16 +1095,28 @@ bool USBHIDManager::saveSettings()
|
||||
nvs_set_u8(nvs_handle, key, settings.spell_gamepad_buttons[i]);
|
||||
}
|
||||
|
||||
// Commit gamepad namespace
|
||||
err = nvs_commit(nvs_handle);
|
||||
nvs_close(nvs_handle);
|
||||
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to commit NVS settings");
|
||||
ESP_LOGE(TAG, "Failed to commit gamepad NVS settings");
|
||||
nvs_close(nvs_handle);
|
||||
return false;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "USB HID settings saved to NVS");
|
||||
// Verify gamepad values were actually written
|
||||
uint8_t verify_gpad_sens = 0;
|
||||
uint8_t verify_gpad_deadzone = 0;
|
||||
uint8_t verify_gpad_invert = 0;
|
||||
nvs_get_u8(nvs_handle, "gamepad_sens_10x", &verify_gpad_sens);
|
||||
nvs_get_u8(nvs_handle, "gamepad_deadzone_100", &verify_gpad_deadzone);
|
||||
nvs_get_u8(nvs_handle, "gamepad_invert_y", &verify_gpad_invert);
|
||||
ESP_LOGI(TAG, "✅ Verified gamepad NVS write: sens=%d (%.1fx), deadzone=%d (%.2f), invert=%d",
|
||||
verify_gpad_sens, verify_gpad_sens / 10.0f, verify_gpad_deadzone, verify_gpad_deadzone / 100.0f, verify_gpad_invert);
|
||||
|
||||
nvs_close(nvs_handle);
|
||||
|
||||
ESP_LOGI(TAG, "✅ All USB HID settings saved to NVS");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -977,11 +1124,15 @@ bool USBHIDManager::resetSettings()
|
||||
{
|
||||
// Reset to defaults
|
||||
settings.mouse_sensitivity = 1.0f;
|
||||
settings.invert_mouse_y = true; // Default: inverted (typical UI behavior)
|
||||
settings.invert_mouse_y = false; // Default: natural (wand UP = cursor UP)
|
||||
settings.mouse_enabled = true; // Default: enabled
|
||||
settings.keyboard_enabled = true; // Default: enabled
|
||||
settings.hid_mode = HID_MODE_MOUSE;
|
||||
settings.gamepad_sensitivity = 1.0f;
|
||||
settings.gamepad_deadzone = 0.05f;
|
||||
settings.gamepad_invert_y = false; // Default: natural (wand UP = stick UP)
|
||||
memset(settings.spell_keycodes, 0, sizeof(settings.spell_keycodes));
|
||||
memset(settings.spell_gamepad_buttons, 0, sizeof(settings.spell_gamepad_buttons));
|
||||
|
||||
mouse_sensitivity = 1.0f;
|
||||
setHidMode(HID_MODE_MOUSE);
|
||||
@@ -1025,7 +1176,7 @@ void USBHIDManager::setGamepadSensitivityValue(float sensitivity)
|
||||
sensitivity = 5.0f;
|
||||
|
||||
settings.gamepad_sensitivity = sensitivity;
|
||||
ESP_LOGI(TAG, "Gamepad sensitivity set to %.2f", sensitivity);
|
||||
ESP_LOGI(TAG, "🎮 Gamepad sensitivity set to %.2f (will be saved on settings save)", sensitivity);
|
||||
}
|
||||
|
||||
void USBHIDManager::setGamepadDeadzoneValue(float deadzone)
|
||||
@@ -1039,6 +1190,20 @@ void USBHIDManager::setGamepadDeadzoneValue(float deadzone)
|
||||
ESP_LOGI(TAG, "Gamepad dead zone set to %.2f", deadzone);
|
||||
}
|
||||
|
||||
void USBHIDManager::setInvertMouseY(bool invert)
|
||||
{
|
||||
settings.invert_mouse_y = invert;
|
||||
ESP_LOGI(TAG, "🔄 Mouse Y-axis invert set to: %s (wand UP -> cursor %s)",
|
||||
invert ? "true (INVERTED)" : "false (NORMAL)",
|
||||
invert ? "DOWN" : "UP");
|
||||
}
|
||||
|
||||
void USBHIDManager::setGamepadInvertY(bool invert)
|
||||
{
|
||||
settings.gamepad_invert_y = invert;
|
||||
ESP_LOGI(TAG, "🔄 Gamepad Y-axis invert set to: %s", invert ? "true (INVERTED)" : "false (NORMAL)");
|
||||
}
|
||||
|
||||
void USBHIDManager::setSpellGamepadButton(const char *spell_name, uint8_t button)
|
||||
{
|
||||
if (!spell_name)
|
||||
@@ -1083,16 +1248,16 @@ void USBHIDManager::sendSpellGamepadForSpell(const char *spell_name)
|
||||
return;
|
||||
|
||||
uint8_t button = getSpellGamepadButton(spell_name);
|
||||
if (button == 0 || button > 10)
|
||||
if (button == 0 || button > 14)
|
||||
return;
|
||||
|
||||
uint16_t mask = (uint16_t)(1U << (button - 1));
|
||||
uint16_t previous = gamepad_buttons;
|
||||
gamepad_buttons = (previous | mask) & 0x03FF;
|
||||
sendGamepadReport(gamepad_lx, gamepad_ly, gamepad_rx, gamepad_ry, gamepad_buttons, 0x0F);
|
||||
gamepad_buttons = (previous | mask) & 0x3FFF;
|
||||
sendGamepadReport(gamepad_lx, gamepad_ly, gamepad_rx, gamepad_ry, 0, 0, gamepad_buttons, 0x0F);
|
||||
vTaskDelay(pdMS_TO_TICKS(50));
|
||||
gamepad_buttons = previous & 0x03FF;
|
||||
sendGamepadReport(gamepad_lx, gamepad_ly, gamepad_rx, gamepad_ry, gamepad_buttons, 0x0F);
|
||||
gamepad_buttons = previous & 0x3FFF;
|
||||
sendGamepadReport(gamepad_lx, gamepad_ly, gamepad_rx, gamepad_ry, 0, 0, gamepad_buttons, 0x0F);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
+177
-48
@@ -454,6 +454,16 @@ static const char index_html[] = R"rawliteral(
|
||||
<h3>⚙️ Spell & Mouse Settings</h3>
|
||||
<div class="settings-grid">
|
||||
<div>
|
||||
<div style="font-size: 0.9em; color: #4CAF50; margin-bottom: 15px; padding: 10px; background: rgba(76, 175, 80, 0.1); border-left: 3px solid #4CAF50; border-radius: 4px;">
|
||||
<strong>📝 How Spell-to-Key Mapping Works:</strong><br>
|
||||
1. Perform a gesture/spell with your wand<br>
|
||||
2. The device detects which spell you cast<br>
|
||||
3. The assigned keyboard key is sent to your computer<br>
|
||||
4. Works in both <strong>Mouse</strong> and <strong>Keyboard</strong> HID modes!<br>
|
||||
<br>
|
||||
💡 <strong>Example:</strong> Map "Lumos" to key "F" → Cast Lumos → "F" key pressed<br>
|
||||
Perfect for gaming hotkeys, productivity shortcuts, etc!
|
||||
</div>
|
||||
<h4 style="margin: 0 0 10px 0; color: #4CAF50;">Spell Mappings (Full Keyboard)</h4>
|
||||
<input type="text" id="spell-filter" class="spell-mapping-search" placeholder="Filter spells..." oninput="filterSpellMappings()">
|
||||
<div class="spell-mappings-container">
|
||||
@@ -483,19 +493,31 @@ static const char index_html[] = R"rawliteral(
|
||||
<div style="margin: 10px 0;">
|
||||
<label style="display: flex; align-items: center; gap: 8px; cursor: pointer;">
|
||||
<input type="checkbox" id="invert-mouse-y" style="width: 18px; height: 18px;">
|
||||
<span>Invert Y-Axis (wand up = cursor up)</span>
|
||||
<span>Invert Mouse Y-Axis</span>
|
||||
</label>
|
||||
<div style="font-size: 0.8em; color: #888; margin-top: 5px;">Checked = inverted (typical), Unchecked = natural</div>
|
||||
<div style="font-size: 0.8em; color: #888; margin-top: 5px;">
|
||||
📍 Only applies in <strong>Mouse</strong> mode<br>
|
||||
⚠️ <strong>If cursor moves BACKWARDS:</strong><br>
|
||||
• UNCHECKED (default) = wand UP moves cursor UP (natural)<br>
|
||||
• CHECKED = wand UP moves cursor DOWN (inverted)<br>
|
||||
💡 Click "Reset Settings" below if checkbox doesn't work
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin: 10px 0; border-top: 1px solid #444; padding-top: 10px;">
|
||||
<label style="display: block; margin-bottom: 5px;">HID Mode:</label>
|
||||
<select id="hid-mode" style="width: 100%; padding: 8px; border-radius: 4px; background: #111; color: #eee; border: 1px solid #444;">
|
||||
<option value="0">Mouse</option>
|
||||
<option value="1">Keyboard</option>
|
||||
<option value="2">Gamepad</option>
|
||||
<option value="3">Disabled</option>
|
||||
<option value="0">Mouse - Wand controls cursor + spell keys</option>
|
||||
<option value="1">Keyboard - Spell keys only</option>
|
||||
<option value="2">Gamepad - Wand controls joystick + spell buttons</option>
|
||||
<option value="3">Disabled - No HID output</option>
|
||||
</select>
|
||||
<div style="font-size: 0.8em; color: #888; margin-top: 5px;">Only one mode can be active at a time</div>
|
||||
<div style="font-size: 0.8em; color: #4CAF50; margin-top: 8px; padding: 8px; background: rgba(76, 175, 80, 0.1); border-left: 3px solid #4CAF50; border-radius: 4px;">
|
||||
<strong>ℹ️ Mixed Mode Tip:</strong><br>
|
||||
• <strong>Mouse mode:</strong> Wand movement controls cursor AND detected spells send keyboard keys!<br>
|
||||
• <strong>Keyboard mode:</strong> Only spell detection sends keys (no mouse movement)<br>
|
||||
• <strong>Gamepad mode:</strong> Wand controls joystick AND spells trigger gamepad buttons<br>
|
||||
• This lets you aim with the wand while casting spells as hotkeys!
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin: 10px 0; border-top: 1px solid #444; padding-top: 10px;">
|
||||
<label style="display: block; margin-bottom: 5px;">Gamepad Sensitivity:</label>
|
||||
@@ -516,6 +538,10 @@ static const char index_html[] = R"rawliteral(
|
||||
<input type="checkbox" id="invert-gamepad-y" style="width: 18px; height: 18px;">
|
||||
<span>Invert Gamepad Y-Axis</span>
|
||||
</label>
|
||||
<div style="font-size: 0.8em; color: #888; margin-top: 5px;">
|
||||
🎮 Only applies in <strong>Gamepad</strong> mode<br>
|
||||
⚠️ Toggle if wand movement feels backwards in-game
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="background: #222; padding: 10px; border-radius: 5px; margin-top: 10px;">
|
||||
@@ -1611,13 +1637,19 @@ static const char index_html[] = R"rawliteral(
|
||||
|
||||
// Load and save settings with spell mappings
|
||||
function saveSettings() {
|
||||
const invertMouseY = document.getElementById('invert-mouse-y').checked;
|
||||
console.log('💾 Saving settings - invert_mouse_y checkbox state:', invertMouseY);
|
||||
|
||||
const invertGamepadY = document.getElementById('invert-gamepad-y').checked;
|
||||
console.log('💾 Saving settings - gamepad_invert_y checkbox state:', invertGamepadY);
|
||||
|
||||
const settings = {
|
||||
mouse_sensitivity: parseFloat(document.getElementById('mouse-sensitivity').value),
|
||||
invert_mouse_y: document.getElementById('invert-mouse-y').checked,
|
||||
invert_mouse_y: invertMouseY,
|
||||
hid_mode: parseInt(document.getElementById('hid-mode').value),
|
||||
gamepad_sensitivity: parseFloat(document.getElementById('gamepad-sensitivity').value),
|
||||
gamepad_deadzone: parseFloat(document.getElementById('gamepad-deadzone').value),
|
||||
gamepad_invert_y: document.getElementById('invert-gamepad-y').checked,
|
||||
gamepad_invert_y: invertGamepadY,
|
||||
ha_mqtt_enabled: document.getElementById('ha-mqtt-enabled').checked,
|
||||
mqtt_broker: document.getElementById('mqtt-broker').value,
|
||||
mqtt_username: document.getElementById('mqtt-username').value,
|
||||
@@ -1629,7 +1661,11 @@ static const char index_html[] = R"rawliteral(
|
||||
// Collect all spell keycode mappings
|
||||
for (let i = 0; i < SPELL_NAMES.length; i++) {
|
||||
const select = document.getElementById(`spell_${i}`);
|
||||
settings.spells.push(parseInt(select.value));
|
||||
const keycode = parseInt(select.value);
|
||||
settings.spells.push(keycode);
|
||||
if (keycode !== 0) {
|
||||
console.log(`Spell[${i}] '${SPELL_NAMES[i]}': keycode=${keycode} (0x${keycode.toString(16).toUpperCase()})`);
|
||||
}
|
||||
}
|
||||
|
||||
// Collect all spell gamepad button mappings
|
||||
@@ -1659,15 +1695,23 @@ static const char index_html[] = R"rawliteral(
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
console.log('Settings loaded:', data);
|
||||
console.log('🔍 Received invert_mouse_y from backend:', data.invert_mouse_y);
|
||||
console.log('🔍 Received gamepad_invert_y from backend:', data.gamepad_invert_y);
|
||||
|
||||
document.getElementById('mouse-sensitivity').value = data.mouse_sensitivity || 1.0;
|
||||
document.getElementById('sens-value').textContent = (data.mouse_sensitivity || 1.0).toFixed(1) + 'x';
|
||||
document.getElementById('invert-mouse-y').checked = data.invert_mouse_y !== false;
|
||||
document.getElementById('invert-mouse-y').checked = (data.invert_mouse_y === true);
|
||||
|
||||
console.log('✅ Set invert-mouse-y checkbox to:', document.getElementById('invert-mouse-y').checked);
|
||||
|
||||
document.getElementById('hid-mode').value = (data.hid_mode !== undefined) ? data.hid_mode : 0;
|
||||
document.getElementById('gamepad-sensitivity').value = data.gamepad_sensitivity || 1.0;
|
||||
document.getElementById('gpad-sens-value').textContent = (data.gamepad_sensitivity || 1.0).toFixed(1) + 'x';
|
||||
document.getElementById('gamepad-deadzone').value = (data.gamepad_deadzone !== undefined) ? data.gamepad_deadzone : 0.05;
|
||||
document.getElementById('gpad-deadzone-value').textContent = ((data.gamepad_deadzone !== undefined) ? data.gamepad_deadzone : 0.05).toFixed(2);
|
||||
document.getElementById('invert-gamepad-y').checked = data.gamepad_invert_y !== false;
|
||||
document.getElementById('invert-gamepad-y').checked = (data.gamepad_invert_y === true);
|
||||
|
||||
console.log('✅ Set invert-gamepad-y checkbox to:', document.getElementById('invert-gamepad-y').checked);
|
||||
document.getElementById('ha-mqtt-enabled').checked = data.ha_mqtt_enabled !== false;
|
||||
document.getElementById('mqtt-broker').value = data.mqtt_broker || '';
|
||||
document.getElementById('mqtt-username').value = data.mqtt_username || '';
|
||||
@@ -1675,12 +1719,18 @@ static const char index_html[] = R"rawliteral(
|
||||
|
||||
// Load spell keycodes
|
||||
if (data.spells && data.spells.length === SPELL_NAMES.length) {
|
||||
let loaded_count = 0;
|
||||
for (let i = 0; i < data.spells.length; i++) {
|
||||
const select = document.getElementById(`spell_${i}`);
|
||||
if (select) {
|
||||
select.value = data.spells[i];
|
||||
if (data.spells[i] !== 0) {
|
||||
loaded_count++;
|
||||
console.log(`Loading spell[${i}] '${SPELL_NAMES[i]}': keycode=${data.spells[i]} (0x${data.spells[i].toString(16).toUpperCase().padStart(2, '0')})`);
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log(`✓ Loaded ${loaded_count} spell-to-key mappings`);
|
||||
}
|
||||
if (data.gamepad_spells && data.gamepad_spells.length === SPELL_NAMES.length) {
|
||||
for (let i = 0; i < data.gamepad_spells.length; i++) {
|
||||
@@ -1704,23 +1754,11 @@ static const char index_html[] = R"rawliteral(
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
console.log('Settings reset:', data);
|
||||
// Reset all spell mappings to 0 (disabled)
|
||||
for (let i = 0; i < SPELL_NAMES.length; i++) {
|
||||
const select = document.getElementById(`spell_${i}`);
|
||||
if (select) select.value = 0;
|
||||
}
|
||||
for (let i = 0; i < SPELL_NAMES.length; i++) {
|
||||
const select = document.getElementById(`gpad_spell_${i}`);
|
||||
if (select) select.value = 0;
|
||||
}
|
||||
document.getElementById('mouse-sensitivity').value = 1.0;
|
||||
document.getElementById('sens-value').textContent = '1.0x';
|
||||
document.getElementById('gamepad-sensitivity').value = 1.0;
|
||||
document.getElementById('gpad-sens-value').textContent = '1.0x';
|
||||
document.getElementById('gamepad-deadzone').value = 0.05;
|
||||
document.getElementById('gpad-deadzone-value').textContent = '0.05';
|
||||
document.getElementById('invert-gamepad-y').checked = true;
|
||||
showToast('Settings reset to defaults!', 'success');
|
||||
showToast('Settings reset to defaults! Reloading...', 'success');
|
||||
// Reload settings from backend to ensure UI is synced
|
||||
setTimeout(() => {
|
||||
loadSettings();
|
||||
}, 500);
|
||||
})
|
||||
.catch(error => {
|
||||
showToast('Failed to reset settings', 'error');
|
||||
@@ -3012,14 +3050,27 @@ esp_err_t WebServer::settings_get_handler(httpd_req_t *req)
|
||||
int offset = 0;
|
||||
size_t buffer_size = 4096;
|
||||
|
||||
float mouse_sens = usbHID.getMouseSensitivity();
|
||||
bool mouse_invert = usbHID.getInvertMouseY();
|
||||
HIDMode hid_mode = usbHID.getHidMode();
|
||||
float gamepad_sens = usbHID.getGamepadSensitivity();
|
||||
float gamepad_deadzone = usbHID.getGamepadDeadzone();
|
||||
bool gamepad_invert = usbHID.getGamepadInvertY();
|
||||
|
||||
ESP_LOGI(TAG, "📤 Sending settings to UI:");
|
||||
ESP_LOGI(TAG, " mouse_sensitivity=%.2f, invert_mouse_y=%s", mouse_sens, mouse_invert ? "true" : "false");
|
||||
ESP_LOGI(TAG, " hid_mode=%u", static_cast<unsigned>(hid_mode));
|
||||
ESP_LOGI(TAG, " gamepad_sensitivity=%.2f, gamepad_deadzone=%.2f, gamepad_invert_y=%s",
|
||||
gamepad_sens, gamepad_deadzone, gamepad_invert ? "true" : "false");
|
||||
|
||||
offset += snprintf(buffer + offset, buffer_size - offset,
|
||||
"{\"mouse_sensitivity\": %.2f, \"invert_mouse_y\": %s, \"hid_mode\": %u, \"gamepad_sensitivity\": %.2f, \"gamepad_deadzone\": %.2f, \"gamepad_invert_y\": %s, \"spells\": [",
|
||||
usbHID.getMouseSensitivity(),
|
||||
usbHID.getInvertMouseY() ? "true" : "false",
|
||||
static_cast<unsigned>(usbHID.getHidMode()),
|
||||
usbHID.getGamepadSensitivity(),
|
||||
usbHID.getGamepadDeadzone(),
|
||||
usbHID.getGamepadInvertY() ? "true" : "false");
|
||||
mouse_sens,
|
||||
mouse_invert ? "true" : "false",
|
||||
static_cast<unsigned>(hid_mode),
|
||||
gamepad_sens,
|
||||
gamepad_deadzone,
|
||||
gamepad_invert ? "true" : "false");
|
||||
|
||||
const uint8_t *spell_keycodes = usbHID.getSpellKeycodes();
|
||||
for (int i = 0; i < 73; i++)
|
||||
@@ -3231,7 +3282,7 @@ esp_err_t WebServer::settings_save_handler(httpd_req_t *req)
|
||||
char *mouse_ptr = strstr(buffer, "\"mouse_sensitivity\"");
|
||||
if (mouse_ptr)
|
||||
{
|
||||
sscanf(mouse_ptr, "\"mouse_sensitivity\": %f", &mouse_sens);
|
||||
sscanf(mouse_ptr, "\"mouse_sensitivity\" : %f", &mouse_sens);
|
||||
usbHID.setMouseSensitivityValue(mouse_sens);
|
||||
}
|
||||
|
||||
@@ -3239,8 +3290,23 @@ esp_err_t WebServer::settings_save_handler(httpd_req_t *req)
|
||||
char *invert_ptr = strstr(buffer, "\"invert_mouse_y\"");
|
||||
if (invert_ptr)
|
||||
{
|
||||
bool invert = (strstr(invert_ptr, "true") != NULL);
|
||||
usbHID.setInvertMouseY(invert);
|
||||
// Find the colon after the key, then check the value
|
||||
char *value_ptr = strchr(invert_ptr, ':');
|
||||
if (value_ptr)
|
||||
{
|
||||
value_ptr++; // Skip colon
|
||||
while (*value_ptr == ' ' || *value_ptr == '\t')
|
||||
value_ptr++; // Skip whitespace
|
||||
bool invert = (strncmp(value_ptr, "true", 4) == 0);
|
||||
ESP_LOGI(TAG, "🔍 Parsing invert_mouse_y: JSON substring='%.50s...', parsed_value=%s",
|
||||
invert_ptr, invert ? "true" : "false");
|
||||
usbHID.setInvertMouseY(invert);
|
||||
ESP_LOGI(TAG, "✅ Called setInvertMouseY(%s)", invert ? "true" : "false");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGW(TAG, "⚠️ invert_mouse_y not found in JSON!");
|
||||
}
|
||||
|
||||
// Parse HID mode
|
||||
@@ -3248,7 +3314,7 @@ esp_err_t WebServer::settings_save_handler(httpd_req_t *req)
|
||||
if (hid_mode_ptr)
|
||||
{
|
||||
int hid_mode = HID_MODE_MOUSE;
|
||||
sscanf(hid_mode_ptr, "\"hid_mode\": %d", &hid_mode);
|
||||
sscanf(hid_mode_ptr, "\"hid_mode\" : %d", &hid_mode);
|
||||
usbHID.setHidMode(static_cast<HIDMode>(hid_mode));
|
||||
}
|
||||
|
||||
@@ -3257,7 +3323,8 @@ esp_err_t WebServer::settings_save_handler(httpd_req_t *req)
|
||||
if (gpad_sens_ptr)
|
||||
{
|
||||
float gpad_sens = 1.0f;
|
||||
sscanf(gpad_sens_ptr, "\"gamepad_sensitivity\": %f", &gpad_sens);
|
||||
sscanf(gpad_sens_ptr, "\"gamepad_sensitivity\" : %f", &gpad_sens);
|
||||
ESP_LOGI(TAG, "📝 Parsed gamepad_sensitivity: %.2f", gpad_sens);
|
||||
usbHID.setGamepadSensitivityValue(gpad_sens);
|
||||
}
|
||||
|
||||
@@ -3266,7 +3333,8 @@ esp_err_t WebServer::settings_save_handler(httpd_req_t *req)
|
||||
if (gpad_deadzone_ptr)
|
||||
{
|
||||
float gpad_deadzone = 0.05f;
|
||||
sscanf(gpad_deadzone_ptr, "\"gamepad_deadzone\": %f", &gpad_deadzone);
|
||||
sscanf(gpad_deadzone_ptr, "\"gamepad_deadzone\" : %f", &gpad_deadzone);
|
||||
ESP_LOGI(TAG, "📝 Parsed gamepad_deadzone: %.2f", gpad_deadzone);
|
||||
usbHID.setGamepadDeadzoneValue(gpad_deadzone);
|
||||
}
|
||||
|
||||
@@ -3274,15 +3342,37 @@ esp_err_t WebServer::settings_save_handler(httpd_req_t *req)
|
||||
char *gpad_invert_ptr = strstr(buffer, "\"gamepad_invert_y\"");
|
||||
if (gpad_invert_ptr)
|
||||
{
|
||||
bool invert = (strstr(gpad_invert_ptr, "true") != NULL);
|
||||
// Find the colon after the key, then check the value
|
||||
char *value_ptr = strchr(gpad_invert_ptr, ':');
|
||||
bool invert = false;
|
||||
if (value_ptr)
|
||||
{
|
||||
value_ptr++; // Skip colon
|
||||
while (*value_ptr == ' ' || *value_ptr == '\t')
|
||||
value_ptr++; // Skip whitespace
|
||||
invert = (strncmp(value_ptr, "true", 4) == 0);
|
||||
|
||||
ESP_LOGI(TAG, "🔍 Parsing gamepad_invert_y: JSON substring='%.50s...', parsed_value=%s",
|
||||
gpad_invert_ptr, invert ? "true" : "false");
|
||||
}
|
||||
usbHID.setGamepadInvertY(invert);
|
||||
ESP_LOGI(TAG, "✅ Called setGamepadInvertY(%s)", invert ? "true" : "false");
|
||||
}
|
||||
|
||||
// Parse HA MQTT enabled
|
||||
char *ha_mqtt_ptr = strstr(buffer, "\"ha_mqtt_enabled\"");
|
||||
if (ha_mqtt_ptr)
|
||||
{
|
||||
bool enabled = (strstr(ha_mqtt_ptr, "true") != NULL);
|
||||
// Find the colon after the key, then check the value
|
||||
char *value_ptr = strchr(ha_mqtt_ptr, ':');
|
||||
bool enabled = false;
|
||||
if (value_ptr)
|
||||
{
|
||||
value_ptr++; // Skip colon
|
||||
while (*value_ptr == ' ' || *value_ptr == '\t')
|
||||
value_ptr++; // Skip whitespace
|
||||
enabled = (strncmp(value_ptr, "true", 4) == 0);
|
||||
}
|
||||
nvs_handle_t nvs_handle;
|
||||
esp_err_t err = nvs_open("storage", NVS_READWRITE, &nvs_handle);
|
||||
if (err == ESP_OK)
|
||||
@@ -3411,6 +3501,8 @@ esp_err_t WebServer::settings_save_handler(httpd_req_t *req)
|
||||
int matched = sscanf(parse_ptr, "%d", &keycode);
|
||||
if (matched == 1)
|
||||
{
|
||||
ESP_LOGI(TAG, "Setting spell[%d]='%s' to keycode=0x%02X (%d)",
|
||||
spell_idx, SPELL_NAMES[spell_idx], keycode, keycode);
|
||||
usbHID.setSpellKeycode(SPELL_NAMES[spell_idx], (uint8_t)keycode);
|
||||
spell_idx++;
|
||||
// Skip to next comma or bracket
|
||||
@@ -3493,7 +3585,16 @@ esp_err_t WebServer::settings_save_handler(httpd_req_t *req)
|
||||
char *ha_mqtt_ptr = strstr(buffer, "\"ha_mqtt_enabled\"");
|
||||
if (ha_mqtt_ptr)
|
||||
{
|
||||
bool enabled = (strstr(ha_mqtt_ptr, "true") != NULL);
|
||||
// Find the colon after the key, then check the value
|
||||
char *value_ptr = strchr(ha_mqtt_ptr, ':');
|
||||
bool enabled = false;
|
||||
if (value_ptr)
|
||||
{
|
||||
value_ptr++; // Skip colon
|
||||
while (*value_ptr == ' ' || *value_ptr == '\t')
|
||||
value_ptr++; // Skip whitespace
|
||||
enabled = (strncmp(value_ptr, "true", 4) == 0);
|
||||
}
|
||||
nvs_handle_t nvs_handle;
|
||||
esp_err_t err = nvs_open("storage", NVS_READWRITE, &nvs_handle);
|
||||
if (err == ESP_OK)
|
||||
@@ -3973,7 +4074,20 @@ esp_err_t WebServer::hotspot_settings_handler(httpd_req_t *req)
|
||||
ESP_LOGI(TAG, "Received hotspot settings: %s", buffer);
|
||||
|
||||
// Parse settings
|
||||
bool enabled = (strstr(buffer, "\"enabled\":true") != NULL);
|
||||
char *enabled_ptr = strstr(buffer, "\"enabled\"");
|
||||
bool enabled = false;
|
||||
if (enabled_ptr)
|
||||
{
|
||||
char *value_ptr = strchr(enabled_ptr, ':');
|
||||
if (value_ptr)
|
||||
{
|
||||
value_ptr++;
|
||||
while (*value_ptr == ' ' || *value_ptr == '\t')
|
||||
value_ptr++;
|
||||
enabled = (strncmp(value_ptr, "true", 4) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
char ssid[32] = {0};
|
||||
char password[64] = {0};
|
||||
int channel = 1;
|
||||
@@ -4023,7 +4137,7 @@ esp_err_t WebServer::hotspot_settings_handler(httpd_req_t *req)
|
||||
char *channel_ptr = strstr(buffer, "\"channel\":");
|
||||
if (channel_ptr)
|
||||
{
|
||||
sscanf(channel_ptr, "\"channel\":%d", &channel);
|
||||
sscanf(channel_ptr, "\"channel\" : %d", &channel);
|
||||
}
|
||||
|
||||
// Save hotspot settings to NVS
|
||||
@@ -4147,9 +4261,24 @@ esp_err_t WebServer::system_wifi_mode_handler(httpd_req_t *req)
|
||||
// Parse JSON to extract mode
|
||||
// Expected: {"mode":"client"} or {"mode":"ap"}
|
||||
bool force_ap = false;
|
||||
if (strstr(buf, "\"ap\"") != nullptr)
|
||||
char *mode_ptr = strstr(buf, "\"mode\"");
|
||||
if (mode_ptr)
|
||||
{
|
||||
force_ap = true;
|
||||
char *value_ptr = strchr(mode_ptr, ':');
|
||||
if (value_ptr)
|
||||
{
|
||||
value_ptr++;
|
||||
while (*value_ptr == ' ' || *value_ptr == '\t')
|
||||
value_ptr++;
|
||||
if (*value_ptr == '\"')
|
||||
{
|
||||
value_ptr++;
|
||||
if (strncmp(value_ptr, "ap", 2) == 0)
|
||||
{
|
||||
force_ap = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Setting force_ap_mode to %d", force_ap ? 1 : 0);
|
||||
|
||||
Reference in New Issue
Block a user