1use crate::device::CURRENT_DEVICE;
2use crate::geom::{elbow, nearest_segment_point, Axis, DiagDir, Dir, Point, Vec2};
3use crate::input::{ButtonCode, ButtonStatus, DeviceEvent, FingerStatus};
4use crate::unit::mm_to_px;
5use crate::view::Event;
6use fxhash::FxHashMap;
7use std::f64;
8use std::fmt;
9use std::sync::mpsc::{self, Receiver, Sender};
10use std::sync::{Arc, Mutex};
11use std::thread;
12use std::time::Duration;
13
14pub const TAP_JITTER_MM: f32 = 6.0;
15pub const HOLD_JITTER_MM: f32 = 1.5;
16pub const HOLD_DELAY_SHORT: Duration = Duration::from_millis(666);
17pub const HOLD_DELAY_LONG: Duration = Duration::from_millis(1333);
18
19#[derive(Debug, Copy, Clone)]
20pub enum GestureEvent {
21 Tap(Point),
22 MultiTap([Point; 2]),
23 Swipe {
24 dir: Dir,
25 start: Point,
26 end: Point,
27 },
28 SlantedSwipe {
29 dir: DiagDir,
30 start: Point,
31 end: Point,
32 },
33 MultiSwipe {
34 dir: Dir,
35 starts: [Point; 2],
36 ends: [Point; 2],
37 },
38 Arrow {
39 dir: Dir,
40 start: Point,
41 end: Point,
42 },
43 MultiArrow {
44 dir: Dir,
45 starts: [Point; 2],
46 ends: [Point; 2],
47 },
48 Corner {
49 dir: DiagDir,
50 start: Point,
51 end: Point,
52 },
53 MultiCorner {
54 dir: DiagDir,
55 starts: [Point; 2],
56 ends: [Point; 2],
57 },
58 Pinch {
59 axis: Axis,
60 center: Point,
61 factor: f32,
62 },
63 Spread {
64 axis: Axis,
65 center: Point,
66 factor: f32,
67 },
68 Rotate {
69 center: Point,
70 quarter_turns: i8,
71 angle: f32,
72 },
73 Cross(Point),
74 Diamond(Point),
75 HoldFingerShort(Point, i32),
76 HoldFingerLong(Point, i32),
77 HoldButtonShort(ButtonCode),
78 HoldButtonLong(ButtonCode),
79}
80
81impl fmt::Display for GestureEvent {
82 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
83 match self {
84 GestureEvent::Tap(pt) => write!(f, "Tap {}", pt),
85 GestureEvent::MultiTap(pts) => write!(f, "Multitap {} {}", pts[0], pts[1]),
86 GestureEvent::Swipe { dir, .. } => write!(f, "Swipe {}", dir),
87 GestureEvent::SlantedSwipe { dir, .. } => write!(f, "SlantedSwipe {}", dir),
88 GestureEvent::MultiSwipe { dir, .. } => write!(f, "Multiswipe {}", dir),
89 GestureEvent::Arrow { dir, .. } => write!(f, "Arrow {}", dir),
90 GestureEvent::MultiArrow { dir, .. } => write!(f, "Multiarrow {}", dir),
91 GestureEvent::Corner { dir, .. } => write!(f, "Corner {}", dir),
92 GestureEvent::MultiCorner { dir, .. } => write!(f, "Multicorner {}", dir),
93 GestureEvent::Pinch {
94 axis,
95 center,
96 factor,
97 ..
98 } => write!(f, "Pinch {} {} {:.2}", axis, center, factor),
99 GestureEvent::Spread {
100 axis,
101 center,
102 factor,
103 ..
104 } => write!(f, "Spread {} {} {:.2}", axis, center, factor),
105 GestureEvent::Rotate {
106 center,
107 quarter_turns,
108 ..
109 } => write!(f, "Rotate {} {}", center, *quarter_turns as i32 * 90),
110 GestureEvent::Cross(pt) => write!(f, "Cross {}", pt),
111 GestureEvent::Diamond(pt) => write!(f, "Diamond {}", pt),
112 GestureEvent::HoldFingerShort(pt, id) => write!(f, "Short-held finger {} {}", id, pt),
113 GestureEvent::HoldFingerLong(pt, id) => write!(f, "Long-held finger {} {}", id, pt),
114 GestureEvent::HoldButtonShort(code) => write!(f, "Short-held button {:?}", code),
115 GestureEvent::HoldButtonLong(code) => write!(f, "Long-held button {:?}", code),
116 }
117 }
118}
119
120#[derive(Debug)]
121pub struct TouchState {
122 time: f64,
123 held: bool,
124 positions: Vec<Point>,
125}
126
127pub fn gesture_events(rx: Receiver<DeviceEvent>) -> Receiver<Event> {
128 let (ty, ry) = mpsc::channel();
129 thread::spawn(move || parse_gesture_events(&rx, &ty));
130 ry
131}
132
133pub fn parse_gesture_events(rx: &Receiver<DeviceEvent>, ty: &Sender<Event>) {
134 let contacts: Arc<Mutex<FxHashMap<i32, TouchState>>> =
135 Arc::new(Mutex::new(FxHashMap::default()));
136 let buttons: Arc<Mutex<FxHashMap<ButtonCode, f64>>> =
137 Arc::new(Mutex::new(FxHashMap::default()));
138 let segments: Arc<Mutex<Vec<Vec<Point>>>> = Arc::new(Mutex::new(Vec::new()));
139 let tap_jitter = mm_to_px(TAP_JITTER_MM, CURRENT_DEVICE.dpi);
140 let hold_jitter = mm_to_px(HOLD_JITTER_MM, CURRENT_DEVICE.dpi);
141
142 while let Ok(evt) = rx.recv() {
143 ty.send(Event::Device(evt)).ok();
144 match evt {
145 DeviceEvent::Finger {
146 status: FingerStatus::Down,
147 position,
148 id,
149 time,
150 } => {
151 let mut ct = contacts.lock().unwrap();
152 ct.insert(
153 id,
154 TouchState {
155 time,
156 held: false,
157 positions: vec![position],
158 },
159 );
160 let ty = ty.clone();
161 let contacts = contacts.clone();
162 let segments = segments.clone();
163 thread::spawn(move || {
164 let mut held = false;
165 thread::sleep(HOLD_DELAY_SHORT);
166 {
167 let mut ct = contacts.lock().unwrap();
168 let sg = segments.lock().unwrap();
169 if ct.len() > 1 || !sg.is_empty() {
170 return;
171 }
172 if let Some(ts) = ct.get(&id) {
173 let tp = &ts.positions;
174 if (ts.time - time).abs() < f64::EPSILON
175 && (tp[tp.len() - 1] - position).length() < hold_jitter
176 && (tp[tp.len() / 2] - position).length() < hold_jitter
177 {
178 held = true;
179 ty.send(Event::Gesture(GestureEvent::HoldFingerShort(
180 position, id,
181 )))
182 .ok();
183 }
184 }
185 if held {
186 if let Some(ts) = ct.get_mut(&id) {
187 ts.held = true;
188 }
189 } else {
190 return;
191 }
192 }
193 thread::sleep(HOLD_DELAY_LONG - HOLD_DELAY_SHORT);
194 {
195 let mut ct = contacts.lock().unwrap();
196 let sg = segments.lock().unwrap();
197 if ct.len() > 1 || !sg.is_empty() {
198 return;
199 }
200 if let Some(ts) = ct.get_mut(&id) {
201 let tp = &ts.positions;
202 if (ts.time - time).abs() < f64::EPSILON
203 && (tp[tp.len() - 1] - position).length() < hold_jitter
204 && (tp[tp.len() / 2] - position).length() < hold_jitter
205 {
206 ty.send(Event::Gesture(GestureEvent::HoldFingerLong(position, id)))
207 .ok();
208 }
209 }
210 }
211 });
212 }
213 DeviceEvent::Finger {
214 status: FingerStatus::Motion,
215 position,
216 id,
217 ..
218 } => {
219 let mut ct = contacts.lock().unwrap();
220 if let Some(ref mut ts) = ct.get_mut(&id) {
221 ts.positions.push(position);
222 }
223 }
224 DeviceEvent::Finger {
225 status: FingerStatus::Up,
226 position,
227 id,
228 ..
229 } => {
230 let mut ct = contacts.lock().unwrap();
231 let mut sg = segments.lock().unwrap();
232 if let Some(mut ts) = ct.remove(&id) {
233 if !ts.held {
234 ts.positions.push(position);
235 sg.push(ts.positions);
236 }
237 }
238 if ct.is_empty() && !sg.is_empty() {
239 let len = sg.len();
240 if len == 1 {
241 ty.send(Event::Gesture(interpret_segment(
242 &sg.pop().unwrap(),
243 tap_jitter,
244 )))
245 .ok();
246 } else if len == 2 {
247 let ge1 = interpret_segment(&sg.pop().unwrap(), tap_jitter);
248 let ge2 = interpret_segment(&sg.pop().unwrap(), tap_jitter);
249 match (ge1, ge2) {
250 (GestureEvent::Tap(c1), GestureEvent::Tap(c2)) => {
251 ty.send(Event::Gesture(GestureEvent::MultiTap([c1, c2])))
252 .ok();
253 }
254 (
255 GestureEvent::Swipe {
256 dir: d1,
257 start: s1,
258 end: e1,
259 ..
260 },
261 GestureEvent::Swipe {
262 dir: d2,
263 start: s2,
264 end: e2,
265 ..
266 },
267 ) if d1 == d2 => {
268 ty.send(Event::Gesture(GestureEvent::MultiSwipe {
269 dir: d1,
270 starts: [s1, s2],
271 ends: [e1, e2],
272 }))
273 .ok();
274 }
275 (
276 GestureEvent::Swipe {
277 dir: d1,
278 start: s1,
279 end: e1,
280 ..
281 },
282 GestureEvent::Swipe {
283 dir: d2,
284 start: s2,
285 end: e2,
286 ..
287 },
288 ) if d1 == d2.opposite() => {
289 let center = (s1 + s2) / 2;
290 let ds = (s2 - s1).length();
291 let de = (e2 - e1).length();
292 let factor = de / ds;
293 if factor < 1.0 {
294 ty.send(Event::Gesture(GestureEvent::Pinch {
295 axis: d1.axis(),
296 center,
297 factor,
298 }))
299 .ok();
300 } else {
301 ty.send(Event::Gesture(GestureEvent::Spread {
302 axis: d1.axis(),
303 center,
304 factor,
305 }))
306 .ok();
307 }
308 }
309 (
310 GestureEvent::SlantedSwipe {
311 dir: d1,
312 start: s1,
313 end: e1,
314 ..
315 },
316 GestureEvent::SlantedSwipe {
317 dir: d2,
318 start: s2,
319 end: e2,
320 ..
321 },
322 ) if d1 == d2.opposite() => {
323 let center = (s1 + s2) / 2;
324 let ds = (s2 - s1).length();
325 let de = (e2 - e1).length();
326 let factor = de / ds;
327 if factor < 1.0 {
328 ty.send(Event::Gesture(GestureEvent::Pinch {
329 axis: Axis::Diagonal,
330 center,
331 factor,
332 }))
333 .ok();
334 } else {
335 ty.send(Event::Gesture(GestureEvent::Spread {
336 axis: Axis::Diagonal,
337 center,
338 factor,
339 }))
340 .ok();
341 }
342 }
343 (
344 GestureEvent::Arrow {
345 dir: Dir::East,
346 start: s1,
347 end: e1,
348 },
349 GestureEvent::Arrow {
350 dir: Dir::West,
351 start: s2,
352 end: e2,
353 },
354 )
355 | (
356 GestureEvent::Arrow {
357 dir: Dir::West,
358 start: s2,
359 end: e2,
360 },
361 GestureEvent::Arrow {
362 dir: Dir::East,
363 start: s1,
364 end: e1,
365 },
366 ) if s1.x < s2.x => {
367 ty.send(Event::Gesture(GestureEvent::Cross(
368 (s1 + e1 + s2 + e2) / 4,
369 )))
370 .ok();
371 }
372 (
373 GestureEvent::Arrow {
374 dir: Dir::West,
375 start: s1,
376 end: e1,
377 },
378 GestureEvent::Arrow {
379 dir: Dir::East,
380 start: s2,
381 end: e2,
382 },
383 )
384 | (
385 GestureEvent::Arrow {
386 dir: Dir::East,
387 start: s2,
388 end: e2,
389 },
390 GestureEvent::Arrow {
391 dir: Dir::West,
392 start: s1,
393 end: e1,
394 },
395 ) if s1.x < s2.x => {
396 ty.send(Event::Gesture(GestureEvent::Diamond(
397 (s1 + e1 + s2 + e2) / 4,
398 )))
399 .ok();
400 }
401 (
402 GestureEvent::Arrow {
403 dir: d1,
404 start: s1,
405 end: e1,
406 },
407 GestureEvent::Arrow {
408 dir: d2,
409 start: s2,
410 end: e2,
411 },
412 ) if d1 == d2 => {
413 ty.send(Event::Gesture(GestureEvent::MultiArrow {
414 dir: d1,
415 starts: [s1, s2],
416 ends: [e1, e2],
417 }))
418 .ok();
419 }
420 (
421 GestureEvent::Corner {
422 dir: d1,
423 start: s1,
424 end: e1,
425 },
426 GestureEvent::Corner {
427 dir: d2,
428 start: s2,
429 end: e2,
430 },
431 ) if d1 == d2 => {
432 ty.send(Event::Gesture(GestureEvent::MultiCorner {
433 dir: d1,
434 starts: [s1, s2],
435 ends: [e1, e2],
436 }))
437 .ok();
438 }
439 (
440 GestureEvent::Tap(c),
441 GestureEvent::Swipe {
442 start: s, end: e, ..
443 },
444 )
445 | (
446 GestureEvent::Swipe {
447 start: s, end: e, ..
448 },
449 GestureEvent::Tap(c),
450 )
451 | (
452 GestureEvent::Tap(c),
453 GestureEvent::Arrow {
454 start: s, end: e, ..
455 },
456 )
457 | (
458 GestureEvent::Arrow {
459 start: s, end: e, ..
460 },
461 GestureEvent::Tap(c),
462 )
463 | (
464 GestureEvent::Tap(c),
465 GestureEvent::Corner {
466 start: s, end: e, ..
467 },
468 )
469 | (
470 GestureEvent::Corner {
471 start: s, end: e, ..
472 },
473 GestureEvent::Tap(c),
474 ) => {
475 let angle = ((e - c).angle() - (s - c).angle()).to_degrees();
477 let quarter_turns = (angle / 90.0).round() as i8;
478 ty.send(Event::Gesture(GestureEvent::Rotate {
479 angle,
480 quarter_turns,
481 center: c,
482 }))
483 .ok();
484 }
485 _ => (),
486 }
487 } else {
488 sg.clear();
489 }
490 }
491 }
492 DeviceEvent::Button {
493 status: ButtonStatus::Pressed,
494 code,
495 time,
496 } => {
497 let mut bt = buttons.lock().unwrap();
498 bt.insert(code, time);
499 let ty = ty.clone();
500 let buttons = buttons.clone();
501 thread::spawn(move || {
502 thread::sleep(HOLD_DELAY_SHORT);
503 {
504 let bt = buttons.lock().unwrap();
505 if let Some(&initial_time) = bt.get(&code) {
506 if (initial_time - time).abs() < f64::EPSILON {
507 ty.send(Event::Gesture(GestureEvent::HoldButtonShort(code)))
508 .ok();
509 }
510 }
511 }
512 thread::sleep(HOLD_DELAY_LONG - HOLD_DELAY_SHORT);
513 {
514 let bt = buttons.lock().unwrap();
515 if let Some(&initial_time) = bt.get(&code) {
516 if (initial_time - time).abs() < f64::EPSILON {
517 ty.send(Event::Gesture(GestureEvent::HoldButtonLong(code)))
518 .ok();
519 }
520 }
521 }
522 });
523 }
524 DeviceEvent::Button {
525 status: ButtonStatus::Released,
526 code,
527 ..
528 } => {
529 let mut bt = buttons.lock().unwrap();
530 bt.remove(&code);
531 }
532 _ => (),
533 }
534 }
535}
536
537fn interpret_segment(sp: &[Point], tap_jitter: f32) -> GestureEvent {
538 let a = sp[0];
539 let b = sp[sp.len() - 1];
540 let ab = b - a;
541 let d = ab.length();
542 if d < tap_jitter {
543 GestureEvent::Tap(a)
544 } else {
545 let p = sp[elbow(sp)];
546 let (n, p) = {
547 let p: Vec2 = p.into();
548 let (n, _) = nearest_segment_point(p, a.into(), b.into());
549 (n, p)
550 };
551 let np = p - n;
552 let ds = np.length();
553 if ds > d / 5.0 {
554 let g = (np.x as f32 / np.y as f32).abs();
555 if g < 0.5 || g > 2.0 {
556 GestureEvent::Arrow {
557 dir: np.dir(),
558 start: a,
559 end: b,
560 }
561 } else {
562 GestureEvent::Corner {
563 dir: np.diag_dir(),
564 start: a,
565 end: b,
566 }
567 }
568 } else {
569 let g = (ab.x as f32 / ab.y as f32).abs();
570 if g < 0.5 || g > 2.0 {
571 GestureEvent::Swipe {
572 start: a,
573 end: b,
574 dir: ab.dir(),
575 }
576 } else {
577 GestureEvent::SlantedSwipe {
578 start: a,
579 end: b,
580 dir: ab.diag_dir(),
581 }
582 }
583 }
584 }
585}