From ffd99798edb08217a40c480980afea15403815fb Mon Sep 17 00:00:00 2001 From: johndoe6345789 Date: Mon, 5 Jan 2026 07:57:44 +0000 Subject: [PATCH] feat: Add mouse grab state change event and related handling in input services --- src/events/event_types.hpp | 8 +++ src/services/impl/sdl_input_service.cpp | 74 ++++++++++++++++++++++-- src/services/impl/sdl_input_service.hpp | 7 +++ src/services/impl/sdl_window_service.cpp | 11 ++++ 4 files changed, 96 insertions(+), 4 deletions(-) diff --git a/src/events/event_types.hpp b/src/events/event_types.hpp index f38da30..cf739d2 100644 --- a/src/events/event_types.hpp +++ b/src/events/event_types.hpp @@ -32,6 +32,7 @@ enum class EventType { MouseButtonPressed, MouseButtonReleased, MouseWheel, + MouseGrabChanged, TextInput, // Rendering events @@ -147,6 +148,13 @@ struct MouseWheelEvent { bool flipped; }; +/** + * @brief Mouse grab state change event data. + */ +struct MouseGrabEvent { + bool grabbed; +}; + /** * @brief Text input event data. */ diff --git a/src/services/impl/sdl_input_service.cpp b/src/services/impl/sdl_input_service.cpp index eac0760..c027aff 100644 --- a/src/services/impl/sdl_input_service.cpp +++ b/src/services/impl/sdl_input_service.cpp @@ -66,10 +66,31 @@ SdlInputService::SdlInputService(std::shared_ptr eventBus, OnTextInput(e); }); + eventBus_->Subscribe(events::EventType::WindowFocusGained, [this](const events::Event& e) { + OnWindowFocusGained(e); + }); + + eventBus_->Subscribe(events::EventType::WindowFocusLost, [this](const events::Event& e) { + OnWindowFocusLost(e); + }); + + eventBus_->Subscribe(events::EventType::MouseGrabChanged, [this](const events::Event& e) { + OnMouseGrabChanged(e); + }); + if (logger_) { logger_->Trace("SdlInputService", "SdlInputService", "eventBus=" + std::string(eventBus_ ? "set" : "null")); } + if (configService_) { + const auto& mouseGrabConfig = configService_->GetMouseGrabConfig(); + mouseGrabGatesLook_ = mouseGrabConfig.enabled && + (mouseGrabConfig.grabOnClick || mouseGrabConfig.startGrabbed); + if (logger_) { + logger_->Trace("SdlInputService", "SdlInputService", + "mouseGrabGatesLook=" + std::string(mouseGrabGatesLook_ ? "true" : "false")); + } + } BuildActionKeyMapping(); EnsureGamepadSubsystem(); } @@ -102,8 +123,10 @@ void SdlInputService::ProcessEvent(const SDL_Event& event) { // GUI input processing guiInputSnapshot_.mouseX = static_cast(event.motion.x); guiInputSnapshot_.mouseY = static_cast(event.motion.y); - guiInputSnapshot_.mouseDeltaX += static_cast(event.motion.xrel); - guiInputSnapshot_.mouseDeltaY += static_cast(event.motion.yrel); + if (ShouldCaptureMouseDelta()) { + guiInputSnapshot_.mouseDeltaX += static_cast(event.motion.xrel); + guiInputSnapshot_.mouseDeltaY += static_cast(event.motion.yrel); + } break; case SDL_EVENT_MOUSE_BUTTON_DOWN: @@ -218,8 +241,10 @@ void SdlInputService::OnMouseMoved(const events::Event& event) { state_.mouseY = mouseEvent.y; guiInputSnapshot_.mouseX = mouseEvent.x; guiInputSnapshot_.mouseY = mouseEvent.y; - guiInputSnapshot_.mouseDeltaX += mouseEvent.deltaX; - guiInputSnapshot_.mouseDeltaY += mouseEvent.deltaY; + if (ShouldCaptureMouseDelta()) { + guiInputSnapshot_.mouseDeltaX += mouseEvent.deltaX; + guiInputSnapshot_.mouseDeltaY += mouseEvent.deltaY; + } } void SdlInputService::OnMouseButtonPressed(const events::Event& event) { @@ -275,6 +300,37 @@ void SdlInputService::OnTextInput(const events::Event& event) { guiInputSnapshot_.textInput += textEvent.text; } +void SdlInputService::OnWindowFocusGained(const events::Event& event) { + (void)event; + windowFocused_ = true; + if (logger_) { + logger_->Trace("SdlInputService", "OnWindowFocusGained", "windowFocused=true"); + } +} + +void SdlInputService::OnWindowFocusLost(const events::Event& event) { + (void)event; + windowFocused_ = false; + guiInputSnapshot_.mouseDeltaX = 0.0f; + guiInputSnapshot_.mouseDeltaY = 0.0f; + if (logger_) { + logger_->Trace("SdlInputService", "OnWindowFocusLost", "windowFocused=false"); + } +} + +void SdlInputService::OnMouseGrabChanged(const events::Event& event) { + const auto& grabEvent = event.GetData(); + mouseGrabbed_ = grabEvent.grabbed; + if (!mouseGrabbed_) { + guiInputSnapshot_.mouseDeltaX = 0.0f; + guiInputSnapshot_.mouseDeltaY = 0.0f; + } + if (logger_) { + logger_->Trace("SdlInputService", "OnMouseGrabChanged", + "grabbed=" + std::string(mouseGrabbed_ ? "true" : "false")); + } +} + void SdlInputService::BuildActionKeyMapping() { actionKeyNames_.clear(); gamepadButtonActions_.clear(); @@ -462,6 +518,16 @@ bool SdlInputService::IsActionKeyPressed(const std::string& action) const { return false; } +bool SdlInputService::ShouldCaptureMouseDelta() const { + if (!windowFocused_) { + return false; + } + if (mouseGrabGatesLook_) { + return mouseGrabbed_; + } + return true; +} + void SdlInputService::EnsureGamepadSubsystem() { uint32_t initialized = SDL_WasInit(0); if ((initialized & SDL_INIT_GAMEPAD) != 0) { diff --git a/src/services/impl/sdl_input_service.hpp b/src/services/impl/sdl_input_service.hpp index 7050a1a..7ac78c5 100644 --- a/src/services/impl/sdl_input_service.hpp +++ b/src/services/impl/sdl_input_service.hpp @@ -53,6 +53,9 @@ private: GuiInputSnapshot guiInputSnapshot_; IGuiScriptService* guiScriptService_ = nullptr; SDL_Gamepad* gamepad_ = nullptr; + bool windowFocused_ = true; + bool mouseGrabbed_ = false; + bool mouseGrabGatesLook_ = false; SDL_GamepadButton musicToggleButton_ = SDL_GAMEPAD_BUTTON_START; SDL_GamepadButton dpadUpButton_ = SDL_GAMEPAD_BUTTON_DPAD_UP; SDL_GamepadButton dpadDownButton_ = SDL_GAMEPAD_BUTTON_DPAD_DOWN; @@ -75,6 +78,9 @@ private: void OnMouseButtonReleased(const events::Event& event); void OnMouseWheel(const events::Event& event); void OnTextInput(const events::Event& event); + void OnWindowFocusGained(const events::Event& event); + void OnWindowFocusLost(const events::Event& event); + void OnMouseGrabChanged(const events::Event& event); void EnsureGamepadSubsystem(); void TryOpenGamepad(); void CloseGamepad(); @@ -82,6 +88,7 @@ private: void BuildActionKeyMapping(); void ApplyKeyMapping(SDL_Keycode key, bool isDown); bool IsActionKeyPressed(const std::string& action) const; + bool ShouldCaptureMouseDelta() const; // GUI key mapping (extracted from old Sdl3App) static const std::unordered_map kGuiKeyNames; diff --git a/src/services/impl/sdl_window_service.cpp b/src/services/impl/sdl_window_service.cpp index 5e1d5f2..e25de35 100644 --- a/src/services/impl/sdl_window_service.cpp +++ b/src/services/impl/sdl_window_service.cpp @@ -378,6 +378,17 @@ void SdlWindowService::ApplyMouseGrab(bool grabbed) { if (success) { mouseGrabbed_ = grabbed; + if (eventBus_) { + eventBus_->Publish(events::Event{ + events::EventType::MouseGrabChanged, + GetCurrentTime(), + events::MouseGrabEvent{grabbed} + }); + } + if (logger_) { + logger_->Trace("SdlWindowService", "ApplyMouseGrab", + "mouseGrabChanged=true, grabbed=" + std::string(grabbed ? "true" : "false")); + } } else if (logger_) { logger_->Trace("SdlWindowService", "ApplyMouseGrab", "grabChangeFailed=true"); }