carnelian/
input_ext.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#![allow(unused)]
6use crate::geometry::{IntPoint, IntSize};
7use crate::input::*;
8use fidl_fuchsia_input_report as hid_input_report;
9use std::collections::{BTreeMap, HashSet, VecDeque};
10use zx::MonotonicInstant;
11
12#[derive(Clone, Copy)]
13struct ContactDetails {
14    event_time: u64,
15    location: IntPoint,
16    size: IntSize,
17}
18
19struct DownContact {
20    last: ContactDetails,
21    next: ContactDetails,
22}
23
24struct TouchDevice {
25    down_contacts: BTreeMap<touch::ContactId, DownContact>,
26    buttons: HashSet<hid_input_report::TouchButton>,
27}
28
29pub(crate) struct TouchEventResampler {
30    events: VecDeque<Event>,
31    touch_devices: BTreeMap<DeviceId, TouchDevice>,
32}
33
34impl TouchEventResampler {
35    /// Create new touch event resampler.
36    pub fn new() -> Self {
37        Self { events: VecDeque::new(), touch_devices: BTreeMap::new() }
38    }
39
40    /// Enqueue any type of event.
41    pub fn enqueue(&mut self, event: Event) {
42        self.events.push_back(event);
43    }
44
45    /// Dequeue non-moved events older than |sample_time| and sample touch
46    /// contacts at |sample_time|.
47    pub fn dequeue_and_sample(&mut self, sample_time: MonotonicInstant) -> Vec<Event> {
48        let sample_time_ns = sample_time.into_nanos() as u64;
49
50        // Process events until sample time.
51        self.process_events(sample_time_ns);
52
53        // Dequeue events older than sample time.
54        let mut events = self.dequeue_events_until(sample_time_ns);
55
56        // Add resampled move events for all tracked touch contacts.
57        events.extend(self.touch_devices.iter().filter_map(|(device_id, device)| {
58            if device.down_contacts.is_empty() {
59                None
60            } else {
61                let contacts = device.down_contacts.iter().map(|(contact_id, contact)| {
62                    let p = contact.last;
63                    let n = contact.next;
64                    touch::Contact {
65                        contact_id: *contact_id,
66                        // Resample location and size if the next contact details are passed
67                        // sample time. Otherwise, use the latest contact details we have.
68                        phase: if n.event_time > sample_time_ns && n.event_time > p.event_time {
69                            let interval = (n.event_time - p.event_time) as f32;
70                            let scalar = (sample_time_ns - p.event_time) as f32 / interval;
71                            let location =
72                                p.location.to_f32() + (n.location - p.location).to_f32() * scalar;
73                            let size = p.size.to_f32() + (n.size - p.size).to_f32() * scalar;
74                            touch::Phase::Moved(location.to_i32(), size.to_i32())
75                        } else {
76                            touch::Phase::Moved(n.location, n.size)
77                        },
78                    }
79                });
80
81                let touch_event =
82                    touch::Event { contacts: contacts.collect(), buttons: device.buttons.clone() };
83                Some(Event {
84                    event_time: sample_time_ns,
85                    device_id: device_id.clone(),
86                    event_type: EventType::Touch(touch_event),
87                })
88            }
89        }));
90
91        events
92    }
93
94    fn process_events(&mut self, sample_time_ns: u64) {
95        for Event { event_time, device_id, event_type } in &self.events {
96            if let EventType::Touch(touch_event) = event_type {
97                // Update contact details if event time is more recent than sample time. Otherwise,
98                // add/remove contact from currently tracked down contacts.
99                if *event_time > sample_time_ns {
100                    if let Some(device) = self.touch_devices.get_mut(&device_id.clone()) {
101                        for touch::Contact { contact_id, phase } in &touch_event.contacts {
102                            if let touch::Phase::Moved(location, size) = phase {
103                                if let Some(down_contact) =
104                                    device.down_contacts.get_mut(&contact_id)
105                                {
106                                    // Update contact details if current details are not already more
107                                    // recent than sample time.
108                                    if down_contact.next.event_time < sample_time_ns {
109                                        down_contact.next = ContactDetails {
110                                            event_time: *event_time,
111                                            location: *location,
112                                            size: *size,
113                                        };
114                                    }
115                                }
116                            }
117                        }
118                    }
119                } else {
120                    // Insert device if it doesn't already exist.
121                    let device = self.touch_devices.entry(device_id.clone()).or_insert_with(|| {
122                        TouchDevice {
123                            down_contacts: BTreeMap::new(),
124                            buttons: touch_event.buttons.clone(),
125                        }
126                    });
127
128                    // Update buttons state.
129                    device.buttons = touch_event.buttons.clone();
130
131                    for contact in &touch_event.contacts {
132                        match contact.phase {
133                            touch::Phase::Down(location, size)
134                            | touch::Phase::Moved(location, size) => {
135                                let details =
136                                    ContactDetails { event_time: *event_time, location, size };
137                                device.down_contacts.insert(
138                                    contact.contact_id,
139                                    DownContact { last: details, next: details },
140                                );
141                            }
142                            touch::Phase::Up | touch::Phase::Remove | touch::Phase::Cancel => {
143                                device.down_contacts.remove(&contact.contact_id);
144                            }
145                        }
146                    }
147                }
148            }
149        }
150    }
151
152    fn dequeue_events_until(&mut self, sample_time_ns: u64) -> Vec<Event> {
153        let mut events = vec![];
154
155        while let Some(event) = self.events.front() {
156            // Stop dequeuing events if more recent than sample time.
157            if event.event_time > sample_time_ns {
158                break;
159            }
160
161            let event = self.events.pop_front().unwrap();
162            if let EventType::Touch(touch_event) = &event.event_type {
163                if let Some(device) = self.touch_devices.get(&event.device_id.clone()) {
164                    let contacts = touch_event.contacts.iter().filter_map(|contact| {
165                        match contact.phase {
166                            touch::Phase::Moved(_, _) => {
167                                // Skip moved phase if we're tracking contact.
168                                if device.down_contacts.contains_key(&contact.contact_id) {
169                                    None
170                                } else {
171                                    Some(contact.clone())
172                                }
173                            }
174                            _ => Some(contact.clone()),
175                        }
176                    });
177
178                    let touch_event = touch::Event {
179                        contacts: contacts.collect(),
180                        buttons: device.buttons.clone(),
181                    };
182                    if !touch_event.contacts.is_empty() {
183                        events.push(Event {
184                            event_time: event.event_time,
185                            device_id: event.device_id.clone(),
186                            event_type: EventType::Touch(touch_event),
187                        });
188                    }
189                }
190            } else {
191                events.push(event);
192            }
193        }
194
195        events
196    }
197}
198
199#[cfg(test)]
200mod touch_event_resampling_tests {
201    use super::*;
202    use std::collections::HashSet;
203
204    fn create_test_down_phase(x: i32, y: i32) -> touch::Phase {
205        touch::Phase::Down(euclid::point2(x, y), IntSize::zero())
206    }
207
208    fn create_test_moved_phase(x: i32, y: i32) -> touch::Phase {
209        touch::Phase::Moved(euclid::point2(x, y), IntSize::zero())
210    }
211
212    fn create_test_event(phase: touch::Phase, event_time: u64) -> Event {
213        let touch_event = touch::Event {
214            contacts: vec![touch::Contact { contact_id: touch::ContactId(100), phase }],
215            buttons: HashSet::new(),
216        };
217        Event {
218            event_time: event_time,
219            device_id: DeviceId("test-device-id-1".to_string()),
220            event_type: EventType::Touch(touch_event),
221        }
222    }
223
224    #[test]
225    fn test_resampling() {
226        let mut resampler = TouchEventResampler::new();
227
228        resampler.enqueue(create_test_event(create_test_down_phase(0, 0), 1000));
229        resampler.enqueue(create_test_event(create_test_moved_phase(10, 0), 2000));
230        resampler.enqueue(create_test_event(create_test_moved_phase(20, 0), 3000));
231        resampler.enqueue(create_test_event(create_test_moved_phase(30, 0), 4000));
232        resampler.enqueue(create_test_event(touch::Phase::Up, 4000));
233
234        // No events should be dequeue at time 0.
235        assert_eq!(resampler.dequeue_and_sample(MonotonicInstant::from_nanos(500)), vec![]);
236
237        // Down event and first resampled moved event.
238        let result = resampler.dequeue_and_sample(MonotonicInstant::from_nanos(1500));
239        assert_eq!(result.len(), 2);
240        assert_eq!(result[0], create_test_event(create_test_down_phase(0, 0), 1000));
241        assert_eq!(result[1], create_test_event(create_test_moved_phase(5, 0), 1500));
242
243        // One resampled moved event.
244        let result = resampler.dequeue_and_sample(MonotonicInstant::from_nanos(2500));
245        assert_eq!(result.len(), 1);
246        assert_eq!(result[0], create_test_event(create_test_moved_phase(15, 0), 2500));
247
248        // Another resampled moved event.
249        let result = resampler.dequeue_and_sample(MonotonicInstant::from_nanos(3500));
250        assert_eq!(result.len(), 1);
251        assert_eq!(result[0], create_test_event(create_test_moved_phase(25, 0), 3500));
252
253        // Last resampled moved event.
254        let result = resampler.dequeue_and_sample(MonotonicInstant::from_nanos(4500));
255        assert_eq!(result.len(), 2);
256        assert_eq!(result[0], create_test_event(create_test_moved_phase(30, 0), 4000));
257        assert_eq!(result[1], create_test_event(touch::Phase::Up, 4000));
258    }
259}