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}