1use std::{collections::HashMap, mem, num::NonZeroU32, ops, time::Duration};
21use zng_app::{
22 DInstant,
23 event::{EventPropagationHandle, event, event_args},
24 hn,
25 shortcut::ModifiersState,
26 timer::{DeadlineVar, TIMERS},
27 view_process::{
28 VIEW_PROCESS_INITED_EVENT,
29 raw_device_events::InputDeviceId,
30 raw_events::{RAW_MOUSE_LEFT_EVENT, RAW_TOUCH_CONFIG_CHANGED_EVENT, RAW_TOUCH_EVENT, RawTouchArgs},
31 },
32 widget::{
33 WidgetId,
34 info::{HitTestInfo, InteractionPath, WIDGET_TREE_CHANGED_EVENT},
35 },
36 window::WindowId,
37};
38
39use zng_app_context::app_local;
40use zng_ext_window::{NestedWindowWidgetInfoExt as _, WINDOWS};
41use zng_layout::unit::{
42 AngleRadian, Dip, DipPoint, DipToPx, DipVector, Factor, Px, PxPoint, PxToDip, PxTransform, PxVector, TimeUnits, euclid,
43};
44use zng_var::{Var, VarHandle, impl_from_and_into_var, var};
45pub use zng_view_api::{
46 config::TouchConfig,
47 touch::{TouchForce, TouchId, TouchPhase, TouchUpdate},
48};
49
50use crate::{
51 keyboard::MODIFIERS_CHANGED_EVENT,
52 pointer_capture::{CaptureInfo, POINTER_CAPTURE, POINTER_CAPTURE_EVENT},
53};
54
55struct PressedInfo {
56 touch_propagation: EventPropagationHandle,
57 target: InteractionPath,
58 device_id: InputDeviceId,
59 position: DipPoint,
60 force: Option<TouchForce>,
61 hits: HitTestInfo,
62 velocity_samples: Vec<(DInstant, DipPoint)>,
63}
64impl PressedInfo {
65 fn push_velocity_sample(&mut self, timestamp: DInstant, position: DipPoint) {
66 if let Some(last) = self.velocity_samples.last_mut()
67 && timestamp.duration_since(last.0) < 1.ms()
68 {
69 last.1 = position;
70 return;
71 }
72
73 if self.velocity_samples.len() == 4 {
74 self.velocity_samples.remove(0);
75 }
76 self.velocity_samples.push((timestamp, position));
77 }
78
79 fn velocity(&self) -> DipVector {
80 if self.velocity_samples.len() < 4 {
81 DipVector::zero()
82 } else {
83 let samples = [
84 self.velocity_samples[0].1.cast::<f64>(),
85 self.velocity_samples[1].1.cast(),
86 self.velocity_samples[2].1.cast(),
87 self.velocity_samples[3].1.cast(),
88 ];
89 let velocity_at = |end_i: usize| {
90 let start_i = end_i - 1;
91
92 let start_t = self.velocity_samples[start_i].0;
93 let end_t = self.velocity_samples[end_i].0;
94
95 let start_s = samples[start_i];
96 let end_s = samples[end_i];
97
98 let delta = (end_t - start_t).as_secs_f64();
99
100 if delta > 0.0 {
101 (end_s - start_s) / delta
102 } else {
103 euclid::vec2(0.0, 0.0)
104 }
105 };
106
107 let v23 = velocity_at(3) * 0.6;
108 let v12 = velocity_at(2) * 0.35;
109 let v01 = velocity_at(1) * 0.05;
110 let v = v23 + v12 + v01;
111
112 v.cast::<f32>().cast()
113 }
114 }
115}
116
117pub struct TOUCH;
125
126impl TOUCH {
127 pub fn touch_config(&self) -> Var<TouchConfig> {
133 TOUCH_SV.read().touch_config.clone()
134 }
135
136 pub fn sys_touch_config(&self) -> Var<TouchConfig> {
148 TOUCH_SV.read().sys_touch_config.read_only()
149 }
150
151 pub fn positions(&self) -> Var<Vec<TouchPosition>> {
153 TOUCH_SV.read().positions.read_only()
154 }
155
156 pub fn touch_from_mouse_events(&self) -> Var<bool> {
160 TOUCH_SV.read().touch_from_mouse_events.clone()
161 }
162}
163
164#[derive(Debug, Clone, PartialEq)]
170pub struct TouchPosition {
171 pub window_id: WindowId,
173 pub touch: TouchId,
175 pub position: DipPoint,
177
178 pub start_time: DInstant,
180 pub update_time: DInstant,
182}
183
184app_local! {
185 static TOUCH_SV: TouchService = {
186 hooks();
187 let sys_touch_config = var(TouchConfig::default());
188 let touch_from_mouse_events = var(false);
189 let mut _mouse_handles = Default::default();
190 touch_from_mouse_events
191 .hook(move |a| {
192 if *a.value() {
193 _mouse_handles = hooks_touch_from_mouse();
194 } else {
195 _mouse_handles = Default::default();
196 }
197 true
198 })
199 .perm();
200 TouchService {
201 touch_config: sys_touch_config.cow(),
202 sys_touch_config,
203 positions: var(vec![]),
204 touch_from_mouse_events,
205 modifiers: Default::default(),
206 pressed: Default::default(),
207 tap_gesture: Default::default(),
208 transform_gesture: Default::default(),
209 long_press_gesture: Default::default(),
210 mouse_touch: Default::default(),
211 }
212 };
213}
214struct TouchService {
215 touch_config: Var<TouchConfig>,
216 sys_touch_config: Var<TouchConfig>,
217 positions: Var<Vec<TouchPosition>>,
218 touch_from_mouse_events: Var<bool>,
219
220 modifiers: ModifiersState,
221 pressed: HashMap<TouchId, PressedInfo>,
222 tap_gesture: TapGesture,
223 transform_gesture: TransformGesture,
224 long_press_gesture: LongPressGesture,
225 mouse_touch: Option<TouchId>,
226}
227
228#[derive(Debug, Clone, PartialEq)]
230pub struct TouchMove {
231 pub touch: TouchId,
237
238 pub touch_propagation: EventPropagationHandle,
242
243 pub moves: Vec<(DipPoint, Option<TouchForce>)>,
247
248 pub velocity: DipVector,
252
253 pub hits: HitTestInfo,
255
256 pub target: InteractionPath,
258}
259impl TouchMove {
260 pub fn position(&self) -> DipPoint {
262 self.moves.last().map(|(p, _)| *p).unwrap_or_else(DipPoint::zero)
263 }
264}
265
266event_args! {
267 pub struct TouchMoveArgs {
269 pub window_id: WindowId,
271
272 pub device_id: InputDeviceId,
274
275 pub touches: Vec<TouchMove>,
280
281 pub capture: Option<CaptureInfo>,
283
284 pub modifiers: ModifiersState,
286
287 ..
288
289 fn is_in_target(&self, id: WidgetId) -> bool {
293 for t in &self.touches {
294 if t.target.contains(id) {
295 return true;
296 }
297 }
298 if let Some(c) = &self.capture {
299 return c.target.contains(id);
300 }
301 false
302 }
303 }
304
305 pub struct TouchInputArgs {
307 pub window_id: WindowId,
309
310 pub device_id: InputDeviceId,
312
313 pub touch: TouchId,
319
320 pub touch_propagation: EventPropagationHandle,
337
338 pub position: DipPoint,
340
341 pub force: Option<TouchForce>,
343
344 pub velocity: DipVector,
351
352 pub phase: TouchPhase,
356
357 pub hits: HitTestInfo,
359
360 pub target: InteractionPath,
362
363 pub capture: Option<CaptureInfo>,
365
366 pub modifiers: ModifiersState,
368
369 ..
370
371 fn is_in_target(&self, id: WidgetId) -> bool {
376 if self.target.contains(id) {
377 return true;
378 }
379 if let Some(c) = &self.capture {
380 return c.target.contains(id);
381 }
382 false
383 }
384 }
385
386 pub struct TouchedArgs {
388 pub window_id: WindowId,
390
391 pub device_id: Option<InputDeviceId>,
393
394 pub touch: TouchId,
400
401 pub touch_propagation: EventPropagationHandle,
405
406 pub position: DipPoint,
408
409 pub force: Option<TouchForce>,
411
412 pub phase: TouchPhase,
414
415 pub hits: HitTestInfo,
417
418 pub prev_target: Option<InteractionPath>,
420
421 pub target: Option<InteractionPath>,
423
424 pub prev_capture: Option<CaptureInfo>,
426
427 pub capture: Option<CaptureInfo>,
429
430 ..
431
432 fn is_in_target(&self, id: WidgetId) -> bool {
438 if let Some(p) = &self.prev_target
439 && p.contains(id)
440 {
441 return true;
442 }
443 if let Some(p) = &self.target
444 && p.contains(id)
445 {
446 return true;
447 }
448 if let Some(c) = &self.capture {
449 return c.target.contains(id);
450 }
451 false
452 }
453 }
454
455 pub struct TouchTapArgs {
457 pub window_id: WindowId,
459
460 pub device_id: InputDeviceId,
462
463 pub touch: TouchId,
469
470 pub position: DipPoint,
472
473 pub hits: HitTestInfo,
475
476 pub target: InteractionPath,
478
479 pub modifiers: ModifiersState,
481
482 pub tap_count: NonZeroU32,
484
485 ..
486
487 fn is_in_target(&self, id: WidgetId) -> bool {
491 self.target.contains(id)
492 }
493 }
494
495 pub struct TouchLongPressArgs {
497 pub window_id: WindowId,
499
500 pub device_id: InputDeviceId,
502
503 pub touch: TouchId,
509
510 pub position: DipPoint,
512
513 pub hits: HitTestInfo,
515
516 pub target: InteractionPath,
518
519 pub modifiers: ModifiersState,
521
522 pub start_time: DInstant,
524
525 ..
526
527 fn is_in_target(&self, id: WidgetId) -> bool {
531 self.target.contains(id)
532 }
533 }
534
535 pub struct TouchTransformArgs {
537 pub window_id: WindowId,
539
540 pub device_id: InputDeviceId,
542
543 pub first_info: TouchTransformInfo,
545
546 pub latest_info: TouchTransformInfo,
548
549 pub velocity: [PxVector; 2],
551
552 pub scale_factor: Factor,
556
557 pub phase: TouchPhase,
559
560 pub hits: HitTestInfo,
563
564 pub target: InteractionPath,
566
567 pub capture: Option<CaptureInfo>,
569
570 pub modifiers: ModifiersState,
572
573 ..
574
575 fn is_in_target(&self, id: WidgetId) -> bool {
580 if self.target.contains(id) {
581 return true;
582 }
583 if let Some(c) = &self.capture {
584 return c.target.contains(id);
585 }
586 false
587 }
588 }
589}
590
591impl TouchMoveArgs {
592 pub fn capture_allows(&self, wgt: (WindowId, WidgetId)) -> bool {
597 self.capture.as_ref().map(|c| c.allows(wgt)).unwrap_or(true)
598 }
599}
600
601impl TouchInputArgs {
602 pub fn capture_allows(&self, wgt: (WindowId, WidgetId)) -> bool {
607 self.capture.as_ref().map(|c| c.allows(wgt)).unwrap_or(true)
608 }
609
610 pub fn is_touch_start(&self) -> bool {
614 matches!(self.phase, TouchPhase::Start)
615 }
616
617 pub fn is_touch_end(&self) -> bool {
621 matches!(self.phase, TouchPhase::End)
622 }
623
624 pub fn is_touch_cancel(&self) -> bool {
628 matches!(self.phase, TouchPhase::Cancel)
629 }
630
631 pub fn inertia_x(&self, friction: Dip) -> (Dip, Duration) {
644 Self::inertia(self.velocity.x, friction)
645 }
646
647 pub fn inertia_y(&self, friction: Dip) -> (Dip, Duration) {
655 Self::inertia(self.velocity.y, friction)
656 }
657
658 fn inertia(velocity: Dip, friction: Dip) -> (Dip, Duration) {
659 let cfg = TOUCH.touch_config().get();
660 let signal = if velocity >= 0 { 1.0 } else { -1.0 };
661 let velocity = velocity.abs();
662
663 if velocity < cfg.min_fling_velocity {
664 (Dip::new(0), Duration::ZERO)
665 } else {
666 let velocity = velocity.min(cfg.max_fling_velocity).to_f32();
667 let friction = friction.to_f32();
668
669 let time = velocity / friction;
670 let offset = (velocity * time) - (friction * time);
671
672 (Dip::from(offset) * signal, time.secs())
673 }
674 }
675
676 pub fn position_wgt(&self, wgt: (WindowId, WidgetId)) -> Option<PxPoint> {
678 let tree = WINDOWS.widget_tree(wgt.0)?;
679 tree.get(wgt.1)?
680 .inner_transform()
681 .inverse()?
682 .transform_point(self.position.to_px(tree.scale_factor()))
683 }
684}
685
686impl TouchedArgs {
687 pub fn capture_allows(&self, wgt: (WindowId, WidgetId)) -> bool {
692 self.capture.as_ref().map(|c| c.allows(wgt)).unwrap_or(true)
693 }
694
695 pub fn is_touch_move(&self) -> bool {
697 self.device_id.is_some()
698 }
699
700 pub fn is_widget_move(&self) -> bool {
702 self.device_id.is_none()
703 }
704
705 pub fn is_capture_change(&self) -> bool {
707 self.prev_capture != self.capture
708 }
709
710 pub fn is_touch_enter(&self, wgt: (WindowId, WidgetId)) -> bool {
712 !self.was_touched(wgt) && self.is_touched(wgt)
713 }
714
715 pub fn is_touch_leave(&self, wgt: (WindowId, WidgetId)) -> bool {
717 self.was_touched(wgt) && !self.is_touched(wgt)
718 }
719
720 pub fn is_touch_enter_enabled(&self, wgt: (WindowId, WidgetId)) -> bool {
722 (!self.was_touched(wgt) || self.was_disabled(wgt.1)) && self.is_touched(wgt) && self.is_enabled(wgt.1)
723 }
724
725 pub fn is_touch_leave_enabled(&self, wgt: (WindowId, WidgetId)) -> bool {
727 self.was_touched(wgt) && self.was_enabled(wgt.1) && (!self.is_touched(wgt) || self.is_disabled(wgt.1))
728 }
729
730 pub fn is_touch_enter_disabled(&self, wgt: (WindowId, WidgetId)) -> bool {
732 (!self.was_touched(wgt) || self.was_enabled(wgt.1)) && self.is_touched(wgt) && self.is_disabled(wgt.1)
733 }
734
735 pub fn is_touch_leave_disabled(&self, wgt: (WindowId, WidgetId)) -> bool {
737 self.was_touched(wgt) && self.was_disabled(wgt.1) && (!self.is_touched(wgt) || self.is_enabled(wgt.1))
738 }
739
740 pub fn was_touched(&self, wgt: (WindowId, WidgetId)) -> bool {
745 if let Some(cap) = &self.prev_capture
746 && !cap.allows(wgt)
747 {
748 return false;
749 }
750
751 if let Some(t) = &self.prev_target {
752 return t.contains(wgt.1);
753 }
754
755 false
756 }
757
758 pub fn is_touched(&self, wgt: (WindowId, WidgetId)) -> bool {
763 if let Some(cap) = &self.capture
764 && !cap.allows(wgt)
765 {
766 return false;
767 }
768
769 if let Some(t) = &self.target {
770 return t.contains(wgt.1);
771 }
772
773 false
774 }
775 pub fn was_enabled(&self, widget_id: WidgetId) -> bool {
779 match &self.prev_target {
780 Some(t) => t.contains_enabled(widget_id),
781 None => false,
782 }
783 }
784
785 pub fn was_disabled(&self, widget_id: WidgetId) -> bool {
789 match &self.prev_target {
790 Some(t) => t.contains_disabled(widget_id),
791 None => false,
792 }
793 }
794
795 pub fn is_enabled(&self, widget_id: WidgetId) -> bool {
799 match &self.target {
800 Some(t) => t.contains_enabled(widget_id),
801 None => false,
802 }
803 }
804
805 pub fn is_disabled(&self, widget_id: WidgetId) -> bool {
809 match &self.target {
810 Some(t) => t.contains_disabled(widget_id),
811 None => false,
812 }
813 }
814}
815
816impl TouchTransformArgs {
817 pub fn capture_allows(&self, wgt: (WindowId, WidgetId)) -> bool {
822 self.capture.as_ref().map(|c| c.allows(wgt)).unwrap_or(true)
823 }
824
825 pub fn local_info(&self, wgt: (WindowId, WidgetId)) -> [TouchTransformInfo; 2] {
830 let mut first = self.first_info.clone();
831 let mut latest = self.latest_info.clone();
832
833 let offset = WINDOWS
834 .widget_tree(wgt.0)
835 .and_then(|t| t.get(wgt.1))
836 .map(|w| w.bounds_info().inner_offset())
837 .unwrap_or_default();
838
839 first -= offset;
840 latest -= offset;
841
842 [first, latest]
843 }
844
845 pub fn translation(&self) -> euclid::Vector2D<f32, Px> {
850 self.first_info.translation(&self.latest_info)
851 }
852
853 pub fn translation_x(&self) -> f32 {
858 self.first_info.translation_x(&self.latest_info)
859 }
860
861 pub fn translation_y(&self) -> f32 {
866 self.first_info.translation_y(&self.latest_info)
867 }
868
869 pub fn rotation(&self) -> AngleRadian {
874 self.first_info.rotation(&self.latest_info)
875 }
876
877 pub fn scale(&self) -> Factor {
882 self.first_info.scale(&self.latest_info)
883 }
884
885 pub fn scale_x(&self) -> Factor {
890 self.first_info.scale_x(&self.latest_info)
891 }
892
893 pub fn scale_y(&self) -> Factor {
898 self.first_info.scale_y(&self.latest_info)
899 }
900
901 pub fn transform(&self, mode: TouchTransformMode) -> PxTransform {
906 self.first_info.transform(&self.latest_info, mode)
907 }
908
909 pub fn local_transform(&self, mode: TouchTransformMode, wgt: (WindowId, WidgetId)) -> PxTransform {
913 let [first, latest] = self.local_info(wgt);
914
915 let mut r = first.transform(&latest, mode);
916
917 if mode.contains(TouchTransformMode::ROTATE)
918 || mode.contains(TouchTransformMode::SCALE_X)
919 || mode.contains(TouchTransformMode::SCALE_Y)
920 {
921 let c = latest.center.to_vector();
922 r = PxTransform::Offset(-c).then(&r).then_translate(c);
923 }
924
925 r
926 }
927
928 pub fn translation_velocity(&self) -> PxVector {
930 (self.velocity[0] + self.velocity[1]) / Px(2)
931 }
932
933 pub fn translation_inertia_x(&self, deceleration: Dip) -> (Px, Duration) {
942 self.inertia((self.velocity[0].x + self.velocity[1].x) / Px(2), deceleration)
943 }
944
945 pub fn translation_inertia_y(&self, deceleration: Dip) -> (Px, Duration) {
954 self.inertia((self.velocity[0].y + self.velocity[1].y) / Px(2), deceleration)
955 }
956
957 pub fn is_start(&self) -> bool {
966 matches!(self.phase, TouchPhase::Start)
967 }
968
969 pub fn is_end(&self) -> bool {
975 matches!(self.phase, TouchPhase::End)
976 }
977
978 pub fn is_cancel(&self) -> bool {
984 matches!(self.phase, TouchPhase::Cancel)
985 }
986
987 fn inertia(&self, velocity: Px, deceleration: Dip) -> (Px, Duration) {
988 let friction = deceleration.to_px(self.scale_factor);
989 let cfg = TOUCH.touch_config().get();
990 let min_fling_velocity = cfg.min_fling_velocity.to_px(self.scale_factor);
991
992 let signal = if velocity >= 0 { 1.0 } else { -1.0 };
993 let velocity = velocity.abs();
994
995 if velocity < min_fling_velocity {
996 (Px(0), Duration::ZERO)
997 } else {
998 let max_fling_velocity = cfg.max_fling_velocity.to_px(self.scale_factor);
999 let velocity = velocity.min(max_fling_velocity).0 as f32;
1000 let friction = friction.0 as f32;
1001
1002 let time = velocity / friction;
1003 let offset = 0.5 * friction * time * time;
1004 (Px(offset.round() as _) * signal, time.secs())
1005 }
1006 }
1007}
1008
1009event! {
1010 pub static TOUCH_MOVE_EVENT: TouchMoveArgs {
1012 let _ = TOUCH_SV.read();
1013 };
1014
1015 pub static TOUCH_INPUT_EVENT: TouchInputArgs {
1017 let _ = TOUCH_SV.read();
1018 };
1019
1020 pub static TOUCHED_EVENT: TouchedArgs {
1022 let _ = TOUCH_SV.read();
1023 };
1024
1025 pub static TOUCH_TAP_EVENT: TouchTapArgs {
1027 let _ = TOUCH_SV.read();
1028 };
1029
1030 pub static TOUCH_TRANSFORM_EVENT: TouchTransformArgs {
1032 let _ = TOUCH_SV.read();
1033 };
1034
1035 pub static TOUCH_LONG_PRESS_EVENT: TouchLongPressArgs {
1039 let _ = TOUCH_SV.read();
1040 };
1041}
1042
1043impl TouchService {
1044 fn on_input(&mut self, args: &RawTouchArgs, update: &TouchUpdate) {
1045 if let Some(w) = WINDOWS.widget_tree(args.window_id) {
1046 let mut hits = w.root().hit_test(update.position.to_px(w.scale_factor()));
1047 let mut target = hits
1048 .target()
1049 .and_then(|t| w.get(t.widget_id))
1050 .map(|t| t.interaction_path())
1051 .unwrap_or_else(|| w.root().interaction_path());
1052 let mut position = update.position;
1053
1054 if let Some(wgt) = w.get(target.widget_id())
1056 && let Some(w) = wgt.nested_window_tree()
1057 {
1058 let f = w.scale_factor();
1059 let p = update.position.to_px(f);
1060 let p = wgt.inner_transform().inverse().and_then(|t| t.transform_point(p)).unwrap_or(p);
1061 position = p.to_dip(f);
1062 hits = w.root().hit_test(p);
1063 target = hits
1064 .target()
1065 .and_then(|t| w.get(t.widget_id))
1066 .map(|t| t.interaction_path())
1067 .unwrap_or_else(|| w.root().interaction_path());
1068 }
1069
1070 let target = match target.unblocked() {
1071 Some(t) => t,
1072 None => return, };
1074
1075 let capture_info = POINTER_CAPTURE.current_capture().get();
1076
1077 let (gesture_handle, velocity) = match update.phase {
1078 TouchPhase::Start => {
1079 let handle = EventPropagationHandle::new();
1080 if let Some(weird) = self.pressed.insert(
1081 update.touch,
1082 PressedInfo {
1083 touch_propagation: handle.clone(),
1084 target: target.clone(),
1085 device_id: args.device_id,
1086 position,
1087 force: update.force,
1088 hits: hits.clone(),
1089 velocity_samples: vec![], },
1091 ) {
1092 weird.touch_propagation.stop();
1093 }
1094 (handle, DipVector::zero())
1095 }
1096 TouchPhase::End => {
1097 if let Some(handle) = self.pressed.remove(&update.touch) {
1098 let vel = handle.velocity();
1099 (handle.touch_propagation, vel)
1100 } else {
1101 let weird = EventPropagationHandle::new();
1102 weird.stop();
1103 (weird, DipVector::zero())
1104 }
1105 }
1106 TouchPhase::Cancel => {
1107 let handle = self.pressed.remove(&update.touch).map(|i| i.touch_propagation).unwrap_or_default();
1108 handle.stop();
1109 (handle, DipVector::zero())
1110 }
1111 TouchPhase::Move => unreachable!(),
1112 };
1113
1114 match update.phase {
1115 TouchPhase::Start => {
1116 let pos_info = TouchPosition {
1117 window_id: hits.window_id(),
1118 touch: update.touch,
1119 position,
1120 start_time: args.timestamp,
1121 update_time: args.timestamp,
1122 };
1123 self.positions.modify(move |p| {
1124 let p = &mut **p;
1125 if let Some(weird) = p.iter().position(|p| p.touch == pos_info.touch) {
1126 p.remove(weird);
1127 }
1128 p.push(pos_info);
1129 });
1130 }
1131 _ => {
1132 let touch = update.touch;
1133 self.positions.modify(move |p| {
1134 if let Some(i) = p.iter().position(|p| p.touch == touch) {
1135 p.remove(i);
1136 }
1137 });
1138 }
1139 }
1140
1141 let args = TouchInputArgs::now(
1142 hits.window_id(),
1143 args.device_id,
1144 update.touch,
1145 gesture_handle,
1146 position,
1147 update.force,
1148 velocity,
1149 update.phase,
1150 hits,
1151 target,
1152 capture_info,
1153 self.modifiers,
1154 );
1155
1156 let touched_args = {
1157 let (prev_target, target) = match args.phase {
1160 TouchPhase::Start => (None, Some(args.target.clone())),
1161 TouchPhase::End | TouchPhase::Cancel => (Some(args.target.clone()), None),
1162 TouchPhase::Move => unreachable!(),
1163 };
1164
1165 TouchedArgs::now(
1166 args.window_id,
1167 args.device_id,
1168 args.touch,
1169 args.touch_propagation.clone(),
1170 args.position,
1171 args.force,
1172 args.phase,
1173 args.hits.clone(),
1174 prev_target,
1175 target,
1176 args.capture.clone(),
1177 args.capture.clone(),
1178 )
1179 };
1180
1181 TOUCH_INPUT_EVENT.notify(args);
1182 TOUCHED_EVENT.notify(touched_args);
1183 } else {
1184 for u in &args.touches {
1186 if let Some(i) = self.pressed.remove(&u.touch) {
1187 let capture = POINTER_CAPTURE.current_capture().get();
1188 let args = TouchedArgs::now(
1189 args.window_id,
1190 args.device_id,
1191 u.touch,
1192 i.touch_propagation,
1193 u.position,
1194 u.force,
1195 u.phase,
1196 HitTestInfo::no_hits(args.window_id),
1197 Some(i.target),
1198 None,
1199 capture.clone(),
1200 capture,
1201 );
1202 TOUCHED_EVENT.notify(args);
1203 }
1204 }
1205 }
1206 }
1207
1208 fn on_move(&mut self, args: &RawTouchArgs, mut moves: Vec<TouchMove>) {
1209 if !moves.is_empty()
1210 && let Some(w) = WINDOWS.widget_tree(args.window_id)
1211 {
1212 let mut window_blocked_remove = vec![];
1213 for m in &mut moves {
1214 m.hits = w.root().hit_test(m.position().to_px(w.scale_factor()));
1215 let target = m
1216 .hits
1217 .target()
1218 .and_then(|t| w.get(t.widget_id))
1219 .map(|t| t.interaction_path())
1220 .unwrap_or_else(|| w.root().interaction_path());
1221
1222 match target.unblocked() {
1223 Some(t) => {
1224 m.target = t;
1225 if let Some(wgt) = w.get(m.target.widget_id())
1227 && let Some(w) = wgt.nested_window_tree()
1228 {
1229 let transform = wgt.inner_transform().inverse();
1230 let factor = w.scale_factor();
1231 let mut position = PxPoint::zero(); for (mv, _) in &mut m.moves {
1233 let p = mv.to_px(factor);
1234 let p = transform.and_then(|t| t.transform_point(p)).unwrap_or(p);
1235 *mv = p.to_dip(factor);
1236 position = p;
1237 }
1238 m.hits = w.root().hit_test(position);
1239 let target = m
1240 .hits
1241 .target()
1242 .and_then(|t| w.get(t.widget_id))
1243 .map(|t| t.interaction_path())
1244 .unwrap_or_else(|| w.root().interaction_path());
1245
1246 match target.unblocked() {
1247 Some(t) => m.target = t,
1248 None => window_blocked_remove.push(m.touch),
1249 }
1250 }
1251 }
1252 None => {
1253 window_blocked_remove.push(m.touch);
1254 }
1255 }
1256 }
1257
1258 let position_updates: Vec<_> = moves
1259 .iter()
1260 .map(|m| TouchPosition {
1261 window_id: args.window_id,
1262 touch: m.touch,
1263 position: m.position(),
1264 start_time: args.timestamp, update_time: args.timestamp,
1266 })
1267 .collect();
1268 self.positions.modify(move |p| {
1269 for mut update in position_updates {
1270 if let Some(i) = p.iter().position(|p| p.touch == update.touch) {
1271 update.start_time = p[i].start_time;
1272 p[i] = update;
1273 }
1274 }
1275 });
1276
1277 let capture_info = POINTER_CAPTURE.current_capture().get();
1278
1279 let mut touched_events = vec![];
1280
1281 for touch in window_blocked_remove {
1282 let touch_move = moves.iter().position(|t| t.touch == touch).unwrap();
1283 moves.swap_remove(touch_move);
1284
1285 if let Some(i) = self.pressed.remove(&touch) {
1286 i.touch_propagation.stop();
1287 let args = TouchedArgs::now(
1288 args.window_id,
1289 args.device_id,
1290 touch,
1291 i.touch_propagation,
1292 DipPoint::splat(Dip::new(-1)),
1293 None,
1294 TouchPhase::Cancel,
1295 HitTestInfo::no_hits(args.window_id),
1296 i.target,
1297 None,
1298 None,
1299 None,
1300 );
1301 touched_events.push(args);
1302 }
1303 }
1304 for m in &mut moves {
1305 if let Some(i) = self.pressed.get_mut(&m.touch) {
1306 let (position, force) = *m.moves.last().unwrap();
1307 i.push_velocity_sample(args.timestamp, position);
1308 m.velocity = i.velocity();
1309 i.position = position;
1310 i.force = force;
1311 i.hits = m.hits.clone();
1312 if i.target != m.target {
1313 let args = TouchedArgs::now(
1314 args.window_id,
1315 args.device_id,
1316 m.touch,
1317 m.touch_propagation.clone(),
1318 position,
1319 force,
1320 TouchPhase::Move,
1321 m.hits.clone(),
1322 i.target.clone(),
1323 m.target.clone(),
1324 capture_info.clone(),
1325 capture_info.clone(),
1326 );
1327 i.target = m.target.clone();
1328 touched_events.push(args);
1329 }
1330 }
1331 }
1332
1333 if !moves.is_empty() {
1334 let args = TouchMoveArgs::now(args.window_id, args.device_id, moves, capture_info, self.modifiers);
1335 TOUCH_MOVE_EVENT.notify(args);
1336 }
1337
1338 for args in touched_events {
1339 TOUCHED_EVENT.notify(args);
1340 }
1341 }
1342 }
1343
1344 fn continue_pressed(&mut self, window_id: WindowId) {
1345 let mut tree = None;
1346
1347 let mut window_blocked_remove = vec![];
1348
1349 for (touch, info) in &mut self.pressed {
1350 if info.target.window_id() != window_id {
1351 continue;
1352 }
1353
1354 let tree = tree.get_or_insert_with(|| WINDOWS.widget_tree(window_id).unwrap());
1355 info.hits = tree.root().hit_test(info.position.to_px(tree.scale_factor()));
1356
1357 let target = if let Some(t) = info.hits.target() {
1358 tree.get(t.widget_id).map(|w| w.interaction_path()).unwrap_or_else(|| {
1359 tracing::error!("hits target `{}` not found", t.widget_id);
1360 tree.root().interaction_path()
1361 })
1362 } else {
1363 tree.root().interaction_path()
1364 }
1365 .unblocked();
1366
1367 if let Some(target) = target {
1368 if info.target != target {
1369 let capture = POINTER_CAPTURE.current_capture().get();
1370 let prev = mem::replace(&mut info.target, target.clone());
1371
1372 let args = TouchedArgs::now(
1373 info.target.window_id(),
1374 None,
1375 *touch,
1376 info.touch_propagation.clone(),
1377 info.position,
1378 info.force,
1379 TouchPhase::Move,
1380 info.hits.clone(),
1381 prev,
1382 target,
1383 capture.clone(),
1384 capture,
1385 );
1386 TOUCHED_EVENT.notify(args);
1387 }
1388 } else {
1389 window_blocked_remove.push(*touch);
1390 }
1391 }
1392
1393 for touch in window_blocked_remove {
1394 if let Some(i) = self.pressed.remove(&touch) {
1395 i.touch_propagation.stop();
1396 let args = TouchedArgs::now(
1397 i.target.window_id(),
1398 None,
1399 touch,
1400 i.touch_propagation,
1401 DipPoint::splat(Dip::new(-1)),
1402 None,
1403 TouchPhase::Cancel,
1404 HitTestInfo::no_hits(i.target.window_id()),
1405 i.target,
1406 None,
1407 None,
1408 None,
1409 );
1410 TOUCHED_EVENT.notify(args);
1411 }
1412 }
1413 }
1414}
1415
1416struct PendingDoubleTap {
1417 window_id: WindowId,
1418 device_id: InputDeviceId,
1419 target: WidgetId,
1420 count: NonZeroU32,
1421 timestamp: DInstant,
1422}
1423struct PendingTap {
1424 window_id: WindowId,
1425 device_id: InputDeviceId,
1426 touch: TouchId,
1427 target: WidgetId,
1428
1429 propagation: EventPropagationHandle,
1430}
1431impl PendingTap {
1432 fn retain(&self, window_id: WindowId, device_id: InputDeviceId, touch: TouchId) -> bool {
1436 if self.propagation.is_stopped() {
1437 return false;
1439 }
1440
1441 if window_id != self.window_id || device_id != self.device_id {
1442 return false;
1444 }
1445
1446 if touch != self.touch {
1447 return false;
1449 }
1450
1451 true
1453 }
1454}
1455
1456struct PendingLongPress {
1457 window_id: WindowId,
1458 device_id: InputDeviceId,
1459 touch: TouchId,
1460 target: WidgetId,
1461 position: DipPoint,
1462 start_time: DInstant,
1463 modifiers: ModifiersState,
1464
1465 propagation: EventPropagationHandle,
1466
1467 delay: DeadlineVar,
1468 canceled: bool,
1469}
1470
1471#[derive(Default)]
1472struct LongPressGesture {
1473 pending: Option<PendingLongPress>,
1474}
1475impl LongPressGesture {
1476 fn on_input(&mut self, args: &TouchInputArgs, cfg: &Var<TouchConfig>) {
1477 match args.phase {
1478 TouchPhase::Start => {
1479 if let Some(p) = &mut self.pending {
1480 p.canceled = true;
1482 } else {
1483 let delay = TIMERS.deadline(cfg.get().tap_max_time);
1484 delay
1485 .hook(|a| {
1486 let elapsed = a.value().has_elapsed();
1487 if elapsed {
1488 TOUCH_SV.write().long_press_gesture.on_update();
1489 }
1490 !elapsed
1491 })
1492 .perm();
1493 self.pending = Some(PendingLongPress {
1494 window_id: args.window_id,
1495 device_id: args.device_id,
1496 touch: args.touch,
1497 position: args.position,
1498 start_time: args.timestamp,
1499 modifiers: args.modifiers,
1500 target: args.target.widget_id(),
1501 propagation: args.touch_propagation.clone(),
1502 delay,
1503 canceled: false,
1504 });
1505 }
1506 }
1507 TouchPhase::End | TouchPhase::Cancel => {
1508 if let Some(p) = &self.pending
1509 && args.touch_propagation == p.propagation
1510 {
1511 self.pending = None;
1512 }
1513 }
1514 TouchPhase::Move => unreachable!(),
1515 }
1516 }
1517
1518 fn on_move(&mut self, args: &TouchMoveArgs, cfg: &Var<TouchConfig>) {
1519 if let Some(p) = &mut self.pending
1520 && !p.canceled
1521 && !p.propagation.is_stopped()
1522 {
1523 for m in &args.touches {
1524 if p.propagation == m.touch_propagation {
1525 let dist = p.position - m.position().to_vector();
1526 let max = cfg.get().tap_area;
1527 if dist.x.abs() > max.width || dist.y.abs() > max.height {
1528 p.canceled = true;
1529 break;
1530 }
1531 } else {
1532 p.canceled = true;
1533 break;
1534 }
1535 }
1536 }
1537 }
1538
1539 fn on_update(&mut self) {
1540 if let Some(p) = &mut self.pending
1541 && !p.canceled
1542 && !p.propagation.is_stopped()
1543 && p.delay.get().has_elapsed()
1544 {
1545 if let Some(w) = WINDOWS.widget_tree(p.window_id)
1546 && let Some(w) = w.get(p.target)
1547 {
1548 let hits = w.hit_test(p.position.to_px(w.tree().scale_factor()));
1549 if hits.contains(p.target) {
1550 p.propagation.stop();
1551
1552 let args = TouchLongPressArgs::now(
1553 p.window_id,
1554 p.device_id,
1555 p.touch,
1556 p.position,
1557 hits,
1558 w.interaction_path(),
1559 p.modifiers,
1560 p.start_time,
1561 );
1562 TOUCH_LONG_PRESS_EVENT.notify(args);
1563 return;
1564 }
1565 }
1566 p.canceled = true;
1567 }
1568 }
1569
1570 fn clear(&mut self) {
1571 self.pending = None;
1572 }
1573}
1574
1575#[derive(Default)]
1576struct TapGesture {
1577 pending_double: Option<PendingDoubleTap>,
1578 pending: Option<PendingTap>,
1579}
1580impl TapGesture {
1581 fn on_input(&mut self, args: &TouchInputArgs, cfg: &Var<TouchConfig>) {
1582 match args.phase {
1583 TouchPhase::Start => {
1584 if self.pending.is_some() {
1585 self.pending = None;
1586 self.pending_double = None;
1587 } else {
1588 self.pending = Some(PendingTap {
1589 window_id: args.window_id,
1590 device_id: args.device_id,
1591 touch: args.touch,
1592 target: args.target.widget_id(),
1593 propagation: args.touch_propagation.clone(),
1594 });
1595 }
1596 }
1597 TouchPhase::End => {
1598 let pending_double = self.pending_double.take();
1599
1600 if let Some(p) = self.pending.take() {
1601 if !p.retain(args.window_id, args.device_id, args.touch) {
1602 return;
1603 }
1604
1605 p.propagation.stop(); let tree = if let Some(w) = WINDOWS.widget_tree(args.window_id) {
1608 w
1609 } else {
1610 return;
1611 };
1612
1613 match tree.get(p.target) {
1614 Some(t) => {
1615 if !t.hit_test(args.position.to_px(tree.scale_factor())).contains(p.target) {
1616 return;
1618 }
1619 }
1620 None => return,
1621 }
1622
1623 if let Some(target) = args.target.sub_path(p.target) {
1624 let tap_count = if let Some(double) = pending_double {
1625 if double.window_id == p.window_id
1626 && double.device_id == p.device_id
1627 && double.target == p.target
1628 && double.timestamp.elapsed() <= cfg.get().double_tap_max_time
1629 {
1630 NonZeroU32::new(double.count.get() + 1).unwrap()
1631 } else {
1632 NonZeroU32::new(1).unwrap()
1633 }
1634 } else {
1635 NonZeroU32::new(1).unwrap()
1636 };
1637
1638 self.pending_double = Some(PendingDoubleTap {
1639 window_id: args.window_id,
1640 device_id: args.device_id,
1641 target: p.target,
1642 count: tap_count,
1643 timestamp: args.timestamp,
1644 });
1645
1646 TOUCH_TAP_EVENT.notify(TouchTapArgs::new(
1647 args.timestamp,
1648 args.propagation.clone(),
1649 p.window_id,
1650 p.device_id,
1651 p.touch,
1652 args.position,
1653 args.hits.clone(),
1654 target.into_owned(),
1655 args.modifiers,
1656 tap_count,
1657 ));
1658 }
1659 }
1660 }
1661 TouchPhase::Cancel => {
1662 if let Some(p) = self.pending.take() {
1663 p.propagation.stop();
1664 }
1665 self.pending = None;
1666 self.pending_double = None;
1667 }
1668 TouchPhase::Move => unreachable!(),
1669 }
1670 }
1671
1672 fn on_move(&mut self, args: &TouchMoveArgs) {
1673 if let Some(p) = &self.pending {
1674 for t in &args.touches {
1675 if !p.retain(args.window_id, args.device_id, t.touch) {
1676 self.pending = None;
1677 self.pending_double = None;
1678 break;
1679 }
1680 }
1681 }
1682 }
1683
1684 fn clear(&mut self) {
1685 self.pending = None;
1686 self.pending_double = None;
1687 }
1688}
1689
1690#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
1692pub struct TouchTransformInfo {
1693 pub touches: [euclid::Point2D<f32, Px>; 2],
1695
1696 pub center: euclid::Point2D<f32, Px>,
1698
1699 pub deviation: f32,
1703
1704 pub deviation_x: f32,
1708
1709 pub deviation_y: f32,
1713
1714 pub angle: AngleRadian,
1716}
1717impl TouchTransformInfo {
1718 pub fn new_f32(touches: [euclid::Point2D<f32, Px>; 2]) -> Self {
1720 let a = touches[0].to_vector();
1721 let b = touches[1].to_vector();
1722
1723 let center = (a + b) / 2.0;
1724 let deviation = (a - center).length();
1725 let deviation_x = (a.x - center.x).abs();
1726 let deviation_y = (a.y - center.y).abs();
1727
1728 Self {
1729 touches,
1730 center: center.to_point(),
1731 deviation: deviation.max(1.0),
1732 deviation_x: deviation_x.max(1.0),
1733 deviation_y: deviation_y.max(1.0),
1734 angle: AngleRadian((a.y - b.y).atan2(a.x - b.x)),
1735 }
1736 }
1737
1738 pub fn new(touches: [PxPoint; 2]) -> Self {
1740 Self::new_f32([touches[0].to_f32(), touches[1].to_f32()])
1741 }
1742
1743 pub fn new_dip(touches: [DipPoint; 2], scale_factor: Factor) -> Self {
1745 Self::new_f32([touches[0].to_f32().to_px(scale_factor), touches[1].to_f32().to_px(scale_factor)])
1746 }
1747}
1748impl TouchTransformInfo {
1749 pub fn translation(&self, other: &Self) -> euclid::Vector2D<f32, Px> {
1751 other.center.to_vector() - self.center.to_vector()
1752 }
1753
1754 pub fn translation_x(&self, other: &Self) -> f32 {
1756 other.center.x - self.center.x
1757 }
1758
1759 pub fn translation_y(&self, other: &Self) -> f32 {
1761 other.center.y - self.center.y
1762 }
1763
1764 pub fn rotation(&self, other: &Self) -> AngleRadian {
1766 other.angle - self.angle
1767 }
1768
1769 pub fn scale(&self, other: &Self) -> Factor {
1771 Factor(other.deviation / self.deviation)
1772 }
1773
1774 pub fn scale_x(&self, other: &Self) -> Factor {
1776 Factor(other.deviation_x / self.deviation_x)
1777 }
1778
1779 pub fn scale_y(&self, other: &Self) -> Factor {
1781 Factor(other.deviation_y / self.deviation_y)
1782 }
1783
1784 pub fn transform(&self, other: &Self, mode: TouchTransformMode) -> PxTransform {
1786 let mut m = PxTransform::identity();
1787
1788 if mode.contains(TouchTransformMode::TRANSLATE) {
1789 m = m.then_translate(self.translation(other));
1790 } else if mode.contains(TouchTransformMode::TRANSLATE_X) {
1791 let t = euclid::vec2(self.translation_x(other), 0.0);
1792 m = m.then_translate(t);
1793 } else if mode.contains(TouchTransformMode::TRANSLATE_Y) {
1794 let t = euclid::vec2(0.0, self.translation_y(other));
1795 m = m.then_translate(t);
1796 }
1797
1798 if mode.contains(TouchTransformMode::SCALE) {
1799 let s = self.scale(other).0;
1800 m = m.then(&PxTransform::scale(s, s));
1801 } else if mode.contains(TouchTransformMode::SCALE_X) {
1802 let s = self.scale_x(other);
1803 m = m.then(&PxTransform::scale(s.0, 1.0))
1804 } else if mode.contains(TouchTransformMode::SCALE_Y) {
1805 let s = self.scale_y(other);
1806 m = m.then(&PxTransform::scale(1.0, s.0))
1807 }
1808
1809 if mode.contains(TouchTransformMode::ROTATE) {
1810 let a = self.rotation(other);
1811 m = m.then(&PxTransform::rotation(0.0, 0.0, a.into()));
1812 }
1813
1814 m
1815 }
1816
1817 pub fn is_single(&self) -> bool {
1819 self.touches[0] == self.touches[1]
1820 }
1821}
1822impl ops::AddAssign<euclid::Vector2D<f32, Px>> for TouchTransformInfo {
1823 fn add_assign(&mut self, rhs: euclid::Vector2D<f32, Px>) {
1824 self.touches[0] += rhs;
1825 self.touches[1] += rhs;
1826 self.center += rhs;
1827 }
1828}
1829impl ops::Add<euclid::Vector2D<f32, Px>> for TouchTransformInfo {
1830 type Output = Self;
1831
1832 fn add(mut self, rhs: euclid::Vector2D<f32, Px>) -> Self::Output {
1833 self += rhs;
1834 self
1835 }
1836}
1837impl ops::AddAssign<PxVector> for TouchTransformInfo {
1838 fn add_assign(&mut self, rhs: PxVector) {
1839 *self += rhs.cast::<f32>();
1840 }
1841}
1842impl ops::Add<PxVector> for TouchTransformInfo {
1843 type Output = Self;
1844
1845 fn add(mut self, rhs: PxVector) -> Self::Output {
1846 self += rhs;
1847 self
1848 }
1849}
1850impl ops::SubAssign<euclid::Vector2D<f32, Px>> for TouchTransformInfo {
1851 fn sub_assign(&mut self, rhs: euclid::Vector2D<f32, Px>) {
1852 self.touches[0] -= rhs;
1853 self.touches[1] -= rhs;
1854 self.center -= rhs;
1855 }
1856}
1857impl ops::Sub<euclid::Vector2D<f32, Px>> for TouchTransformInfo {
1858 type Output = Self;
1859
1860 fn sub(mut self, rhs: euclid::Vector2D<f32, Px>) -> Self::Output {
1861 self -= rhs;
1862 self
1863 }
1864}
1865impl ops::SubAssign<PxVector> for TouchTransformInfo {
1866 fn sub_assign(&mut self, rhs: PxVector) {
1867 *self -= rhs.cast::<f32>();
1868 }
1869}
1870impl ops::Sub<PxVector> for TouchTransformInfo {
1871 type Output = Self;
1872
1873 fn sub(mut self, rhs: PxVector) -> Self::Output {
1874 self -= rhs;
1875 self
1876 }
1877}
1878
1879bitflags! {
1880 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
1883 #[serde(transparent)]
1884 pub struct TouchTransformMode: u8 {
1885 const TRANSLATE_X = 0b0000_0001;
1887 const TRANSLATE_Y = 0b0000_0010;
1889 const TRANSLATE = Self::TRANSLATE_X.bits() | Self::TRANSLATE_Y.bits();
1891
1892 const SCALE_X = 0b0000_0100;
1894 const SCALE_Y = 0b0000_1000;
1896 const SCALE = 0b0001_1100;
1898
1899 const ROTATE = 0b0010_0000;
1901
1902 const ALL = Self::TRANSLATE.bits() | Self::SCALE.bits() | Self::ROTATE.bits();
1904 }
1905}
1906impl_from_and_into_var! {
1907 fn from(all_or_empty: bool) -> TouchTransformMode {
1908 if all_or_empty {
1909 TouchTransformMode::ALL
1910 } else {
1911 TouchTransformMode::empty()
1912 }
1913 }
1914}
1915
1916#[derive(Default)]
1917enum TransformGesture {
1918 #[default]
1919 NoStartedZero,
1920
1921 NotStartedOne {
1922 window_id: WindowId,
1923 device_id: InputDeviceId,
1924 start_position: DipPoint,
1925 position: DipPoint,
1926 handle: EventPropagationHandle,
1927 },
1928 NotStartedTwo {
1929 window_id: WindowId,
1930 device_id: InputDeviceId,
1931 start_position: [DipPoint; 2],
1932 position: [DipPoint; 2],
1933 handle: [EventPropagationHandle; 2],
1934 scale_factor: Factor,
1935 },
1936
1937 StartedOne {
1938 window_id: WindowId,
1939 device_id: InputDeviceId,
1940 position: DipPoint,
1941 velocity: DipVector,
1942 scale_factor: Factor,
1943 handle: EventPropagationHandle,
1944 first_info: TouchTransformInfo,
1945 hits: HitTestInfo,
1946 target: InteractionPath,
1947 },
1948 StartedTwo {
1949 window_id: WindowId,
1950 device_id: InputDeviceId,
1951 position: [DipPoint; 2],
1952 velocity: [DipVector; 2],
1953 scale_factor: Factor,
1954 handle: [EventPropagationHandle; 2],
1955 first_info: TouchTransformInfo,
1956 hits: HitTestInfo,
1957 target: InteractionPath,
1958 },
1959}
1960impl TransformGesture {
1961 fn on_input(&mut self, args: &TouchInputArgs) {
1962 match mem::take(self) {
1963 Self::NoStartedZero => {
1964 if TouchPhase::Start == args.phase && !args.touch_propagation.is_stopped() {
1965 *self = Self::NotStartedOne {
1966 window_id: args.window_id,
1967 device_id: args.device_id,
1968 start_position: args.position,
1969 position: args.position,
1970 handle: args.touch_propagation.clone(),
1971 }
1972 }
1973 }
1974 Self::NotStartedOne {
1975 window_id,
1976 device_id,
1977 position,
1978 handle,
1979 ..
1980 } => {
1981 if TouchPhase::Start == args.phase
1982 && window_id == args.window_id
1983 && device_id == args.device_id
1984 && !args.touch_propagation.is_stopped()
1985 && !handle.is_stopped()
1986 && handle != args.touch_propagation
1987 && let Some(w) = WINDOWS.widget_tree(args.window_id)
1988 {
1989 *self = Self::NotStartedTwo {
1990 window_id: args.window_id,
1991 device_id: args.device_id,
1992 start_position: [position, args.position],
1993 position: [position, args.position],
1994 handle: [handle, args.touch_propagation.clone()],
1995 scale_factor: w.scale_factor(),
1996 }
1997 }
1998 }
1999 Self::NotStartedTwo { .. } => {
2000 }
2002 Self::StartedOne {
2003 window_id,
2004 device_id,
2005 position,
2006 velocity,
2007 scale_factor,
2008 handle,
2009 first_info,
2010 hits,
2011 target,
2012 } => match args.phase {
2013 TouchPhase::Start
2014 if window_id == args.window_id
2015 && device_id == args.device_id
2016 && !args.touch_propagation.is_stopped()
2017 && !handle.is_stopped()
2018 && handle != args.touch_propagation =>
2019 {
2020 *self = Self::StartedTwo {
2021 window_id,
2022 device_id,
2023 position: [position, args.position],
2024 velocity: [velocity, args.velocity],
2025 scale_factor,
2026 handle: [handle, args.touch_propagation.clone()],
2027 first_info,
2028 hits,
2029 target,
2030 };
2031 }
2032 TouchPhase::Move => unreachable!(),
2033 TouchPhase::End if handle == args.touch_propagation => {
2034 let position = args.position;
2035
2036 let latest_info = TouchTransformInfo::new_dip([position, position], scale_factor);
2037 let capture = POINTER_CAPTURE.current_capture().get();
2038
2039 let velocity = velocity.to_px(scale_factor);
2040
2041 let args = TouchTransformArgs::now(
2042 window_id,
2043 device_id,
2044 first_info,
2045 latest_info,
2046 [velocity, velocity],
2047 scale_factor,
2048 TouchPhase::End,
2049 hits,
2050 target,
2051 capture,
2052 args.modifiers,
2053 );
2054 TOUCH_TRANSFORM_EVENT.notify(args);
2055 }
2056 _ => {
2057 *self = Self::StartedOne {
2059 window_id,
2060 device_id,
2061 position,
2062 velocity,
2063 scale_factor,
2064 handle,
2065 first_info,
2066 hits,
2067 target,
2068 };
2069 self.clear();
2070 }
2071 },
2072 Self::StartedTwo {
2073 window_id,
2074 device_id,
2075 mut position,
2076 velocity,
2077 scale_factor,
2078 handle,
2079 first_info,
2080 hits,
2081 target,
2082 } => {
2083 if TouchPhase::End == args.phase && handle.iter().any(|h| h == &args.touch_propagation) {
2084 let i = handle.iter().position(|h| h == &args.touch_propagation).unwrap();
2085 position[i] = args.position;
2086
2087 let latest_info = TouchTransformInfo::new_dip(position, scale_factor);
2088 let capture = POINTER_CAPTURE.current_capture().get();
2089
2090 let velocity = [velocity[0].to_px(scale_factor), velocity[1].to_px(scale_factor)];
2091
2092 let args = TouchTransformArgs::now(
2093 window_id,
2094 device_id,
2095 first_info,
2096 latest_info,
2097 velocity,
2098 scale_factor,
2099 TouchPhase::End,
2100 hits,
2101 target,
2102 capture,
2103 args.modifiers,
2104 );
2105 TOUCH_TRANSFORM_EVENT.notify(args);
2106 } else {
2107 *self = Self::StartedTwo {
2108 window_id,
2109 device_id,
2110 position,
2111 velocity,
2112 scale_factor,
2113 handle,
2114 first_info,
2115 hits,
2116 target,
2117 };
2118 self.clear();
2119 }
2120 }
2121 }
2122 }
2123
2124 fn on_move(&mut self, args: &TouchMoveArgs, cfg: &Var<TouchConfig>) {
2125 match self {
2126 Self::NoStartedZero => {}
2127 Self::NotStartedOne {
2128 start_position,
2129 position,
2130 handle,
2131 window_id,
2132 device_id,
2133 } => {
2134 if handle.is_stopped() {
2135 *self = Self::NoStartedZero;
2136 } else {
2137 let mut moved = false;
2138 for t in &args.touches {
2139 if handle == &t.touch_propagation {
2140 *position = t.position();
2141 moved = true;
2142 } else {
2143 *self = Self::NoStartedZero;
2144 return;
2145 }
2146 }
2147 if moved {
2148 let cfg = cfg.get();
2149 if (position.x - start_position.x).abs() > cfg.double_tap_area.width
2150 || (position.y - start_position.y).abs() > cfg.double_tap_area.height
2151 {
2152 if let Some(w) = WINDOWS.widget_tree(*window_id) {
2153 let scale_factor = w.scale_factor();
2154 let first_info = TouchTransformInfo::new_dip([*start_position, *start_position], scale_factor);
2155 let latest_info = TouchTransformInfo::new_dip([*position, *position], scale_factor);
2156
2157 let hits = w.root().hit_test(first_info.center.cast());
2158 let target = hits
2159 .target()
2160 .and_then(|t| w.get(t.widget_id))
2161 .map(|t| t.interaction_path())
2162 .unwrap_or_else(|| w.root().interaction_path());
2163
2164 let target = match target.unblocked() {
2165 Some(t) => t,
2166 None => {
2167 *self = Self::NoStartedZero;
2168 return; }
2170 };
2171 let capture = POINTER_CAPTURE.current_capture().get();
2172
2173 handle.stop();
2175
2176 let args = TouchTransformArgs::now(
2177 *window_id,
2178 *device_id,
2179 first_info.clone(),
2180 latest_info,
2181 [PxVector::zero(); 2],
2182 scale_factor,
2183 TouchPhase::Start,
2184 hits.clone(),
2185 target.clone(),
2186 capture,
2187 args.modifiers,
2188 );
2189 TOUCH_TRANSFORM_EVENT.notify(args);
2190
2191 *self = Self::StartedOne {
2192 window_id: *window_id,
2193 device_id: *device_id,
2194 position: *position,
2195 velocity: DipVector::zero(),
2196 scale_factor,
2197 handle: handle.clone(),
2198 first_info,
2199 hits,
2200 target,
2201 };
2202 } else {
2203 *self = Self::NoStartedZero;
2204 }
2205 }
2206 }
2207 }
2208 }
2209 Self::NotStartedTwo {
2210 start_position,
2211 position,
2212 handle,
2213 scale_factor,
2214 window_id,
2215 device_id,
2216 } => {
2217 if handle[0].is_stopped() || handle[1].is_stopped() {
2218 *self = Self::NoStartedZero;
2219 } else {
2220 let mut any_moved = false;
2221 for t in &args.touches {
2222 if let Some(i) = handle.iter().position(|h| h == &t.touch_propagation) {
2223 position[i] = t.position();
2224 any_moved = true;
2225 } else {
2226 *self = Self::NoStartedZero;
2227 return;
2228 }
2229 }
2230
2231 if any_moved {
2232 let first_info = TouchTransformInfo::new_dip(*start_position, *scale_factor);
2233 let latest_info = TouchTransformInfo::new_dip(*position, *scale_factor);
2234
2235 let start = {
2236 let translation = first_info.translation(&latest_info);
2237 translation.x > 0.0 && translation.y > 0.0
2238 } || {
2239 let scale = first_info.scale(&latest_info);
2240 scale.0 != 1.0
2241 } || {
2242 let rotate = first_info.rotation(&latest_info);
2243 rotate.0 != 0.0
2244 };
2245
2246 if start {
2247 if let Some(w) = WINDOWS.widget_tree(*window_id) {
2248 let hits = w.root().hit_test(first_info.center.cast());
2249 let target = hits
2250 .target()
2251 .and_then(|t| w.get(t.widget_id))
2252 .map(|t| t.interaction_path())
2253 .unwrap_or_else(|| w.root().interaction_path());
2254
2255 let target = match target.unblocked() {
2256 Some(t) => t,
2257 None => {
2258 *self = Self::NoStartedZero;
2259 return; }
2261 };
2262 let capture = POINTER_CAPTURE.current_capture().get();
2263
2264 for h in handle.iter() {
2265 h.stop();
2267 }
2268
2269 let args = TouchTransformArgs::now(
2270 *window_id,
2271 *device_id,
2272 first_info.clone(),
2273 latest_info,
2274 [PxVector::zero(); 2],
2275 *scale_factor,
2276 TouchPhase::Start,
2277 hits.clone(),
2278 target.clone(),
2279 capture,
2280 args.modifiers,
2281 );
2282 TOUCH_TRANSFORM_EVENT.notify(args);
2283
2284 *self = Self::StartedTwo {
2285 window_id: *window_id,
2286 device_id: *device_id,
2287 position: *position,
2288 velocity: [DipVector::zero(); 2],
2289 scale_factor: *scale_factor,
2290 handle: handle.clone(),
2291 first_info,
2292 hits,
2293 target,
2294 };
2295 } else {
2296 *self = Self::NoStartedZero;
2297 }
2298 }
2299 }
2300 }
2301 }
2302 Self::StartedOne {
2303 window_id,
2304 device_id,
2305 position,
2306 velocity,
2307 scale_factor,
2308 handle,
2309 first_info,
2310 hits,
2311 target,
2312 } => {
2313 let mut any_moved = false;
2314 for t in &args.touches {
2315 if handle == &t.touch_propagation {
2316 *position = t.position();
2317 *velocity = t.velocity;
2318 any_moved = true;
2319 } else {
2320 self.clear();
2321 return;
2322 }
2323 }
2324
2325 if any_moved {
2326 let latest_info = TouchTransformInfo::new_dip([*position, *position], *scale_factor);
2327 let capture = POINTER_CAPTURE.current_capture().get();
2328
2329 let velocity = velocity.to_px(*scale_factor);
2330
2331 let args = TouchTransformArgs::now(
2332 *window_id,
2333 *device_id,
2334 first_info.clone(),
2335 latest_info,
2336 [velocity, velocity],
2337 *scale_factor,
2338 TouchPhase::Move,
2339 hits.clone(),
2340 target.clone(),
2341 capture,
2342 args.modifiers,
2343 );
2344 TOUCH_TRANSFORM_EVENT.notify(args);
2345 }
2346 }
2347 Self::StartedTwo {
2348 window_id,
2349 device_id,
2350 position,
2351 scale_factor,
2352 velocity,
2353 handle,
2354 first_info,
2355 hits,
2356 target,
2357 } => {
2358 let mut any_moved = false;
2359 for t in &args.touches {
2360 if let Some(i) = handle.iter().position(|h| h == &t.touch_propagation) {
2361 position[i] = t.position();
2362 velocity[i] = t.velocity;
2363 any_moved = true;
2364 } else {
2365 self.clear();
2366 return;
2367 }
2368 }
2369
2370 if any_moved {
2371 let latest_info = TouchTransformInfo::new_dip(*position, *scale_factor);
2372 let capture = POINTER_CAPTURE.current_capture().get();
2373
2374 let velocity = [velocity[0].to_px(*scale_factor), velocity[1].to_px(*scale_factor)];
2375
2376 let args = TouchTransformArgs::now(
2377 *window_id,
2378 *device_id,
2379 first_info.clone(),
2380 latest_info,
2381 velocity,
2382 *scale_factor,
2383 TouchPhase::Move,
2384 hits.clone(),
2385 target.clone(),
2386 capture,
2387 args.modifiers,
2388 );
2389 TOUCH_TRANSFORM_EVENT.notify(args);
2390 }
2391 }
2392 }
2393 }
2394
2395 fn clear(&mut self) {
2396 match mem::take(self) {
2397 TransformGesture::StartedOne {
2398 window_id,
2399 device_id,
2400 scale_factor,
2401 first_info,
2402 hits,
2403 target,
2404 ..
2405 }
2406 | TransformGesture::StartedTwo {
2407 window_id,
2408 device_id,
2409 scale_factor,
2410 first_info,
2411 hits,
2412 target,
2413 ..
2414 } => {
2415 let args = TouchTransformArgs::now(
2416 window_id,
2417 device_id,
2418 first_info.clone(),
2419 first_info,
2420 [PxVector::zero(); 2],
2421 scale_factor,
2422 TouchPhase::Cancel,
2423 hits,
2424 target,
2425 None,
2426 ModifiersState::empty(),
2427 );
2428 TOUCH_TRANSFORM_EVENT.notify(args);
2429 }
2430 _ => {}
2431 }
2432 }
2433}
2434
2435fn hooks() {
2436 WIDGET_TREE_CHANGED_EVENT
2437 .hook(|args| {
2438 TOUCH_SV.write().continue_pressed(args.tree.window_id());
2439 true
2440 })
2441 .perm();
2442
2443 RAW_TOUCH_EVENT
2444 .hook(|args| {
2445 let mut s = TOUCH_SV.write();
2446 let mut pending_move: Vec<TouchMove> = vec![];
2447 for u in &args.touches {
2448 if let TouchPhase::Move = u.phase {
2449 if let Some(e) = pending_move.iter_mut().find(|e| e.touch == u.touch) {
2450 e.moves.push((u.position, u.force));
2451 } else {
2452 pending_move.push(TouchMove {
2453 touch: u.touch,
2454 touch_propagation: if let Some(i) = s.pressed.get(&u.touch) {
2455 i.touch_propagation.clone()
2456 } else {
2457 let weird = EventPropagationHandle::new();
2458 weird.stop();
2459 weird
2460 },
2461 moves: vec![(u.position, u.force)],
2462 velocity: DipVector::zero(),
2463 hits: HitTestInfo::no_hits(args.window_id), target: InteractionPath::new(args.window_id, []),
2465 });
2466 }
2467 } else {
2468 s.on_move(args, mem::take(&mut pending_move));
2469 s.on_input(args, u);
2470 }
2471 }
2472
2473 s.on_move(args, pending_move);
2474 true
2475 })
2476 .perm();
2477
2478 MODIFIERS_CHANGED_EVENT
2479 .hook(|args| {
2480 TOUCH_SV.write().modifiers = args.modifiers;
2481 true
2482 })
2483 .perm();
2484
2485 RAW_TOUCH_CONFIG_CHANGED_EVENT
2486 .hook(|args| {
2487 TOUCH_SV.read().touch_config.set(args.config);
2488 true
2489 })
2490 .perm();
2491
2492 VIEW_PROCESS_INITED_EVENT
2493 .hook(|args| {
2494 if args.is_respawn {
2495 let mut s = TOUCH_SV.write();
2496 s.tap_gesture.clear();
2497 s.transform_gesture.clear();
2498 s.long_press_gesture.clear();
2499 s.positions.set(vec![]);
2500
2501 for (touch, info) in s.pressed.drain() {
2502 let args = TouchInputArgs::now(
2503 info.target.window_id(),
2504 info.device_id,
2505 touch,
2506 info.touch_propagation.clone(),
2507 DipPoint::splat(Dip::new(-1)),
2508 None,
2509 DipVector::zero(),
2510 TouchPhase::Cancel,
2511 HitTestInfo::no_hits(info.target.window_id()),
2512 info.target.clone(),
2513 None,
2514 ModifiersState::empty(),
2515 );
2516 TOUCH_INPUT_EVENT.notify(args);
2517
2518 let args = TouchedArgs::now(
2519 info.target.window_id(),
2520 info.device_id,
2521 touch,
2522 info.touch_propagation,
2523 DipPoint::splat(Dip::new(-1)),
2524 None,
2525 TouchPhase::Cancel,
2526 HitTestInfo::no_hits(info.target.window_id()),
2527 info.target,
2528 None,
2529 None,
2530 None,
2531 );
2532 TOUCHED_EVENT.notify(args);
2533 }
2534 }
2535 true
2536 })
2537 .perm();
2538
2539 TOUCH_INPUT_EVENT
2540 .on_event(
2541 true,
2542 hn!(|args| {
2543 let mut s = TOUCH_SV.write();
2544 let s = &mut *s;
2545 s.tap_gesture.on_input(args, &s.touch_config);
2546 s.transform_gesture.on_input(args);
2547 s.long_press_gesture.on_input(args, &s.touch_config);
2548 }),
2549 )
2550 .perm();
2551
2552 TOUCH_MOVE_EVENT
2553 .on_event(
2554 true,
2555 hn!(|args| {
2556 let mut s = TOUCH_SV.write();
2557 let s = &mut *s;
2558 s.tap_gesture.on_move(args);
2559 s.transform_gesture.on_move(args, &s.touch_config);
2560 s.long_press_gesture.on_move(args, &s.touch_config);
2561 }),
2562 )
2563 .perm();
2564
2565 POINTER_CAPTURE_EVENT
2566 .hook(|args| {
2567 let s = TOUCH_SV.read();
2568 for (touch, info) in &s.pressed {
2569 let args = TouchedArgs::now(
2570 info.target.window_id(),
2571 info.device_id,
2572 *touch,
2573 info.touch_propagation.clone(),
2574 info.position,
2575 info.force,
2576 TouchPhase::Move,
2577 info.hits.clone(),
2578 info.target.clone(),
2579 info.target.clone(),
2580 args.prev_capture.clone(),
2581 args.new_capture.clone(),
2582 );
2583 TOUCHED_EVENT.notify(args);
2584 }
2585 true
2586 })
2587 .perm();
2588}
2589fn hooks_touch_from_mouse() -> [VarHandle; 3] {
2590 use crate::mouse::*;
2591 [
2592 MOUSE_MOVE_EVENT.hook(|args| {
2593 if let Some(id) = TOUCH_SV.read().mouse_touch {
2594 args.propagation.stop();
2595
2596 RAW_TOUCH_EVENT.notify(RawTouchArgs::now(
2597 args.window_id,
2598 args.device_id,
2599 vec![TouchUpdate::new(id, TouchPhase::Move, args.position, None)],
2600 ));
2601 }
2602 true
2603 }),
2604 MOUSE_INPUT_EVENT.hook(|args| {
2605 if args.button == super::mouse::MouseButton::Left {
2606 args.propagation.stop();
2607
2608 let mut s = TOUCH_SV.write();
2609
2610 let phase = match args.state {
2611 ButtonState::Pressed => {
2612 if s.mouse_touch.is_some() {
2613 return true;
2614 }
2615 s.mouse_touch = Some(TouchId(u64::MAX));
2616 TouchPhase::Start
2617 }
2618 ButtonState::Released => {
2619 if s.mouse_touch.is_none() {
2620 return true;
2621 }
2622 s.mouse_touch = None;
2623 TouchPhase::End
2624 }
2625 };
2626
2627 RAW_TOUCH_EVENT.notify(RawTouchArgs::now(
2628 args.window_id,
2629 args.device_id.unwrap_or(InputDeviceId::new_unique()),
2630 vec![TouchUpdate::new(TouchId(u64::MAX), phase, args.position, None)],
2631 ));
2632 }
2633 true
2634 }),
2635 RAW_MOUSE_LEFT_EVENT.hook(|args| {
2636 if let Some(id) = TOUCH_SV.write().mouse_touch.take() {
2637 RAW_TOUCH_EVENT.notify(RawTouchArgs::now(
2638 args.window_id,
2639 args.device_id,
2640 vec![TouchUpdate::new(id, TouchPhase::Cancel, DipPoint::zero(), None)],
2641 ))
2642 }
2643 true
2644 }),
2645 ]
2646}