feat: Add mouse grab state change event and related handling in input services

This commit is contained in:
2026-01-05 07:57:44 +00:00
parent 2a8a36adab
commit ffd99798ed
4 changed files with 96 additions and 4 deletions

View File

@@ -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.
*/

View File

@@ -66,10 +66,31 @@ SdlInputService::SdlInputService(std::shared_ptr<events::IEventBus> 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<float>(event.motion.x);
guiInputSnapshot_.mouseY = static_cast<float>(event.motion.y);
guiInputSnapshot_.mouseDeltaX += static_cast<float>(event.motion.xrel);
guiInputSnapshot_.mouseDeltaY += static_cast<float>(event.motion.yrel);
if (ShouldCaptureMouseDelta()) {
guiInputSnapshot_.mouseDeltaX += static_cast<float>(event.motion.xrel);
guiInputSnapshot_.mouseDeltaY += static_cast<float>(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<events::MouseGrabEvent>();
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) {

View File

@@ -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<SDL_Keycode, std::string> kGuiKeyNames;

View File

@@ -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");
}