yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
sdl3_input_backend.cc
Go to the documentation of this file.
2
3#include "imgui/imgui.h"
4#include "util/log.h"
5
6namespace yaze {
7namespace emu {
8namespace input {
9
11
13
15 if (initialized_) {
16 LOG_WARN("InputBackend", "SDL3 backend already initialized");
17 return true;
18 }
19
20 config_ = config;
21
23
24 // Initialize gamepad if enabled
27 if (gamepads_[0]) {
28 LOG_INFO("InputBackend", "SDL3 Gamepad connected for player 1");
29 }
30 }
31
32 initialized_ = true;
33 LOG_INFO("InputBackend", "SDL3 Input Backend initialized");
34 return true;
35}
36
38 if (initialized_) {
39 // Close all gamepads
40 for (int i = 0; i < 4; ++i) {
41 if (gamepads_[i]) {
43 gamepads_[i] = nullptr;
44 }
45 }
46 initialized_ = false;
47 LOG_INFO("InputBackend", "SDL3 Input Backend shut down");
48 }
49}
50
52 if (!initialized_) return ControllerState{};
53
54 ControllerState state;
55
57 // Continuous polling mode (for games)
58 // SDL3: SDL_GetKeyboardState returns const bool* instead of const Uint8*
59 platform::KeyboardState keyboard_state = SDL_GetKeyboardState(nullptr);
60
61 // Respect ImGui text capture unless explicitly overridden
62 ImGuiIO& io = ImGui::GetIO();
63 if (io.WantTextInput && !config_.ignore_imgui_text_input) {
64 return ControllerState{};
65 }
66
67 // Map keyboard to SNES buttons using SDL3 API
68 // Use platform::IsKeyPressed helper to handle bool* vs Uint8* difference
69 state.SetButton(
71 platform::IsKeyPressed(keyboard_state,
72 SDL_GetScancodeFromKey(config_.key_b, nullptr)));
73 state.SetButton(
75 platform::IsKeyPressed(keyboard_state,
76 SDL_GetScancodeFromKey(config_.key_y, nullptr)));
77 state.SetButton(
80 keyboard_state,
81 SDL_GetScancodeFromKey(config_.key_select, nullptr)));
82 state.SetButton(
85 keyboard_state,
86 SDL_GetScancodeFromKey(config_.key_start, nullptr)));
87 state.SetButton(
90 keyboard_state, SDL_GetScancodeFromKey(config_.key_up, nullptr)));
91 state.SetButton(
94 keyboard_state, SDL_GetScancodeFromKey(config_.key_down, nullptr)));
95 state.SetButton(
98 keyboard_state, SDL_GetScancodeFromKey(config_.key_left, nullptr)));
99 state.SetButton(
102 keyboard_state,
103 SDL_GetScancodeFromKey(config_.key_right, nullptr)));
104 state.SetButton(
106 platform::IsKeyPressed(keyboard_state,
107 SDL_GetScancodeFromKey(config_.key_a, nullptr)));
108 state.SetButton(
110 platform::IsKeyPressed(keyboard_state,
111 SDL_GetScancodeFromKey(config_.key_x, nullptr)));
112 state.SetButton(
114 platform::IsKeyPressed(keyboard_state,
115 SDL_GetScancodeFromKey(config_.key_l, nullptr)));
116 state.SetButton(
118 platform::IsKeyPressed(keyboard_state,
119 SDL_GetScancodeFromKey(config_.key_r, nullptr)));
120
121 // Poll gamepad if enabled
123 PollGamepad(state, player);
124 }
125 } else {
126 // Event-based mode (use cached event state)
127 state = event_state_;
128 }
129
130 return state;
131}
132
134 int gamepad_index = (player > 0 && player <= 4) ? player - 1 : 0;
135 platform::GamepadHandle gamepad = gamepads_[gamepad_index];
136
137 if (!gamepad) return;
138
139 // Map gamepad buttons to SNES buttons using SDL3 Gamepad API
140 // SDL3 uses SDL_GAMEPAD_BUTTON_* with directional naming (SOUTH, EAST, etc.)
142 state.SetButton(SnesButton::A, true);
143 }
145 state.SetButton(SnesButton::B, true);
146 }
148 state.SetButton(SnesButton::X, true);
149 }
151 state.SetButton(SnesButton::Y, true);
152 }
154 state.SetButton(SnesButton::L, true);
155 }
156 if (platform::GetGamepadButton(gamepad,
158 state.SetButton(SnesButton::R, true);
159 }
161 state.SetButton(SnesButton::START, true);
162 }
164 state.SetButton(SnesButton::SELECT, true);
165 }
166
167 // D-pad buttons
169 state.SetButton(SnesButton::UP, true);
170 }
172 state.SetButton(SnesButton::DOWN, true);
173 }
175 state.SetButton(SnesButton::LEFT, true);
176 }
178 state.SetButton(SnesButton::RIGHT, true);
179 }
180
181 // Left analog stick for D-pad (with deadzone)
182 int16_t axis_x = platform::GetGamepadAxis(gamepad, platform::kGamepadAxisLeftX);
183 int16_t axis_y = platform::GetGamepadAxis(gamepad, platform::kGamepadAxisLeftY);
184
185 if (axis_x < -kAxisDeadzone) {
186 state.SetButton(SnesButton::LEFT, true);
187 } else if (axis_x > kAxisDeadzone) {
188 state.SetButton(SnesButton::RIGHT, true);
189 }
190
191 if (axis_y < -kAxisDeadzone) {
192 state.SetButton(SnesButton::UP, true);
193 } else if (axis_y > kAxisDeadzone) {
194 state.SetButton(SnesButton::DOWN, true);
195 }
196}
197
199 if (!initialized_ || !event) return;
200
201 SDL_Event* sdl_event = static_cast<SDL_Event*>(event);
202
203 // Handle keyboard events
204 // SDL3: Uses SDL_EVENT_KEY_DOWN/UP instead of SDL_KEYDOWN/UP
205 // SDL3: Uses event.key.key instead of event.key.keysym.sym
206 if (sdl_event->type == platform::kEventKeyDown) {
208 } else if (sdl_event->type == platform::kEventKeyUp) {
210 }
211
212 // Handle gamepad connection/disconnection events
213 HandleGamepadEvent(*sdl_event);
214}
215
216void SDL3InputBackend::HandleGamepadEvent(const SDL_Event& event) {
217#ifdef YAZE_USE_SDL3
218 // SDL3 uses SDL_EVENT_GAMEPAD_ADDED/REMOVED
219 if (event.type == SDL_EVENT_GAMEPAD_ADDED) {
220 // Try to open the gamepad if we have a free slot
221 for (int i = 0; i < 4; ++i) {
222 if (!gamepads_[i]) {
223 gamepads_[i] = SDL_OpenGamepad(event.gdevice.which);
224 if (gamepads_[i]) {
225 LOG_INFO("InputBackend", "SDL3 Gamepad connected for player %d", i + 1);
226 }
227 break;
228 }
229 }
230 } else if (event.type == SDL_EVENT_GAMEPAD_REMOVED) {
231 // Find and close the disconnected gamepad
232 for (int i = 0; i < 4; ++i) {
233 if (gamepads_[i] &&
234 SDL_GetGamepadID(gamepads_[i]) == event.gdevice.which) {
235 SDL_CloseGamepad(gamepads_[i]);
236 gamepads_[i] = nullptr;
237 LOG_INFO("InputBackend", "SDL3 Gamepad disconnected for player %d", i + 1);
238 break;
239 }
240 }
241 }
242#else
243 // SDL2 uses SDL_CONTROLLERDEVICEADDED/REMOVED
244 if (event.type == SDL_CONTROLLERDEVICEADDED) {
245 for (int i = 0; i < 4; ++i) {
246 if (!gamepads_[i]) {
247 gamepads_[i] = platform::OpenGamepad(event.cdevice.which);
248 if (gamepads_[i]) {
249 LOG_INFO("InputBackend", "Gamepad connected for player " +
250 std::to_string(i + 1));
251 }
252 break;
253 }
254 }
255 } else if (event.type == SDL_CONTROLLERDEVICEREMOVED) {
256 for (int i = 0; i < 4; ++i) {
257 if (gamepads_[i] && SDL_JoystickInstanceID(
258 SDL_GameControllerGetJoystick(gamepads_[i])) ==
259 event.cdevice.which) {
261 gamepads_[i] = nullptr;
262 LOG_INFO("InputBackend", "Gamepad disconnected for player " +
263 std::to_string(i + 1));
264 break;
265 }
266 }
267 }
268#endif
269}
270
271void SDL3InputBackend::UpdateEventState(int keycode, bool pressed) {
272 // Map keycode to button and update event state
273 if (keycode == config_.key_a)
275 else if (keycode == config_.key_b)
277 else if (keycode == config_.key_x)
279 else if (keycode == config_.key_y)
281 else if (keycode == config_.key_l)
283 else if (keycode == config_.key_r)
285 else if (keycode == config_.key_start)
287 else if (keycode == config_.key_select)
289 else if (keycode == config_.key_up)
291 else if (keycode == config_.key_down)
293 else if (keycode == config_.key_left)
295 else if (keycode == config_.key_right)
297}
298
300
302 config_ = config;
303
304 // Re-initialize gamepad if gamepad settings changed
305 if (config_.enable_gamepad && !gamepads_[0]) {
307 if (gamepads_[0]) {
308 LOG_INFO("InputBackend", "SDL3 Gamepad connected for player 1");
309 }
310 } else if (!config_.enable_gamepad && gamepads_[0]) {
312 gamepads_[0] = nullptr;
313 }
314}
315
316std::string SDL3InputBackend::GetBackendName() const { return "SDL3"; }
317
319
320} // namespace input
321} // namespace emu
322} // namespace yaze
void ProcessEvent(void *event) override
Process platform-specific events (optional)
void SetConfig(const InputConfig &config) override
Update configuration (hot-reload)
static constexpr int16_t kAxisDeadzone
platform::GamepadHandle gamepads_[4]
void PollGamepad(ControllerState &state, int player)
Poll gamepad state and update controller state.
InputConfig GetConfig() const override
Get current configuration.
std::string GetBackendName() const override
Get backend name for debugging.
void HandleGamepadEvent(const SDL_Event &event)
Handle gamepad connection/disconnection.
void Shutdown() override
Shutdown the input backend.
bool Initialize(const InputConfig &config) override
Initialize the input backend.
ControllerState Poll(int player=1) override
Poll current input state (call every frame)
void UpdateEventState(int keycode, bool pressed)
Update event state from keyboard event.
bool IsInitialized() const override
Check if backend is initialized.
#define LOG_WARN(category, format,...)
Definition log.h:107
#define LOG_INFO(category, format,...)
Definition log.h:105
void ApplyDefaultKeyBindings(InputConfig &config)
Apply default keyboard bindings if unset.
constexpr auto kGamepadButtonA
Definition sdl_compat.h:248
constexpr auto kEventKeyDown
Definition sdl_compat.h:53
constexpr auto kGamepadButtonLeftShoulder
Definition sdl_compat.h:254
int16_t GetGamepadAxis(GamepadHandle gamepad, SDL_GameControllerAxis axis)
Definition sdl_compat.h:211
constexpr auto kGamepadAxisLeftY
Definition sdl_compat.h:262
constexpr auto kGamepadButtonDpadDown
Definition sdl_compat.h:257
constexpr auto kGamepadAxisLeftX
Definition sdl_compat.h:261
SDL_GameController * GamepadHandle
Definition sdl_compat.h:193
constexpr auto kGamepadButtonDpadRight
Definition sdl_compat.h:259
constexpr auto kEventKeyUp
Definition sdl_compat.h:54
GamepadHandle OpenGamepad(int index)
Definition sdl_compat.h:195
constexpr auto kGamepadButtonX
Definition sdl_compat.h:250
SDL_Keycode GetKeyFromEvent(const SDL_Event &event)
Get keyboard state from SDL event.
Definition sdl_compat.h:115
constexpr auto kGamepadButtonDpadUp
Definition sdl_compat.h:256
bool IsKeyPressed(KeyboardState state, SDL_Scancode scancode)
Check if a key is pressed using the keyboard state.
Definition sdl_compat.h:142
bool GetGamepadButton(GamepadHandle gamepad, SDL_GameControllerButton button)
Definition sdl_compat.h:206
constexpr auto kGamepadButtonB
Definition sdl_compat.h:249
constexpr auto kGamepadButtonRightShoulder
Definition sdl_compat.h:255
constexpr auto kGamepadButtonStart
Definition sdl_compat.h:253
const Uint8 * KeyboardState
Definition sdl_compat.h:32
void CloseGamepad(GamepadHandle gamepad)
Definition sdl_compat.h:202
constexpr auto kGamepadButtonDpadLeft
Definition sdl_compat.h:258
constexpr auto kGamepadButtonBack
Definition sdl_compat.h:252
constexpr auto kGamepadButtonY
Definition sdl_compat.h:251
Controller state (16-bit SNES controller format)
void SetButton(SnesButton button, bool pressed)
Input configuration (platform-agnostic key codes)