2 #include <ossia/detail/hash_map.hpp>
4 #include <ossia/detail/timer.hpp>
5 #include <ossia/network/context.hpp>
6 #include <ossia/protocols/joystick/joystick_protocol.hpp>
8 #if __has_include(<SDL2/SDL.h>)
14 #include <ossia/detail/fmt.hpp>
21 struct sdl_joystick_context
23 sdl_joystick_context()
25 SDL_SetHint(SDL_HINT_NO_SIGNAL_HANDLERS,
"1");
27 SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS,
"1");
29 if(
int ret = SDL_Init(SDL_INIT_JOYSTICK); ret < 0)
30 throw std::runtime_error(fmt::format(
"SDL Init failure: {}", SDL_GetError()));
32 SDL_JoystickEventState(SDL_ENABLE);
35 static sdl_joystick_context& instance()
37 static sdl_joystick_context instance{};
41 ~sdl_joystick_context()
45 ev.type = SDL_FIRSTEVENT;
52 class joystick_protocol_manager
55 static joystick_protocol_manager& instance()
57 static joystick_protocol_manager instance{};
61 joystick_protocol_manager() { sdl_joystick_context::instance(); }
63 ~joystick_protocol_manager() { SDL_Quit(); }
65 bool joystick_is_registered(
const SDL_JoystickID joystick_id)
67 return m_joystick_protocols.find(joystick_id) != m_joystick_protocols.end();
70 void register_protocol(joystick_protocol& protocol)
72 const SDL_JoystickID joystick_id = protocol.m_joystick_id;
74 if(joystick_is_registered(joystick_id))
75 throw std::runtime_error(
"A protocol is already registered for this joystick");
78 std::lock_guard<std::mutex> _{m_joystick_protocols_mutex};
79 m_joystick_protocols[joystick_id] = &protocol;
83 void unregister_protocol(joystick_protocol& protocol)
85 const SDL_JoystickID joystick_id = protocol.m_joystick_id;
87 if(!joystick_is_registered(joystick_id))
88 throw std::runtime_error(
89 "Cannot unregister a protocol that haven't been registered");
92 std::lock_guard<std::mutex> _{m_joystick_protocols_mutex};
93 m_joystick_protocols.erase(joystick_id);
97 joystick_protocol* get_protocol_by_id(
const SDL_JoystickID
id)
99 joystick_protocol* ret =
nullptr;
101 std::lock_guard<std::mutex> _{m_joystick_protocols_mutex};
102 auto it = m_joystick_protocols.find(
id);
103 if(it != m_joystick_protocols.end())
109 ossia::hash_map<SDL_JoystickID, joystick_protocol*> m_joystick_protocols;
110 std::mutex m_joystick_protocols_mutex;
115 struct joystick_event_processor
119 explicit timer_context(boost::asio::io_context& ctx)
125 timer_context(timer_context&&) =
default;
126 timer_context& operator=(timer_context&&) =
default;
128 boost::asio::io_context* context{};
133 static inline std::atomic_int instance_count = 0;
134 joystick_event_processor(joystick_protocol_manager& manager)
139 ~joystick_event_processor() =
default;
141 static joystick_event_processor& instance(joystick_protocol_manager& manager)
143 static joystick_event_processor instance{manager};
147 void register_context(boost::asio::io_context& ctx)
149 for(
auto& tm : this->m_timers)
151 if(tm.context == &ctx)
158 m_timers.emplace_back(ctx);
160 if(instance_count > 0)
162 auto& tm = m_timers.back();
167 void start(ossia::timer& timer)
169 using namespace std::literals;
170 timer.set_delay(4ms);
171 timer.start([
this] { this->process_events(); });
174 void unregister_context(boost::asio::io_context& ctx)
176 for(
auto it = m_timers.begin(); it != m_timers.end();)
179 if(tm.context == &ctx)
184 it = m_timers.erase(it);
193 void start_event_loop()
195 if(instance_count++ > 0)
198 for(
auto& tm : m_timers)
202 void stop_event_loop()
204 if(--instance_count > 0)
207 using namespace std::literals;
210 ev.type = SDL_FIRSTEVENT;
213 for(
auto& tm : m_timers)
220 proto->m_device->apply_incoming_message({*proto, 0}, *param, std::move(val));
223 void push_axis(
const SDL_JoyAxisEvent& ev)
225 if(
auto p = m_manager.get_protocol_by_id(ev.which))
227 const float res = (ev.value + .5f) / (0x7FFF + .5f);
228 push(p, p->m_axis_parameters[ev.axis], res);
232 void push_button(
const SDL_JoyButtonEvent& ev)
234 if(
auto p = m_manager.get_protocol_by_id(ev.which))
236 push(p, p->m_button_parameters[ev.button],
bool(ev.state == SDL_PRESSED));
240 void push_hat(
const SDL_JoyHatEvent& ev)
242 if(
auto p = m_manager.get_protocol_by_id(ev.which))
244 const uint8_t v = ev.value;
245 float x = 0.0f, y = 0.0f;
249 else if(v & SDL_HAT_RIGHT)
254 else if(v & SDL_HAT_DOWN)
257 push(p, p->m_hat_parameters[ev.hat], std::array<float, 2>{x, y});
261 void process_event(
const SDL_Event& ev)
265 case SDL_JOYAXISMOTION:
269 case SDL_JOYBUTTONDOWN:
270 case SDL_JOYBUTTONUP:
271 push_button(ev.jbutton);
274 case SDL_JOYHATMOTION:
283 void process_events()
287 int max_event_count = 20;
288 while(SDL_PollEvent(&ev) && max_event_count-- > 0)
294 joystick_protocol_manager& m_manager;
295 std::vector<timer_context> m_timers;
The parameter_base class.
Definition: ossia/network/base/parameter.hpp:48
The value class.
Definition: value.hpp:173