Skip to main content

ferroui_base/input/
touch_device.rs

1use super::raw::{IRawInputEventArgs, RawPointerEventArgs, RawPointerEventType};
2use super::{
3    CaptureSource, IInputDevice, IPointer, IPointerDevice, InputElement, MouseButton, Pointer, PointerEventArgs,
4    PointerPointProperties, PointerPressedEventArgs, PointerReleasedEventArgs, PointerType, RawInputModifiers,
5};
6use crate::{Rect, Size, Thickness};
7use std::any::Any;
8use std::cell::{Cell, RefCell};
9use std::collections::HashMap;
10use std::rc::Rc;
11
12/// Handles raw touch events.
13///
14/// This class is supposed to be used on per-toplevel basis; don't use a
15/// shared one.
16pub struct TouchDevice {
17    pointers: RefCell<HashMap<i64, Rc<Pointer>>>,
18    disposed: Cell<bool>,
19    click_count: Cell<i32>,
20    last_click_rect: Cell<Rect>,
21    last_click_time: Cell<u64>,
22}
23
24impl TouchDevice {
25    /// Creates a touch device.
26    pub fn new() -> Rc<TouchDevice> {
27        Rc::new(TouchDevice {
28            pointers: RefCell::new(HashMap::new()),
29            disposed: Cell::new(false),
30            click_count: Cell::new(0),
31            last_click_rect: Cell::new(Rect::default()),
32            last_click_time: Cell::new(0),
33        })
34    }
35
36    fn get_modifiers(modifiers: RawInputModifiers, is_left_button_down: bool) -> RawInputModifiers {
37        let mut rv = modifiers & RawInputModifiers::KEYBOARD_MASK;
38        if is_left_button_down {
39            rv |= RawInputModifiers::LEFT_MOUSE_BUTTON;
40        }
41        rv
42    }
43
44    /// Releases the device and its pointers.
45    pub fn dispose(&self) {
46        if self.disposed.get() {
47            return;
48        }
49
50        let values: Vec<_> = self.pointers.borrow_mut().drain().map(|(_, pointer)| pointer).collect();
51        self.disposed.set(true);
52
53        for p in values {
54            p.dispose();
55        }
56    }
57
58    /// Notifies the device that the capture of its pointers was lost in
59    /// the platform.
60    pub fn platform_capture_lost(&self) {
61        let pointers: Vec<_> = self.pointers.borrow().values().cloned().collect();
62        for pointer in pointers {
63            pointer.platform_capture_lost();
64        }
65    }
66}
67
68impl IInputDevice for TouchDevice {
69    fn process_raw_event(&self, ev: &dyn IRawInputEventArgs) {
70        if ev.handled() || self.disposed.get() {
71            return;
72        }
73
74        let args = ev.downcast_ref::<RawPointerEventArgs>().expect("a touch device processes raw pointer events");
75        let hit = args.input_hit_test_result().1;
76        let existing = self.pointers.borrow().get(&args.raw_pointer_id()).cloned();
77
78        let pointer = match existing {
79            Some(pointer) => pointer,
80            None => {
81                if args.type_() == RawPointerEventType::TouchEnd {
82                    return;
83                }
84
85                let is_primary = self.pointers.borrow().is_empty();
86                let pointer = Pointer::new(Pointer::get_next_free_id(), PointerType::Touch, is_primary);
87                self.pointers.borrow_mut().insert(args.raw_pointer_id(), pointer.clone());
88                pointer.capture_with_source(hit.as_ref(), CaptureSource::Implicit);
89                pointer
90            }
91        };
92
93        let root_element = args.root().root_element();
94        let mut target = pointer.captured().or(hit).unwrap_or_else(|| root_element.clone());
95        let gesture_recognizer = pointer.captured_gesture_recognizer();
96        let gesture_target = gesture_recognizer.as_ref().and_then(|recognizer| recognizer.target());
97        let update_kind = args.type_().to_update_kind();
98        let key_modifier = args.input_modifiers().to_key_modifiers();
99
100        if args.type_() == RawPointerEventType::TouchBegin {
101            if self.pointers.borrow().len() > 1 {
102                self.click_count.set(1);
103                self.last_click_time.set(0);
104                self.last_click_rect.set(Rect::default());
105            } else if let Some(settings) = target.get_platform_settings() {
106                let double_click_time = settings.get_double_tap_time(PointerType::Touch).as_secs_f64() * 1000.0;
107                let double_click_size = settings.get_double_tap_size(PointerType::Touch);
108
109                if !self.last_click_rect.get().contains(args.position())
110                    || ev.timestamp().wrapping_sub(self.last_click_time.get()) as f64 > double_click_time
111                {
112                    self.click_count.set(0);
113                }
114
115                self.click_count.set(self.click_count.get() + 1);
116                self.last_click_time.set(ev.timestamp());
117                self.last_click_rect.set(Rect::from_position_size(args.position(), Size::default()).inflate_thickness(
118                    Thickness::symmetric(double_click_size.width / 2.0, double_click_size.height / 2.0),
119                ));
120            }
121
122            target.raise_event(
123                &PointerPressedEventArgs::new(
124                    &target,
125                    pointer.clone(),
126                    &root_element,
127                    args.position(),
128                    ev.timestamp(),
129                    PointerPointProperties::from_raw_point(
130                        Self::get_modifiers(args.input_modifiers(), true),
131                        update_kind,
132                        args.point(),
133                    ),
134                    key_modifier,
135                    self.click_count.get(),
136                )
137                .with_platform_input_event_cookie(args.platform_input_event_cookie()),
138            );
139        }
140
141        if args.type_() == RawPointerEventType::TouchEnd {
142            self.pointers.borrow_mut().remove(&args.raw_pointer_id());
143
144            target = gesture_target.clone().unwrap_or(target);
145
146            let e = PointerReleasedEventArgs::new(
147                &target,
148                pointer.clone(),
149                &root_element,
150                args.position(),
151                ev.timestamp(),
152                PointerPointProperties::from_raw_point(
153                    Self::get_modifiers(args.input_modifiers(), false),
154                    update_kind,
155                    args.point(),
156                ),
157                key_modifier,
158                MouseButton::Left,
159            );
160
161            match (&gesture_target, pointer.captured_gesture_recognizer()) {
162                (Some(_), Some(recognizer)) => recognizer.pointer_released_internal(&e),
163                (Some(_), None) => {}
164                (None, _) => target.raise_event(&e),
165            }
166
167            pointer.capture_lost(CaptureSource::Implicit);
168            pointer.dispose();
169        }
170
171        if args.type_() == RawPointerEventType::TouchCancel {
172            self.pointers.borrow_mut().remove(&args.raw_pointer_id());
173            pointer.dispose();
174        }
175
176        if args.type_() == RawPointerEventType::TouchUpdate {
177            target = gesture_target.clone().unwrap_or(target);
178
179            let e = PointerEventArgs::new(
180                Some(InputElement::pointer_moved_event()),
181                &target,
182                pointer.clone(),
183                Some(&root_element),
184                args.position(),
185                ev.timestamp(),
186                PointerPointProperties::from_raw_point(
187                    Self::get_modifiers(args.input_modifiers(), true),
188                    update_kind,
189                    args.point(),
190                ),
191                key_modifier,
192            )
193            .with_previous_points(args.intermediate_points());
194
195            match (&gesture_target, pointer.captured_gesture_recognizer()) {
196                (Some(_), Some(recognizer)) => recognizer.pointer_moved_internal(&e),
197                (Some(_), None) => {}
198                (None, _) => target.raise_event(&e),
199            }
200        }
201    }
202
203    fn as_any(&self) -> &dyn Any {
204        self
205    }
206
207    fn as_pointer_device(&self) -> Option<&dyn IPointerDevice> {
208        Some(self)
209    }
210}
211
212impl IPointerDevice for TouchDevice {
213    fn try_get_pointer(&self, ev: &RawPointerEventArgs) -> Option<Rc<dyn IPointer>> {
214        self.pointers.borrow().get(&ev.raw_pointer_id()).map(|pointer| pointer.clone() as Rc<dyn IPointer>)
215    }
216}