From f32e069c4bb97765f1e0f760db22cc3d737cc4d9 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Thu, 2 Jul 2026 00:03:18 -0600 Subject: [PATCH] Improve mouse hiding logic (#2163) * Improve mouse hiding logic * Restore ImGui logic --- include/dusk/mouse.h | 8 +-- src/d/actor/d_a_alink_link.inc | 2 +- src/d/d_camera.cpp | 2 +- src/dusk/mouse.cpp | 126 +++++++++++++++++++-------------- src/m_Do/m_Do_main.cpp | 4 +- 5 files changed, 82 insertions(+), 60 deletions(-) diff --git a/include/dusk/mouse.h b/include/dusk/mouse.h index 514d14534a..c98d53c18f 100644 --- a/include/dusk/mouse.h +++ b/include/dusk/mouse.h @@ -4,9 +4,9 @@ namespace dusk::mouse { void read(); -void getAimDeltas(float& out_yaw, float& out_pitch); -void getCameraDeltas(float& out_yaw, float& out_pitch); +void get_aim_deltas(float& out_yaw, float& out_pitch); +void get_camera_deltas(float& out_yaw, float& out_pitch); void handle_event(const SDL_Event& event) noexcept; -void onFocusLost(); -void onFocusGained(); +void on_focus_lost(); +void on_focus_gained(); } // namespace dusk::mouse diff --git a/src/d/actor/d_a_alink_link.inc b/src/d/actor/d_a_alink_link.inc index cf2f2544d6..b5dcfe06e6 100644 --- a/src/d/actor/d_a_alink_link.inc +++ b/src/d/actor/d_a_alink_link.inc @@ -156,7 +156,7 @@ BOOL daAlink_c::setBodyAngleToCamera() { f32 final_yaw = 0.f; f32 final_pitch = 0.f; if (dusk::getSettings().game.enableMouseAim) { - dusk::mouse::getAimDeltas(final_yaw, final_pitch); + dusk::mouse::get_aim_deltas(final_yaw, final_pitch); } if (dusk::getSettings().game.enableGyroAim) { f32 gyro_yaw = 0.f; diff --git a/src/d/d_camera.cpp b/src/d/d_camera.cpp index b92a0cc4b6..ed0de09b63 100644 --- a/src/d/d_camera.cpp +++ b/src/d/d_camera.cpp @@ -7716,7 +7716,7 @@ bool dCamera_c::freeCamera() { f32 yaw_rad = 0.0f; f32 pitch_rad = 0.0f; - dusk::mouse::getCameraDeltas(yaw_rad, pitch_rad); + dusk::mouse::get_camera_deltas(yaw_rad, pitch_rad); if (dusk::getSettings().game.enableMouseCamera && (yaw_rad != 0.0f || pitch_rad != 0.0f) && !dComIfGp_checkCameraAttentionStatus(dComIfGp_getPlayerCameraID(0), 0x8)) { diff --git a/src/dusk/mouse.cpp b/src/dusk/mouse.cpp index f1aa5672fd..a1fd4efda8 100644 --- a/src/dusk/mouse.cpp +++ b/src/dusk/mouse.cpp @@ -1,54 +1,69 @@ #include "dusk/mouse.h" +#include "d/actor/d_a_alink.h" +#include "d/d_com_inf_game.h" #include "dusk/menu_pointer.h" #include "dusk/settings.h" #include "dusk/ui/ui.hpp" -#include "d/actor/d_a_alink.h" -#include "d/d_com_inf_game.h" -#include -#include #include #include +#include +#include + +#include namespace dusk::mouse { namespace { -constexpr float kMousePixelToRad = 0.0025f; -constexpr int kIdleHideFrames = 99; // Approx. 3 seconds with 33ms ticks +using Clock = std::chrono::steady_clock; -float s_aim_yaw_rad = 0.0f; -float s_aim_pitch_rad = 0.0f; -float s_camera_yaw_rad = 0.0f; +constexpr float kMousePixelToRad = 0.0025f; +constexpr auto kCursorIdleDuration = std::chrono::seconds(1); + +float s_aim_yaw_rad = 0.0f; +float s_aim_pitch_rad = 0.0f; +float s_camera_yaw_rad = 0.0f; float s_camera_pitch_rad = 0.0f; -int s_idle_frames = 0; +Clock::time_point s_last_cursor_motion = Clock::now(); void reset_deltas() { s_aim_yaw_rad = s_aim_pitch_rad = 0.0f; s_camera_yaw_rad = s_camera_pitch_rad = 0.0f; } -bool queryMouseAimContext() { +bool query_mouse_aim_context() { return getSettings().game.enableMouseAim.getValue() && dCamera_c::isAimActive(); } -bool wantMouseCapture() { - return getSettings().game.enableMouseCamera.getValue() || queryMouseAimContext(); +bool want_mouse_capture() { + return getSettings().game.enableMouseCamera.getValue() || query_mouse_aim_context(); } -bool isWindowFocused(SDL_Window* window) { +bool mouse_input_enabled() { + const auto& game = getSettings().game; + return game.enableMouseAim.getValue() || game.enableMouseCamera.getValue(); +} + +bool is_window_focused(SDL_Window* window) { if (window == nullptr) { return false; } return (SDL_GetWindowFlags(window) & SDL_WINDOW_INPUT_FOCUS) != 0; } -bool shouldCaptureMouse(SDL_Window* window) { - if (window == nullptr || ui::any_document_visible() || menu_pointer::active()) { - return false; - } - return wantMouseCapture() && isWindowFocused(window); +bool imgui_windows_visible() { + return ImGui::GetIO().MetricsRenderWindows > 0; } -bool syncCaptureState(SDL_Window* window, bool should_capture) { +bool should_capture_mouse(SDL_Window* window) { + if (window == nullptr || ui::any_document_visible() || imgui_windows_visible() || + menu_pointer::active()) + { + return false; + } + return want_mouse_capture() && is_window_focused(window); +} + +bool sync_capture_state(SDL_Window* window, bool should_capture) { if (window == nullptr) { reset_deltas(); return false; @@ -78,7 +93,7 @@ bool syncCaptureState(SDL_Window* window, bool should_capture) { return is_captured; } -void accumulateDeltas(float mx_rel, float my_rel, bool camera_active, bool aim_active) { +void accumulate_deltas(float mx_rel, float my_rel, bool camera_active, bool aim_active) { const auto& game = getSettings().game; const bool mirror_mode = game.enableMirrorMode.getValue(); const bool invert_y = game.invertMouseY.getValue(); @@ -114,57 +129,62 @@ void set_cursor_visible(bool visible) { } } -void update_cursor_visibility(SDL_Window* window, bool captured) { - if (window == nullptr || !isWindowFocused(window)) { - return; - } +bool cursor_idle() { + return Clock::now() - s_last_cursor_motion >= kCursorIdleDuration; +} +bool should_show_cursor(bool captured) { if (captured) { - s_idle_frames = 0; - set_cursor_visible(false); + return false; + } + if (ui::any_document_visible()) { + return true; + } + if (imgui_windows_visible()) { + return true; + } + if (menu_pointer::enabled() && menu_pointer::active()) { + return true; + } + if (mouse_input_enabled()) { + return false; + } + return !cursor_idle(); +} + +void update_cursor_visibility(SDL_Window* window, bool captured) { + if (window == nullptr || !is_window_focused(window)) { return; } - const ImGuiIO& io = ImGui::GetIO(); - if (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f) { - s_idle_frames = 0; - set_cursor_visible(true); - return; - } - - if (s_idle_frames < kIdleHideFrames) { - ++s_idle_frames; - set_cursor_visible(true); - } else { - set_cursor_visible(false); - } + set_cursor_visible(should_show_cursor(captured)); } } // namespace void read() { SDL_Window* window = aurora::window::get_sdl_window(); - const bool capture_active = syncCaptureState(window, shouldCaptureMouse(window)); + const bool capture_active = sync_capture_state(window, should_capture_mouse(window)); update_cursor_visibility(window, capture_active); if (!capture_active) { return; } - const bool aim_active = capture_active && queryMouseAimContext(); + const bool aim_active = capture_active && query_mouse_aim_context(); const bool camera_active = capture_active && getSettings().game.enableMouseCamera; float mx_rel = 0.0f; float my_rel = 0.0f; SDL_GetRelativeMouseState(&mx_rel, &my_rel); - accumulateDeltas(mx_rel, my_rel, camera_active, aim_active); + accumulate_deltas(mx_rel, my_rel, camera_active, aim_active); } -void getAimDeltas(float& out_yaw, float& out_pitch) { +void get_aim_deltas(float& out_yaw, float& out_pitch) { out_yaw = s_aim_yaw_rad; out_pitch = s_aim_pitch_rad; } -void getCameraDeltas(float& out_yaw, float& out_pitch) { +void get_camera_deltas(float& out_yaw, float& out_pitch) { out_yaw = 0.0f; out_pitch = 0.0f; @@ -178,26 +198,28 @@ void getCameraDeltas(float& out_yaw, float& out_pitch) { void handle_event(const SDL_Event& event) noexcept { switch (event.type) { + case SDL_EVENT_MOUSE_MOTION: + s_last_cursor_motion = Clock::now(); + break; case SDL_EVENT_WINDOW_FOCUS_LOST: - onFocusLost(); + on_focus_lost(); break; case SDL_EVENT_WINDOW_FOCUS_GAINED: - onFocusGained(); + on_focus_gained(); break; } } -void onFocusLost() { +void on_focus_lost() { SDL_Window* window = aurora::window::get_sdl_window(); if (window != nullptr) { - syncCaptureState(window, false); + sync_capture_state(window, false); } - s_idle_frames = 0; set_cursor_visible(true); } -void onFocusGained() { +void on_focus_gained() { SDL_Window* window = aurora::window::get_sdl_window(); - syncCaptureState(window, shouldCaptureMouse(window)); + sync_capture_state(window, should_capture_mouse(window)); } } // namespace dusk::mouse diff --git a/src/m_Do/m_Do_main.cpp b/src/m_Do/m_Do_main.cpp index 0d1e695524..0a190ed3dd 100644 --- a/src/m_Do/m_Do_main.cpp +++ b/src/m_Do/m_Do_main.cpp @@ -249,12 +249,12 @@ void main01(void) { goto eventsDone; case AURORA_PAUSED: dusk::audio::SetPaused(true); - dusk::mouse::onFocusLost(); + dusk::mouse::on_focus_lost(); break; case AURORA_UNPAUSED: dusk::audio::SetPaused(false); dusk::game_clock::reset_frame_timer(); - dusk::mouse::onFocusGained(); + dusk::mouse::on_focus_gained(); break; case AURORA_SDL_EVENT: dusk::mouse::handle_event(event->sdl);