Skip to main content

carnelian/input/
report.rs

1// Copyright 2021 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
5use crate::app::Config;
6use crate::app::strategies::framebuffer::{AutoRepeatContext, AutoRepeatTimer};
7use crate::drawing::DisplayRotation;
8use crate::geometry::{IntVector, LimitToBounds};
9use crate::input::{
10    Button, ButtonSet, DeviceId, Event, EventType, Modifiers, consumer_control,
11    input3_key_to_hid_usage, keyboard, mouse, touch,
12};
13use crate::{IntPoint, IntRect, IntSize};
14use euclid::{point2, size2, vec2};
15use fidl_fuchsia_input_report as fidl_input_report;
16use keymaps::Keymap;
17use std::collections::HashSet;
18
19#[derive(Debug)]
20pub struct TouchScale {
21    pub target_size: IntSize,
22    pub x: fidl_fuchsia_input::Range,
23    pub x_span: f32,
24    pub y: fidl_fuchsia_input::Range,
25    pub y_span: f32,
26}
27
28fn restrict_to_range(value: i64, range: &fidl_fuchsia_input::Range) -> i64 {
29    if value < range.min {
30        range.min
31    } else if value > range.max {
32        range.max
33    } else {
34        value
35    }
36}
37
38fn scale_value(value: i64, span: f32, range: &fidl_fuchsia_input::Range, value_max: i32) -> i32 {
39    let value = restrict_to_range(value, range) - range.min;
40    let value_fraction = value as f32 / span;
41    (value_fraction * value_max as f32) as i32
42}
43
44impl TouchScale {
45    fn calculate_span(range: &fidl_fuchsia_input::Range) -> f32 {
46        if range.max <= range.min { 1.0 } else { (range.max - range.min) as f32 }
47    }
48
49    pub fn new(
50        target_size: &IntSize,
51        x: &fidl_fuchsia_input::Range,
52        y: &fidl_fuchsia_input::Range,
53    ) -> Self {
54        Self {
55            target_size: *target_size,
56            x: *x,
57            x_span: Self::calculate_span(x),
58            y: *y,
59            y_span: Self::calculate_span(y),
60        }
61    }
62
63    pub fn scale(&self, pt: &IntPoint) -> IntPoint {
64        let x = scale_value(pt.x as i64, self.x_span, &self.x, self.target_size.width);
65        let y = scale_value(pt.y as i64, self.y_span, &self.y, self.target_size.height);
66        point2(x, y)
67    }
68}
69
70fn create_keyboard_event(
71    event_time: u64,
72    device_id: &DeviceId,
73    phase: keyboard::Phase,
74    key: fidl_fuchsia_input::Key,
75    modifiers: &Modifiers,
76    keymap: &Keymap<'_>,
77) -> Event {
78    let hid_usage = input3_key_to_hid_usage(key);
79    let code_point =
80        keymap.hid_usage_to_code_point_for_mods(hid_usage, modifiers.shift, modifiers.caps_lock);
81    let keyboard_event = keyboard::Event { phase, code_point, hid_usage, modifiers: *modifiers };
82    Event {
83        event_time,
84        device_id: device_id.clone(),
85        event_type: EventType::Keyboard(keyboard_event),
86    }
87}
88
89pub(crate) struct InputReportHandler<'a> {
90    device_id: DeviceId,
91    view_size: IntSize,
92    display_rotation: DisplayRotation,
93    touch_scale: Option<TouchScale>,
94    keymap: &'a Keymap<'a>,
95    repeating: Option<fidl_fuchsia_input::Key>,
96    cursor_position: IntPoint,
97    pressed_mouse_buttons: HashSet<u8>,
98    pressed_keys: HashSet<fidl_fuchsia_input::Key>,
99    raw_contacts: HashSet<touch::RawContact>,
100    pressed_consumer_control_buttons: HashSet<fidl_fuchsia_input::ConsumerControlButton>,
101}
102
103impl<'a> InputReportHandler<'a> {
104    pub fn new(
105        device_id: DeviceId,
106        size: IntSize,
107        display_rotation: DisplayRotation,
108        device_descriptor: &fidl_input_report::DeviceDescriptor,
109        keymap: &'a Keymap<'a>,
110    ) -> Self {
111        let touch_scale = device_descriptor
112            .touch
113            .as_ref()
114            .and_then(|touch| touch.input.as_ref())
115            .and_then(|input_descriptor| input_descriptor.contacts.as_ref())
116            .and_then(|contacts| contacts.first())
117            .and_then(|contact_input_descriptor| {
118                if contact_input_descriptor.position_x.is_some()
119                    && contact_input_descriptor.position_y.is_some()
120                {
121                    Some(TouchScale::new(
122                        &size,
123                        &contact_input_descriptor.position_x.as_ref().expect("position_x").range,
124                        &contact_input_descriptor.position_y.as_ref().expect("position_y").range,
125                    ))
126                } else {
127                    None
128                }
129            });
130        Self::new_with_scale(device_id, size, display_rotation, touch_scale, keymap)
131    }
132
133    pub fn new_with_scale(
134        device_id: DeviceId,
135        size: IntSize,
136        display_rotation: DisplayRotation,
137        touch_scale: Option<TouchScale>,
138        keymap: &'a Keymap<'a>,
139    ) -> Self {
140        Self {
141            device_id: device_id,
142            view_size: size,
143            display_rotation,
144            keymap,
145            repeating: None,
146            touch_scale,
147            cursor_position: IntPoint::zero(),
148            pressed_mouse_buttons: HashSet::new(),
149            pressed_keys: HashSet::new(),
150            raw_contacts: HashSet::new(),
151            pressed_consumer_control_buttons: HashSet::new(),
152        }
153    }
154
155    fn handle_mouse_input_report(
156        &mut self,
157        event_time: u64,
158        device_id: &DeviceId,
159        mouse: &fidl_input_report::MouseInputReport,
160    ) -> Vec<Event> {
161        let transform = self.display_rotation.inv_transform(&self.view_size.to_f32());
162        let new_cursor_position = self.cursor_position
163            + vec2(mouse.movement_x.unwrap_or(0) as i32, mouse.movement_y.unwrap_or(0) as i32);
164        let m = self.view_size;
165        let bounds = IntRect::new(IntPoint::zero(), m);
166        let new_cursor_position = bounds.limit_to_bounds(new_cursor_position);
167        let pressed_buttons: HashSet<u8> = if let Some(ref pressed_buttons) = mouse.pressed_buttons
168        {
169            let pressed_buttons_set = pressed_buttons.iter().cloned().collect();
170            pressed_buttons_set
171        } else {
172            HashSet::new()
173        };
174
175        let button_set = ButtonSet::new(&pressed_buttons);
176
177        let move_event = if new_cursor_position != self.cursor_position {
178            let event = mouse::create_event(
179                event_time,
180                device_id,
181                &button_set,
182                new_cursor_position,
183                &transform,
184                mouse::Phase::Moved,
185            );
186            Some(event)
187        } else {
188            None
189        };
190
191        self.cursor_position = new_cursor_position;
192
193        let newly_pressed = pressed_buttons.difference(&self.pressed_mouse_buttons).map(|button| {
194            mouse::create_event(
195                event_time,
196                device_id,
197                &button_set,
198                new_cursor_position,
199                &transform,
200                mouse::Phase::Down(Button(*button)),
201            )
202        });
203
204        let released = self.pressed_mouse_buttons.difference(&pressed_buttons).map(|button| {
205            mouse::create_event(
206                event_time,
207                device_id,
208                &button_set,
209                new_cursor_position,
210                &transform,
211                mouse::Phase::Up(Button(*button)),
212            )
213        });
214
215        let wheel_v = mouse.scroll_v.unwrap_or(0) as i32;
216        let wheel_h = mouse.scroll_h.unwrap_or(0) as i32;
217        let wheel = if wheel_v != 0 || wheel_h != 0 {
218            Some(mouse::create_event(
219                event_time,
220                device_id,
221                &button_set,
222                new_cursor_position,
223                &transform,
224                mouse::Phase::Wheel(IntVector::new(wheel_h, wheel_v)),
225            ))
226        } else {
227            None
228        };
229
230        let events = newly_pressed.chain(move_event).chain(wheel).chain(released).collect();
231        self.pressed_mouse_buttons = pressed_buttons;
232        events
233    }
234
235    fn handle_keyboard_input_report(
236        &mut self,
237        event_time: u64,
238        device_id: &DeviceId,
239        keyboard: &fidl_input_report::KeyboardInputReport,
240        context: &mut dyn AutoRepeatTimer,
241    ) -> Vec<Event> {
242        let pressed_keys: HashSet<fidl_fuchsia_input::Key> =
243            if let Some(ref pressed_keys) = keyboard.pressed_keys3 {
244                HashSet::from_iter(pressed_keys.iter().map(|key| *key))
245            } else {
246                HashSet::new()
247            };
248
249        let modifiers = Modifiers::from_pressed_keys_3(&pressed_keys);
250
251        let mut first_non_modifier: Option<fidl_fuchsia_input::Key> = None;
252
253        let newly_pressed = pressed_keys.difference(&self.pressed_keys).map(|key| {
254            if first_non_modifier.is_none() && !Modifiers::is_modifier(key) {
255                first_non_modifier = Some(*key);
256            }
257            create_keyboard_event(
258                event_time,
259                device_id,
260                keyboard::Phase::Pressed,
261                *key,
262                &modifiers,
263                self.keymap,
264            )
265        });
266
267        let mut repeating: Option<fidl_fuchsia_input::Key> = self.repeating.clone();
268
269        let released = self.pressed_keys.difference(&pressed_keys).map(|key| {
270            if repeating.as_ref() == Some(key) {
271                repeating = None;
272            }
273
274            create_keyboard_event(
275                event_time,
276                device_id,
277                keyboard::Phase::Released,
278                *key,
279                &modifiers,
280                self.keymap,
281            )
282        });
283
284        let events = newly_pressed.chain(released).collect();
285        self.pressed_keys = pressed_keys;
286        self.repeating = first_non_modifier.or(repeating);
287        if Config::get().keyboard_autorepeat && self.repeating.is_some() {
288            context.schedule_autorepeat_timer(&self.device_id);
289        }
290        events
291    }
292
293    pub fn handle_keyboard_autorepeat(
294        &mut self,
295        device_id: &DeviceId,
296        context: &mut AutoRepeatContext,
297    ) -> Vec<Event> {
298        if let Some(key) = self.repeating.as_ref() {
299            let repeat_time = zx::MonotonicInstant::get();
300            let modifiers = Modifiers::from_pressed_keys_3(&self.pressed_keys);
301            context.continue_autorepeat_timer(&self.device_id);
302            let repeat = create_keyboard_event(
303                repeat_time.into_nanos() as u64,
304                device_id,
305                keyboard::Phase::Repeat,
306                *key,
307                &modifiers,
308                self.keymap,
309            );
310            vec![repeat]
311        } else {
312            context.cancel_autorepeat_timer();
313            Vec::new()
314        }
315    }
316
317    fn handle_touch_input_report(
318        &mut self,
319        event_time: u64,
320        device_id: &DeviceId,
321        touch: &fidl_input_report::TouchInputReport,
322    ) -> Vec<Event> {
323        if self.touch_scale.is_none() {
324            return Vec::new();
325        }
326
327        let pressed_buttons: HashSet<fidl_input_report::TouchButton> =
328            if let Some(ref pressed_buttons) = touch.pressed_buttons {
329                let pressed_buttons_set = pressed_buttons.iter().cloned().collect();
330                pressed_buttons_set
331            } else {
332                HashSet::new()
333            };
334
335        let raw_contacts: HashSet<touch::RawContact> = if let Some(ref contacts) = touch.contacts {
336            let id_iter = contacts.iter().filter_map(|contact| {
337                if contact.position_x.is_none() || contact.position_y.is_none() {
338                    return None;
339                }
340                let contact_id = contact.contact_id.expect("contact_id");
341                let contact_size =
342                    if contact.contact_width.is_none() || contact.contact_height.is_none() {
343                        None
344                    } else {
345                        Some(size2(
346                            contact.contact_width.expect("contact_width") as i32,
347                            contact.contact_height.expect("contact_height") as i32,
348                        ))
349                    };
350                Some(touch::RawContact {
351                    contact_id,
352                    position: point2(
353                        contact.position_x.expect("position_x") as i32,
354                        contact.position_y.expect("position_y") as i32,
355                    ),
356                    contact_size,
357                    pressure: contact.pressure,
358                })
359            });
360            HashSet::from_iter(id_iter)
361        } else {
362            HashSet::new()
363        };
364
365        let transform = self.display_rotation.inv_transform(&self.view_size.to_f32());
366        let touch_scale = self.touch_scale.as_ref().expect("touch_scale");
367
368        let t = |point: IntPoint| transform.transform_point(point.to_f32()).to_i32();
369
370        let maintained_contacts =
371            self.raw_contacts.intersection(&raw_contacts).map(|raw_contact| touch::Contact {
372                contact_id: touch::ContactId(raw_contact.contact_id),
373                phase: touch::Phase::Moved(
374                    t(touch_scale.scale(&raw_contact.position)),
375                    raw_contact.contact_size.unwrap_or_else(|| IntSize::zero()),
376                ),
377            });
378
379        let new_contacts =
380            raw_contacts.difference(&self.raw_contacts).map(|raw_contact| touch::Contact {
381                contact_id: touch::ContactId(raw_contact.contact_id),
382                phase: touch::Phase::Down(
383                    t(touch_scale.scale(&raw_contact.position)),
384                    raw_contact.contact_size.unwrap_or_else(|| IntSize::zero()),
385                ),
386            });
387
388        let ended_contacts =
389            self.raw_contacts.difference(&raw_contacts).map(|raw_contact| touch::Contact {
390                contact_id: touch::ContactId(raw_contact.contact_id),
391                phase: touch::Phase::Up,
392            });
393
394        let contacts: Vec<touch::Contact> =
395            new_contacts.chain(maintained_contacts).chain(ended_contacts).collect();
396
397        self.raw_contacts = raw_contacts;
398
399        let touch_event = touch::Event { contacts: contacts, buttons: pressed_buttons };
400        let event = Event {
401            event_time,
402            device_id: device_id.clone(),
403            event_type: EventType::Touch(touch_event),
404        };
405        vec![event]
406    }
407
408    fn handle_consumer_control_report(
409        &mut self,
410        event_time: u64,
411        device_id: &DeviceId,
412        consumer_control: &fidl_input_report::ConsumerControlInputReport,
413    ) -> Vec<Event> {
414        fn create_consumer_control_event(
415            event_time: u64,
416            device_id: &DeviceId,
417            phase: consumer_control::Phase,
418            button: fidl_fuchsia_input::ConsumerControlButton,
419        ) -> Event {
420            let consumer_control_event = consumer_control::Event { phase, button };
421            Event {
422                event_time,
423                device_id: device_id.clone(),
424                event_type: EventType::ConsumerControl(consumer_control_event),
425            }
426        }
427
428        let pressed_consumer_control_buttons: HashSet<fidl_fuchsia_input::ConsumerControlButton> =
429            if let Some(ref pressed_buttons) = consumer_control.pressed_buttons {
430                let pressed_buttons_set = pressed_buttons.iter().cloned().collect();
431                pressed_buttons_set
432            } else {
433                HashSet::new()
434            };
435        let newly_pressed = pressed_consumer_control_buttons
436            .difference(&self.pressed_consumer_control_buttons)
437            .map(|button| {
438                create_consumer_control_event(
439                    event_time,
440                    device_id,
441                    consumer_control::Phase::Down,
442                    *button,
443                )
444            });
445
446        let released = self
447            .pressed_consumer_control_buttons
448            .difference(&pressed_consumer_control_buttons)
449            .map(|button| {
450                create_consumer_control_event(
451                    event_time,
452                    device_id,
453                    consumer_control::Phase::Up,
454                    *button,
455                )
456            });
457        let events = newly_pressed.chain(released).collect();
458        self.pressed_consumer_control_buttons = pressed_consumer_control_buttons;
459        events
460    }
461
462    pub fn handle_input_report(
463        &mut self,
464        device_id: &DeviceId,
465        input_report: &fidl_input_report::InputReport,
466        context: &mut dyn AutoRepeatTimer,
467    ) -> Vec<Event> {
468        let mut events = Vec::new();
469        let event_time = input_report.event_time.unwrap_or(0) as u64;
470        if let Some(mouse) = input_report.mouse.as_ref() {
471            events.extend(self.handle_mouse_input_report(event_time, device_id, mouse));
472        }
473        if let Some(keyboard) = input_report.keyboard.as_ref() {
474            events.extend(
475                self.handle_keyboard_input_report(event_time, &device_id, keyboard, context),
476            );
477        }
478        if let Some(touch) = input_report.touch.as_ref() {
479            events.extend(self.handle_touch_input_report(event_time, &device_id, touch));
480        }
481        if let Some(consumer_control) = input_report.consumer_control.as_ref() {
482            events.extend(self.handle_consumer_control_report(
483                event_time,
484                &device_id,
485                consumer_control,
486            ));
487        }
488        events
489    }
490}