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