From 0ba8e18dc4c9816d077ff3108d58453746884bce Mon Sep 17 00:00:00 2001 From: KojoZero Date: Tue, 28 Apr 2026 20:13:55 -0700 Subject: [PATCH] added c-stick toggle and stylus related gui changes --- .../configuration/configure_input.cpp | 2 +- src/citra_qt/configuration/configure_input.ui | 153 +++++++++------- src/common/settings.h | 3 + src/core/frontend/cursor.cpp | 172 +++++++++--------- src/core/hle/service/hid/hid.cpp | 12 +- src/core/hle/service/hid/hid.h | 4 +- src/core/hle/service/ir/extra_hid.cpp | 19 +- 7 files changed, 208 insertions(+), 157 deletions(-) diff --git a/src/citra_qt/configuration/configure_input.cpp b/src/citra_qt/configuration/configure_input.cpp index 2cc319968..67b697dae 100644 --- a/src/citra_qt/configuration/configure_input.cpp +++ b/src/citra_qt/configuration/configure_input.cpp @@ -171,7 +171,7 @@ ConfigureInput::ConfigureInput(Core::System& _system, QWidget* parent) ui->buttonDpadUp, ui->buttonDpadDown, ui->buttonDpadLeft, ui->buttonDpadRight, ui->buttonL, ui->buttonR, ui->buttonStart, ui->buttonSelect, ui->buttonDebug, ui->buttonGpio14, ui->buttonZL, ui->buttonZR, - ui->buttonHome, ui->buttonPower, + ui->buttonHome, ui->buttonPower, ui->buttonToggleCStick, }; analog_map_buttons = {{ diff --git a/src/citra_qt/configuration/configure_input.ui b/src/citra_qt/configuration/configure_input.ui index 67cc7688f..bcc6820a2 100644 --- a/src/citra_qt/configuration/configure_input.ui +++ b/src/citra_qt/configuration/configure_input.ui @@ -29,7 +29,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -68,6 +68,14 @@ true + + + 0 + -180 + 416 + 802 + + @@ -88,7 +96,7 @@ - ZR: + Stylus Touch / ZR: @@ -124,7 +132,7 @@ - ZL: + Stylus Mod / ZL: @@ -344,17 +352,17 @@ false - - + + - + - Start: + Circle Mod: - + @@ -380,24 +388,6 @@ - - - - - - Home: - - - - - - - - - - - - @@ -416,24 +406,6 @@ - - - - - - Circle Mod: - - - - - - - - - - - - @@ -452,6 +424,42 @@ + + + + + + Start: + + + + + + + + + + + + + + + + + + Home: + + + + + + + + + + + + @@ -470,6 +478,24 @@ + + + + + + Toggle C-Stick: + + + + + + + + + + + + @@ -572,7 +598,7 @@ - QLayout::SetDefaultConstraint + QLayout::SizeConstraint::SetDefaultConstraint @@ -580,7 +606,7 @@ Deadzone: 0 - Qt::AlignHCenter + Qt::AlignmentFlag::AlignHCenter @@ -589,7 +615,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -634,25 +660,25 @@ - QLayout::SetDefaultConstraint + QLayout::SizeConstraint::SetDefaultConstraint - Qt::LeftToRight + Qt::LayoutDirection::LeftToRight Diagonals - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter - Qt::Horizontal + Qt::Orientation::Horizontal @@ -697,7 +723,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -707,7 +733,7 @@ - C-Stick + Stylus / C-Stick false @@ -868,14 +894,14 @@ Diagonals - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter - Qt::Horizontal + Qt::Orientation::Horizontal @@ -884,7 +910,7 @@ - QLayout::SetDefaultConstraint + QLayout::SizeConstraint::SetDefaultConstraint @@ -894,7 +920,7 @@ Deadzone: 0 - Qt::AlignHCenter + Qt::AlignmentFlag::AlignHCenter @@ -903,7 +929,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -919,7 +945,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -957,7 +983,7 @@ - Qt::LeftToRight + Qt::LayoutDirection::LeftToRight Motion / Touch... @@ -985,7 +1011,7 @@ - Qt::LeftToRight + Qt::LayoutDirection::LeftToRight Auto Map @@ -1013,7 +1039,7 @@ - Qt::LeftToRight + Qt::LayoutDirection::LeftToRight Clear All @@ -1041,7 +1067,7 @@ - Qt::LeftToRight + Qt::LayoutDirection::LeftToRight Restore Defaults @@ -1094,6 +1120,7 @@ buttonCircleMod buttonDebug buttonGpio14 + buttonToggleCStick buttonMotionTouch buttonAutoMap buttonClearAll diff --git a/src/common/settings.h b/src/common/settings.h index 5eca53421..f67f072df 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -151,6 +151,8 @@ enum Values { Home, Power, + ToggleCStick, + NumButtons, }; @@ -185,6 +187,7 @@ static const std::array mapping = {{ "button_zr", "button_home", "button_power", + "button_togglecstick", }}; } // namespace NativeButton diff --git a/src/core/frontend/cursor.cpp b/src/core/frontend/cursor.cpp index 8eac37830..93d41058a 100644 --- a/src/core/frontend/cursor.cpp +++ b/src/core/frontend/cursor.cpp @@ -12,100 +12,102 @@ void Cursor::update(){ modButtons = Service::HID::Module::getModButtons(); setRotation(); if (deviceInUse == 0){ - if (inMacro){ - runMacro(); - } else { - // LOG_INFO(Core, "Stylus X: {:.2f}, Stylus Y: {:.2f}, Stylus Mod: {}, Stylus Touch: {}", stylusInput[0], stylusInput[1], stylusInput[2], stylusInput[3]); - // Reset the cursor position if macro was just played - if (justFinishedMacro > 0){ - justFinishedMacro = 0; - rawCursorPos[0] = macroInitPos[0]; - rawCursorPos[1] = macroInitPos[1]; - } - - // Macros - if (modButtons[0]){ - circle(0); - return; - } else if (modButtons[1]){ - rub(); - return; - } else if (modButtons[2]){ - if (!macroBtnPressed){ - // Add macro - return; - } - } else if (modButtons[3]){ - circle(1); - return; + if (!Service::HID::Module::cstickEnabled){ + if (inMacro){ + runMacro(); } else { - if (macroBtnPressed){ - macroBtnPressed = false; + // LOG_INFO(Core, "Stylus X: {:.2f}, Stylus Y: {:.2f}, Stylus Mod: {}, Stylus Touch: {}", stylusInput[0], stylusInput[1], stylusInput[2], stylusInput[3]); + // Reset the cursor position if macro was just played + if (justFinishedMacro > 0){ + justFinishedMacro = 0; + rawCursorPos[0] = macroInitPos[0]; + rawCursorPos[1] = macroInitPos[1]; } - } - normStylusDirection[0] = stylusInput[0]; - normStylusDirection[1] = stylusInput[1]; + // Macros + if (modButtons[0]){ + circle(0); + return; + } else if (modButtons[1]){ + rub(); + return; + } else if (modButtons[2]){ + if (!macroBtnPressed){ + // Add macro + return; + } + } else if (modButtons[3]){ + circle(1); + return; + } else { + if (macroBtnPressed){ + macroBtnPressed = false; + } + } - int maxSpeed = 50; - float multiplier = 0.5f * pow(4.0f, maxSpeed / 100.0f); // 0 is 0.5x speed, 100 is 2.0x speed. - float heightSpeed = (240.0f / 33.0f) * multiplier; - bool stylusModPressed = stylusInput[2]; - float responsecurve = 175.0f / 100.0f; - float speedupratio = 400.0f / 100.0f; - float joystickScaled[2] = {0.0f}; - float radialLength = std::sqrt((normStylusDirection[0] * normStylusDirection[0]) + (normStylusDirection[1] * normStylusDirection[1])); - float finalLength; - float curvedLength; - if (radialLength > 0) { - // Get X and Y as a relation to the radial length - float rComponents[2]; - rComponents[0] = normStylusDirection[0]/radialLength; - rComponents[1] = normStylusDirection[1]/radialLength; - // Apply response curve and output - curvedLength = std::pow(radialLength, responsecurve); - finalLength = stylusModPressed ? curvedLength * speedupratio : curvedLength; - joystickScaled[0] = rComponents[0] * finalLength; - joystickScaled[1] = rComponents[1] * finalLength; - } - // The code below sets the cursor position to the position of the joystick (absolute). Needs to be readjusted for standalone melonDS - // _joystickCursorPosition = vec2((NDS_SCREEN_WIDTH/2.0f)+(std::min(1.0,(normStylusDirection[0]/0.7071))*(NDS_SCREEN_WIDTH/2.0f)), (NDS_SCREEN_HEIGHT/2.0f)+(std::min(1.0,(normStylusDirection[1]/0.7071))*(NDS_SCREEN_HEIGHT/2.0f))); + normStylusDirection[0] = stylusInput[0]; + normStylusDirection[1] = stylusInput[1]; - float tempX = joystickScaled[0]; - float tempY = joystickScaled[1]; + int maxSpeed = 50; + float multiplier = 0.5f * pow(4.0f, maxSpeed / 100.0f); // 0 is 0.5x speed, 100 is 2.0x speed. + float heightSpeed = (240.0f / 33.0f) * multiplier; + bool stylusModPressed = stylusInput[2]; + float responsecurve = 175.0f / 100.0f; + float speedupratio = 400.0f / 100.0f; + float joystickScaled[2] = {0.0f}; + float radialLength = std::sqrt((normStylusDirection[0] * normStylusDirection[0]) + (normStylusDirection[1] * normStylusDirection[1])); + float finalLength; + float curvedLength; + if (radialLength > 0) { + // Get X and Y as a relation to the radial length + float rComponents[2]; + rComponents[0] = normStylusDirection[0]/radialLength; + rComponents[1] = normStylusDirection[1]/radialLength; + // Apply response curve and output + curvedLength = std::pow(radialLength, responsecurve); + finalLength = stylusModPressed ? curvedLength * speedupratio : curvedLength; + joystickScaled[0] = rComponents[0] * finalLength; + joystickScaled[1] = rComponents[1] * finalLength; + } + // The code below sets the cursor position to the position of the joystick (absolute). Needs to be readjusted for standalone melonDS + // _joystickCursorPosition = vec2((NDS_SCREEN_WIDTH/2.0f)+(std::min(1.0,(normStylusDirection[0]/0.7071))*(NDS_SCREEN_WIDTH/2.0f)), (NDS_SCREEN_HEIGHT/2.0f)+(std::min(1.0,(normStylusDirection[1]/0.7071))*(NDS_SCREEN_HEIGHT/2.0f))); - switch (rotation) - { - case 1: // 90° - joystickScaled[0] = tempY; - joystickScaled[1] = -tempX; - break; - case 2: // 180° - joystickScaled[0] = -tempX; - joystickScaled[1] = -tempY; - break; - case 3: // 270° - joystickScaled[0] = -tempY; - joystickScaled[1] = tempX; - break; - default: - break; - } + float tempX = joystickScaled[0]; + float tempY = joystickScaled[1]; - rawCursorPos[0] += joystickScaled[0]*heightSpeed; - rawCursorPos[1] += joystickScaled[1]*heightSpeed; + switch (rotation) + { + case 1: // 90° + joystickScaled[0] = tempY; + joystickScaled[1] = -tempX; + break; + case 2: // 180° + joystickScaled[0] = -tempX; + joystickScaled[1] = -tempY; + break; + case 3: // 270° + joystickScaled[0] = -tempY; + joystickScaled[1] = tempX; + break; + default: + break; + } - // Clamp to region and ready position information for touchscreen - clamp(); - updateCursorPos(); + rawCursorPos[0] += joystickScaled[0]*heightSpeed; + rawCursorPos[1] += joystickScaled[1]*heightSpeed; - // Handle stylus touch button presses - if (stylusInput[3]){ - touchScreen(); - wasTouching = true; - } else if (wasTouching && !stylusInput[3]){ - release(); - wasTouching = false; + // Clamp to region and ready position information for touchscreen + clamp(); + updateCursorPos(); + + // Handle stylus touch button presses + if (stylusInput[3]){ + touchScreen(); + wasTouching = true; + } else if (wasTouching && !stylusInput[3]){ + release(); + wasTouching = false; + } } } } else { diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 74f5258d1..77b51c922 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -32,7 +32,7 @@ SERIALIZE_EXPORT_IMPL(Service::HID::Module) namespace Service::HID { std::array Module::stylusInput = {}; std::array Module::modButtons = {}; - +bool Module::cstickEnabled = false; template void Module::serialize(Archive& ar, const unsigned int file_version) { DEBUG_SERIALIZATION_POINT; @@ -128,6 +128,8 @@ void Module::LoadInputDevices() { Settings::values.current_input_profile.buttons[Settings::NativeButton::ZL]); zr_button = Input::CreateDevice( Settings::values.current_input_profile.buttons[Settings::NativeButton::ZR]); + toggle_cstick_button = Input::CreateDevice( + Settings::values.current_input_profile.buttons[Settings::NativeButton::ToggleCStick]); circle_pad = Input::CreateDevice( Settings::values.current_input_profile.analogs[Settings::NativeAnalog::CirclePad]); c_stick = Input::CreateDevice( @@ -236,6 +238,14 @@ void Module::UpdatePadCallback(std::uintptr_t user_data, s64 cycles_late) { for (int i = 0; i < 4; i++){ modButtons[i] = zl_button->GetStatus() && buttons[i - BUTTON_HID_BEGIN]->GetStatus(); } + + //Toggle for Cstick + if (!prev_toggle_cstick_button_state && toggle_cstick_button->GetStatus()){ + cstickEnabled = !cstickEnabled; + } + //LOG_INFO(Service_HID, "C-Stick Enabled: {}, Prev C-Stick Button State {}, Current C-Stick Button State {}", cstickEnabled, prev_toggle_cstick_button_state, toggle_cstick_button->GetStatus()); + prev_toggle_cstick_button_state = toggle_cstick_button->GetStatus(); + // Get current circle pad position and update circle pad direction float circle_pad_x_f, circle_pad_y_f; std::tie(circle_pad_x_f, circle_pad_y_f) = circle_pad->GetStatus(); diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 363bb0350..5fcf82642 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -244,7 +244,6 @@ public: Interface(std::shared_ptr hid, const char* name, u32 max_session); // Stylus X, Y, ZL, ZR std::shared_ptr GetModule() const; - protected: /** * HID::GetIPCHandles service function @@ -337,6 +336,7 @@ public: void ReloadInputDevices(); static std::array getStylusInputs(); static std::array getModButtons(); + static bool cstickEnabled; const PadState& GetState() const; // Updating period for each HID device. These empirical values are measured from a 11.2 3DS. @@ -391,6 +391,7 @@ private: buttons; std::unique_ptr zl_button; std::unique_ptr zr_button; + std::unique_ptr toggle_cstick_button; std::unique_ptr circle_pad; std::unique_ptr c_stick; std::unique_ptr motion_device; @@ -399,6 +400,7 @@ private: std::unique_ptr touch_btn_device; static std::array stylusInput; static std::array modButtons; + bool prev_toggle_cstick_button_state = false; std::shared_ptr artic_controller; std::shared_ptr artic_client; diff --git a/src/core/hle/service/ir/extra_hid.cpp b/src/core/hle/service/ir/extra_hid.cpp index e5dc486cb..fcb1b7dab 100644 --- a/src/core/hle/service/ir/extra_hid.cpp +++ b/src/core/hle/service/ir/extra_hid.cpp @@ -262,13 +262,20 @@ void ExtraHID::SendHIDStatus() { } else { float x, y; std::tie(x, y) = c_stick->GetStatus(); - - response.c_stick.header.Assign(static_cast(ResponseID::PollHID)); - response.c_stick.c_stick_x.Assign(static_cast(C_STICK_CENTER + C_STICK_RADIUS * x)); - response.c_stick.c_stick_y.Assign(static_cast(C_STICK_CENTER + C_STICK_RADIUS * y)); response.buttons.battery_level.Assign(0x1F); - response.buttons.zl_not_held.Assign(!zl->GetStatus()); - response.buttons.zr_not_held.Assign(!zr->GetStatus()); + response.c_stick.header.Assign(static_cast(ResponseID::PollHID)); + if (Service::HID::Module::cstickEnabled){ + response.c_stick.c_stick_x.Assign(static_cast(C_STICK_CENTER + C_STICK_RADIUS * x)); + response.c_stick.c_stick_y.Assign(static_cast(C_STICK_CENTER + C_STICK_RADIUS * y)); + response.buttons.zl_not_held.Assign(!zl->GetStatus()); + response.buttons.zr_not_held.Assign(!zr->GetStatus()); + } else { + response.c_stick.c_stick_x.Assign(static_cast(C_STICK_CENTER)); + response.c_stick.c_stick_y.Assign(static_cast(C_STICK_CENTER)); + response.buttons.zl_not_held.Assign(true); + response.buttons.zr_not_held.Assign(true); + } + response.buttons.r_not_held.Assign(1); response.unknown = 0; }