mirror of
https://github.com/johndoe6345789/SDL3CPlusPlus.git
synced 2026-05-02 09:34:58 +00:00
feat: Enhance input handling and window services
- Added mouse delta tracking to InputState for improved mouse movement feedback. - Introduced FPS mode toggle in GUI demo, allowing for relative mouse movement and cursor visibility control. - Implemented input service methods for mouse position, delta, wheel, and key/action state checks. - Updated SDL input service to handle relative mouse mode and mouse grabbing more effectively. - Enhanced window service with methods to manage mouse grabbing and cursor visibility. - Updated interface definitions for IInputService and IWindowService to include new functionalities.
This commit is contained in:
@@ -59,6 +59,8 @@ function InputState:new()
|
||||
local instance = {
|
||||
mouseX = 0,
|
||||
mouseY = 0,
|
||||
mouseDeltaX = 0,
|
||||
mouseDeltaY = 0,
|
||||
mouseDown = false,
|
||||
mouseDownPrevious = false,
|
||||
wheel = 0,
|
||||
@@ -68,10 +70,12 @@ function InputState:new()
|
||||
return setmetatable(instance, self)
|
||||
end
|
||||
|
||||
function InputState:setMouse(x, y, isDown)
|
||||
function InputState:setMouse(x, y, isDown, deltaX, deltaY)
|
||||
self.mouseDownPrevious = self.mouseDown
|
||||
self.mouseX = x
|
||||
self.mouseY = y
|
||||
self.mouseDeltaX = deltaX or 0
|
||||
self.mouseDeltaY = deltaY or 0
|
||||
self.mouseDown = isDown
|
||||
end
|
||||
|
||||
@@ -102,6 +106,8 @@ end
|
||||
function InputState:resetTransient()
|
||||
self.textInput = ""
|
||||
self.wheel = 0
|
||||
self.mouseDeltaX = 0
|
||||
self.mouseDeltaY = 0
|
||||
end
|
||||
|
||||
local Context = {}
|
||||
|
||||
@@ -20,6 +20,38 @@ local buttonStates = {
|
||||
|
||||
local statusMessage = 'Ready'
|
||||
local viewProjectionLogged = false
|
||||
local fpsMode = false
|
||||
local fpsToggleWasDown = false
|
||||
|
||||
local function setFpsMode(enabled)
|
||||
fpsMode = enabled
|
||||
if window_set_relative_mouse_mode then
|
||||
window_set_relative_mouse_mode(enabled)
|
||||
end
|
||||
if window_set_mouse_grabbed then
|
||||
window_set_mouse_grabbed(enabled)
|
||||
end
|
||||
if window_set_cursor_visible then
|
||||
window_set_cursor_visible(not enabled)
|
||||
end
|
||||
statusMessage = enabled and "FPS mode enabled" or "FPS mode disabled"
|
||||
log_trace("FPS mode toggled: %s", enabled and "on" or "off")
|
||||
end
|
||||
|
||||
local function updateFpsModeToggle()
|
||||
if not input_is_key_down then
|
||||
return
|
||||
end
|
||||
local down = input_is_key_down("F1")
|
||||
if down and not fpsToggleWasDown then
|
||||
setFpsMode(not fpsMode)
|
||||
end
|
||||
fpsToggleWasDown = down
|
||||
if fpsMode and window_get_mouse_grabbed and not window_get_mouse_grabbed() then
|
||||
fpsMode = false
|
||||
statusMessage = "FPS mode disabled"
|
||||
end
|
||||
end
|
||||
|
||||
local shader_variants = {
|
||||
default = {
|
||||
@@ -83,14 +115,37 @@ local function drawTestButtons()
|
||||
buttonStates.button2 and "ON" or "OFF",
|
||||
buttonStates.button3 and "ON" or "OFF",
|
||||
buttonStates.button4 and "ON" or "OFF")
|
||||
Gui.text(ctx, {x = 70, y = 320, width = 360, height = 30}, statesText, {
|
||||
Gui.text(ctx, {x = 70, y = 315, width = 360, height = 22}, statesText, {
|
||||
fontSize = 16,
|
||||
alignX = "center",
|
||||
color = {1.0, 0.8, 0.8, 1.0},
|
||||
})
|
||||
|
||||
local deltaX = input.mouseDeltaX or 0
|
||||
local deltaY = input.mouseDeltaY or 0
|
||||
Gui.text(ctx, {x = 70, y = 340, width = 360, height = 20},
|
||||
string.format("Mouse d: %.1f, %.1f", deltaX, deltaY), {
|
||||
fontSize = 14,
|
||||
alignX = "center",
|
||||
color = {0.85, 0.9, 0.85, 1.0},
|
||||
})
|
||||
|
||||
local grabState = window_get_mouse_grabbed and window_get_mouse_grabbed() or false
|
||||
local fpsLabel = fpsMode and "ON" or "OFF"
|
||||
Gui.text(ctx, {x = 70, y = 362, width = 360, height = 20},
|
||||
string.format("FPS Mode: %s (grab=%s, F1 toggle)", fpsLabel, grabState and "on" or "off"), {
|
||||
fontSize = 14,
|
||||
alignX = "center",
|
||||
color = {0.85, 0.85, 0.95, 1.0},
|
||||
})
|
||||
|
||||
if Gui.button(ctx, "fps_toggle", {x = 155, y = 385, width = 140, height = 28},
|
||||
fpsMode and "FPS: ON" or "FPS: OFF") then
|
||||
setFpsMode(not fpsMode)
|
||||
end
|
||||
|
||||
-- Reset button
|
||||
if Gui.button(ctx, "reset", {x = 175, y = 370, width = 100, height = 40}, "Reset") then
|
||||
if Gui.button(ctx, "reset", {x = 175, y = 418, width = 100, height = 28}, "Reset") then
|
||||
buttonStates.button1 = false
|
||||
buttonStates.button2 = false
|
||||
buttonStates.button3 = false
|
||||
@@ -123,14 +178,31 @@ function get_view_projection(aspect)
|
||||
end
|
||||
|
||||
function get_gui_commands()
|
||||
updateFpsModeToggle()
|
||||
ctx:beginFrame(input)
|
||||
drawTestButtons()
|
||||
Gui.cursor(ctx, input, {
|
||||
size = 16,
|
||||
thickness = 2,
|
||||
color = {1.0, 0.9, 0.2, 1.0},
|
||||
activeColor = {1.0, 0.35, 0.15, 1.0},
|
||||
})
|
||||
if fpsMode then
|
||||
local width, height = 1024, 768
|
||||
if window_get_size then
|
||||
local w, h = window_get_size()
|
||||
if type(w) == "number" and type(h) == "number" then
|
||||
width, height = w, h
|
||||
end
|
||||
end
|
||||
Gui.cursor(ctx, {mouseX = width * 0.5, mouseY = height * 0.5, mouseDown = input.mouseDown}, {
|
||||
size = 18,
|
||||
thickness = 2,
|
||||
color = {0.9, 0.95, 1.0, 1.0},
|
||||
activeColor = {1.0, 0.4, 0.2, 1.0},
|
||||
})
|
||||
else
|
||||
Gui.cursor(ctx, input, {
|
||||
size = 16,
|
||||
thickness = 2,
|
||||
color = {1.0, 0.9, 0.2, 1.0},
|
||||
activeColor = {1.0, 0.35, 0.15, 1.0},
|
||||
})
|
||||
end
|
||||
ctx:endFrame()
|
||||
return ctx:getCommands()
|
||||
end
|
||||
|
||||
@@ -262,6 +262,8 @@ void ServiceBasedApp::RegisterServices() {
|
||||
registry_.GetService<services::IMeshService>(),
|
||||
registry_.GetService<services::IAudioCommandService>(),
|
||||
registry_.GetService<services::IPhysicsBridgeService>(),
|
||||
registry_.GetService<services::IInputService>(),
|
||||
registry_.GetService<services::IWindowService>(),
|
||||
runtimeConfig_.luaDebug);
|
||||
|
||||
// Script-facing services
|
||||
|
||||
@@ -5,12 +5,64 @@
|
||||
|
||||
#include <btBulletDynamicsCommon.h>
|
||||
#include <lua.hpp>
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cctype>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace {
|
||||
bool TryParseMouseButtonName(const char* name, uint8_t& button) {
|
||||
if (!name) {
|
||||
return false;
|
||||
}
|
||||
std::string lower(name);
|
||||
std::transform(lower.begin(), lower.end(), lower.begin(),
|
||||
[](unsigned char ch) { return static_cast<char>(std::tolower(ch)); });
|
||||
if (lower == "left") {
|
||||
button = SDL_BUTTON_LEFT;
|
||||
return true;
|
||||
}
|
||||
if (lower == "right") {
|
||||
button = SDL_BUTTON_RIGHT;
|
||||
return true;
|
||||
}
|
||||
if (lower == "middle") {
|
||||
button = SDL_BUTTON_MIDDLE;
|
||||
return true;
|
||||
}
|
||||
if (lower == "x1" || lower == "extra1") {
|
||||
button = SDL_BUTTON_X1;
|
||||
return true;
|
||||
}
|
||||
if (lower == "x2" || lower == "extra2") {
|
||||
button = SDL_BUTTON_X2;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_Keycode ReadKeycodeFromLua(lua_State* L, int index, bool& ok) {
|
||||
ok = true;
|
||||
if (lua_isnumber(L, index)) {
|
||||
return static_cast<SDL_Keycode>(lua_tointeger(L, index));
|
||||
}
|
||||
if (lua_isstring(L, index)) {
|
||||
const char* name = lua_tostring(L, index);
|
||||
SDL_Keycode key = SDL_GetKeyFromName(name);
|
||||
if (key == SDLK_UNKNOWN) {
|
||||
ok = false;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
ok = false;
|
||||
return SDLK_UNKNOWN;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
ScriptEngineService::ScriptEngineService(const std::filesystem::path& scriptPath,
|
||||
@@ -18,11 +70,15 @@ ScriptEngineService::ScriptEngineService(const std::filesystem::path& scriptPath
|
||||
std::shared_ptr<IMeshService> meshService,
|
||||
std::shared_ptr<IAudioCommandService> audioCommandService,
|
||||
std::shared_ptr<IPhysicsBridgeService> physicsBridgeService,
|
||||
std::shared_ptr<IInputService> inputService,
|
||||
std::shared_ptr<IWindowService> windowService,
|
||||
bool debugEnabled)
|
||||
: logger_(std::move(logger)),
|
||||
meshService_(std::move(meshService)),
|
||||
audioCommandService_(std::move(audioCommandService)),
|
||||
physicsBridgeService_(std::move(physicsBridgeService)),
|
||||
inputService_(std::move(inputService)),
|
||||
windowService_(std::move(windowService)),
|
||||
scriptPath_(scriptPath),
|
||||
debugEnabled_(debugEnabled) {
|
||||
if (logger_) {
|
||||
@@ -31,7 +87,9 @@ ScriptEngineService::ScriptEngineService(const std::filesystem::path& scriptPath
|
||||
", debugEnabled=" + std::string(debugEnabled_ ? "true" : "false") +
|
||||
", meshService=" + std::string(meshService_ ? "set" : "null") +
|
||||
", audioCommandService=" + std::string(audioCommandService_ ? "set" : "null") +
|
||||
", physicsBridgeService=" + std::string(physicsBridgeService_ ? "set" : "null"));
|
||||
", physicsBridgeService=" + std::string(physicsBridgeService_ ? "set" : "null") +
|
||||
", inputService=" + std::string(inputService_ ? "set" : "null") +
|
||||
", windowService=" + std::string(windowService_ ? "set" : "null"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +114,8 @@ void ScriptEngineService::Initialize() {
|
||||
bindingContext_->meshService = meshService_;
|
||||
bindingContext_->audioCommandService = audioCommandService_;
|
||||
bindingContext_->physicsBridgeService = physicsBridgeService_;
|
||||
bindingContext_->inputService = inputService_;
|
||||
bindingContext_->windowService = windowService_;
|
||||
bindingContext_->logger = logger_;
|
||||
|
||||
luaState_ = luaL_newstate();
|
||||
@@ -160,6 +220,22 @@ void ScriptEngineService::RegisterBindings(lua_State* L) {
|
||||
bind("audio_play_background", &ScriptEngineService::AudioPlayBackground);
|
||||
bind("audio_play_sound", &ScriptEngineService::AudioPlaySound);
|
||||
bind("audio_stop_background", &ScriptEngineService::AudioStopBackground);
|
||||
bind("input_get_mouse_position", &ScriptEngineService::InputGetMousePosition);
|
||||
bind("input_get_mouse_delta", &ScriptEngineService::InputGetMouseDelta);
|
||||
bind("input_get_mouse_wheel", &ScriptEngineService::InputGetMouseWheel);
|
||||
bind("input_is_key_down", &ScriptEngineService::InputIsKeyDown);
|
||||
bind("input_is_action_down", &ScriptEngineService::InputIsActionDown);
|
||||
bind("input_is_mouse_down", &ScriptEngineService::InputIsMouseDown);
|
||||
bind("input_get_text", &ScriptEngineService::InputGetText);
|
||||
bind("window_get_size", &ScriptEngineService::WindowGetSize);
|
||||
bind("window_set_title", &ScriptEngineService::WindowSetTitle);
|
||||
bind("window_is_minimized", &ScriptEngineService::WindowIsMinimized);
|
||||
bind("window_set_mouse_grabbed", &ScriptEngineService::WindowSetMouseGrabbed);
|
||||
bind("window_get_mouse_grabbed", &ScriptEngineService::WindowGetMouseGrabbed);
|
||||
bind("window_set_relative_mouse_mode", &ScriptEngineService::WindowSetRelativeMouseMode);
|
||||
bind("window_get_relative_mouse_mode", &ScriptEngineService::WindowGetRelativeMouseMode);
|
||||
bind("window_set_cursor_visible", &ScriptEngineService::WindowSetCursorVisible);
|
||||
bind("window_is_cursor_visible", &ScriptEngineService::WindowIsCursorVisible);
|
||||
}
|
||||
|
||||
int ScriptEngineService::LoadMeshFromFile(lua_State* L) {
|
||||
@@ -384,6 +460,222 @@ int ScriptEngineService::AudioStopBackground(lua_State* L) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ScriptEngineService::InputGetMousePosition(lua_State* L) {
|
||||
auto* context = static_cast<LuaBindingContext*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
if (!context || !context->inputService) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "Input service not available");
|
||||
return 2;
|
||||
}
|
||||
auto [x, y] = context->inputService->GetMousePosition();
|
||||
lua_pushnumber(L, x);
|
||||
lua_pushnumber(L, y);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int ScriptEngineService::InputGetMouseDelta(lua_State* L) {
|
||||
auto* context = static_cast<LuaBindingContext*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
if (!context || !context->inputService) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "Input service not available");
|
||||
return 2;
|
||||
}
|
||||
const auto& state = context->inputService->GetState();
|
||||
lua_pushnumber(L, state.mouseDeltaX);
|
||||
lua_pushnumber(L, state.mouseDeltaY);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int ScriptEngineService::InputGetMouseWheel(lua_State* L) {
|
||||
auto* context = static_cast<LuaBindingContext*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
if (!context || !context->inputService) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "Input service not available");
|
||||
return 2;
|
||||
}
|
||||
const auto& state = context->inputService->GetState();
|
||||
lua_pushnumber(L, state.mouseWheelDeltaX);
|
||||
lua_pushnumber(L, state.mouseWheelDeltaY);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int ScriptEngineService::InputIsKeyDown(lua_State* L) {
|
||||
auto* context = static_cast<LuaBindingContext*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
if (!context || !context->inputService) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "Input service not available");
|
||||
return 2;
|
||||
}
|
||||
bool ok = false;
|
||||
SDL_Keycode key = ReadKeycodeFromLua(L, 1, ok);
|
||||
if (!ok) {
|
||||
lua_pushboolean(L, 0);
|
||||
return 1;
|
||||
}
|
||||
lua_pushboolean(L, context->inputService->IsKeyPressed(key));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ScriptEngineService::InputIsActionDown(lua_State* L) {
|
||||
auto* context = static_cast<LuaBindingContext*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
if (!context || !context->inputService) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "Input service not available");
|
||||
return 2;
|
||||
}
|
||||
const char* action = luaL_checkstring(L, 1);
|
||||
lua_pushboolean(L, context->inputService->IsActionPressed(action));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ScriptEngineService::InputIsMouseDown(lua_State* L) {
|
||||
auto* context = static_cast<LuaBindingContext*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
if (!context || !context->inputService) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "Input service not available");
|
||||
return 2;
|
||||
}
|
||||
uint8_t button = SDL_BUTTON_LEFT;
|
||||
if (lua_isnumber(L, 1)) {
|
||||
button = static_cast<uint8_t>(lua_tointeger(L, 1));
|
||||
} else if (lua_isstring(L, 1)) {
|
||||
const char* name = lua_tostring(L, 1);
|
||||
if (!TryParseMouseButtonName(name, button)) {
|
||||
lua_pushboolean(L, 0);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
lua_pushboolean(L, 0);
|
||||
return 1;
|
||||
}
|
||||
lua_pushboolean(L, context->inputService->IsMouseButtonPressed(button));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ScriptEngineService::InputGetText(lua_State* L) {
|
||||
auto* context = static_cast<LuaBindingContext*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
if (!context || !context->inputService) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "Input service not available");
|
||||
return 2;
|
||||
}
|
||||
const auto& state = context->inputService->GetState();
|
||||
lua_pushstring(L, state.textInput.c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ScriptEngineService::WindowGetSize(lua_State* L) {
|
||||
auto* context = static_cast<LuaBindingContext*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
if (!context || !context->windowService) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "Window service not available");
|
||||
return 2;
|
||||
}
|
||||
auto [width, height] = context->windowService->GetSize();
|
||||
lua_pushinteger(L, static_cast<lua_Integer>(width));
|
||||
lua_pushinteger(L, static_cast<lua_Integer>(height));
|
||||
return 2;
|
||||
}
|
||||
|
||||
int ScriptEngineService::WindowSetTitle(lua_State* L) {
|
||||
auto* context = static_cast<LuaBindingContext*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
if (!context || !context->windowService) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "Window service not available");
|
||||
return 2;
|
||||
}
|
||||
const char* title = luaL_checkstring(L, 1);
|
||||
context->windowService->SetTitle(title);
|
||||
lua_pushboolean(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ScriptEngineService::WindowIsMinimized(lua_State* L) {
|
||||
auto* context = static_cast<LuaBindingContext*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
if (!context || !context->windowService) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "Window service not available");
|
||||
return 2;
|
||||
}
|
||||
lua_pushboolean(L, context->windowService->IsMinimized());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ScriptEngineService::WindowSetMouseGrabbed(lua_State* L) {
|
||||
auto* context = static_cast<LuaBindingContext*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
if (!context || !context->windowService) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "Window service not available");
|
||||
return 2;
|
||||
}
|
||||
bool grabbed = lua_toboolean(L, 1);
|
||||
context->windowService->SetMouseGrabbed(grabbed);
|
||||
lua_pushboolean(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ScriptEngineService::WindowGetMouseGrabbed(lua_State* L) {
|
||||
auto* context = static_cast<LuaBindingContext*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
if (!context || !context->windowService) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "Window service not available");
|
||||
return 2;
|
||||
}
|
||||
lua_pushboolean(L, context->windowService->IsMouseGrabbed());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ScriptEngineService::WindowSetRelativeMouseMode(lua_State* L) {
|
||||
auto* context = static_cast<LuaBindingContext*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
if (!context || !context->windowService) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "Window service not available");
|
||||
return 2;
|
||||
}
|
||||
bool enabled = lua_toboolean(L, 1);
|
||||
context->windowService->SetRelativeMouseMode(enabled);
|
||||
if (context->inputService) {
|
||||
context->inputService->SetRelativeMouseMode(enabled);
|
||||
}
|
||||
lua_pushboolean(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ScriptEngineService::WindowGetRelativeMouseMode(lua_State* L) {
|
||||
auto* context = static_cast<LuaBindingContext*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
if (!context || !context->windowService) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "Window service not available");
|
||||
return 2;
|
||||
}
|
||||
lua_pushboolean(L, context->windowService->IsRelativeMouseMode());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ScriptEngineService::WindowSetCursorVisible(lua_State* L) {
|
||||
auto* context = static_cast<LuaBindingContext*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
if (!context || !context->windowService) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "Window service not available");
|
||||
return 2;
|
||||
}
|
||||
bool visible = lua_toboolean(L, 1);
|
||||
context->windowService->SetCursorVisible(visible);
|
||||
lua_pushboolean(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ScriptEngineService::WindowIsCursorVisible(lua_State* L) {
|
||||
auto* context = static_cast<LuaBindingContext*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
if (!context || !context->windowService) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "Window service not available");
|
||||
return 2;
|
||||
}
|
||||
lua_pushboolean(L, context->windowService->IsCursorVisible());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ScriptEngineService::GlmMatrixFromTransform(lua_State* L) {
|
||||
auto* context = static_cast<LuaBindingContext*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
auto logger = context ? context->logger : nullptr;
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include "../interfaces/i_audio_command_service.hpp"
|
||||
#include "../interfaces/i_mesh_service.hpp"
|
||||
#include "../interfaces/i_physics_bridge_service.hpp"
|
||||
#include "../interfaces/i_input_service.hpp"
|
||||
#include "../interfaces/i_window_service.hpp"
|
||||
#include "../interfaces/i_logger.hpp"
|
||||
#include "../../di/lifecycle.hpp"
|
||||
#include <filesystem>
|
||||
@@ -25,6 +27,8 @@ public:
|
||||
std::shared_ptr<IMeshService> meshService,
|
||||
std::shared_ptr<IAudioCommandService> audioCommandService,
|
||||
std::shared_ptr<IPhysicsBridgeService> physicsBridgeService,
|
||||
std::shared_ptr<IInputService> inputService,
|
||||
std::shared_ptr<IWindowService> windowService,
|
||||
bool debugEnabled = false);
|
||||
~ScriptEngineService() override;
|
||||
|
||||
@@ -47,6 +51,8 @@ private:
|
||||
std::shared_ptr<IMeshService> meshService;
|
||||
std::shared_ptr<IAudioCommandService> audioCommandService;
|
||||
std::shared_ptr<IPhysicsBridgeService> physicsBridgeService;
|
||||
std::shared_ptr<IInputService> inputService;
|
||||
std::shared_ptr<IWindowService> windowService;
|
||||
std::shared_ptr<ILogger> logger;
|
||||
};
|
||||
|
||||
@@ -59,11 +65,29 @@ private:
|
||||
static int AudioPlaySound(lua_State* L);
|
||||
static int AudioStopBackground(lua_State* L);
|
||||
static int GlmMatrixFromTransform(lua_State* L);
|
||||
static int InputGetMousePosition(lua_State* L);
|
||||
static int InputGetMouseDelta(lua_State* L);
|
||||
static int InputGetMouseWheel(lua_State* L);
|
||||
static int InputIsKeyDown(lua_State* L);
|
||||
static int InputIsActionDown(lua_State* L);
|
||||
static int InputIsMouseDown(lua_State* L);
|
||||
static int InputGetText(lua_State* L);
|
||||
static int WindowGetSize(lua_State* L);
|
||||
static int WindowSetTitle(lua_State* L);
|
||||
static int WindowIsMinimized(lua_State* L);
|
||||
static int WindowSetMouseGrabbed(lua_State* L);
|
||||
static int WindowGetMouseGrabbed(lua_State* L);
|
||||
static int WindowSetRelativeMouseMode(lua_State* L);
|
||||
static int WindowGetRelativeMouseMode(lua_State* L);
|
||||
static int WindowSetCursorVisible(lua_State* L);
|
||||
static int WindowIsCursorVisible(lua_State* L);
|
||||
|
||||
std::shared_ptr<ILogger> logger_;
|
||||
std::shared_ptr<IMeshService> meshService_;
|
||||
std::shared_ptr<IAudioCommandService> audioCommandService_;
|
||||
std::shared_ptr<IPhysicsBridgeService> physicsBridgeService_;
|
||||
std::shared_ptr<IInputService> inputService_;
|
||||
std::shared_ptr<IWindowService> windowService_;
|
||||
std::filesystem::path scriptPath_;
|
||||
std::filesystem::path scriptDirectory_;
|
||||
bool debugEnabled_ = false;
|
||||
|
||||
@@ -66,6 +66,10 @@ SdlInputService::SdlInputService(std::shared_ptr<events::IEventBus> eventBus,
|
||||
OnTextInput(e);
|
||||
});
|
||||
|
||||
eventBus_->Subscribe(events::EventType::WindowResized, [this](const events::Event& e) {
|
||||
OnWindowResized(e);
|
||||
});
|
||||
|
||||
eventBus_->Subscribe(events::EventType::WindowFocusGained, [this](const events::Event& e) {
|
||||
OnWindowFocusGained(e);
|
||||
});
|
||||
@@ -86,9 +90,23 @@ SdlInputService::SdlInputService(std::shared_ptr<events::IEventBus> eventBus,
|
||||
const auto& mouseGrabConfig = configService_->GetMouseGrabConfig();
|
||||
mouseGrabGatesLook_ = mouseGrabConfig.enabled &&
|
||||
(mouseGrabConfig.grabOnClick || mouseGrabConfig.startGrabbed);
|
||||
mouseRelativeMode_ = mouseGrabConfig.relativeMode;
|
||||
guiWindowWidth_ = configService_->GetWindowWidth();
|
||||
guiWindowHeight_ = configService_->GetWindowHeight();
|
||||
if (guiWindowWidth_ > 0 && guiWindowHeight_ > 0) {
|
||||
guiCursorX_ = static_cast<float>(guiWindowWidth_) * 0.5f;
|
||||
guiCursorY_ = static_cast<float>(guiWindowHeight_) * 0.5f;
|
||||
state_.mouseX = guiCursorX_;
|
||||
state_.mouseY = guiCursorY_;
|
||||
guiInputSnapshot_.mouseX = guiCursorX_;
|
||||
guiInputSnapshot_.mouseY = guiCursorY_;
|
||||
}
|
||||
if (logger_) {
|
||||
logger_->Trace("SdlInputService", "SdlInputService",
|
||||
"mouseGrabGatesLook=" + std::string(mouseGrabGatesLook_ ? "true" : "false"));
|
||||
"mouseGrabGatesLook=" + std::string(mouseGrabGatesLook_ ? "true" : "false") +
|
||||
", relativeMode=" + std::string(mouseRelativeMode_ ? "true" : "false") +
|
||||
", guiWindow=" + std::to_string(guiWindowWidth_) + "x" +
|
||||
std::to_string(guiWindowHeight_));
|
||||
}
|
||||
}
|
||||
BuildActionKeyMapping();
|
||||
@@ -118,15 +136,10 @@ void SdlInputService::ProcessEvent(const SDL_Event& event) {
|
||||
break;
|
||||
|
||||
case SDL_EVENT_MOUSE_MOTION:
|
||||
state_.mouseX = event.motion.x;
|
||||
state_.mouseY = event.motion.y;
|
||||
// GUI input processing
|
||||
guiInputSnapshot_.mouseX = static_cast<float>(event.motion.x);
|
||||
guiInputSnapshot_.mouseY = static_cast<float>(event.motion.y);
|
||||
if (ShouldCaptureMouseDelta()) {
|
||||
guiInputSnapshot_.mouseDeltaX += static_cast<float>(event.motion.xrel);
|
||||
guiInputSnapshot_.mouseDeltaY += static_cast<float>(event.motion.yrel);
|
||||
}
|
||||
UpdateMousePosition(static_cast<float>(event.motion.x),
|
||||
static_cast<float>(event.motion.y),
|
||||
static_cast<float>(event.motion.xrel),
|
||||
static_cast<float>(event.motion.yrel));
|
||||
break;
|
||||
|
||||
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
||||
@@ -168,6 +181,8 @@ void SdlInputService::ResetFrameState() {
|
||||
logger_->Trace("SdlInputService", "ResetFrameState");
|
||||
}
|
||||
// Reset per-frame state
|
||||
state_.mouseDeltaX = 0.0f;
|
||||
state_.mouseDeltaY = 0.0f;
|
||||
state_.mouseWheelDeltaX = 0.0f;
|
||||
state_.mouseWheelDeltaY = 0.0f;
|
||||
state_.textInput.clear();
|
||||
@@ -195,6 +210,14 @@ bool SdlInputService::IsMouseButtonPressed(uint8_t button) const {
|
||||
return state_.mouseButtonsPressed.count(button) > 0;
|
||||
}
|
||||
|
||||
bool SdlInputService::IsActionPressed(const std::string& action) const {
|
||||
if (logger_) {
|
||||
logger_->Trace("SdlInputService", "IsActionPressed",
|
||||
"action=" + action);
|
||||
}
|
||||
return IsActionKeyPressed(action);
|
||||
}
|
||||
|
||||
std::pair<float, float> SdlInputService::GetMousePosition() const {
|
||||
if (logger_) {
|
||||
logger_->Trace("SdlInputService", "GetMousePosition");
|
||||
@@ -202,6 +225,21 @@ std::pair<float, float> SdlInputService::GetMousePosition() const {
|
||||
return {state_.mouseX, state_.mouseY};
|
||||
}
|
||||
|
||||
void SdlInputService::SetRelativeMouseMode(bool enabled) {
|
||||
if (logger_) {
|
||||
logger_->Trace("SdlInputService", "SetRelativeMouseMode",
|
||||
"enabled=" + std::string(enabled ? "true" : "false"));
|
||||
}
|
||||
mouseRelativeMode_ = enabled;
|
||||
}
|
||||
|
||||
bool SdlInputService::IsRelativeMouseMode() const {
|
||||
if (logger_) {
|
||||
logger_->Trace("SdlInputService", "IsRelativeMouseMode");
|
||||
}
|
||||
return mouseRelativeMode_;
|
||||
}
|
||||
|
||||
void SdlInputService::OnKeyPressed(const events::Event& event) {
|
||||
const auto& keyEvent = event.GetData<events::KeyEvent>();
|
||||
if (logger_) {
|
||||
@@ -237,14 +275,7 @@ void SdlInputService::OnMouseMoved(const events::Event& event) {
|
||||
", deltaX=" + std::to_string(mouseEvent.deltaX) +
|
||||
", deltaY=" + std::to_string(mouseEvent.deltaY));
|
||||
}
|
||||
state_.mouseX = mouseEvent.x;
|
||||
state_.mouseY = mouseEvent.y;
|
||||
guiInputSnapshot_.mouseX = mouseEvent.x;
|
||||
guiInputSnapshot_.mouseY = mouseEvent.y;
|
||||
if (ShouldCaptureMouseDelta()) {
|
||||
guiInputSnapshot_.mouseDeltaX += mouseEvent.deltaX;
|
||||
guiInputSnapshot_.mouseDeltaY += mouseEvent.deltaY;
|
||||
}
|
||||
UpdateMousePosition(mouseEvent.x, mouseEvent.y, mouseEvent.deltaX, mouseEvent.deltaY);
|
||||
}
|
||||
|
||||
void SdlInputService::OnMouseButtonPressed(const events::Event& event) {
|
||||
@@ -300,6 +331,18 @@ void SdlInputService::OnTextInput(const events::Event& event) {
|
||||
guiInputSnapshot_.textInput += textEvent.text;
|
||||
}
|
||||
|
||||
void SdlInputService::OnWindowResized(const events::Event& event) {
|
||||
const auto& resized = event.GetData<events::WindowResizedEvent>();
|
||||
guiWindowWidth_ = resized.width;
|
||||
guiWindowHeight_ = resized.height;
|
||||
ClampGuiCursor();
|
||||
if (logger_) {
|
||||
logger_->Trace("SdlInputService", "OnWindowResized",
|
||||
"width=" + std::to_string(guiWindowWidth_) +
|
||||
", height=" + std::to_string(guiWindowHeight_));
|
||||
}
|
||||
}
|
||||
|
||||
void SdlInputService::OnWindowFocusGained(const events::Event& event) {
|
||||
(void)event;
|
||||
windowFocused_ = true;
|
||||
@@ -530,6 +573,46 @@ bool SdlInputService::ShouldCaptureMouseDelta() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void SdlInputService::UpdateMousePosition(float x, float y, float deltaX, float deltaY) {
|
||||
if (mouseRelativeMode_ && mouseGrabbed_) {
|
||||
guiCursorX_ += deltaX;
|
||||
guiCursorY_ += deltaY;
|
||||
ClampGuiCursor();
|
||||
state_.mouseX = guiCursorX_;
|
||||
state_.mouseY = guiCursorY_;
|
||||
guiInputSnapshot_.mouseX = guiCursorX_;
|
||||
guiInputSnapshot_.mouseY = guiCursorY_;
|
||||
if (logger_ && !relativeCursorLogged_) {
|
||||
logger_->Trace("SdlInputService", "UpdateMousePosition",
|
||||
"relativeCursor=true, startX=" + std::to_string(guiCursorX_) +
|
||||
", startY=" + std::to_string(guiCursorY_));
|
||||
relativeCursorLogged_ = true;
|
||||
}
|
||||
} else {
|
||||
state_.mouseX = x;
|
||||
state_.mouseY = y;
|
||||
guiInputSnapshot_.mouseX = x;
|
||||
guiInputSnapshot_.mouseY = y;
|
||||
guiCursorX_ = x;
|
||||
guiCursorY_ = y;
|
||||
}
|
||||
|
||||
if (ShouldCaptureMouseDelta()) {
|
||||
guiInputSnapshot_.mouseDeltaX += deltaX;
|
||||
guiInputSnapshot_.mouseDeltaY += deltaY;
|
||||
}
|
||||
state_.mouseDeltaX += deltaX;
|
||||
state_.mouseDeltaY += deltaY;
|
||||
}
|
||||
|
||||
void SdlInputService::ClampGuiCursor() {
|
||||
if (guiWindowWidth_ == 0 || guiWindowHeight_ == 0) {
|
||||
return;
|
||||
}
|
||||
guiCursorX_ = std::clamp(guiCursorX_, 0.0f, static_cast<float>(guiWindowWidth_ - 1));
|
||||
guiCursorY_ = std::clamp(guiCursorY_, 0.0f, static_cast<float>(guiWindowHeight_ - 1));
|
||||
}
|
||||
|
||||
void SdlInputService::EnsureGamepadSubsystem() {
|
||||
uint32_t initialized = SDL_WasInit(0);
|
||||
if ((initialized & SDL_INIT_GAMEPAD) != 0) {
|
||||
|
||||
@@ -41,7 +41,10 @@ public:
|
||||
}
|
||||
bool IsKeyPressed(SDL_Keycode key) const override;
|
||||
bool IsMouseButtonPressed(uint8_t button) const override;
|
||||
bool IsActionPressed(const std::string& action) const override;
|
||||
std::pair<float, float> GetMousePosition() const override;
|
||||
void SetRelativeMouseMode(bool enabled) override;
|
||||
bool IsRelativeMouseMode() const override;
|
||||
void SetGuiScriptService(IGuiScriptService* guiScriptService) override;
|
||||
void UpdateGuiInput() override;
|
||||
|
||||
@@ -56,6 +59,12 @@ private:
|
||||
bool windowFocused_ = true;
|
||||
bool mouseGrabbed_ = false;
|
||||
bool mouseGrabGatesLook_ = false;
|
||||
bool mouseRelativeMode_ = false;
|
||||
float guiCursorX_ = 0.0f;
|
||||
float guiCursorY_ = 0.0f;
|
||||
uint32_t guiWindowWidth_ = 0;
|
||||
uint32_t guiWindowHeight_ = 0;
|
||||
bool relativeCursorLogged_ = false;
|
||||
SDL_GamepadButton musicToggleButton_ = SDL_GAMEPAD_BUTTON_START;
|
||||
SDL_GamepadButton dpadUpButton_ = SDL_GAMEPAD_BUTTON_DPAD_UP;
|
||||
SDL_GamepadButton dpadDownButton_ = SDL_GAMEPAD_BUTTON_DPAD_DOWN;
|
||||
@@ -78,6 +87,7 @@ private:
|
||||
void OnMouseButtonReleased(const events::Event& event);
|
||||
void OnMouseWheel(const events::Event& event);
|
||||
void OnTextInput(const events::Event& event);
|
||||
void OnWindowResized(const events::Event& event);
|
||||
void OnWindowFocusGained(const events::Event& event);
|
||||
void OnWindowFocusLost(const events::Event& event);
|
||||
void OnMouseGrabChanged(const events::Event& event);
|
||||
@@ -89,6 +99,8 @@ private:
|
||||
void ApplyKeyMapping(SDL_Keycode key, bool isDown);
|
||||
bool IsActionKeyPressed(const std::string& action) const;
|
||||
bool ShouldCaptureMouseDelta() const;
|
||||
void UpdateMousePosition(float x, float y, float deltaX, float deltaY);
|
||||
void ClampGuiCursor();
|
||||
|
||||
// GUI key mapping (extracted from old Sdl3App)
|
||||
static const std::unordered_map<SDL_Keycode, std::string> kGuiKeyNames;
|
||||
|
||||
@@ -215,7 +215,7 @@ void SdlWindowService::CreateWindow(const WindowConfig& config) {
|
||||
mouseGrabbed_ = false;
|
||||
ConfigureMouseGrabBindings();
|
||||
if (mouseGrabConfig_.enabled && mouseGrabConfig_.startGrabbed) {
|
||||
ApplyMouseGrab(true);
|
||||
ApplyMouseGrab(true, false);
|
||||
}
|
||||
|
||||
logger_->TraceVariable("window_", reinterpret_cast<void*>(window_));
|
||||
@@ -228,7 +228,7 @@ void SdlWindowService::DestroyWindow() {
|
||||
"windowIsNull=" + std::string(window_ ? "false" : "true"));
|
||||
if (window_) {
|
||||
if (mouseGrabbed_) {
|
||||
ApplyMouseGrab(false);
|
||||
ApplyMouseGrab(false, false);
|
||||
}
|
||||
SDL_StopTextInput(window_);
|
||||
SDL_DestroyWindow(window_);
|
||||
@@ -259,6 +259,81 @@ bool SdlWindowService::IsMinimized() const {
|
||||
return (flags & SDL_WINDOW_MINIMIZED) != 0;
|
||||
}
|
||||
|
||||
void SdlWindowService::SetMouseGrabbed(bool grabbed) {
|
||||
if (logger_) {
|
||||
logger_->Trace("SdlWindowService", "SetMouseGrabbed",
|
||||
"grabbed=" + std::string(grabbed ? "true" : "false"));
|
||||
}
|
||||
if (!window_) {
|
||||
return;
|
||||
}
|
||||
if (!mouseGrabConfig_.enabled) {
|
||||
mouseGrabConfig_.enabled = true;
|
||||
}
|
||||
ApplyMouseGrab(grabbed, true);
|
||||
}
|
||||
|
||||
bool SdlWindowService::IsMouseGrabbed() const {
|
||||
if (logger_) {
|
||||
logger_->Trace("SdlWindowService", "IsMouseGrabbed");
|
||||
}
|
||||
return mouseGrabbed_;
|
||||
}
|
||||
|
||||
void SdlWindowService::SetRelativeMouseMode(bool enabled) {
|
||||
if (logger_) {
|
||||
logger_->Trace("SdlWindowService", "SetRelativeMouseMode",
|
||||
"enabled=" + std::string(enabled ? "true" : "false"));
|
||||
}
|
||||
mouseGrabConfig_.relativeMode = enabled;
|
||||
if (!window_) {
|
||||
return;
|
||||
}
|
||||
if (!SDL_SetWindowRelativeMouseMode(window_, enabled) && logger_) {
|
||||
logger_->Error("SdlWindowService: " +
|
||||
BuildSdlErrorMessage("SDL_SetWindowRelativeMouseMode failed", platformService_));
|
||||
}
|
||||
if (mouseGrabbed_ && mouseGrabConfig_.enabled) {
|
||||
ApplyMouseGrab(mouseGrabbed_, true);
|
||||
}
|
||||
}
|
||||
|
||||
bool SdlWindowService::IsRelativeMouseMode() const {
|
||||
if (logger_) {
|
||||
logger_->Trace("SdlWindowService", "IsRelativeMouseMode");
|
||||
}
|
||||
return mouseGrabConfig_.relativeMode;
|
||||
}
|
||||
|
||||
void SdlWindowService::SetCursorVisible(bool visible) {
|
||||
if (logger_) {
|
||||
logger_->Trace("SdlWindowService", "SetCursorVisible",
|
||||
"visible=" + std::string(visible ? "true" : "false"));
|
||||
}
|
||||
if (!window_) {
|
||||
return;
|
||||
}
|
||||
mouseGrabConfig_.hideCursor = !visible;
|
||||
bool cursorResult = visible ? SDL_ShowCursor() : SDL_HideCursor();
|
||||
if (!cursorResult && logger_) {
|
||||
logger_->Error("SdlWindowService: " +
|
||||
BuildSdlErrorMessage(visible ? "SDL_ShowCursor failed" : "SDL_HideCursor failed",
|
||||
platformService_));
|
||||
} else {
|
||||
cursorVisible_ = visible;
|
||||
}
|
||||
if (mouseGrabbed_ && mouseGrabConfig_.enabled) {
|
||||
ApplyMouseGrab(mouseGrabbed_, true);
|
||||
}
|
||||
}
|
||||
|
||||
bool SdlWindowService::IsCursorVisible() const {
|
||||
if (logger_) {
|
||||
logger_->Trace("SdlWindowService", "IsCursorVisible");
|
||||
}
|
||||
return cursorVisible_;
|
||||
}
|
||||
|
||||
void SdlWindowService::PollEvents() {
|
||||
logger_->Trace("SdlWindowService", "PollEvents");
|
||||
SDL_Event event;
|
||||
@@ -273,7 +348,7 @@ void SdlWindowService::PollEvents() {
|
||||
logger_->Info("SdlWindowService: Mouse grab triggered by click (button=" +
|
||||
std::to_string(event.button.button) + ")");
|
||||
}
|
||||
ApplyMouseGrab(true);
|
||||
ApplyMouseGrab(true, false);
|
||||
}
|
||||
|
||||
// Handle release separately (doesn't suppress event)
|
||||
@@ -284,7 +359,7 @@ void SdlWindowService::PollEvents() {
|
||||
if (logger_) {
|
||||
logger_->Info("SdlWindowService: Mouse grab released by escape key");
|
||||
}
|
||||
ApplyMouseGrab(false);
|
||||
ApplyMouseGrab(false, false);
|
||||
}
|
||||
|
||||
// Only publish event if it's not the grab-triggering click
|
||||
@@ -348,7 +423,7 @@ void SdlWindowService::HandleMouseGrabEvent(const SDL_Event& sdlEvent) {
|
||||
if (mouseGrabConfig_.grabOnClick &&
|
||||
sdlEvent.type == SDL_EVENT_MOUSE_BUTTON_DOWN &&
|
||||
sdlEvent.button.button == grabMouseButton_) {
|
||||
ApplyMouseGrab(true);
|
||||
ApplyMouseGrab(true, false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -356,15 +431,15 @@ void SdlWindowService::HandleMouseGrabEvent(const SDL_Event& sdlEvent) {
|
||||
sdlEvent.type == SDL_EVENT_KEY_DOWN &&
|
||||
sdlEvent.key.key == releaseKey_ &&
|
||||
!sdlEvent.key.repeat) {
|
||||
ApplyMouseGrab(false);
|
||||
ApplyMouseGrab(false, false);
|
||||
}
|
||||
}
|
||||
|
||||
void SdlWindowService::ApplyMouseGrab(bool grabbed) {
|
||||
void SdlWindowService::ApplyMouseGrab(bool grabbed, bool force) {
|
||||
if (!window_ || !mouseGrabConfig_.enabled) {
|
||||
return;
|
||||
}
|
||||
if (mouseGrabbed_ == grabbed) {
|
||||
if (!force && mouseGrabbed_ == grabbed) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -400,6 +475,16 @@ void SdlWindowService::ApplyMouseGrab(bool grabbed) {
|
||||
logger_->Error("SdlWindowService: " +
|
||||
BuildSdlErrorMessage(grabbed ? "SDL_HideCursor failed" : "SDL_ShowCursor failed",
|
||||
platformService_));
|
||||
} else {
|
||||
cursorVisible_ = !grabbed;
|
||||
}
|
||||
} else {
|
||||
bool cursorResult = SDL_ShowCursor();
|
||||
if (!cursorResult && logger_) {
|
||||
logger_->Error("SdlWindowService: " +
|
||||
BuildSdlErrorMessage("SDL_ShowCursor failed", platformService_));
|
||||
} else {
|
||||
cursorVisible_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,6 +53,12 @@ public:
|
||||
void PollEvents() override;
|
||||
void SetTitle(const std::string& title) override;
|
||||
bool IsMinimized() const override;
|
||||
void SetMouseGrabbed(bool grabbed) override;
|
||||
bool IsMouseGrabbed() const override;
|
||||
void SetRelativeMouseMode(bool enabled) override;
|
||||
bool IsRelativeMouseMode() const override;
|
||||
void SetCursorVisible(bool visible) override;
|
||||
bool IsCursorVisible() const override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<ILogger> logger_;
|
||||
@@ -63,6 +69,7 @@ private:
|
||||
bool initialized_ = false;
|
||||
MouseGrabConfig mouseGrabConfig_{};
|
||||
bool mouseGrabbed_ = false;
|
||||
bool cursorVisible_ = true;
|
||||
uint8_t grabMouseButton_ = SDL_BUTTON_LEFT;
|
||||
SDL_Keycode releaseKey_ = SDLK_ESCAPE;
|
||||
|
||||
@@ -70,7 +77,7 @@ private:
|
||||
void PublishEvent(const SDL_Event& sdlEvent);
|
||||
double GetCurrentTime() const;
|
||||
void HandleMouseGrabEvent(const SDL_Event& sdlEvent);
|
||||
void ApplyMouseGrab(bool grabbed);
|
||||
void ApplyMouseGrab(bool grabbed, bool force);
|
||||
void ConfigureMouseGrabBindings();
|
||||
};
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@ class IGuiScriptService;
|
||||
struct InputState {
|
||||
float mouseX = 0.0f;
|
||||
float mouseY = 0.0f;
|
||||
float mouseDeltaX = 0.0f;
|
||||
float mouseDeltaY = 0.0f;
|
||||
float mouseWheelDeltaX = 0.0f;
|
||||
float mouseWheelDeltaY = 0.0f;
|
||||
std::unordered_set<SDL_Keycode> keysPressed;
|
||||
@@ -74,6 +76,14 @@ public:
|
||||
*/
|
||||
virtual bool IsMouseButtonPressed(uint8_t button) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Check if an action is currently pressed based on input bindings.
|
||||
*
|
||||
* @param action The action name to check
|
||||
* @return true if the action is pressed, false otherwise
|
||||
*/
|
||||
virtual bool IsActionPressed(const std::string& action) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Get the current mouse position.
|
||||
*
|
||||
@@ -81,6 +91,22 @@ public:
|
||||
*/
|
||||
virtual std::pair<float, float> GetMousePosition() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Set whether mouse input should be treated as relative motion.
|
||||
*
|
||||
* This updates internal cursor tracking for script usage.
|
||||
*
|
||||
* @param enabled true for relative mode, false for absolute
|
||||
*/
|
||||
virtual void SetRelativeMouseMode(bool enabled) = 0;
|
||||
|
||||
/**
|
||||
* @brief Check whether mouse input is treated as relative motion.
|
||||
*
|
||||
* @return true if relative mode is enabled, false otherwise
|
||||
*/
|
||||
virtual bool IsRelativeMouseMode() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Set the GUI script service for GUI input processing.
|
||||
*
|
||||
|
||||
@@ -92,6 +92,48 @@ public:
|
||||
* @return true if minimized, false otherwise
|
||||
*/
|
||||
virtual bool IsMinimized() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Set mouse grab (capture) state.
|
||||
*
|
||||
* @param grabbed true to grab, false to release
|
||||
*/
|
||||
virtual void SetMouseGrabbed(bool grabbed) = 0;
|
||||
|
||||
/**
|
||||
* @brief Check if the mouse is currently grabbed.
|
||||
*
|
||||
* @return true if grabbed, false otherwise
|
||||
*/
|
||||
virtual bool IsMouseGrabbed() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Enable or disable relative mouse mode.
|
||||
*
|
||||
* @param enabled true for relative mode, false for absolute
|
||||
*/
|
||||
virtual void SetRelativeMouseMode(bool enabled) = 0;
|
||||
|
||||
/**
|
||||
* @brief Check if relative mouse mode is enabled.
|
||||
*
|
||||
* @return true if enabled, false otherwise
|
||||
*/
|
||||
virtual bool IsRelativeMouseMode() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Show or hide the OS cursor.
|
||||
*
|
||||
* @param visible true to show, false to hide
|
||||
*/
|
||||
virtual void SetCursorVisible(bool visible) = 0;
|
||||
|
||||
/**
|
||||
* @brief Check if the OS cursor is visible.
|
||||
*
|
||||
* @return true if visible, false otherwise
|
||||
*/
|
||||
virtual bool IsCursorVisible() const = 0;
|
||||
};
|
||||
|
||||
} // namespace sdl3cpp::services
|
||||
|
||||
Reference in New Issue
Block a user