Skip to main content

inset_services/
hardware_keyboard.rs

1//! Flutter counterpart: `services/hardware_keyboard.dart`.
2
3use std::collections::{HashMap, HashSet};
4use std::rc::Rc;
5use std::time::Duration;
6
7use inset_embedder::{KeyData, KeyEventDeviceType, KeyEventType};
8use inset_foundation::{App, Handle};
9
10use crate::keyboard_key::{LogicalKeyboardKey, PhysicalKeyboardKey};
11
12/// Represents a lock mode of a keyboard, such as [`KeyboardLockMode::CapsLock`].
13///
14/// A lock mode locks some of a keyboard's keys into a distinct mode of operation,
15/// depending on the lock settings selected. The status of the mode is toggled
16/// with each key down of its corresponding logical key. A [`KeyboardLockMode`]
17/// object is used to query whether this mode is enabled on the keyboard.
18///
19/// Only a limited number of modes are supported, which are enumerated as
20/// members of this enum. Manual constructing of this type is prohibited.
21#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
22pub enum KeyboardLockMode {
23    /// Represents the number lock mode on the keyboard.
24    ///
25    /// On supporting systems, enabling number lock mode usually allows key
26    /// presses of the number pad to input numbers, instead of acting as up, down,
27    /// left, right, page up, end, etc.
28    NumLock,
29
30    /// Represents the scrolling lock mode on the keyboard.
31    ///
32    /// On supporting systems and applications (such as a spreadsheet), enabling
33    /// scrolling lock mode usually allows key presses of the cursor keys to
34    /// scroll the document instead of the cursor.
35    ScrollLock,
36
37    /// Represents the capital letters lock mode on the keyboard.
38    ///
39    /// On supporting systems, enabling capital lock mode allows key presses of
40    /// the letter keys to input uppercase letters instead of lowercase.
41    CapsLock,
42}
43
44impl KeyboardLockMode {
45    /// The logical key that triggers this lock mode.
46    pub fn logical_key(&self) -> LogicalKeyboardKey {
47        match self {
48            KeyboardLockMode::NumLock => LogicalKeyboardKey::NUM_LOCK,
49            KeyboardLockMode::ScrollLock => LogicalKeyboardKey::SCROLL_LOCK,
50            KeyboardLockMode::CapsLock => LogicalKeyboardKey::CAPS_LOCK,
51        }
52    }
53
54    /// Returns the [`KeyboardLockMode`] constant from the logical key, or
55    /// `None`, if not found.
56    pub fn find_lock_by_logical_key(logical_key: LogicalKeyboardKey) -> Option<KeyboardLockMode> {
57        KNOWN_LOCK_MODES
58            .iter()
59            .copied()
60            .find(|lock_mode| lock_mode.logical_key() == logical_key)
61    }
62}
63
64/// Dart's `KeyboardLockMode._knownLockModes`.
65static KNOWN_LOCK_MODES: &[KeyboardLockMode] = &[
66    KeyboardLockMode::NumLock,
67    KeyboardLockMode::ScrollLock,
68    KeyboardLockMode::CapsLock,
69];
70
71/// An event indicating that the user has pressed a key down on the keyboard.
72///
73/// See also:
74///
75///  * [`KeyRepeatEvent`], a key event representing the user holding a key,
76///    causing repeated events.
77///  * [`KeyUpEvent`], a key event representing the user releasing a key.
78///  * [`HardwareKeyboard`], which produces this event.
79#[derive(Clone, Debug, PartialEq, Eq)]
80pub struct KeyDownEvent {
81    /// See [`KeyEvent::physical_key`].
82    pub physical_key: PhysicalKeyboardKey,
83
84    /// See [`KeyEvent::logical_key`].
85    pub logical_key: LogicalKeyboardKey,
86
87    /// See [`KeyEvent::character`].
88    pub character: Option<String>,
89
90    /// See [`KeyEvent::time_stamp`].
91    pub time_stamp: Duration,
92
93    /// See [`KeyEvent::device_type`].
94    pub device_type: KeyEventDeviceType,
95
96    /// See [`KeyEvent::synthesized`].
97    pub synthesized: bool,
98}
99
100impl KeyDownEvent {
101    /// Creates a key event that represents the user pressing a key.
102    pub fn new(
103        physical_key: PhysicalKeyboardKey,
104        logical_key: LogicalKeyboardKey,
105        time_stamp: Duration,
106    ) -> KeyDownEvent {
107        KeyDownEvent {
108            physical_key,
109            logical_key,
110            character: None,
111            time_stamp,
112            device_type: KeyEventDeviceType::Keyboard,
113            synthesized: false,
114        }
115    }
116
117    /// Dart `KeyDownEvent(character:)`.
118    pub fn character(mut self, character: impl Into<String>) -> KeyDownEvent {
119        self.character = Some(character.into());
120        self
121    }
122
123    /// Dart `KeyDownEvent(deviceType:)`.
124    pub fn device_type(mut self, device_type: KeyEventDeviceType) -> KeyDownEvent {
125        self.device_type = device_type;
126        self
127    }
128
129    /// Dart `KeyDownEvent(synthesized:)`.
130    pub fn synthesized(mut self, synthesized: bool) -> KeyDownEvent {
131        self.synthesized = synthesized;
132        self
133    }
134}
135
136/// An event indicating that the user has released a key on the keyboard.
137///
138/// See also:
139///
140///  * [`KeyDownEvent`], a key event representing the user pressing a key.
141///  * [`KeyRepeatEvent`], a key event representing the user holding a key,
142///    causing repeated events.
143///  * [`HardwareKeyboard`], which produces this event.
144#[derive(Clone, Debug, PartialEq, Eq)]
145pub struct KeyUpEvent {
146    /// See [`KeyEvent::physical_key`].
147    pub physical_key: PhysicalKeyboardKey,
148
149    /// See [`KeyEvent::logical_key`].
150    pub logical_key: LogicalKeyboardKey,
151
152    /// See [`KeyEvent::time_stamp`].
153    pub time_stamp: Duration,
154
155    /// See [`KeyEvent::device_type`].
156    pub device_type: KeyEventDeviceType,
157
158    /// See [`KeyEvent::synthesized`].
159    pub synthesized: bool,
160}
161
162impl KeyUpEvent {
163    /// Creates a key event that represents the user releasing a key.
164    pub fn new(
165        physical_key: PhysicalKeyboardKey,
166        logical_key: LogicalKeyboardKey,
167        time_stamp: Duration,
168    ) -> KeyUpEvent {
169        KeyUpEvent {
170            physical_key,
171            logical_key,
172            time_stamp,
173            device_type: KeyEventDeviceType::Keyboard,
174            synthesized: false,
175        }
176    }
177
178    /// Dart `KeyUpEvent(deviceType:)`.
179    pub fn device_type(mut self, device_type: KeyEventDeviceType) -> KeyUpEvent {
180        self.device_type = device_type;
181        self
182    }
183
184    /// Dart `KeyUpEvent(synthesized:)`.
185    pub fn synthesized(mut self, synthesized: bool) -> KeyUpEvent {
186        self.synthesized = synthesized;
187        self
188    }
189}
190
191/// An event indicating that the user has been holding a key on the keyboard
192/// and causing repeated events.
193///
194/// Repeat events are not guaranteed and are provided only if supported by the
195/// underlying platform.
196///
197/// See also:
198///
199///  * [`KeyDownEvent`], a key event representing the user pressing a key.
200///  * [`KeyUpEvent`], a key event representing the user releasing a key.
201///  * [`HardwareKeyboard`], which produces this event.
202#[derive(Clone, Debug, PartialEq, Eq)]
203pub struct KeyRepeatEvent {
204    /// See [`KeyEvent::physical_key`].
205    pub physical_key: PhysicalKeyboardKey,
206
207    /// See [`KeyEvent::logical_key`].
208    pub logical_key: LogicalKeyboardKey,
209
210    /// See [`KeyEvent::character`].
211    pub character: Option<String>,
212
213    /// See [`KeyEvent::time_stamp`].
214    pub time_stamp: Duration,
215
216    /// See [`KeyEvent::device_type`].
217    pub device_type: KeyEventDeviceType,
218}
219
220impl KeyRepeatEvent {
221    /// Creates a key event that represents the user holding a key.
222    pub fn new(
223        physical_key: PhysicalKeyboardKey,
224        logical_key: LogicalKeyboardKey,
225        time_stamp: Duration,
226    ) -> KeyRepeatEvent {
227        KeyRepeatEvent {
228            physical_key,
229            logical_key,
230            character: None,
231            time_stamp,
232            device_type: KeyEventDeviceType::Keyboard,
233        }
234    }
235
236    /// Dart `KeyRepeatEvent(character:)`.
237    pub fn character(mut self, character: impl Into<String>) -> KeyRepeatEvent {
238        self.character = Some(character.into());
239        self
240    }
241
242    /// Dart `KeyRepeatEvent(deviceType:)`.
243    pub fn device_type(mut self, device_type: KeyEventDeviceType) -> KeyRepeatEvent {
244        self.device_type = device_type;
245        self
246    }
247}
248
249/// Defines the interface for keyboard key events.
250///
251/// The [`KeyEvent`] provides a universal model for key event information from a
252/// hardware keyboard across platforms.
253///
254/// See also:
255///
256///  * [`HardwareKeyboard`] for full introduction to key event model and handling.
257///  * [`KeyDownEvent`], the variant for events representing the user pressing a
258///    key.
259///  * [`KeyRepeatEvent`], the variant for events representing the user holding a
260///    key, causing repeated events.
261///  * [`KeyUpEvent`], the variant for events representing the user releasing a
262///    key.
263#[derive(Clone, Debug, PartialEq, Eq)]
264pub enum KeyEvent {
265    /// [`KeyDownEvent`].
266    Down(KeyDownEvent),
267    /// [`KeyUpEvent`].
268    Up(KeyUpEvent),
269    /// [`KeyRepeatEvent`].
270    Repeat(KeyRepeatEvent),
271}
272
273impl KeyEvent {
274    /// Returns an object representing the physical location of this key.
275    ///
276    /// A [`PhysicalKeyboardKey`] represents a USB HID code sent from the keyboard,
277    /// ignoring the key map, modifier keys (like SHIFT), and the label on the key.
278    ///
279    /// [`PhysicalKeyboardKey`]s are used to describe and test for keys in a
280    /// particular location. A [`PhysicalKeyboardKey`] may have a name, but the name
281    /// is a mnemonic ("keyA" is easier to remember than 0x70004), derived from the
282    /// key's effect on a QWERTY keyboard. The name does not represent the key's
283    /// effect whatsoever (a physical "keyA" can be the Q key on an AZERTY
284    /// keyboard).
285    ///
286    /// For instance, if you wanted to make a game where the key to the right of
287    /// the CAPS LOCK key made the player move left, you would be comparing a
288    /// physical key with [`PhysicalKeyboardKey::KEY_A`], since that is the key next
289    /// to the CAPS LOCK key on a QWERTY keyboard. This would return the same thing
290    /// even on an AZERTY keyboard where the key next to the CAPS LOCK produces a
291    /// "Q" when pressed.
292    ///
293    /// If you want to make your app respond to a key with a particular character
294    /// on it regardless of location of the key, use
295    /// [`logical_key`](Self::logical_key) instead.
296    ///
297    /// Also, even though physical keys are defined with USB HID codes, their
298    /// values are not necessarily the same HID codes produced by the hardware and
299    /// presented to the driver. On most platforms, Flutter has to map the
300    /// platform representation back to a HID code because the original HID
301    /// code is not provided.
302    pub fn physical_key(&self) -> PhysicalKeyboardKey {
303        match self {
304            KeyEvent::Down(event) => event.physical_key,
305            KeyEvent::Up(event) => event.physical_key,
306            KeyEvent::Repeat(event) => event.physical_key,
307        }
308    }
309
310    /// Returns an object representing the logical key that was pressed.
311    ///
312    /// This method takes into account the key map and modifier keys (like SHIFT)
313    /// to determine which logical key to return.
314    ///
315    /// If you are looking for the character produced by a key event, use
316    /// [`character`](Self::character) instead.
317    pub fn logical_key(&self) -> LogicalKeyboardKey {
318        match self {
319            KeyEvent::Down(event) => event.logical_key,
320            KeyEvent::Up(event) => event.logical_key,
321            KeyEvent::Repeat(event) => event.logical_key,
322        }
323    }
324
325    /// Returns the Unicode character (grapheme cluster) completed by this
326    /// keystroke, if any.
327    ///
328    /// This will only return a character if this keystroke, combined with any
329    /// preceding keystroke(s), generates a character, and only on a "key down"
330    /// event. It will return `None` if no character has been generated by the
331    /// keystroke (e.g. a "dead" or "combining" key), or if the corresponding key
332    /// is a key without a visual representation, such as a modifier key or a
333    /// control key. It will also return `None` if this is a "key up" event.
334    ///
335    /// This can return multiple Unicode code points, since some characters (more
336    /// accurately referred to as grapheme clusters) are made up of more than one
337    /// code point.
338    ///
339    /// The character doesn't take into account edits by an input method editor
340    /// (IME), or manage the visibility of the soft keyboard on touch devices.
341    ///
342    /// The character is not available on [`KeyUpEvent`]s.
343    pub fn character(&self) -> Option<&str> {
344        match self {
345            KeyEvent::Down(event) => event.character.as_deref(),
346            KeyEvent::Up(_) => None,
347            KeyEvent::Repeat(event) => event.character.as_deref(),
348        }
349    }
350
351    /// Time of event, relative to an arbitrary start point.
352    ///
353    /// All events share the same time stamp origin.
354    pub fn time_stamp(&self) -> Duration {
355        match self {
356            KeyEvent::Down(event) => event.time_stamp,
357            KeyEvent::Up(event) => event.time_stamp,
358            KeyEvent::Repeat(event) => event.time_stamp,
359        }
360    }
361
362    /// The source device type for the key event.
363    ///
364    /// Not all platforms supply an accurate type.
365    ///
366    /// Defaults to [`KeyEventDeviceType::Keyboard`].
367    pub fn device_type(&self) -> KeyEventDeviceType {
368        match self {
369            KeyEvent::Down(event) => event.device_type,
370            KeyEvent::Up(event) => event.device_type,
371            KeyEvent::Repeat(event) => event.device_type,
372        }
373    }
374
375    /// Whether this event is synthesized by Flutter to synchronize key states.
376    ///
377    /// A non-synthesized event is converted from a native event, and a native
378    /// event can only be converted to one non-synthesized event. Some properties
379    /// might be changed during the conversion (for example, a native repeat event
380    /// might be converted to a Flutter down event when necessary.)
381    ///
382    /// A synthesized event is created without a source native event in order to
383    /// synchronize key states. For example, if the native platform shows that a
384    /// shift key that was previously held has been released somehow without the
385    /// key up event dispatched (probably due to loss of focus), a synthesized key
386    /// up event will be added to regularized the event stream.
387    ///
388    /// For detailed introduction to the regularized event model, see
389    /// [`HardwareKeyboard`].
390    ///
391    /// A [`KeyRepeatEvent`] is never synthesized.
392    pub fn synthesized(&self) -> bool {
393        match self {
394            KeyEvent::Down(event) => event.synthesized,
395            KeyEvent::Up(event) => event.synthesized,
396            KeyEvent::Repeat(_) => false,
397        }
398    }
399
400    /// The host's [`KeyData`] this event was made from, as `KeyEventManager` reads it: what an
401    /// app hands back to the host, such as a key it kept back for the menu bar
402    /// (`MenuBar::perform_key_equivalent`).
403    pub fn to_key_data(&self) -> KeyData {
404        KeyData {
405            time_stamp: self.time_stamp(),
406            event_type: match self {
407                KeyEvent::Down(_) => KeyEventType::Down,
408                KeyEvent::Up(_) => KeyEventType::Up,
409                KeyEvent::Repeat(_) => KeyEventType::Repeat,
410            },
411            device_type: self.device_type(),
412            physical: self.physical_key().usb_hid_usage,
413            logical: self.logical_key().key_id,
414            character: self.character().map(str::to_owned),
415            synthesized: self.synthesized(),
416        }
417    }
418}
419
420impl From<KeyDownEvent> for KeyEvent {
421    fn from(event: KeyDownEvent) -> KeyEvent {
422        KeyEvent::Down(event)
423    }
424}
425
426impl From<KeyUpEvent> for KeyEvent {
427    fn from(event: KeyUpEvent) -> KeyEvent {
428        KeyEvent::Up(event)
429    }
430}
431
432impl From<KeyRepeatEvent> for KeyEvent {
433    fn from(event: KeyRepeatEvent) -> KeyEvent {
434        KeyEvent::Repeat(event)
435    }
436}
437
438/// The signature for [`HardwareKeyboard::add_handler`], a callback to decide
439/// whether the entire framework handles a key event.
440///
441/// [`HardwareKeyboard::remove_handler`] matches the handler by allocation
442/// (`Rc::ptr_eq`), where Dart matches the function by identity.
443pub type KeyEventCallback = Rc<dyn Fn(&mut App, &KeyEvent) -> bool>;
444
445/// Manages key events from hardware keyboards.
446///
447/// [`HardwareKeyboard`] manages all key events of the application from hardware
448/// keyboards (in contrast to on-screen keyboards). It receives key data from the
449/// native platform, dispatches key events to registered handlers, and records the
450/// keyboard state.
451///
452/// To stay notified whenever keys are pressed, held, or released, add a handler
453/// with [`add_handler`](Self::add_handler). Handlers should be removed with
454/// [`remove_handler`](Self::remove_handler) when notification is no longer
455/// necessary, or when the handler is being disposed.
456///
457/// To query whether a key is being held, or a lock mode is enabled, use
458/// [`physical_keys_pressed`](Self::physical_keys_pressed),
459/// [`logical_keys_pressed`](Self::logical_keys_pressed), or
460/// [`lock_modes_enabled`](Self::lock_modes_enabled). These states will have been
461/// updated with the event when used during a key event handler.
462///
463/// ## Event model
464///
465/// Flutter uses a universal event model ([`KeyEvent`]) and key options
466/// ([`LogicalKeyboardKey`] and [`PhysicalKeyboardKey`]) regardless of the native
467/// platform, while preserving platform-specific features as much as possible.
468///
469/// [`HardwareKeyboard`] guarantees that the key model is "regularized": The key
470/// event stream consists of "key tap sequences", where a key tap sequence is
471/// defined as one [`KeyDownEvent`], zero or more [`KeyRepeatEvent`]s, and one
472/// [`KeyUpEvent`] in order, all with the same physical key and logical key.
473///
474/// Example:
475///
476///  * Tap and hold key A, US layout:
477///     * `KeyDownEvent(physicalKey: keyA, logicalKey: keyA, character: "a")`
478///     * `KeyRepeatEvent(physicalKey: keyA, logicalKey: keyA, character: "a")`
479///     * `KeyUpEvent(physicalKey: keyA, logicalKey: keyA)`
480///  * Press ShiftLeft, tap key A, then release ShiftLeft, US layout:
481///     * `KeyDownEvent(physicalKey: shiftLeft, logicalKey: shiftLeft)`
482///     * `KeyDownEvent(physicalKey: keyA, logicalKey: keyA, character: "A")`
483///     * `KeyUpEvent(physicalKey: keyA, logicalKey: keyA)`
484///     * `KeyUpEvent(physicalKey: shiftLeft, logicalKey: shiftLeft)`
485///
486/// When the application starts, all keys are released, and all lock modes are
487/// disabled. Upon key events, [`HardwareKeyboard`] will update its states, then
488/// dispatch callbacks: [`KeyDownEvent`]s and [`KeyUpEvent`]s set or reset the
489/// pressing state, while [`KeyDownEvent`]s also toggle lock modes.
490///
491/// Flutter will try to synchronize with the ground truth of keyboard states
492/// using synthesized events ([`KeyEvent::synthesized`]), subject to the
493/// availability of the platform. The desynchronization can be caused by
494/// non-empty initial state or a change in the focused window or application.
495///
496/// Flutter does not distinguish between multiple keyboards. Flutter will
497/// process all events as if they come from a single keyboard, and try to
498/// resolve any conflicts and provide a regularized key event stream, which
499/// can deviate from the ground truth.
500///
501/// Dart's `HardwareKeyboard.instance` is [`instance`](Self::instance), the App's
502/// singleton.
503#[derive(Default)]
504pub struct HardwareKeyboard {
505    pressed_keys: HashMap<PhysicalKeyboardKey, LogicalKeyboardKey>,
506    lock_modes: HashSet<KeyboardLockMode>,
507    handlers: Vec<KeyEventCallback>,
508    during_dispatch: bool,
509    modified_handlers: Option<Vec<KeyEventCallback>>,
510}
511
512impl HardwareKeyboard {
513    /// The current [`HardwareKeyboard`], if one has been created.
514    ///
515    /// Dart's `HardwareKeyboard.instance`.
516    pub fn instance(app: &mut App) -> Handle<HardwareKeyboard> {
517        app.singleton::<HardwareKeyboard>()
518    }
519
520    /// The set of [`PhysicalKeyboardKey`]s that are pressed.
521    ///
522    /// If called from a key event handler, the result will already include the
523    /// effect of the event.
524    ///
525    /// See also:
526    ///
527    ///  * [`logical_keys_pressed`](Self::logical_keys_pressed), which tells if a
528    ///    logical key is being pressed.
529    pub fn physical_keys_pressed(self: Handle<Self>, app: &App) -> HashSet<PhysicalKeyboardKey> {
530        app.get(self).pressed_keys.keys().copied().collect()
531    }
532
533    /// The set of [`LogicalKeyboardKey`]s that are pressed.
534    ///
535    /// If called from a key event handler, the result will already include the
536    /// effect of the event.
537    ///
538    /// See also:
539    ///
540    ///  * [`physical_keys_pressed`](Self::physical_keys_pressed), which tells if a
541    ///    physical key is being pressed.
542    pub fn logical_keys_pressed(self: Handle<Self>, app: &App) -> HashSet<LogicalKeyboardKey> {
543        app.get(self).pressed_keys.values().copied().collect()
544    }
545
546    /// Returns the logical key that corresponds to the given pressed physical key.
547    ///
548    /// Returns `None` if the physical key is not currently pressed.
549    pub fn look_up_layout(
550        self: Handle<Self>,
551        app: &App,
552        physical_key: PhysicalKeyboardKey,
553    ) -> Option<LogicalKeyboardKey> {
554        app.get(self).pressed_keys.get(&physical_key).copied()
555    }
556
557    /// The set of [`KeyboardLockMode`] that are enabled.
558    ///
559    /// Lock keys, such as CapsLock, are logical keys that toggle their
560    /// respective boolean states on key down events. Such flags are usually used
561    /// as modifier to other keys or events.
562    ///
563    /// If called from a key event handler, the result will already include the
564    /// effect of the event.
565    pub fn lock_modes_enabled(self: Handle<Self>, app: &App) -> HashSet<KeyboardLockMode> {
566        app.get(self).lock_modes.clone()
567    }
568
569    /// Returns true if the given [`LogicalKeyboardKey`] is pressed, according to
570    /// the [`HardwareKeyboard`].
571    pub fn is_logical_key_pressed(self: Handle<Self>, app: &App, key: LogicalKeyboardKey) -> bool {
572        app.get(self)
573            .pressed_keys
574            .values()
575            .any(|&pressed| pressed == key)
576    }
577
578    /// Returns true if the given [`PhysicalKeyboardKey`] is pressed, according to
579    /// the [`HardwareKeyboard`].
580    pub fn is_physical_key_pressed(
581        self: Handle<Self>,
582        app: &App,
583        key: PhysicalKeyboardKey,
584    ) -> bool {
585        app.get(self).pressed_keys.contains_key(&key)
586    }
587
588    /// Returns true if a logical CTRL modifier key is pressed, regardless of
589    /// which side of the keyboard it is on.
590    ///
591    /// Use [`is_logical_key_pressed`](Self::is_logical_key_pressed) if you need to
592    /// know which control key was pressed.
593    pub fn is_control_pressed(self: Handle<Self>, app: &App) -> bool {
594        self.is_logical_key_pressed(app, LogicalKeyboardKey::CONTROL_LEFT)
595            || self.is_logical_key_pressed(app, LogicalKeyboardKey::CONTROL_RIGHT)
596    }
597
598    /// Returns true if a logical SHIFT modifier key is pressed, regardless of
599    /// which side of the keyboard it is on.
600    ///
601    /// Use [`is_logical_key_pressed`](Self::is_logical_key_pressed) if you need to
602    /// know which shift key was pressed.
603    pub fn is_shift_pressed(self: Handle<Self>, app: &App) -> bool {
604        self.is_logical_key_pressed(app, LogicalKeyboardKey::SHIFT_LEFT)
605            || self.is_logical_key_pressed(app, LogicalKeyboardKey::SHIFT_RIGHT)
606    }
607
608    /// Returns true if a logical ALT modifier key is pressed, regardless of which
609    /// side of the keyboard it is on.
610    ///
611    /// The `AltGr` key that appears on some keyboards is considered to be the
612    /// same as [`LogicalKeyboardKey::ALT_RIGHT`] on some platforms (notably
613    /// Android). On platforms that can distinguish between `altRight` and
614    /// `altGr`, a press of `AltGr` will not return true here, and will need to be
615    /// tested for separately.
616    ///
617    /// Use [`is_logical_key_pressed`](Self::is_logical_key_pressed) if you need to
618    /// know which alt key was pressed.
619    pub fn is_alt_pressed(self: Handle<Self>, app: &App) -> bool {
620        self.is_logical_key_pressed(app, LogicalKeyboardKey::ALT_LEFT)
621            || self.is_logical_key_pressed(app, LogicalKeyboardKey::ALT_RIGHT)
622    }
623
624    /// Returns true if a logical META modifier key is pressed, regardless of
625    /// which side of the keyboard it is on.
626    ///
627    /// Use [`is_logical_key_pressed`](Self::is_logical_key_pressed) if you need to
628    /// know which meta key was pressed.
629    pub fn is_meta_pressed(self: Handle<Self>, app: &App) -> bool {
630        self.is_logical_key_pressed(app, LogicalKeyboardKey::META_LEFT)
631            || self.is_logical_key_pressed(app, LogicalKeyboardKey::META_RIGHT)
632    }
633
634    /// Register a listener that is called every time a hardware key event
635    /// occurs.
636    ///
637    /// All registered handlers will be invoked in order regardless of
638    /// their return value. The return value indicates whether Flutter
639    /// "handles" the event. If any handler returns true, the event
640    /// will not be propagated to other native components in the add-to-app
641    /// scenario.
642    ///
643    /// If an object added a handler, it must remove the handler before it is
644    /// disposed.
645    ///
646    /// If used during event dispatching, the addition will not take effect
647    /// until after the dispatching.
648    ///
649    /// See also:
650    ///
651    ///  * [`remove_handler`](Self::remove_handler), which removes the handler.
652    pub fn add_handler(self: Handle<Self>, app: &mut App, handler: KeyEventCallback) {
653        let keyboard = app.get_mut(self);
654        if keyboard.during_dispatch {
655            keyboard
656                .modified_handlers
657                .get_or_insert_with(|| keyboard.handlers.clone())
658                .push(handler);
659        } else {
660            keyboard.handlers.push(handler);
661        }
662    }
663
664    /// Stop calling the given listener every time a hardware key event
665    /// occurs.
666    ///
667    /// The `handler` argument must be a clone of the one used in
668    /// [`add_handler`](Self::add_handler). If multiple exist, the first one will
669    /// be removed. If none is found, then this method is a no-op.
670    ///
671    /// If used during event dispatching, the removal will not take effect
672    /// until after the event has been dispatched.
673    pub fn remove_handler(self: Handle<Self>, app: &mut App, handler: &KeyEventCallback) {
674        let keyboard = app.get_mut(self);
675        let handlers = if keyboard.during_dispatch {
676            keyboard
677                .modified_handlers
678                .get_or_insert_with(|| keyboard.handlers.clone())
679        } else {
680            &mut keyboard.handlers
681        };
682        if let Some(index) = handlers
683            .iter()
684            .position(|candidate| Rc::ptr_eq(candidate, handler))
685        {
686            handlers.remove(index);
687        }
688    }
689
690    /// Update the pressed keys to the state the host reports.
691    ///
692    /// Both the framework and the host maintain a state of the current pressed
693    /// keys. There are edge cases, related to startup and restart, where the
694    /// framework needs to resynchronize its keyboard state. `keyboard_state` maps
695    /// a USB HID usage to the logical key id pressed on it.
696    pub fn sync_keyboard_state(
697        self: Handle<Self>,
698        app: &mut App,
699        keyboard_state: &HashMap<u64, u64>,
700    ) {
701        let keyboard = app.get_mut(self);
702        for (&physical, &logical) in keyboard_state {
703            keyboard.pressed_keys.insert(
704                PhysicalKeyboardKey::new(physical),
705                LogicalKeyboardKey::new(logical),
706            );
707        }
708    }
709
710    fn dispatch_key_event(self: Handle<Self>, app: &mut App, event: &KeyEvent) -> bool {
711        // This dispatching could have used the same algorithm as `ChangeNotifier`,
712        // but since 1) it shouldn't be necessary to support reentrantly
713        // dispatching, 2) there shouldn't be many handlers (most apps should use
714        // only 1, this function just uses a simpler algorithm.
715        debug_assert!(
716            !app.get(self).during_dispatch,
717            "Nested keyboard dispatching is not supported"
718        );
719        app.get_mut(self).during_dispatch = true;
720        let mut handled = false;
721        // Dart iterates the field; a handler re-enters `App`, so the list is taken
722        // out of the arena for the walk.
723        let handlers = app.get(self).handlers.clone();
724        for handler in handlers {
725            let this_result = handler(app, event);
726            handled = handled || this_result;
727        }
728        let keyboard = app.get_mut(self);
729        keyboard.during_dispatch = false;
730        if let Some(modified_handlers) = keyboard.modified_handlers.take() {
731            keyboard.handlers = modified_handlers;
732        }
733        handled
734    }
735
736    /// Process a new [`KeyEvent`] by recording the state changes and dispatching
737    /// to handlers.
738    ///
739    /// Returns true if any handler handled the event.
740    pub fn handle_key_event(self: Handle<Self>, app: &mut App, event: &KeyEvent) -> bool {
741        let physical_key = event.physical_key();
742        let logical_key = event.logical_key();
743        match event {
744            KeyEvent::Down(_) => {
745                app.get_mut(self)
746                    .pressed_keys
747                    .insert(physical_key, logical_key);
748                if let Some(lock_mode) = KeyboardLockMode::find_lock_by_logical_key(logical_key) {
749                    let lock_modes = &mut app.get_mut(self).lock_modes;
750                    if lock_modes.contains(&lock_mode) {
751                        lock_modes.remove(&lock_mode);
752                    } else {
753                        lock_modes.insert(lock_mode);
754                    }
755                }
756            }
757            KeyEvent::Up(_) => {
758                app.get_mut(self).pressed_keys.remove(&physical_key);
759            }
760            KeyEvent::Repeat(_) => {
761                // Update the logical key in case it has changed.
762                app.get_mut(self)
763                    .pressed_keys
764                    .insert(physical_key, logical_key);
765            }
766        }
767        self.dispatch_key_event(app, event)
768    }
769
770    /// Clear all keyboard states and additional handlers.
771    ///
772    /// This is used by the testing framework to make sure that tests are hermetic.
773    pub fn clear_state(self: Handle<Self>, app: &mut App) {
774        let keyboard = app.get_mut(self);
775        keyboard.pressed_keys.clear();
776        keyboard.lock_modes.clear();
777        keyboard.handlers.clear();
778        debug_assert!(keyboard.modified_handlers.is_none());
779    }
780}
781
782/// A singleton class that processes key messages from the platform and
783/// dispatches converted messages accordingly.
784///
785/// [`KeyEventManager`] receives platform key messages by
786/// [`handle_key_data`](Self::handle_key_data), and sends converted events to
787/// [`HardwareKeyboard`] for record keeping and dispatching.
788///
789/// Flutter owns this from `ServicesBinding`; here it is the App's singleton.
790#[derive(Default)]
791pub struct KeyEventManager {
792    /// Filled on first [`KeyEventManager::instance`]. `Default` cannot mint Handles.
793    hardware_keyboard: Option<Handle<HardwareKeyboard>>,
794}
795
796impl KeyEventManager {
797    /// The current [`KeyEventManager`], if one has been created.
798    pub fn instance(app: &mut App) -> Handle<KeyEventManager> {
799        let this: Handle<KeyEventManager> = app.singleton();
800        if app.get(this).hardware_keyboard.is_none() {
801            let hardware_keyboard = HardwareKeyboard::instance(app);
802            app.get_mut(this).hardware_keyboard = Some(hardware_keyboard);
803        }
804        this
805    }
806
807    /// The keyboard this manager records key events on.
808    pub fn hardware_keyboard(self: Handle<Self>, app: &App) -> Handle<HardwareKeyboard> {
809        app.get(self)
810            .hardware_keyboard
811            .expect("KeyEventManager::instance must run first")
812    }
813
814    /// Dispatch a key data to the hardware keyboard and its handlers.
815    ///
816    /// This method is the handler to the host's `key_data` API.
817    ///
818    /// Returns whether a handler handled the event.
819    pub fn handle_key_data(self: Handle<Self>, app: &mut App, data: KeyData) -> bool {
820        // Having 0 as the physical and logical ID indicates an empty key data
821        // (the only occasion either field can be 0,) transmitted to ensure
822        // that the transit mode is correctly inferred. These events should be
823        // ignored.
824        if data.physical == 0 && data.logical == 0 {
825            return false;
826        }
827        debug_assert!(data.physical != 0 && data.logical != 0);
828        let event = KeyEventManager::event_from_data(data);
829        self.hardware_keyboard(app).handle_key_event(app, &event)
830    }
831
832    fn event_from_data(key_data: KeyData) -> KeyEvent {
833        let physical_key = PhysicalKeyboardKey::find_key_by_code(key_data.physical)
834            .unwrap_or(PhysicalKeyboardKey::new(key_data.physical));
835        let logical_key = LogicalKeyboardKey::find_key_by_key_id(key_data.logical)
836            .unwrap_or(LogicalKeyboardKey::new(key_data.logical));
837        let time_stamp = key_data.time_stamp;
838        match key_data.event_type {
839            KeyEventType::Down => {
840                let mut event = KeyDownEvent::new(physical_key, logical_key, time_stamp)
841                    .synthesized(key_data.synthesized)
842                    .device_type(key_data.device_type);
843                if let Some(character) = key_data.character {
844                    event = event.character(character);
845                }
846                KeyEvent::Down(event)
847            }
848            KeyEventType::Up => {
849                debug_assert!(key_data.character.is_none());
850                KeyEvent::Up(
851                    KeyUpEvent::new(physical_key, logical_key, time_stamp)
852                        .synthesized(key_data.synthesized)
853                        .device_type(key_data.device_type),
854                )
855            }
856            KeyEventType::Repeat => {
857                let mut event = KeyRepeatEvent::new(physical_key, logical_key, time_stamp)
858                    .device_type(key_data.device_type);
859                if let Some(character) = key_data.character {
860                    event = event.character(character);
861                }
862                KeyEvent::Repeat(event)
863            }
864        }
865    }
866}
867
868#[cfg(test)]
869mod tests {
870    use std::cell::RefCell;
871    use std::collections::{HashMap, HashSet};
872    use std::rc::Rc;
873    use std::time::Duration;
874
875    use inset_embedder::{KeyData, KeyEventType};
876    use inset_foundation::{App, AppCell};
877
878    use super::{
879        HardwareKeyboard, KeyDownEvent, KeyEvent, KeyEventCallback, KeyEventManager,
880        KeyRepeatEvent, KeyUpEvent, KeyboardLockMode,
881    };
882    use crate::keyboard_key::{LogicalKeyboardKey, PhysicalKeyboardKey};
883
884    fn down(physical: PhysicalKeyboardKey, logical: LogicalKeyboardKey) -> KeyEvent {
885        KeyEvent::Down(KeyDownEvent::new(physical, logical, Duration::ZERO))
886    }
887
888    fn up(physical: PhysicalKeyboardKey, logical: LogicalKeyboardKey) -> KeyEvent {
889        KeyEvent::Up(KeyUpEvent::new(physical, logical, Duration::ZERO))
890    }
891
892    #[test]
893    fn an_event_gives_back_the_key_data_it_was_made_from() {
894        let data = KeyData {
895            time_stamp: Duration::from_millis(1234),
896            event_type: KeyEventType::Repeat,
897            physical: PhysicalKeyboardKey::KEY_O.usb_hid_usage,
898            logical: LogicalKeyboardKey::KEY_O.key_id,
899            character: Some("o".to_owned()),
900            ..KeyData::default()
901        };
902        assert_eq!(
903            KeyEventManager::event_from_data(data.clone()).to_key_data(),
904            data
905        );
906    }
907
908    #[test]
909    fn a_down_up_pair_updates_the_pressed_key_sets() {
910        let cell = AppCell::new();
911        let mut app = cell.borrow_mut();
912        let keyboard = HardwareKeyboard::instance(&mut app);
913
914        keyboard.handle_key_event(
915            &mut app,
916            &down(PhysicalKeyboardKey::KEY_A, LogicalKeyboardKey::KEY_A),
917        );
918        assert_eq!(
919            keyboard.physical_keys_pressed(&app),
920            HashSet::from([PhysicalKeyboardKey::KEY_A])
921        );
922        assert_eq!(
923            keyboard.logical_keys_pressed(&app),
924            HashSet::from([LogicalKeyboardKey::KEY_A])
925        );
926        assert!(keyboard.is_physical_key_pressed(&app, PhysicalKeyboardKey::KEY_A));
927        assert!(keyboard.is_logical_key_pressed(&app, LogicalKeyboardKey::KEY_A));
928        assert_eq!(
929            keyboard.look_up_layout(&app, PhysicalKeyboardKey::KEY_A),
930            Some(LogicalKeyboardKey::KEY_A)
931        );
932
933        keyboard.handle_key_event(
934            &mut app,
935            &up(PhysicalKeyboardKey::KEY_A, LogicalKeyboardKey::KEY_A),
936        );
937        assert!(keyboard.physical_keys_pressed(&app).is_empty());
938        assert!(keyboard.logical_keys_pressed(&app).is_empty());
939    }
940
941    #[test]
942    fn a_repeat_event_keeps_the_key_pressed_and_updates_the_logical_key() {
943        let cell = AppCell::new();
944        let mut app = cell.borrow_mut();
945        let keyboard = HardwareKeyboard::instance(&mut app);
946
947        keyboard.handle_key_event(
948            &mut app,
949            &down(PhysicalKeyboardKey::KEY_A, LogicalKeyboardKey::KEY_A),
950        );
951        keyboard.handle_key_event(
952            &mut app,
953            &KeyEvent::Repeat(
954                KeyRepeatEvent::new(
955                    PhysicalKeyboardKey::KEY_A,
956                    LogicalKeyboardKey::KEY_Q,
957                    Duration::ZERO,
958                )
959                .character("q"),
960            ),
961        );
962        assert_eq!(
963            keyboard.physical_keys_pressed(&app),
964            HashSet::from([PhysicalKeyboardKey::KEY_A])
965        );
966        assert_eq!(
967            keyboard.look_up_layout(&app, PhysicalKeyboardKey::KEY_A),
968            Some(LogicalKeyboardKey::KEY_Q)
969        );
970    }
971
972    #[test]
973    fn is_shift_pressed_answers_for_either_side() {
974        let cell = AppCell::new();
975        let mut app = cell.borrow_mut();
976        let keyboard = HardwareKeyboard::instance(&mut app);
977        assert!(!keyboard.is_shift_pressed(&app));
978
979        keyboard.handle_key_event(
980            &mut app,
981            &down(
982                PhysicalKeyboardKey::SHIFT_RIGHT,
983                LogicalKeyboardKey::SHIFT_RIGHT,
984            ),
985        );
986        assert!(keyboard.is_shift_pressed(&app));
987        assert!(!keyboard.is_control_pressed(&app));
988
989        keyboard.handle_key_event(
990            &mut app,
991            &up(
992                PhysicalKeyboardKey::SHIFT_RIGHT,
993                LogicalKeyboardKey::SHIFT_RIGHT,
994            ),
995        );
996        keyboard.handle_key_event(
997            &mut app,
998            &down(
999                PhysicalKeyboardKey::SHIFT_LEFT,
1000                LogicalKeyboardKey::SHIFT_LEFT,
1001            ),
1002        );
1003        assert!(keyboard.is_shift_pressed(&app));
1004    }
1005
1006    #[test]
1007    fn a_lock_key_toggles_its_mode_on_every_down() {
1008        let cell = AppCell::new();
1009        let mut app = cell.borrow_mut();
1010        let keyboard = HardwareKeyboard::instance(&mut app);
1011        let caps_lock = down(
1012            PhysicalKeyboardKey::CAPS_LOCK,
1013            LogicalKeyboardKey::CAPS_LOCK,
1014        );
1015
1016        keyboard.handle_key_event(&mut app, &caps_lock);
1017        assert_eq!(
1018            keyboard.lock_modes_enabled(&app),
1019            HashSet::from([KeyboardLockMode::CapsLock])
1020        );
1021        keyboard.handle_key_event(
1022            &mut app,
1023            &up(
1024                PhysicalKeyboardKey::CAPS_LOCK,
1025                LogicalKeyboardKey::CAPS_LOCK,
1026            ),
1027        );
1028        assert_eq!(
1029            keyboard.lock_modes_enabled(&app),
1030            HashSet::from([KeyboardLockMode::CapsLock])
1031        );
1032        keyboard.handle_key_event(&mut app, &caps_lock);
1033        assert!(keyboard.lock_modes_enabled(&app).is_empty());
1034    }
1035
1036    #[test]
1037    fn handlers_receive_events_and_can_claim_them() {
1038        let cell = AppCell::new();
1039        let mut app = cell.borrow_mut();
1040        let keyboard = HardwareKeyboard::instance(&mut app);
1041        let seen: Rc<RefCell<Vec<LogicalKeyboardKey>>> = Rc::new(RefCell::new(Vec::new()));
1042
1043        let recorded = Rc::clone(&seen);
1044        let observer: KeyEventCallback = Rc::new(move |_app, event: &KeyEvent| {
1045            recorded.borrow_mut().push(event.logical_key());
1046            false
1047        });
1048        let claimer: KeyEventCallback = Rc::new(|_app, _event: &KeyEvent| true);
1049        keyboard.add_handler(&mut app, Rc::clone(&observer));
1050
1051        assert!(!keyboard.handle_key_event(
1052            &mut app,
1053            &down(PhysicalKeyboardKey::KEY_A, LogicalKeyboardKey::KEY_A)
1054        ));
1055        assert_eq!(*seen.borrow(), vec![LogicalKeyboardKey::KEY_A]);
1056
1057        keyboard.add_handler(&mut app, Rc::clone(&claimer));
1058        assert!(keyboard.handle_key_event(
1059            &mut app,
1060            &up(PhysicalKeyboardKey::KEY_A, LogicalKeyboardKey::KEY_A)
1061        ));
1062        assert_eq!(seen.borrow().len(), 2, "every handler runs");
1063
1064        keyboard.remove_handler(&mut app, &observer);
1065        keyboard.handle_key_event(
1066            &mut app,
1067            &down(PhysicalKeyboardKey::KEY_B, LogicalKeyboardKey::KEY_B),
1068        );
1069        assert_eq!(seen.borrow().len(), 2, "a removed handler is not called");
1070
1071        keyboard.clear_state(&mut app);
1072        assert!(keyboard.physical_keys_pressed(&app).is_empty());
1073        assert!(!keyboard.handle_key_event(
1074            &mut app,
1075            &down(PhysicalKeyboardKey::KEY_C, LogicalKeyboardKey::KEY_C)
1076        ));
1077    }
1078
1079    #[test]
1080    fn a_handler_added_during_dispatch_takes_effect_after_it() {
1081        let cell = AppCell::new();
1082        let mut app = cell.borrow_mut();
1083        let keyboard = HardwareKeyboard::instance(&mut app);
1084        let calls = Rc::new(RefCell::new(0));
1085
1086        let counted = Rc::clone(&calls);
1087        let late: KeyEventCallback = Rc::new(move |_app, _event: &KeyEvent| {
1088            *counted.borrow_mut() += 1;
1089            false
1090        });
1091        let adder: KeyEventCallback = Rc::new(move |app: &mut App, _event: &KeyEvent| {
1092            let keyboard = HardwareKeyboard::instance(app);
1093            keyboard.add_handler(app, Rc::clone(&late));
1094            false
1095        });
1096        keyboard.add_handler(&mut app, adder);
1097
1098        keyboard.handle_key_event(
1099            &mut app,
1100            &down(PhysicalKeyboardKey::KEY_A, LogicalKeyboardKey::KEY_A),
1101        );
1102        assert_eq!(*calls.borrow(), 0, "the addition waits for the dispatch");
1103        keyboard.handle_key_event(
1104            &mut app,
1105            &up(PhysicalKeyboardKey::KEY_A, LogicalKeyboardKey::KEY_A),
1106        );
1107        assert_eq!(*calls.borrow(), 1);
1108    }
1109
1110    #[test]
1111    fn key_data_becomes_an_event_the_keyboard_records() {
1112        let cell = AppCell::new();
1113        let mut app = cell.borrow_mut();
1114        let manager = KeyEventManager::instance(&mut app);
1115        let keyboard = manager.hardware_keyboard(&app);
1116
1117        assert!(!manager.handle_key_data(
1118            &mut app,
1119            KeyData {
1120                physical: 0,
1121                logical: 0,
1122                ..KeyData::default()
1123            }
1124        ));
1125        assert!(keyboard.physical_keys_pressed(&app).is_empty());
1126
1127        manager.handle_key_data(
1128            &mut app,
1129            KeyData {
1130                time_stamp: Duration::from_millis(3),
1131                event_type: KeyEventType::Down,
1132                physical: PhysicalKeyboardKey::KEY_A.usb_hid_usage,
1133                logical: LogicalKeyboardKey::KEY_A.key_id,
1134                character: Some("a".to_owned()),
1135                ..KeyData::default()
1136            },
1137        );
1138        assert_eq!(
1139            keyboard.physical_keys_pressed(&app),
1140            HashSet::from([PhysicalKeyboardKey::KEY_A])
1141        );
1142
1143        manager.handle_key_data(
1144            &mut app,
1145            KeyData {
1146                time_stamp: Duration::from_millis(4),
1147                event_type: KeyEventType::Up,
1148                physical: PhysicalKeyboardKey::KEY_A.usb_hid_usage,
1149                logical: LogicalKeyboardKey::KEY_A.key_id,
1150                ..KeyData::default()
1151            },
1152        );
1153        assert!(keyboard.physical_keys_pressed(&app).is_empty());
1154    }
1155
1156    #[test]
1157    fn sync_keyboard_state_records_what_the_host_reports() {
1158        let cell = AppCell::new();
1159        let mut app = cell.borrow_mut();
1160        let keyboard = HardwareKeyboard::instance(&mut app);
1161        keyboard.sync_keyboard_state(
1162            &mut app,
1163            &HashMap::from([(
1164                PhysicalKeyboardKey::SHIFT_LEFT.usb_hid_usage,
1165                LogicalKeyboardKey::SHIFT_LEFT.key_id,
1166            )]),
1167        );
1168        assert!(keyboard.is_shift_pressed(&app));
1169    }
1170}