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