Sparkle 0.0.1
Loading...
Searching...
No Matches
spk_input_trigger.hpp
1#pragma once
2
3#include "structure/math/spk_vector2.hpp"
4#include "structure/system/device/spk_keyboard.hpp"
5#include "structure/system/device/spk_mouse.hpp"
6#include "structure/system/event/spk_update_event.hpp"
7#include "structure/system/time/spk_duration.hpp"
8#include "structure/system/time/spk_timer.hpp"
9#include "type/spk_input_state.hpp"
10
11#include <functional>
12#include <stdexcept>
13#include <type_traits>
14#include <utility>
15
16namespace spk
17{
23 {
24 public:
26 virtual ~InputTrigger() = default;
31 virtual bool isInitialized() const = 0;
36 virtual void initialize(spk::UpdateEvent &p_event) = 0;
38 virtual void update() = 0;
39 };
40
47 template <typename Device, typename DeviceValue>
49 {
50 public:
52 using Job = std::function<void(const Device *)>;
54 using Predicate = std::function<bool()>;
56 static inline const long long NoRepeat = -1;
57
58 private:
59 const Device *_device = nullptr;
60
61 DeviceValue _deviceValue;
62 spk::InputState _targetState;
63
64 spk::Duration _repeatInterval;
65 spk::Timer _timer;
66 Job _onTriggerCallback;
67 Predicate _predicateCallback = []() {
68 return true;
69 };
70
71 bool _lastState = false;
72
73 public:
81 DeviceInputTrigger(DeviceValue p_deviceValue, spk::InputState p_state, spk::Duration p_repeatInterval, const Job &p_jobCallback) :
82 DeviceInputTrigger(p_deviceValue, p_state, p_repeatInterval, [&]() {
83 return (true);
84 },
85 p_jobCallback)
86 {
87 }
88
97 DeviceInputTrigger(DeviceValue p_deviceValue, spk::InputState p_state, spk::Duration p_repeatInterval, const Predicate &p_predicateCallback, const Job &p_jobCallback) :
98 _deviceValue(p_deviceValue),
99 _targetState(p_state),
100 _repeatInterval(p_repeatInterval),
101 _timer(p_repeatInterval),
102 _onTriggerCallback(p_jobCallback),
103 _predicateCallback(p_predicateCallback)
104 {
105 }
106
112 void setDeviceValue(const DeviceValue &p_deviceValue, const spk::InputState &p_state)
113 {
114 _deviceValue = p_deviceValue;
115 _targetState = p_state;
116 }
117
122 void setRepeatInterval(const spk::Duration &p_repeatInterval)
123 {
124 _repeatInterval = p_repeatInterval;
125 _timer = spk::Timer(_repeatInterval);
126 }
127
132 void setCallback(const Job &p_callback)
133 {
134 _onTriggerCallback = p_callback;
135 }
136
141 void setPredicate(Predicate p_callback)
142 {
143 _predicateCallback = p_callback ? std::move(p_callback) : Predicate{[]() {
144 return true;
145 }};
146 }
147
152 bool isInitialized() const override
153 {
154 return (_device != nullptr);
155 }
156
161 void initialize(spk::UpdateEvent &p_event) override
162 {
163 if constexpr (std::is_same_v<Device, spk::Mouse>)
164 {
165 _device = p_event.mouse;
166 }
167 else if constexpr (std::is_same_v<Device, spk::Keyboard>)
168 {
169 _device = p_event.keyboard;
170 }
171 else
172 {
173 throw std::runtime_error("Invalid device type");
174 }
175 }
176
181 const Device *device() const
182 {
183 return (_device);
184 }
185
190 void setDevice(const Device *p_device)
191 {
192 _device = p_device;
193 }
194
196 void update() override
197 {
198 if (_device == nullptr)
199 {
200 throw std::runtime_error("Can't update a DeviceInputTrigger without device");
201 }
202
203 spk::InputState currentState = (*_device)[_deviceValue];
204
205 bool needTrigger = (currentState == _targetState);
206
207 bool justPressed = needTrigger && _lastState == false;
208 _lastState = needTrigger;
209
210 const bool shouldFire = _predicateCallback() &&
211 (justPressed == true ||
212 (justPressed == false && needTrigger && _repeatInterval >= spk::Duration(0, spk::TimeUnit::Nanosecond) && _timer.state() != spk::Timer::State::Running));
213
214 if (shouldFire == true)
215 {
216 _onTriggerCallback(_device);
217
218 if (_repeatInterval > spk::Duration(0, spk::TimeUnit::Nanosecond))
219 {
220 _timer.start();
221 }
222 }
223 }
224 };
225
226 using KeyboardInputTrigger = DeviceInputTrigger<spk::Keyboard, spk::Keyboard::Key>;
227 using MouseButtonInputTrigger = DeviceInputTrigger<spk::Mouse, spk::Mouse::Button>;
228
234 {
235 public:
240 enum class Mode
241 {
242 Absolute,
243 Delta
244 };
245
246 private:
247 std::function<void(const spk::Vector2Int &)> _onTriggerCallback;
248 Mode _mode;
249 const spk::Mouse *_mouse;
250
251 public:
257 MouseMotionTrigger(Mode p_mode, const std::function<void(const spk::Vector2Int &)> &p_callback) :
258 _onTriggerCallback(p_callback),
259 _mode(p_mode),
260 _mouse(nullptr)
261 {
262 }
263
268 bool isInitialized() const override
269 {
270 return (_mouse != nullptr);
271 }
272
277 void initialize(spk::UpdateEvent &p_event) override
278 {
279 _mouse = p_event.mouse;
280 }
281
286 const spk::Mouse *mouse() const
287 {
288 return (_mouse);
289 }
290
295 void setMouse(const spk::Mouse *p_mouse)
296 {
297 _mouse = p_mouse;
298 }
299
301 void update() override
302 {
303 if (_mouse == nullptr)
304 {
305 throw std::runtime_error("Can't update a MouseMotionTrigger without device");
306 }
307
308 _onTriggerCallback(_mode == Mode::Absolute ? _mouse->position : _mouse->deltaPosition);
309 }
310 };
311}
void setCallback(const Job &p_callback)
Sets the callback to invoke when triggered.
Definition spk_input_trigger.hpp:132
void setDevice(const Device *p_device)
Manually sets the device.
Definition spk_input_trigger.hpp:190
std::function< void(const Device *)> Job
Callback type invoked when the trigger fires.
Definition spk_input_trigger.hpp:52
static const long long NoRepeat
Definition spk_input_trigger.hpp:56
void setPredicate(Predicate p_callback)
Sets the predicate tested before firing.
Definition spk_input_trigger.hpp:141
std::function< bool()> Predicate
Predicate type tested before firing.
Definition spk_input_trigger.hpp:54
const Device * device() const
Returns the assigned device.
Definition spk_input_trigger.hpp:181
void update() override
Updates the trigger and fires callbacks if needed.
Definition spk_input_trigger.hpp:196
void initialize(spk::UpdateEvent &p_event) override
Initializes the trigger by extracting the device from an update event.
Definition spk_input_trigger.hpp:161
void setDeviceValue(const DeviceValue &p_deviceValue, const spk::InputState &p_state)
Sets the device value and target state.
Definition spk_input_trigger.hpp:112
void setRepeatInterval(const spk::Duration &p_repeatInterval)
Sets the repeat interval.
Definition spk_input_trigger.hpp:122
bool isInitialized() const override
Reports whether the trigger is initialized.
Definition spk_input_trigger.hpp:152
DeviceInputTrigger(DeviceValue p_deviceValue, spk::InputState p_state, spk::Duration p_repeatInterval, const Job &p_jobCallback)
Creates a device trigger with a callback.
Definition spk_input_trigger.hpp:81
DeviceInputTrigger(DeviceValue p_deviceValue, spk::InputState p_state, spk::Duration p_repeatInterval, const Predicate &p_predicateCallback, const Job &p_jobCallback)
Creates a device trigger with predicate and callback.
Definition spk_input_trigger.hpp:97
Strongly-typed time span with cached conversions between ns/ms/s.
Definition spk_duration.hpp:15
Interface for input-triggered callbacks.
Definition spk_input_trigger.hpp:23
virtual void initialize(spk::UpdateEvent &p_event)=0
Initializes the trigger using an update event.
virtual ~InputTrigger()=default
Virtual destructor.
virtual bool isInitialized() const =0
Reports whether the trigger is initialized.
virtual void update()=0
Updates the trigger state.
void update() override
Updates the trigger and fires the callback.
Definition spk_input_trigger.hpp:301
Mode
Mouse motion mode to report.
Definition spk_input_trigger.hpp:241
void setMouse(const spk::Mouse *p_mouse)
Manually sets the mouse.
Definition spk_input_trigger.hpp:295
bool isInitialized() const override
Reports whether the trigger is initialized.
Definition spk_input_trigger.hpp:268
void initialize(spk::UpdateEvent &p_event) override
Initializes the trigger by extracting the mouse from an update event.
Definition spk_input_trigger.hpp:277
MouseMotionTrigger(Mode p_mode, const std::function< void(const spk::Vector2Int &)> &p_callback)
Creates a mouse motion trigger.
Definition spk_input_trigger.hpp:257
const spk::Mouse * mouse() const
Returns the assigned mouse.
Definition spk_input_trigger.hpp:286
Countdown helper tracking elapsed ratio and timeout state.
Definition spk_timer.hpp:24
Captures mouse state at a given instant (buttons, position, wheel).
Definition spk_mouse.hpp:17
Carries per-frame update timing and input state snapshot.
Definition spk_update_event.hpp:15
const spk::Mouse * mouse
Snapshot of the mouse state for the frame.
Definition spk_update_event.hpp:19
const spk::Keyboard * keyboard
Snapshot of the keyboard state for the frame.
Definition spk_update_event.hpp:21