Line data Source code
1 : /**
2 : Copyright (c) 2022 Roman Katuntsev <sbkarr@stappler.org>
3 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
4 :
5 : Permission is hereby granted, free of charge, to any person obtaining a copy
6 : of this software and associated documentation files (the "Software"), to deal
7 : in the Software without restriction, including without limitation the rights
8 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 : copies of the Software, and to permit persons to whom the Software is
10 : furnished to do so, subject to the following conditions:
11 :
12 : The above copyright notice and this permission notice shall be included in
13 : all copies or substantial portions of the Software.
14 :
15 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 : THE SOFTWARE.
22 : **/
23 :
24 : #ifndef XENOLITH_SCENE_INPUT_XLGESTURERECOGNIZER_H_
25 : #define XENOLITH_SCENE_INPUT_XLGESTURERECOGNIZER_H_
26 :
27 : #include "XLCommon.h"
28 : #include "XLInput.h"
29 : #include "SPMovingAverage.h"
30 :
31 : namespace STAPPLER_VERSIONIZED stappler::xenolith {
32 :
33 : static constexpr float TapDistanceAllowed = 12.0f;
34 : static constexpr float TapDistanceAllowedMulti = 32.0f;
35 : static constexpr TimeInterval TapIntervalAllowed = TimeInterval::microseconds(300000ULL);
36 :
37 : class InputListener;
38 :
39 : enum class GestureEvent {
40 : /** Action just started, listener should return true if it want to "capture" it.
41 : * Captured actions will be automatically propagated to end-listener
42 : * Other listeners branches will not recieve updates on action, that was not captured by them.
43 : * Only one listener on every level can capture action. If one of the listeners return 'true',
44 : * action will be captured by this listener, no other listener on this level can capture this action.
45 : */
46 : Began,
47 :
48 : /** Action was activated:
49 : * on Touch - touch was moved
50 : * on Tap - n-th tap was recognized
51 : * on Press - long touch was recognized
52 : * on Swipe - touch was moved
53 : * on Pinch - any of two touches was moved, scale was changed
54 : * on Rotate - any of two touches was moved, rotation angle was changed
55 : */
56 : Activated,
57 : Moved = Activated,
58 : OnLongPress = Activated,
59 : Repeat = Activated,
60 :
61 : /** Action was successfully ended, no recognition errors was occurred */
62 : Ended,
63 :
64 : /** Action was not successfully ended, recognizer detects error in action
65 : * pattern and failed to continue recognition */
66 : Cancelled,
67 : };
68 :
69 : struct GestureData {
70 : GestureEvent event = GestureEvent::Began;
71 : const InputEvent *input = nullptr;
72 :
73 96 : Vec2 location() const { return input->currentLocation; }
74 184 : uint32_t getId() const { return input->data.id; }
75 : };
76 :
77 : struct GestureScroll : GestureData {
78 : Vec2 pos;
79 : Vec2 amount;
80 :
81 : const Vec2 &location() const;
82 : void cleanup();
83 : };
84 :
85 : struct GestureTap : GestureData {
86 : Vec2 pos;
87 : uint32_t id = maxOf<uint32_t>();
88 : uint32_t count = 0;
89 : Time time;
90 :
91 : void cleanup();
92 : };
93 :
94 : struct GesturePress : GestureData {
95 : Vec2 pos;
96 : uint32_t id = maxOf<uint32_t>();
97 : TimeInterval limit;
98 : TimeInterval time;
99 : uint32_t tickCount = 0;
100 :
101 : void cleanup();
102 : };
103 :
104 : struct GestureSwipe : GestureData {
105 : Vec2 firstTouch;
106 : Vec2 secondTouch;
107 : Vec2 midpoint;
108 : Vec2 delta;
109 : Vec2 velocity;
110 : float density = 1.0f;
111 :
112 : void cleanup();
113 : };
114 :
115 : struct GesturePinch : GestureData {
116 : Vec2 first;
117 : Vec2 second;
118 : Vec2 center;
119 : float startDistance = 0.0f;
120 : float prevDistance = 0.0f;
121 : float distance = 0.0f;
122 : float scale = 0.0f;
123 : float velocity = 0.0f;
124 : float density = 1.0f;
125 :
126 : void cleanup();
127 : };
128 :
129 : class GestureRecognizer : public Ref {
130 : public:
131 : using EventMask = std::bitset<toInt(InputEventName::Max)>;
132 : using ButtonMask = std::bitset<toInt(InputMouseButton::Max)>;
133 :
134 1166 : virtual ~GestureRecognizer() { }
135 :
136 : virtual bool init();
137 :
138 : virtual bool canHandleEvent(const InputEvent &event) const;
139 : virtual InputEventState handleInputEvent(const InputEvent &, float density);
140 :
141 : virtual void onEnter(InputListener *);
142 : virtual void onExit();
143 :
144 : uint32_t getEventCount() const;
145 : bool hasEvent(const InputEvent &) const;
146 :
147 : EventMask getEventMask() const;
148 :
149 : virtual void update(uint64_t dt);
150 : virtual Vec2 getLocation() const;
151 : virtual void cancel();
152 :
153 21 : virtual void setMaxEvents(size_t value) { _maxEvents = value; }
154 21 : virtual size_t getMaxEvents() const { return _maxEvents; }
155 :
156 : protected:
157 : virtual bool canAddEvent(const InputEvent &) const;
158 : virtual InputEventState addEvent(const InputEvent &, float density);
159 : virtual InputEventState removeEvent(const InputEvent &, bool success, float density);
160 : virtual InputEventState renewEvent(const InputEvent &, float density);
161 :
162 : virtual InputEvent *getTouchById(uint32_t id, uint32_t *index);
163 :
164 : Vector<InputEvent> _events;
165 : size_t _maxEvents = 0;
166 : EventMask _eventMask;
167 : ButtonMask _buttonMask;
168 : float _density = 1.0f;
169 : };
170 :
171 : class GestureTouchRecognizer : public GestureRecognizer {
172 : public:
173 : using InputCallback = Function<bool(const GestureData &)>;
174 :
175 302 : virtual ~GestureTouchRecognizer() { }
176 :
177 : virtual bool init(InputCallback &&, ButtonMask &&);
178 :
179 : // disable touches if no button specified
180 : virtual bool canHandleEvent(const InputEvent &event) const override;
181 :
182 : void removeRecognizedEvent(uint32_t);
183 :
184 : protected:
185 : using GestureRecognizer::init;
186 :
187 : virtual InputEventState addEvent(const InputEvent &, float density) override;
188 : virtual InputEventState removeEvent(const InputEvent &, bool successful, float density) override;
189 : virtual InputEventState renewEvent(const InputEvent &, float density) override;
190 :
191 : GestureData _event = GestureData{GestureEvent::Cancelled, nullptr};
192 : InputCallback _callback;
193 : };
194 :
195 : class GestureTapRecognizer : public GestureRecognizer {
196 : public:
197 : using InputCallback = Function<void(const GestureTap &)>;
198 : using ButtonMask = std::bitset<toInt(InputMouseButton::Max)>;
199 :
200 1452 : virtual ~GestureTapRecognizer() { }
201 :
202 : virtual bool init(InputCallback &&, ButtonMask &&, uint32_t maxTapCount);
203 :
204 : virtual void update(uint64_t dt) override;
205 : virtual void cancel() override;
206 :
207 : protected:
208 : using GestureRecognizer::init;
209 :
210 : virtual InputEventState addEvent(const InputEvent &, float density) override;
211 : virtual InputEventState removeEvent(const InputEvent &, bool successful, float density) override;
212 : virtual InputEventState renewEvent(const InputEvent &, float density) override;
213 :
214 : virtual void registerTap();
215 :
216 : GestureTap _gesture;
217 : InputCallback _callback;
218 : uint32_t _maxTapCount = 2;
219 : InputEvent _tmpEvent;
220 : };
221 :
222 : class GesturePressRecognizer : public GestureRecognizer {
223 : public:
224 : using InputCallback = Function<bool(const GesturePress &)>;
225 :
226 1116 : virtual ~GesturePressRecognizer() { }
227 :
228 : virtual bool init(InputCallback &&, TimeInterval interval, bool continuous, ButtonMask &&);
229 :
230 : virtual void update(uint64_t dt) override;
231 : virtual void cancel() override;
232 :
233 : protected:
234 : using GestureRecognizer::init;
235 :
236 : virtual InputEventState addEvent(const InputEvent &, float density) override;
237 : virtual InputEventState removeEvent(const InputEvent &, bool successful, float density) override;
238 : virtual InputEventState renewEvent(const InputEvent &, float density) override;
239 :
240 : Time _lastTime = Time::now();
241 : bool _notified = false;
242 :
243 : GesturePress _gesture;
244 : InputCallback _callback;
245 :
246 : TimeInterval _interval;
247 : bool _continuous = false;
248 : };
249 :
250 : class GestureSwipeRecognizer : public GestureRecognizer {
251 : public:
252 : using InputCallback = Function<bool(const GestureSwipe &)>;
253 :
254 348 : virtual ~GestureSwipeRecognizer() { }
255 :
256 : virtual bool init(InputCallback &&, float threshold, bool includeThreshold, ButtonMask &&);
257 :
258 : virtual void cancel() override;
259 :
260 : protected:
261 : using GestureRecognizer::init;
262 :
263 : virtual InputEventState addEvent(const InputEvent &, float density) override;
264 : virtual InputEventState removeEvent(const InputEvent &, bool successful, float density) override;
265 : virtual InputEventState renewEvent(const InputEvent &, float density) override;
266 :
267 : Time _lastTime;
268 : math::MovingAverage<4> _velocityX, _velocityY;
269 :
270 : bool _swipeBegin = false;
271 : uint32_t _currentTouch = maxOf<uint32_t>();
272 :
273 : GestureSwipe _gesture;
274 : InputCallback _callback;
275 :
276 : float _threshold = 6.0f;
277 : bool _includeThreshold = true;
278 : };
279 :
280 : class GesturePinchRecognizer : public GestureRecognizer {
281 : public:
282 : using InputCallback = Function<void(const GesturePinch &)>;
283 :
284 84 : virtual ~GesturePinchRecognizer() { }
285 :
286 : virtual bool init(InputCallback &&, ButtonMask &&);
287 :
288 : virtual void cancel() override;
289 :
290 : protected:
291 : using GestureRecognizer::init;
292 :
293 : virtual InputEventState addEvent(const InputEvent &, float density) override;
294 : virtual InputEventState removeEvent(const InputEvent &, bool successful, float density) override;
295 : virtual InputEventState renewEvent(const InputEvent &, float density) override;
296 :
297 : Time _lastTime;
298 : math::MovingAverage<3> _velocity;
299 :
300 : GesturePinch _gesture;
301 : InputCallback _callback;
302 : };
303 :
304 : class GestureScrollRecognizer : public GestureRecognizer {
305 : public:
306 : using InputCallback = Function<bool(const GestureScroll &)>;
307 :
308 264 : virtual ~GestureScrollRecognizer() { }
309 :
310 : virtual bool init(InputCallback &&);
311 :
312 : virtual InputEventState handleInputEvent(const InputEvent &, float density) override;
313 :
314 : protected:
315 : using GestureRecognizer::init;
316 :
317 : GestureScroll _gesture;
318 : InputCallback _callback;
319 : };
320 :
321 : class GestureMoveRecognizer : public GestureRecognizer {
322 : public:
323 : using InputCallback = Function<bool(const GestureData &)>;
324 :
325 84 : virtual ~GestureMoveRecognizer() { }
326 :
327 : virtual bool init(InputCallback &&, bool withinNode);
328 :
329 : virtual bool canHandleEvent(const InputEvent &event) const override;
330 : virtual InputEventState handleInputEvent(const InputEvent &, float density) override;
331 :
332 : virtual void onEnter(InputListener *) override;
333 : virtual void onExit() override;
334 :
335 : protected:
336 : using GestureRecognizer::init;
337 :
338 : GestureData _event = GestureData{GestureEvent::Cancelled, nullptr};
339 : InputCallback _callback;
340 : InputListener *_listener = nullptr;
341 : bool _onlyWithinNode = true;
342 : };
343 :
344 : class GestureKeyRecognizer : public GestureRecognizer {
345 : public:
346 : using InputCallback = Function<bool(const GestureData &)>;
347 : using KeyMask = std::bitset<toInt(InputKeyCode::Max)>;
348 :
349 168 : virtual ~GestureKeyRecognizer() { }
350 :
351 : virtual bool init(InputCallback &&, KeyMask &&);
352 :
353 : virtual bool canHandleEvent(const InputEvent &) const override;
354 :
355 : bool isKeyPressed(InputKeyCode) const;
356 :
357 : protected:
358 : using GestureRecognizer::init;
359 :
360 : virtual InputEventState addEvent(const InputEvent &, float density) override;
361 : virtual InputEventState removeEvent(const InputEvent &, bool success, float density) override;
362 : virtual InputEventState renewEvent(const InputEvent &, float density) override;
363 :
364 : KeyMask _keyMask;
365 : KeyMask _pressedKeys;
366 : InputCallback _callback;
367 : };
368 :
369 : class GestureMouseOverRecognizer : public GestureRecognizer {
370 : public:
371 : using InputCallback = Function<bool(const GestureData &)>;
372 :
373 894 : virtual ~GestureMouseOverRecognizer() { }
374 :
375 : virtual bool init(InputCallback &&, float padding = 0.0f);
376 :
377 : virtual InputEventState handleInputEvent(const InputEvent &, float density) override;
378 :
379 : virtual void onEnter(InputListener *) override;
380 : virtual void onExit() override;
381 :
382 : protected:
383 : using GestureRecognizer::init;
384 :
385 : void updateState(const InputEvent &);
386 :
387 : GestureData _event = GestureData{GestureEvent::Cancelled, nullptr};
388 : bool _viewHasPointer = false;
389 : bool _viewHasFocus = false;
390 : bool _hasMouseOver = false;
391 : bool _value = false;
392 : float _padding = 0.0f;
393 : InputCallback _callback;
394 : InputListener *_listener = nullptr;
395 : };
396 :
397 : std::ostream &operator<<(std::ostream &, GestureEvent);
398 :
399 : }
400 :
401 : #endif /* XENOLITH_SCENE_INPUT_XLGESTURERECOGNIZER_H_ */
|