feat: Implement gamepad support and audio control enhancements in input and audio services

This commit is contained in:
2026-01-05 06:32:34 +00:00
parent e7737c60f9
commit 5548d3b3ce
10 changed files with 406 additions and 185 deletions

View File

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