mirror of
https://github.com/johndoe6345789/SDL3CPlusPlus.git
synced 2026-05-01 00:55:07 +00:00
feat: Implement gamepad support and audio control enhancements in input and audio services
This commit is contained in:
@@ -72,4 +72,21 @@ bool AudioCommandService::QueueAudioCommand(AudioCommandType type,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AudioCommandService::StopBackground(std::string& error) {
|
||||
if (logger_) {
|
||||
logger_->Trace("AudioCommandService", "StopBackground");
|
||||
}
|
||||
if (!audioService_) {
|
||||
error = "Audio service not available";
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
audioService_->StopBackground();
|
||||
} catch (const std::exception& ex) {
|
||||
error = ex.what();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
|
||||
@@ -21,6 +21,7 @@ public:
|
||||
const std::string& path,
|
||||
bool loop,
|
||||
std::string& error) override;
|
||||
bool StopBackground(std::string& error) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<IConfigService> configService_;
|
||||
|
||||
@@ -219,6 +219,20 @@ void GuiScriptService::UpdateGuiInput(const GuiInputSnapshot& input) {
|
||||
lua_pushnumber(L, input.wheel);
|
||||
lua_call(L, 2, 0);
|
||||
|
||||
lua_getfield(L, stateIndex, "setGamepad");
|
||||
if (lua_isfunction(L, -1)) {
|
||||
lua_pushvalue(L, stateIndex);
|
||||
lua_pushboolean(L, input.gamepadConnected);
|
||||
lua_pushnumber(L, input.gamepadLeftX);
|
||||
lua_pushnumber(L, input.gamepadLeftY);
|
||||
lua_pushnumber(L, input.gamepadRightX);
|
||||
lua_pushnumber(L, input.gamepadRightY);
|
||||
lua_pushboolean(L, input.gamepadTogglePressed);
|
||||
lua_call(L, 7, 0);
|
||||
} else {
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
if (!input.textInput.empty()) {
|
||||
lua_getfield(L, stateIndex, "addTextInput");
|
||||
lua_pushvalue(L, stateIndex);
|
||||
|
||||
@@ -159,6 +159,7 @@ void ScriptEngineService::RegisterBindings(lua_State* L) {
|
||||
bind("glm_matrix_from_transform", &ScriptEngineService::GlmMatrixFromTransform);
|
||||
bind("audio_play_background", &ScriptEngineService::AudioPlayBackground);
|
||||
bind("audio_play_sound", &ScriptEngineService::AudioPlaySound);
|
||||
bind("audio_stop_background", &ScriptEngineService::AudioStopBackground);
|
||||
}
|
||||
|
||||
int ScriptEngineService::LoadMeshFromFile(lua_State* L) {
|
||||
@@ -360,6 +361,29 @@ int ScriptEngineService::AudioPlaySound(lua_State* L) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ScriptEngineService::AudioStopBackground(lua_State* L) {
|
||||
auto* context = static_cast<LuaBindingContext*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
auto logger = context ? context->logger : nullptr;
|
||||
if (!context || !context->audioCommandService) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "Audio service not available");
|
||||
return 2;
|
||||
}
|
||||
if (logger) {
|
||||
logger->Trace("ScriptEngineService", "AudioStopBackground");
|
||||
}
|
||||
|
||||
std::string error;
|
||||
if (!context->audioCommandService->StopBackground(error)) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, error.c_str());
|
||||
return 2;
|
||||
}
|
||||
|
||||
lua_pushboolean(L, 1);
|
||||
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;
|
||||
|
||||
@@ -57,6 +57,7 @@ private:
|
||||
static int PhysicsGetTransform(lua_State* L);
|
||||
static int AudioPlayBackground(lua_State* L);
|
||||
static int AudioPlaySound(lua_State* L);
|
||||
static int AudioStopBackground(lua_State* L);
|
||||
static int GlmMatrixFromTransform(lua_State* L);
|
||||
|
||||
std::shared_ptr<ILogger> logger_;
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
#include "sdl_input_service.hpp"
|
||||
|
||||
namespace {
|
||||
constexpr float kAxisPositiveMax = static_cast<float>(SDL_JOYSTICK_AXIS_MAX);
|
||||
constexpr float kAxisNegativeMax = static_cast<float>(-SDL_JOYSTICK_AXIS_MIN);
|
||||
|
||||
float NormalizeAxis(Sint16 value) {
|
||||
if (value >= 0) {
|
||||
float normalized = static_cast<float>(value) / kAxisPositiveMax;
|
||||
return normalized > 1.0f ? 1.0f : normalized;
|
||||
}
|
||||
float normalized = static_cast<float>(value) / kAxisNegativeMax;
|
||||
return normalized < -1.0f ? -1.0f : normalized;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
// GUI key mapping extracted from old Sdl3App
|
||||
@@ -9,7 +23,8 @@ const std::unordered_map<SDL_Keycode, std::string> SdlInputService::kGuiKeyNames
|
||||
{SDLK_DELETE, "delete"}, {SDLK_RETURN, "return"}, {SDLK_TAB, "tab"},
|
||||
{SDLK_ESCAPE, "escape"}, {SDLK_LCTRL, "lctrl"}, {SDLK_RCTRL, "rctrl"},
|
||||
{SDLK_LSHIFT, "lshift"}, {SDLK_RSHIFT, "rshift"}, {SDLK_LALT, "lalt"},
|
||||
{SDLK_RALT, "ralt"}
|
||||
{SDLK_RALT, "ralt"}, {SDLK_w, "w"}, {SDLK_a, "a"}, {SDLK_s, "s"},
|
||||
{SDLK_d, "d"}, {SDLK_m, "m"}
|
||||
};
|
||||
|
||||
SdlInputService::SdlInputService(std::shared_ptr<events::IEventBus> eventBus, std::shared_ptr<ILogger> logger)
|
||||
@@ -48,6 +63,11 @@ SdlInputService::SdlInputService(std::shared_ptr<events::IEventBus> eventBus, st
|
||||
logger_->Trace("SdlInputService", "SdlInputService",
|
||||
"eventBus=" + std::string(eventBus_ ? "set" : "null"));
|
||||
}
|
||||
EnsureGamepadSubsystem();
|
||||
}
|
||||
|
||||
SdlInputService::~SdlInputService() {
|
||||
CloseGamepad();
|
||||
}
|
||||
|
||||
void SdlInputService::ProcessEvent(const SDL_Event& event) {
|
||||
@@ -169,6 +189,10 @@ void SdlInputService::OnKeyPressed(const events::Event& event) {
|
||||
", repeat=" + std::string(keyEvent.repeat ? "true" : "false"));
|
||||
}
|
||||
state_.keysPressed.insert(keyEvent.key);
|
||||
auto it = kGuiKeyNames.find(keyEvent.key);
|
||||
if (it != kGuiKeyNames.end()) {
|
||||
guiInputSnapshot_.keyStates[it->second] = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SdlInputService::OnKeyReleased(const events::Event& event) {
|
||||
@@ -181,6 +205,10 @@ void SdlInputService::OnKeyReleased(const events::Event& event) {
|
||||
", repeat=" + std::string(keyEvent.repeat ? "true" : "false"));
|
||||
}
|
||||
state_.keysPressed.erase(keyEvent.key);
|
||||
auto it = kGuiKeyNames.find(keyEvent.key);
|
||||
if (it != kGuiKeyNames.end()) {
|
||||
guiInputSnapshot_.keyStates[it->second] = false;
|
||||
}
|
||||
}
|
||||
|
||||
void SdlInputService::OnMouseMoved(const events::Event& event) {
|
||||
@@ -194,6 +222,8 @@ void SdlInputService::OnMouseMoved(const events::Event& event) {
|
||||
}
|
||||
state_.mouseX = mouseEvent.x;
|
||||
state_.mouseY = mouseEvent.y;
|
||||
guiInputSnapshot_.mouseX = mouseEvent.x;
|
||||
guiInputSnapshot_.mouseY = mouseEvent.y;
|
||||
}
|
||||
|
||||
void SdlInputService::OnMouseButtonPressed(const events::Event& event) {
|
||||
@@ -206,6 +236,9 @@ void SdlInputService::OnMouseButtonPressed(const events::Event& event) {
|
||||
", y=" + std::to_string(buttonEvent.y));
|
||||
}
|
||||
state_.mouseButtonsPressed.insert(buttonEvent.button);
|
||||
if (buttonEvent.button == SDL_BUTTON_LEFT) {
|
||||
guiInputSnapshot_.mouseDown = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SdlInputService::OnMouseButtonReleased(const events::Event& event) {
|
||||
@@ -218,6 +251,9 @@ void SdlInputService::OnMouseButtonReleased(const events::Event& event) {
|
||||
", y=" + std::to_string(buttonEvent.y));
|
||||
}
|
||||
state_.mouseButtonsPressed.erase(buttonEvent.button);
|
||||
if (buttonEvent.button == SDL_BUTTON_LEFT) {
|
||||
guiInputSnapshot_.mouseDown = false;
|
||||
}
|
||||
}
|
||||
|
||||
void SdlInputService::OnMouseWheel(const events::Event& event) {
|
||||
@@ -230,6 +266,7 @@ void SdlInputService::OnMouseWheel(const events::Event& event) {
|
||||
}
|
||||
state_.mouseWheelDeltaX += wheelEvent.deltaX;
|
||||
state_.mouseWheelDeltaY += wheelEvent.deltaY;
|
||||
guiInputSnapshot_.wheel += wheelEvent.deltaY;
|
||||
}
|
||||
|
||||
void SdlInputService::OnTextInput(const events::Event& event) {
|
||||
@@ -239,6 +276,91 @@ void SdlInputService::OnTextInput(const events::Event& event) {
|
||||
"text=" + textEvent.text);
|
||||
}
|
||||
state_.textInput += textEvent.text;
|
||||
guiInputSnapshot_.textInput += textEvent.text;
|
||||
}
|
||||
|
||||
void SdlInputService::EnsureGamepadSubsystem() {
|
||||
uint32_t initialized = SDL_WasInit(0);
|
||||
if ((initialized & SDL_INIT_GAMEPAD) != 0) {
|
||||
return;
|
||||
}
|
||||
bool result = false;
|
||||
if (initialized == 0) {
|
||||
result = SDL_Init(SDL_INIT_GAMEPAD);
|
||||
} else {
|
||||
result = SDL_InitSubSystem(SDL_INIT_GAMEPAD);
|
||||
}
|
||||
if (!result && logger_) {
|
||||
logger_->Error("SdlInputService: SDL_INIT_GAMEPAD failed: " + std::string(SDL_GetError()));
|
||||
}
|
||||
}
|
||||
|
||||
void SdlInputService::TryOpenGamepad() {
|
||||
if (gamepad_) {
|
||||
return;
|
||||
}
|
||||
EnsureGamepadSubsystem();
|
||||
int count = 0;
|
||||
SDL_JoystickID* gamepads = SDL_GetGamepads(&count);
|
||||
if (!gamepads || count <= 0) {
|
||||
if (gamepads) {
|
||||
SDL_free(gamepads);
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (!SDL_IsGamepad(gamepads[i])) {
|
||||
continue;
|
||||
}
|
||||
gamepad_ = SDL_OpenGamepad(gamepads[i]);
|
||||
if (gamepad_) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
SDL_free(gamepads);
|
||||
}
|
||||
|
||||
void SdlInputService::CloseGamepad() {
|
||||
if (gamepad_) {
|
||||
SDL_CloseGamepad(gamepad_);
|
||||
gamepad_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void SdlInputService::UpdateGamepadSnapshot() {
|
||||
if (!gamepad_) {
|
||||
TryOpenGamepad();
|
||||
}
|
||||
|
||||
if (!gamepad_) {
|
||||
guiInputSnapshot_.gamepadConnected = false;
|
||||
guiInputSnapshot_.gamepadLeftX = 0.0f;
|
||||
guiInputSnapshot_.gamepadLeftY = 0.0f;
|
||||
guiInputSnapshot_.gamepadRightX = 0.0f;
|
||||
guiInputSnapshot_.gamepadRightY = 0.0f;
|
||||
guiInputSnapshot_.gamepadTogglePressed = false;
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_JoystickConnectionState connection = SDL_GetGamepadConnectionState(gamepad_);
|
||||
if (connection == SDL_JOYSTICK_CONNECTION_INVALID) {
|
||||
CloseGamepad();
|
||||
guiInputSnapshot_.gamepadConnected = false;
|
||||
guiInputSnapshot_.gamepadLeftX = 0.0f;
|
||||
guiInputSnapshot_.gamepadLeftY = 0.0f;
|
||||
guiInputSnapshot_.gamepadRightX = 0.0f;
|
||||
guiInputSnapshot_.gamepadRightY = 0.0f;
|
||||
guiInputSnapshot_.gamepadTogglePressed = false;
|
||||
return;
|
||||
}
|
||||
|
||||
guiInputSnapshot_.gamepadConnected = true;
|
||||
guiInputSnapshot_.gamepadLeftX = NormalizeAxis(SDL_GetGamepadAxis(gamepad_, SDL_GAMEPAD_AXIS_LEFTX));
|
||||
guiInputSnapshot_.gamepadLeftY = NormalizeAxis(SDL_GetGamepadAxis(gamepad_, SDL_GAMEPAD_AXIS_LEFTY));
|
||||
guiInputSnapshot_.gamepadRightX = NormalizeAxis(SDL_GetGamepadAxis(gamepad_, SDL_GAMEPAD_AXIS_RIGHTX));
|
||||
guiInputSnapshot_.gamepadRightY = NormalizeAxis(SDL_GetGamepadAxis(gamepad_, SDL_GAMEPAD_AXIS_RIGHTY));
|
||||
guiInputSnapshot_.gamepadTogglePressed =
|
||||
SDL_GetGamepadButton(gamepad_, SDL_GAMEPAD_BUTTON_START);
|
||||
}
|
||||
|
||||
void SdlInputService::SetGuiScriptService(IGuiScriptService* guiScriptService) {
|
||||
@@ -255,6 +377,7 @@ void SdlInputService::UpdateGuiInput() {
|
||||
"guiScriptServiceIsNull=" + std::string(guiScriptService_ ? "false" : "true"));
|
||||
}
|
||||
if (guiScriptService_) {
|
||||
UpdateGamepadSnapshot();
|
||||
guiScriptService_->UpdateGuiInput(guiInputSnapshot_);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ public:
|
||||
* @param eventBus Event bus to subscribe to
|
||||
*/
|
||||
explicit SdlInputService(std::shared_ptr<events::IEventBus> eventBus, std::shared_ptr<ILogger> logger);
|
||||
~SdlInputService() override;
|
||||
|
||||
// IInputService interface
|
||||
void ProcessEvent(const SDL_Event& event) override;
|
||||
@@ -46,6 +47,7 @@ private:
|
||||
InputState state_;
|
||||
GuiInputSnapshot guiInputSnapshot_;
|
||||
IGuiScriptService* guiScriptService_ = nullptr;
|
||||
SDL_Gamepad* gamepad_ = nullptr;
|
||||
|
||||
// Event bus listeners
|
||||
void OnKeyPressed(const events::Event& event);
|
||||
@@ -55,6 +57,10 @@ private:
|
||||
void OnMouseButtonReleased(const events::Event& event);
|
||||
void OnMouseWheel(const events::Event& event);
|
||||
void OnTextInput(const events::Event& event);
|
||||
void EnsureGamepadSubsystem();
|
||||
void TryOpenGamepad();
|
||||
void CloseGamepad();
|
||||
void UpdateGamepadSnapshot();
|
||||
|
||||
// GUI key mapping (extracted from old Sdl3App)
|
||||
static const std::unordered_map<SDL_Keycode, std::string> kGuiKeyNames;
|
||||
|
||||
Reference in New Issue
Block a user