Olympe Engine 2.0
2D Game Engine with ECS Architecture
Loading...
Searching...
No Matches
JoystickManager.cpp
Go to the documentation of this file.
1#include "JoystickManager.h"
2#include "EventQueue.h"
3#include "system_utils.h"
4#include <SDL3/SDL.h>
5#include <iostream>
6#include <cstring>
7#include "../InputsManager.h"
8#include "message.h"
10
11//---------------------------------------------------------------------------------------------
17//---------------------------------------------------------------------------------------------
19{
20 std::lock_guard<std::mutex> lock(m_mutex);
21 // Reset per-frame button edge detection for all joysticks
22 for (auto& kv : m_joyStates)
23 {
24 std::memset(kv.second.buttonsPressed, 0, sizeof(kv.second.buttonsPressed));
25 std::memset(kv.second.buttonsReleased, 0, sizeof(kv.second.buttonsReleased));
26 }
27}
28//---------------------------------------------------------------------------------------------
30{
31 if (button < 0 || button >= MAX_BUTTONS) return false;
32 std::lock_guard<std::mutex> lock(m_mutex);
33 auto it = m_joyStates.find(id);
34 if (it == m_joyStates.end()) return false;
35 return it->second.buttons[button];
36}
37//---------------------------------------------------------------------------------------------
39{
40 if (button < 0 || button >= MAX_BUTTONS) return false;
41 std::lock_guard<std::mutex> lock(m_mutex);
42 auto it = m_joyStates.find(id);
43 if (it == m_joyStates.end()) return false;
44 return it->second.buttonsPressed[button];
45}
46//---------------------------------------------------------------------------------------------
48{
49 if (button < 0 || button >= MAX_BUTTONS) return false;
50 std::lock_guard<std::mutex> lock(m_mutex);
51 auto it = m_joyStates.find(id);
52 if (it == m_joyStates.end()) return false;
53 return it->second.buttonsReleased[button];
54}
55//---------------------------------------------------------------------------------------------
57{
58 if (axis < 0 || axis >= MAX_AXES) return 0.0f;
59 std::lock_guard<std::mutex> lock(m_mutex);
60 auto it = m_joyStates.find(id);
61 if (it == m_joyStates.end()) return 0.0f;
62 return it->second.axes[axis];
63}
64//---------------------------------------------------------------------------------------------
66{
67 // std::lock_guard<std::mutex> lock(m_mutex);
68
69 // Enable joystick events so SDL will post them to the event queue
71
73 SYSTEM_LOG << "JoystickManager created and Initialized with " << m_joysticks.size() << " joysticks connected\n";
74}
75//---------------------------------------------------------------------------------------------
76// Scan currently connected joysticks and open them
78{
79 int count = 0;
81 if (ids)
82 {
83 for (int i = 0; i < count; ++i)
84 {
86 }
88 }
89}
90//---------------------------------------------------------------------------------------------
92{
93 std::lock_guard<std::mutex> lock(m_mutex);
94 for (auto &kv : m_joysticks)
95 {
96 if (kv.second.joystick)
97 {
98 SDL_CloseJoystick(kv.second.joystick);
99 }
100 }
101 m_joysticks.clear();
102 SYSTEM_LOG << "JoystickManager Shutdown\n";
103}
104//---------------------------------------------------------------------------------------------
105void JoystickManager::Process(float /*dt*/)
106{
107 // optional polling-based updates could be implemented here
108 // For now, joystick activity is driven by SDL events handled in HandleEvent().
109}
110//---------------------------------------------------------------------------------------------
112{
113 //if (!ev) return; FBind// useless because it is tested before function call
114
115 switch (ev->type)
116 {
118 {
119 // Gamepad added - we can open the underlying joystick if needed
120 SDL_JoystickID id = ev->gdevice.which;
121 OpenJoystick(id);
122 SYSTEM_LOG << "Gamepad added id=" << id << "\n";
123 break;
124 }
126 {
127 SDL_JoystickID id = ev->jdevice.which;
128 OpenJoystick(id);
129 SYSTEM_LOG << "Joystick added id=" << id << "\n";
130
131 //Notify players that their controller has been connected
135 static_cast<int>(id),
136 -1
137 ));
138 break;
139 }
141 {
142 // Gamepad removed - we can close the underlying joystick if needed
143 SDL_JoystickID id = ev->gdevice.which;
144 CloseJoystick(id);
145 SYSTEM_LOG << "Gamepad removed id=" << id << "\n";
146 break;
147 }
149 {
150 SDL_JoystickID id = ev->jdevice.which;
151 CloseJoystick(id);
152 SYSTEM_LOG << "Joystick removed id=" << id << "\n";
153 // send notification to inputmanager
157
158 //Notify players that their controller has been disconnected
162 static_cast<int>(id),
163 -1
164 ));
165 break;
166 }
168 {
169 SDL_JoystickID which = ev->gbutton.which;
170 int button = ev->gbutton.button;
171 bool down = ev->gbutton.down;
173 break;
174 }
176 {
177 SDL_JoystickID which = ev->jbutton.which;
178 int button = ev->jbutton.button;
179 bool down = ev->jbutton.down;
180
181 // Update state for pull API
182 if (button >= 0 && button < MAX_BUTTONS)
183 {
184 std::lock_guard<std::mutex> lock(m_mutex);
185 auto& state = m_joyStates[which];
186 bool wasDown = state.buttons[button];
187 state.buttons[button] = down;
188 if (down && !wasDown)
189 state.buttonsPressed[button] = true;
190 else if (!down && wasDown)
191 state.buttonsReleased[button] = true;
192 }
193
195 break;
196 }
198 {
199 SDL_JoystickID which = ev->gbutton.which;
200 int button = ev->gbutton.button;
201 bool down = ev->gbutton.down;
202
203 // Update state for pull API
204 if (button >= 0 && button < MAX_BUTTONS)
205 {
206 std::lock_guard<std::mutex> lock(m_mutex);
207 auto& state = m_joyStates[which];
208 bool wasDown = state.buttons[button];
209 state.buttons[button] = down;
210 if (down && !wasDown)
211 state.buttonsPressed[button] = true;
212 else if (!down && wasDown)
213 state.buttonsReleased[button] = true;
214 }
215
217 break;
218 }
220 {
221 SDL_JoystickID which = ev->jbutton.which;
222 int button = ev->jbutton.button;
223 bool down = ev->jbutton.down;
224
225 // Update state for pull API
226 if (button >= 0 && button < MAX_BUTTONS)
227 {
228 std::lock_guard<std::mutex> lock(m_mutex);
229 auto& state = m_joyStates[which];
230 bool wasDown = state.buttons[button];
231 state.buttons[button] = down;
232 if (down && !wasDown)
233 state.buttonsPressed[button] = true;
234 else if (!down && wasDown)
235 state.buttonsReleased[button] = true;
236 }
237
239 break;
240 }
242 {
243 SDL_JoystickID which = ev->gaxis.which;
244 int axis = ev->gaxis.axis;
245 Sint16 value = ev->gaxis.value;
246
247 // Update state for pull API (normalize to -1..1)
248 if (axis >= 0 && axis < MAX_AXES)
249 {
250 std::lock_guard<std::mutex> lock(m_mutex);
251 auto& state = m_joyStates[which];
252 float normalized = (value >= 0) ? (value / 32767.0f) : (value / 32768.0f);
253 state.axes[axis] = normalized;
254 }
255
257 break;
258 }
260 {
261 SDL_JoystickID which = ev->jaxis.which;
262 int axis = ev->jaxis.axis;
263 Sint16 value = ev->jaxis.value;
264
265 // Update state for pull API (normalize to -1..1)
266 if (axis >= 0 && axis < MAX_AXES)
267 {
268 std::lock_guard<std::mutex> lock(m_mutex);
269 auto& state = m_joyStates[which];
270 float normalized = (value >= 0) ? (value / 32767.0f) : (value / 32768.0f);
271 state.axes[axis] = normalized;
272 }
273
275 break;
276 }
277
278 default:
279 break;
280 }
281}
282//---------------------------------------------------------------------------------------------
283std::vector<SDL_JoystickID> JoystickManager::GetConnectedJoysticks()
284{
285 std::lock_guard<std::mutex> lock(m_mutex);
286 std::vector<SDL_JoystickID> res;
287 res.reserve(m_joysticks.size());
288 for (auto &kv : m_joysticks) res.push_back(kv.first);
289 return res;
290}
291//---------------------------------------------------------------------------------------------
293{
294 std::lock_guard<std::mutex> lock(m_mutex);
295 return m_joysticks.find(id) != m_joysticks.end();
296}
297//---------------------------------------------------------------------------------------------
299{
300 std::lock_guard<std::mutex> lock(m_mutex);
301 if (m_joysticks.find(instance_id) != m_joysticks.end()) return; // already open
302
304 if (!js)
305 {
306 SYSTEM_LOG << "Failed to open joystick " << instance_id << " : " << SDL_GetError() << "\n";
307 return;
308 }
309
311 info.joystick = js;
313 const char* name = SDL_GetJoystickName(js);
314 info.name = name ? name : "<unknown>";
315 info.numAxes = SDL_GetNumJoystickAxes(js);
316 info.numButtons = SDL_GetNumJoystickButtons(js);
317 info.axes.assign(info.numAxes,0);
318 info.buttons.assign(info.numButtons, false);
319
320 // read initial states
321 for (int a =0; a < info.numAxes; ++a)
322 {
323 info.axes[a] = SDL_GetJoystickAxis(js, a);
324 float normalized = (info.axes[a] >= 0) ? (info.axes[a] / 32767.0f) : (info.axes[a] / 32768.0f);
325 info.axes[a] = (Sint16) normalized;
326 }
327 for (int b =0; b < info.numButtons; ++b)
328 {
329 info.buttons[b] = SDL_GetJoystickButton(js, b);
330 }
331
332 m_joysticks[info.id] = std::move(info);
333}
334//---------------------------------------------------------------------------------------------
336{
337 std::lock_guard<std::mutex> lock(m_mutex);
338 auto it = m_joysticks.find(instance_id);
339 if (it == m_joysticks.end()) return;
340
341 if (it->second.joystick)
342 {
343 SDL_CloseJoystick(it->second.joystick);
344 }
345 m_joysticks.erase(it);
346
347 // Remove pull API state for this joystick
348 {
350 }
351}
352//---------------------------------------------------------------------------------------------
366//---------------------------------------------------------------------------------------------
368{
369 // normalize Sint16 (-32768..32767) to [-1.0,1.0]
370 float normalized = 0.0f;
371 if (value >= 0) normalized = (value / 32767.0f);
372 else normalized = (value / 32768.0f);
373
377 static_cast<int>(which),
378 axis
379 );
380 msg.state = 0;
381 msg.param1 = normalized;
382
384}
385//---------------------------------------------------------------------------------------------
ComponentTypeID GetComponentTypeID_Static()
Definition ECS_Entity.h:56
void Push(const Message &msg)
Definition EventQueue.h:37
static EventQueue & Get()
Definition EventQueue.h:34
static InputsManager & Get()
bool UnbindControllerFromPlayer(short playerID)
short GetPlayerForController(SDL_JoystickID controller) const
bool AddDisconnectedPlayer(short playerID, SDL_JoystickID old_controller)
float GetAxis(SDL_JoystickID id, int axis)
void PostJoystickButtonEvent(SDL_JoystickID which, int button, bool down)
bool GetButton(SDL_JoystickID id, int button)
bool IsButtonReleased(SDL_JoystickID id, int button)
bool IsButtonPressed(SDL_JoystickID id, int button)
std::unordered_map< SDL_JoystickID, JoystickState > m_joyStates
static constexpr int MAX_BUTTONS
bool IsJoystickConnected(SDL_JoystickID id)
static JoystickManager & GetInstance()
void Process(float dt)
void OpenJoystick(SDL_JoystickID instance_id)
void PostJoystickConnectedEvent(SDL_JoystickID which, bool bconnected)
void HandleEvent(const SDL_Event *ev)
void CloseJoystick(SDL_JoystickID instance_id)
std::unordered_map< SDL_JoystickID, JoystickInfo > m_joysticks
std::vector< SDL_JoystickID > GetConnectedJoysticks()
void PostJoystickAxisEvent(SDL_JoystickID which, int axis, Sint16 value)
static constexpr int MAX_AXES
static Message Create(EventType _ev_t, EventDomain _domain, int _d_id=-1, int _c_id=-1, uint64_t _t_uid=0)
Definition message.h:28
@ Olympe_EventType_Joystick_ButtonUp
@ Olympe_EventType_Joystick_ButtonDown
@ Olympe_EventType_Joystick_AxisMotion
@ Olympe_EventType_Joystick_Connected
@ Olympe_EventType_Joystick_Disconnected
#define SYSTEM_LOG