zng_ext_input/
touch.rs

1//! Touch events and service.
2//!
3//! # Events
4//!
5//! Events this extension provides.
6//!
7//! * [`TOUCH_MOVE_EVENT`]
8//! * [`TOUCH_INPUT_EVENT`]
9//! * [`TOUCHED_EVENT`]
10//! * [`TOUCH_TAP_EVENT`]
11//! * [`TOUCH_TRANSFORM_EVENT`]
12//! * [`TOUCH_LONG_PRESS_EVENT`]
13//!
14//! # Services
15//!
16//! Services this extension provides.
17//!
18//! * [`TOUCH`]
19
20use 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
117/// Touch service.
118///
119/// # Touch Capture
120///
121/// Touch capture is integrated with mouse capture in the [`POINTER_CAPTURE`] service.
122///
123/// [`POINTER_CAPTURE`]: crate::pointer_capture::POINTER_CAPTURE
124pub struct TOUCH;
125
126impl TOUCH {
127    /// Variable that defines the touch config for the app.
128    ///
129    /// The value is the same as [`sys_touch_config`], if set the variable disconnects from system config.
130    ///
131    /// [`sys_touch_config`]: Self::sys_touch_config
132    pub fn touch_config(&self) -> Var<TouchConfig> {
133        TOUCH_SV.read().touch_config.clone()
134    }
135
136    /// Read-only variable that tracks the system touch config.
137    ///
138    /// Note that some of these configs are not always used, a tap event for example can happen even if the
139    /// touch moves out of the `tap_area` when there is no ambiguity.
140    ///
141    /// # Value Source
142    ///
143    /// The value comes from the operating system settings, the variable
144    /// updates with a new value if the system setting is changed and on view-process (re)init.
145    ///
146    /// In headless apps the default is [`TouchConfig::default`] and does not change.
147    pub fn sys_touch_config(&self) -> Var<TouchConfig> {
148        TOUCH_SV.read().sys_touch_config.read_only()
149    }
150
151    /// Variable that tracks all current active touches.
152    pub fn positions(&self) -> Var<Vec<TouchPosition>> {
153        TOUCH_SV.read().positions.read_only()
154    }
155
156    /// Test mode, generates touch events for a single touch contact from raw mouse events.
157    ///
158    /// Is disabled by default.
159    pub fn touch_from_mouse_events(&self) -> Var<bool> {
160        TOUCH_SV.read().touch_from_mouse_events.clone()
161    }
162}
163
164/// Active touch positions.
165///
166/// Tracked in [`TOUCH.positions`].
167///
168/// [`TOUCH.positions`]: TOUCH::positions
169#[derive(Debug, Clone, PartialEq)]
170pub struct TouchPosition {
171    /// Touched window.
172    pub window_id: WindowId,
173    /// Unique ID of the touch, among other active touches.
174    pub touch: TouchId,
175    /// Latest touch contact position.
176    pub position: DipPoint,
177
178    /// Touch start timestamp.
179    pub start_time: DInstant,
180    /// Latest move timestamp.
181    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/// Identify the moves of one touch contact in [`TouchMoveArgs`].
229#[derive(Debug, Clone, PartialEq)]
230pub struct TouchMove {
231    /// Identify the touch contact or *finger*.
232    ///
233    /// Multiple points of contact can happen in the same device at the same time,
234    /// this ID identifies each uninterrupted contact. IDs are unique only among other concurrent touches
235    /// on the same device, after a touch is ended an ID may be reused.
236    pub touch: TouchId,
237
238    /// Handle across the lifetime of `touch`.
239    ///
240    /// See [`TouchInputArgs::touch_propagation`] for more details.
241    pub touch_propagation: EventPropagationHandle,
242
243    /// Coalesced moves of the touch since last event.
244    ///
245    /// Last entry is the latest position.
246    pub moves: Vec<(DipPoint, Option<TouchForce>)>,
247
248    /// Velocity in device independent pixels per second.
249    ///
250    /// The velocity is computed from the 4 non-coalesced move events. If is zero before the fourth event.
251    pub velocity: DipVector,
252
253    /// Hit-test result for the latest touch point in the window.
254    pub hits: HitTestInfo,
255
256    /// Full path to the top-most hit in [`hits`](TouchMove::hits).
257    pub target: InteractionPath,
258}
259impl TouchMove {
260    /// Latest position.
261    pub fn position(&self) -> DipPoint {
262        self.moves.last().map(|(p, _)| *p).unwrap_or_else(DipPoint::zero)
263    }
264}
265
266event_args! {
267    /// Arguments for [`TOUCH_MOVE_EVENT`].
268    pub struct TouchMoveArgs {
269        /// Id of window that received all touches in this event.
270        pub window_id: WindowId,
271
272        /// Id of device that generated all touches in this event.
273        pub device_id: InputDeviceId,
274
275        /// All touch contacts that moved since last event.
276        ///
277        /// Note that if a touch contact did not move it will not be in the list, the touch may still be active
278        /// however, the [`TOUCH_INPUT_EVENT`] can be used to track touch start and end.
279        pub touches: Vec<TouchMove>,
280
281        /// Current pointer capture.
282        pub capture: Option<CaptureInfo>,
283
284        /// What modifier keys where pressed when this event happened.
285        pub modifiers: ModifiersState,
286
287        ..
288
289        /// If is in any [`TouchMove::target`] or [`capture`].
290        ///
291        /// [`capture`]: Self::capture
292        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    /// Arguments for [`TOUCH_INPUT_EVENT`].
306    pub struct TouchInputArgs {
307        /// Id of window that received the event.
308        pub window_id: WindowId,
309
310        /// Id of device that generated the event.
311        pub device_id: InputDeviceId,
312
313        /// Identify the touch contact or *finger*.
314        ///
315        /// Multiple points of contact can happen in the same device at the same time,
316        /// this ID identifies each uninterrupted contact. IDs are unique only among other concurrent touches
317        /// on the same device, after a touch is ended an ID may be reused.
318        pub touch: TouchId,
319
320        /// Propagation handle for the [`touch`] lifetime.
321        ///
322        /// The [`TOUCH_INPUT_EVENT`] and [`TOUCH_MOVE_EVENT`] have their own separate propagation handles, but
323        /// touch gesture events aggregate all these events to produce a single *gesture event*, usually only a single
324        /// gesture should be generated, multiple gestures can disambiguate using this `touch_propagation` handle.
325        ///
326        /// As an example, [`TOUCH_TAP_EVENT`] only notifies
327        /// if by the time the gesture completes the `touch_propagation` was not stopped. Touch gesture events or event properties
328        /// must stop touch propagation as soon as they commit to a gesture, a *pan* gesture for example, must stop as soon as
329        /// it starts scrolling, otherwise the user may accidentally scroll and tap a button at the same time.
330        ///
331        /// The propagation handle always signals *stopped* after the touch ends. Handles are unique while at least one
332        /// clone of it remains, this makes this a better unique identifier of a touch contact than [`TouchId`] that may be reused
333        /// by the system as soon as a new touch contact is made.
334        ///
335        /// [`touch`]: Self::touch
336        pub touch_propagation: EventPropagationHandle,
337
338        /// Center of the touch in the window's content area.
339        pub position: DipPoint,
340
341        /// Touch pressure force and angle.
342        pub force: Option<TouchForce>,
343
344        /// Velocity in device independent pixels per second.
345        ///
346        /// This is always zero on `Start` and `Cancel` and is the last move velocity for `End`. Note that
347        /// the velocity value can be less than [`min_fling_velocity`].
348        ///
349        /// [`min_fling_velocity`]: TouchConfig::min_fling_velocity
350        pub velocity: DipVector,
351
352        /// Touch phase.
353        ///
354        /// Does not include `Moved`.
355        pub phase: TouchPhase,
356
357        /// Hit-test result for the touch point in the window.
358        pub hits: HitTestInfo,
359
360        /// Full path to the top-most hit in [`hits`](TouchInputArgs::hits).
361        pub target: InteractionPath,
362
363        /// Current pointer capture.
364        pub capture: Option<CaptureInfo>,
365
366        /// What modifier keys where pressed when this event happened.
367        pub modifiers: ModifiersState,
368
369        ..
370
371        /// If is in [`target`] or [`capture`].
372        ///
373        /// [`target`]: Self::target
374        /// [`capture`]: Self::capture
375        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    /// Arguments for [`TOUCHED_EVENT`].
387    pub struct TouchedArgs {
388        /// Id of window that received the event.
389        pub window_id: WindowId,
390
391        /// Id of device that generated the event.
392        pub device_id: Option<InputDeviceId>,
393
394        /// Identify the touch contact or *finger*.
395        ///
396        /// Multiple points of contact can happen in the same device at the same time,
397        /// this ID identifies each uninterrupted contact. IDs are unique only among other concurrent touches
398        /// on the same device, after a touch is ended an ID may be reused.
399        pub touch: TouchId,
400
401        /// Handle across the lifetime of `touch`.
402        ///
403        /// See [`TouchInputArgs::touch_propagation`] for more details.
404        pub touch_propagation: EventPropagationHandle,
405
406        /// Center of the touch in the window's content area.
407        pub position: DipPoint,
408
409        /// Touch pressure force and angle.
410        pub force: Option<TouchForce>,
411
412        /// Touch phase that caused the contact gain or loss with the widget.
413        pub phase: TouchPhase,
414
415        /// Hit-test result for the touch point in the window.
416        pub hits: HitTestInfo,
417
418        /// Previous top-most hit before the touch moved.
419        pub prev_target: Option<InteractionPath>,
420
421        /// Full path to the top-most hit in [`hits`](TouchInputArgs::hits).
422        pub target: Option<InteractionPath>,
423
424        /// Previous pointer capture.
425        pub prev_capture: Option<CaptureInfo>,
426
427        /// Current pointer capture.
428        pub capture: Option<CaptureInfo>,
429
430        ..
431
432        /// If is in [`prev_target`], [`target`] or [`capture`].
433        ///
434        /// [`prev_target`]: Self::prev_target
435        /// [`target`]: Self::target
436        /// [`capture`]: Self::capture
437        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    /// Arguments for [`TOUCH_TAP_EVENT`].
456    pub struct TouchTapArgs {
457        /// Id of window that received the event.
458        pub window_id: WindowId,
459
460        /// Id of device that generated the event.
461        pub device_id: InputDeviceId,
462
463        /// Identify the touch contact or *finger*.
464        ///
465        /// Multiple points of contact can happen in the same device at the same time,
466        /// this ID identifies each uninterrupted contact. IDs are unique only among other concurrent touches
467        /// on the same device, after a touch is ended an ID may be reused.
468        pub touch: TouchId,
469
470        /// Center of the touch in the window's content area.
471        pub position: DipPoint,
472
473        /// Hit-test result for the touch point in the window.
474        pub hits: HitTestInfo,
475
476        /// Full path to the top-most hit in [`hits`](TouchInputArgs::hits).
477        pub target: InteractionPath,
478
479        /// What modifier keys where pressed when this event happened.
480        pub modifiers: ModifiersState,
481
482        /// Count of taps within the double-tap interval. Number `1` is single tap, `2` is double tap, etc.
483        pub tap_count: NonZeroU32,
484
485        ..
486
487        /// If is in [`target`].
488        ///
489        /// [`target`]: Self::target
490        fn is_in_target(&self, id: WidgetId) -> bool {
491            self.target.contains(id)
492        }
493    }
494
495    /// Arguments for [`TOUCH_LONG_PRESS_EVENT`].
496    pub struct TouchLongPressArgs {
497        /// Id of window that received the event.
498        pub window_id: WindowId,
499
500        /// Id of device that generated the event.
501        pub device_id: InputDeviceId,
502
503        /// Identify the touch contact or *finger*.
504        ///
505        /// Multiple points of contact can happen in the same device at the same time,
506        /// this ID identifies each uninterrupted contact. IDs are unique only among other concurrent touches
507        /// on the same device, after a touch is ended an ID may be reused.
508        pub touch: TouchId,
509
510        /// Center of the touch in the window's content area.
511        pub position: DipPoint,
512
513        /// Hit-test result for the touch point in the window.
514        pub hits: HitTestInfo,
515
516        /// Full path to the top-most hit in [`hits`](TouchInputArgs::hits).
517        pub target: InteractionPath,
518
519        /// What modifier keys where pressed when this touch started.
520        pub modifiers: ModifiersState,
521
522        /// Timestamp of when the touch started.
523        pub start_time: DInstant,
524
525        ..
526
527        /// If is in [`target`].
528        ///
529        /// [`target`]: Self::target
530        fn is_in_target(&self, id: WidgetId) -> bool {
531            self.target.contains(id)
532        }
533    }
534
535    /// Arguments for [`TOUCH_TRANSFORM_EVENT`].
536    pub struct TouchTransformArgs {
537        /// Id of window that received the touch events.
538        pub window_id: WindowId,
539
540        /// Id of the device that generated the touch events.
541        pub device_id: InputDeviceId,
542
543        /// Info collected when the second touch point started.
544        pub first_info: TouchTransformInfo,
545
546        /// Latest update of the two points.
547        pub latest_info: TouchTransformInfo,
548
549        /// Velocity of the `latest_info` touch points.
550        pub velocity: [PxVector; 2],
551
552        /// Scale factor used in the computed pixel values.
553        ///
554        /// This is the window's scale factor when the first touch started.
555        pub scale_factor: Factor,
556
557        /// Gesture phase.
558        pub phase: TouchPhase,
559
560        /// Hit-test result for the center point between the first position of the two touches in the window
561        /// when the gesture started.
562        pub hits: HitTestInfo,
563
564        /// Full path to the top-most hit in [`hits`](TouchInputArgs::hits).
565        pub target: InteractionPath,
566
567        /// Current pointer capture.
568        pub capture: Option<CaptureInfo>,
569
570        /// What modifier keys where pressed when this event happened.
571        pub modifiers: ModifiersState,
572
573        ..
574
575        /// If is in [`target`] and [`capture`].
576        ///
577        /// [`target`]: Self::target
578        /// [`capture`]: Self::capture
579        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    /// If [`capture`] is `None` or [`allows`] the `wgt` to receive this event.
593    ///
594    /// [`capture`]: Self::capture
595    /// [`allows`]: CaptureInfo::allows
596    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    /// If [`capture`] is `None` or [`allows`] the `wgt` to receive this event.
603    ///
604    /// [`capture`]: Self::capture
605    /// [`allows`]: CaptureInfo::allows
606    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    /// If the [`phase`] is start.
611    ///
612    /// [`phase`]: Self::phase
613    pub fn is_touch_start(&self) -> bool {
614        matches!(self.phase, TouchPhase::Start)
615    }
616
617    /// If the [`phase`] is end.
618    ///
619    /// [`phase`]: Self::phase
620    pub fn is_touch_end(&self) -> bool {
621        matches!(self.phase, TouchPhase::End)
622    }
623
624    /// If the [`phase`] is cancel.
625    ///
626    /// [`phase`]: Self::phase
627    pub fn is_touch_cancel(&self) -> bool {
628        matches!(self.phase, TouchPhase::Cancel)
629    }
630
631    /// Compute the final offset and duration for a *fling* animation that simulates inertia movement from the
632    /// [`velocity.x`] and `friction`. Returns 0 if velocity less than [`min_fling_velocity`].
633    ///
634    /// Friction is in dips decelerated per second.
635    ///
636    /// To animate a point using these values:
637    ///
638    /// * Compute the final point by adding the vector offset to the current point.
639    /// * Animate using the duration linear interpolation.
640    ///
641    /// [`velocity.x`]: Self::velocity
642    /// [`min_fling_velocity`]: TouchConfig::min_fling_velocity
643    pub fn inertia_x(&self, friction: Dip) -> (Dip, Duration) {
644        Self::inertia(self.velocity.x, friction)
645    }
646
647    /// Compute the final offset and duration for a *fling* animation that simulates inertia movement from the
648    /// [`velocity.y`] and `friction`. Returns 0 if velocity less than [`min_fling_velocity`].
649    ///
650    /// Friction is in dips decelerated per second.
651    ///
652    /// [`velocity.y`]: Self::velocity
653    /// [`min_fling_velocity`]: TouchConfig::min_fling_velocity
654    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    /// Gets position in the widget inner bounds.
677    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    /// If [`capture`] is `None` or [`allows`] the `wgt` to receive this event.
688    ///
689    /// [`capture`]: Self::capture
690    /// [`allows`]: CaptureInfo::allows
691    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    /// Event caused by the touch position moving over/out of the widget bounds.
696    pub fn is_touch_move(&self) -> bool {
697        self.device_id.is_some()
698    }
699
700    /// Event caused by the widget moving under/out of the mouse position.
701    pub fn is_widget_move(&self) -> bool {
702        self.device_id.is_none()
703    }
704
705    /// Event caused by a pointer capture change.
706    pub fn is_capture_change(&self) -> bool {
707        self.prev_capture != self.capture
708    }
709
710    /// Returns `true` if the `wgt` was not touched, but now is.
711    pub fn is_touch_enter(&self, wgt: (WindowId, WidgetId)) -> bool {
712        !self.was_touched(wgt) && self.is_touched(wgt)
713    }
714
715    /// Returns `true` if the `wgt` was touched, but now isn't.
716    pub fn is_touch_leave(&self, wgt: (WindowId, WidgetId)) -> bool {
717        self.was_touched(wgt) && !self.is_touched(wgt)
718    }
719
720    /// Returns `true` if the `wgt` was not touched or was disabled, but now is touched and enabled.
721    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    /// Returns `true` if the `wgt` was touched and enabled, but now is not touched or is disabled.
726    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    /// Returns `true` if the `wgt` was not touched or was enabled, but now is touched and disabled.
731    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    /// Returns `true` if the `wgt` was touched and disabled, but now is not touched or is enabled.
736    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    /// Returns `true` if the `wgt` is in [`prev_target`] and is allowed by the [`prev_capture`].
741    ///
742    /// [`prev_target`]: Self::prev_target
743    /// [`prev_capture`]: Self::prev_capture
744    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    /// Returns `true` if the `wgt` is in [`target`] and is allowed by the current [`capture`].
759    ///
760    /// [`target`]: Self::target
761    /// [`capture`]: Self::capture
762    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    /// Returns `true` if the widget was enabled in [`prev_target`].
776    ///
777    /// [`prev_target`]: Self::prev_target
778    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    /// Returns `true` if the widget was disabled in [`prev_target`].
786    ///
787    /// [`prev_target`]: Self::prev_target
788    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    /// Returns `true` if the widget is enabled in [`target`].
796    ///
797    /// [`target`]: Self::target
798    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    /// Returns `true` if the widget is disabled in [`target`].
806    ///
807    /// [`target`]: Self::target
808    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    /// If [`capture`] is `None` or [`allows`] the `wgt` to receive this event.
818    ///
819    /// [`capture`]: Self::capture
820    /// [`allows`]: CaptureInfo::allows
821    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    /// Gets the [`first_info`] and [`latest_info`] in the `wgt` inner bounds space.
826    ///
827    /// [`first_info`]: Self::first_info
828    /// [`latest_info`]: Self::latest_info
829    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    /// Computes the translation to transform from [`first_info`] to [`latest_info`].
846    ///
847    /// [`first_info`]: Self::first_info
848    /// [`latest_info`]: Self::latest_info
849    pub fn translation(&self) -> euclid::Vector2D<f32, Px> {
850        self.first_info.translation(&self.latest_info)
851    }
852
853    /// Computes the translation-x to transform from [`first_info`] to [`latest_info`].
854    ///
855    /// [`first_info`]: Self::first_info
856    /// [`latest_info`]: Self::latest_info
857    pub fn translation_x(&self) -> f32 {
858        self.first_info.translation_x(&self.latest_info)
859    }
860
861    /// Computes the translation-y to transform from [`first_info`] to [`latest_info`].
862    ///
863    /// [`first_info`]: Self::first_info
864    /// [`latest_info`]: Self::latest_info
865    pub fn translation_y(&self) -> f32 {
866        self.first_info.translation_y(&self.latest_info)
867    }
868
869    /// Computes the rotation to transform from [`first_info`] to [`latest_info`].
870    ///
871    /// [`first_info`]: Self::first_info
872    /// [`latest_info`]: Self::latest_info
873    pub fn rotation(&self) -> AngleRadian {
874        self.first_info.rotation(&self.latest_info)
875    }
876
877    /// Computes the scale to transform from [`first_info`] to [`latest_info`].
878    ///
879    /// [`first_info`]: Self::first_info
880    /// [`latest_info`]: Self::latest_info
881    pub fn scale(&self) -> Factor {
882        self.first_info.scale(&self.latest_info)
883    }
884
885    /// Computes the scale-y to transform from [`first_info`] to [`latest_info`].
886    ///
887    /// [`first_info`]: Self::first_info
888    /// [`latest_info`]: Self::latest_info
889    pub fn scale_x(&self) -> Factor {
890        self.first_info.scale_x(&self.latest_info)
891    }
892
893    /// Computes the scale-y to transform from [`first_info`] to [`latest_info`].
894    ///
895    /// [`first_info`]: Self::first_info
896    /// [`latest_info`]: Self::latest_info
897    pub fn scale_y(&self) -> Factor {
898        self.first_info.scale_y(&self.latest_info)
899    }
900
901    /// Computes the transform from [`first_info`] to [`latest_info`].
902    ///
903    /// [`first_info`]: Self::first_info
904    /// [`latest_info`]: Self::latest_info
905    pub fn transform(&self, mode: TouchTransformMode) -> PxTransform {
906        self.first_info.transform(&self.latest_info, mode)
907    }
908
909    /// Computes the transform between the [`local_info`] values, rotates and scales around the latest center.
910    ///
911    /// [`local_info`]: Self::local_info
912    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    /// Average velocity.
929    pub fn translation_velocity(&self) -> PxVector {
930        (self.velocity[0] + self.velocity[1]) / Px(2)
931    }
932
933    /// Compute the final offset and duration for a *fling* animation that simulates inertia movement from the
934    /// [`translation_velocity().x`] and `deceleration`. Returns 0 if velocity less than [`min_fling_velocity`].
935    ///
936    /// Deceleration is in dip/s, a good value is 1000. The recommended animation easing function
937    /// is `|t| easing::ease_out(easing::quad, t)`.
938    ///
939    /// [`translation_velocity().x`]: Self::translation_velocity
940    /// [`min_fling_velocity`]: TouchConfig::min_fling_velocity
941    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    /// Compute the final offset and duration for a *fling* animation that simulates inertia movement from the
946    /// [`translation_velocity().y`] and `deceleration`. Returns 0 if velocity less than [`min_fling_velocity`].
947    ///
948    /// Deceleration is in dip/s, a good value is 1000. The recommended animation easing function is
949    /// `|t| easing::ease_out(easing::quad, t)`.
950    ///
951    /// [`translation_velocity().y`]: Self::translation_velocity
952    /// [`min_fling_velocity`]: TouchConfig::min_fling_velocity
953    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    /// If the [`phase`] is start.
958    ///
959    /// Note that the [`latest_info`] may already be different from [`first_info`] if the gesture
960    /// detector awaited to disambiguate before starting the gesture.
961    ///
962    /// [`phase`]: Self::phase
963    /// [`first_info`]: Self::first_info
964    /// [`latest_info`]: Self::latest_info
965    pub fn is_start(&self) -> bool {
966        matches!(self.phase, TouchPhase::Start)
967    }
968
969    /// If the [`phase`] is end.
970    ///
971    /// Any transform already applied must be committed.
972    ///
973    /// [`phase`]: Self::phase
974    pub fn is_end(&self) -> bool {
975        matches!(self.phase, TouchPhase::End)
976    }
977
978    /// If the [`phase`] is cancel.
979    ///
980    /// Any transform already applied must be undone.
981    ///
982    /// [`phase`]: Self::phase
983    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    /// Touch contact moved.
1011    pub static TOUCH_MOVE_EVENT: TouchMoveArgs {
1012        let _ = TOUCH_SV.read();
1013    };
1014
1015    /// Touch contact started or ended.
1016    pub static TOUCH_INPUT_EVENT: TouchInputArgs {
1017        let _ = TOUCH_SV.read();
1018    };
1019
1020    /// Touch made first contact or lost contact with a widget.
1021    pub static TOUCHED_EVENT: TouchedArgs {
1022        let _ = TOUCH_SV.read();
1023    };
1024
1025    /// Touch tap.
1026    pub static TOUCH_TAP_EVENT: TouchTapArgs {
1027        let _ = TOUCH_SV.read();
1028    };
1029
1030    /// Two point touch transform.
1031    pub static TOUCH_TRANSFORM_EVENT: TouchTransformArgs {
1032        let _ = TOUCH_SV.read();
1033    };
1034
1035    /// Touch contact pressed without moving for more then the [`tap_max_time`].
1036    ///
1037    /// [`tap_max_time`]: TouchConfig::tap_max_time
1038    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            // hit-test for nested windows
1055            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, // entire window blocked
1073            };
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![], // skip input (will only have velocity after 4 moves)
1090                        },
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                // touched
1158
1159                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            // did not find window, cleanup touched
1185            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                        // hit-test for nested windows
1226                        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(); // last
1232                            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, // ignored
1265                    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    /// Check if the tap is still possible after a touch move..
1433    ///
1434    /// Returns `true` if it is.
1435    fn retain(&self, window_id: WindowId, device_id: InputDeviceId, touch: TouchId) -> bool {
1436        if self.propagation.is_stopped() {
1437            // cancel, gesture opportunity handled.
1438            return false;
1439        }
1440
1441        if window_id != self.window_id || device_id != self.device_id {
1442            // cancel, not same source or target.
1443            return false;
1444        }
1445
1446        if touch != self.touch {
1447            // cancel, multi-touch.
1448            return false;
1449        }
1450
1451        // retain
1452        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                    // only valid if single touch contact, we use the `pending` presence to track this.
1481                    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(); // touch_propagation always is stopped after touch end.
1606
1607                    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                                // cancel, touch did not end over target.
1617                                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/// Info useful for touch gestures computed from two touch points.
1691#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
1692pub struct TouchTransformInfo {
1693    /// The two touch contact points.
1694    pub touches: [euclid::Point2D<f32, Px>; 2],
1695
1696    /// Middle of the line between the two points.
1697    pub center: euclid::Point2D<f32, Px>,
1698
1699    /// Deviation from the points to the center.
1700    ///
1701    /// Min 1.0
1702    pub deviation: f32,
1703
1704    /// Deviation from the points.x to the center.x.
1705    ///
1706    /// Min 1.0
1707    pub deviation_x: f32,
1708
1709    /// Deviation from the points.y to the center.y.
1710    ///
1711    /// Min 1.0
1712    pub deviation_y: f32,
1713
1714    /// Angle of the line.
1715    pub angle: AngleRadian,
1716}
1717impl TouchTransformInfo {
1718    /// Compute the line info.
1719    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    /// Compute the line info, from round pixels.
1739    pub fn new(touches: [PxPoint; 2]) -> Self {
1740        Self::new_f32([touches[0].to_f32(), touches[1].to_f32()])
1741    }
1742
1743    /// Compute the line info, from device independent pixels.
1744    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    /// Computes the translation to transform from `self` to `other`.
1750    pub fn translation(&self, other: &Self) -> euclid::Vector2D<f32, Px> {
1751        other.center.to_vector() - self.center.to_vector()
1752    }
1753
1754    /// Computes the translation-x to transform from `self` to `other`.
1755    pub fn translation_x(&self, other: &Self) -> f32 {
1756        other.center.x - self.center.x
1757    }
1758
1759    /// Computes the translation-y to transform from `self` to `other`.
1760    pub fn translation_y(&self, other: &Self) -> f32 {
1761        other.center.y - self.center.y
1762    }
1763
1764    /// Computes the rotation to transform from `self` to `other`.
1765    pub fn rotation(&self, other: &Self) -> AngleRadian {
1766        other.angle - self.angle
1767    }
1768
1769    /// Computes the scale to transform from `self` to `other`.
1770    pub fn scale(&self, other: &Self) -> Factor {
1771        Factor(other.deviation / self.deviation)
1772    }
1773
1774    /// Computes the scale-y to transform from `self` to `other`.
1775    pub fn scale_x(&self, other: &Self) -> Factor {
1776        Factor(other.deviation_x / self.deviation_x)
1777    }
1778
1779    /// Computes the scale-y to transform from `self` to `other`.
1780    pub fn scale_y(&self, other: &Self) -> Factor {
1781        Factor(other.deviation_y / self.deviation_y)
1782    }
1783
1784    /// Computes the transform from `self` to `other`.
1785    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    /// If the transform is only a translate calculated from a single touch contact.
1818    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    /// Defines the different transforms that a touch transform can do to keep
1881    /// two touch points in a widget aligned with the touch contacts.
1882    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
1883    #[serde(transparent)]
1884    pub struct TouchTransformMode: u8 {
1885        /// Can translate in the X dimension.
1886        const TRANSLATE_X = 0b0000_0001;
1887        /// Can translate in the y dimension.
1888        const TRANSLATE_Y = 0b0000_0010;
1889        /// Can translate in both dimensions.
1890        const TRANSLATE = Self::TRANSLATE_X.bits() | Self::TRANSLATE_Y.bits();
1891
1892        /// Can scale in the X dimension.
1893        const SCALE_X = 0b0000_0100;
1894        /// Can scale in the Y dimension.
1895        const SCALE_Y = 0b0000_1000;
1896        /// Can scale in both dimensions the same amount.
1897        const SCALE = 0b0001_1100;
1898
1899        /// Can rotate.
1900        const ROTATE = 0b0010_0000;
1901
1902        /// Can translate, scale-square and rotate.
1903        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                // cancel before start
2001            }
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                    // cancel or invalid start
2058                    *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; // entire window blocked
2169                                    }
2170                                };
2171                                let capture = POINTER_CAPTURE.current_capture().get();
2172
2173                                // takeover the gesture.
2174                                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; // entire window blocked
2260                                    }
2261                                };
2262                                let capture = POINTER_CAPTURE.current_capture().get();
2263
2264                                for h in handle.iter() {
2265                                    // takeover the gesture.
2266                                    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), // hit-test deferred
2464                            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}