zng_app/
shortcut.rs

1//! Key combination types.
2//!
3//! This is declared on this crate mostly to support shortcuts in commands, shortcut events
4//! are implemented in the input crate.
5
6use std::fmt;
7
8use bitflags::bitflags;
9use zng_txt::{ToTxt, Txt};
10use zng_unique_id::static_id;
11use zng_var::{Var, impl_from_and_into_var};
12
13#[doc(hidden)]
14pub use zng_view_api::keyboard::{Key, KeyCode};
15
16use crate::event::{Command, CommandMetaVar, CommandMetaVarId};
17
18/// A keyboard key used in a gesture.
19///
20/// Gesture keys are case-insensitive, [`Key::Char`] is matched as case-insensitive.
21///
22/// Note that not all keys work well as gesture keys, you can use `try_into` to filter [`Key`] or [`KeyCode`] values
23/// that do not work.
24///
25/// [`Key::Char`]: zng_view_api::keyboard::Key::Char
26/// [`Key`]: zng_view_api::keyboard::Key
27/// [`KeyCode`]: zng_view_api::keyboard::KeyCode
28#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
29pub enum GestureKey {
30    /// Gesture key identified by the semantic key.
31    Key(Key),
32    /// Gesture key identified by the physical key.
33    Code(KeyCode),
34}
35impl std::hash::Hash for GestureKey {
36    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
37        core::mem::discriminant(self).hash(state);
38        match self {
39            GestureKey::Key(k) => match k {
40                Key::Char(c) => {
41                    for c in c.to_uppercase() {
42                        c.hash(state);
43                    }
44                }
45                Key::Str(s) => {
46                    unicase::UniCase::new(s).hash(state);
47                }
48                k => k.hash(state),
49            },
50            GestureKey::Code(c) => c.hash(state),
51        }
52    }
53}
54impl Eq for GestureKey {}
55impl PartialEq for GestureKey {
56    fn eq(&self, other: &Self) -> bool {
57        match (self, other) {
58            (Self::Key(l0), Self::Key(r0)) => match (l0, r0) {
59                (Key::Char(l), Key::Char(r)) => {
60                    let mut l = l.to_uppercase();
61                    let mut r = r.to_uppercase();
62
63                    while let (Some(l), Some(r)) = (l.next(), r.next()) {
64                        if l != r {
65                            return false;
66                        }
67                    }
68
69                    l.next().is_none() && r.next().is_none()
70                }
71                (Key::Str(l), Key::Str(r)) => unicase::eq(l, r),
72                (l0, r0) => l0 == r0,
73            },
74            (Self::Code(l0), Self::Code(r0)) => l0 == r0,
75            _ => false,
76        }
77    }
78}
79impl fmt::Display for GestureKey {
80    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81        match self {
82            GestureKey::Key(k) => match k {
83                Key::Char(c) => write!(f, "{}", c.to_uppercase()),
84                Key::Str(s) => write!(f, "{s}"),
85                Key::ArrowLeft => write!(f, "←"),
86                Key::ArrowRight => write!(f, "→"),
87                Key::ArrowUp => write!(f, "↑"),
88                Key::ArrowDown => write!(f, "↑"),
89                k => write!(f, "{k:?}"),
90            },
91            GestureKey::Code(c) => write!(f, "{c:?}"),
92        }
93    }
94}
95impl GestureKey {
96    /// If is not any:
97    ///
98    /// * [`Key::is_modifier`]
99    /// * [`Key::is_composition`]
100    /// * [`Key::Unidentified`]
101    /// * [`KeyCode::is_modifier`]
102    /// * [`KeyCode::is_composition`]
103    pub fn is_valid(&self) -> bool {
104        match self {
105            GestureKey::Key(k) => !k.is_modifier() && !k.is_composition() && *k != Key::Unidentified,
106            GestureKey::Code(k) => k.is_modifier() && !k.is_composition(),
107        }
108    }
109}
110
111/// Accepts only keys that are not [`is_modifier`] and not [`is_composition`].
112///
113/// [`is_modifier`]: Key::is_modifier
114/// [`is_composition`]: Key::is_composition
115impl TryFrom<Key> for GestureKey {
116    type Error = Key;
117
118    fn try_from(key: Key) -> Result<Self, Self::Error> {
119        if key.is_modifier() || key.is_composition() || key == Key::Unidentified {
120            Err(key)
121        } else {
122            Ok(Self::Key(key))
123        }
124    }
125}
126/// Accepts only keys that are not [`is_modifier`] and not [`is_composition`].
127///
128/// [`is_modifier`]: KeyCode::is_modifier
129/// [`is_composition`]: KeyCode::is_composition
130impl TryFrom<KeyCode> for GestureKey {
131    type Error = KeyCode;
132
133    fn try_from(key: KeyCode) -> Result<Self, Self::Error> {
134        if key.is_modifier() || key.is_composition() || key.is_unidentified() {
135            Err(key)
136        } else {
137            Ok(Self::Code(key))
138        }
139    }
140}
141impl std::str::FromStr for GestureKey {
142    type Err = ParseError;
143
144    fn from_str(s: &str) -> Result<Self, Self::Err> {
145        match Key::from_str(s) {
146            Key::Str(s) => match KeyCode::from_str(&s) {
147                Ok(k) => {
148                    let key = k
149                        .try_into()
150                        .map_err(|e| ParseError::new(format!("key `{e:?}` cannot be used in gestures")))?;
151
152                    Ok(key)
153                }
154                Err(_) => Ok(Self::Key(Key::Str(s))),
155            },
156            k => {
157                let key = k
158                    .try_into()
159                    .map_err(|e| ParseError::new(format!("key `{e:?}` cannot be used in gestures")))?;
160
161                Ok(key)
162            }
163        }
164    }
165}
166
167/// A keyboard combination.
168#[derive(Clone, serde::Serialize, serde::Deserialize)]
169pub struct KeyGesture {
170    /// The key modifiers.
171    ///
172    /// Equality of key gestures matches the [`ambit`] modifiers, so a `L_CTRL` is equal to a `R_CTRL` in a key gesture,
173    /// the actual bit flag is preserved in the state and can be extracted from the shortcut.
174    ///
175    /// [`ambit`]: ModifiersState::ambit
176    pub modifiers: ModifiersState,
177    /// The key.
178    pub key: GestureKey,
179}
180impl PartialEq for KeyGesture {
181    fn eq(&self, other: &Self) -> bool {
182        self.modifiers.ambit() == other.modifiers.ambit() && self.key == other.key
183    }
184}
185impl Eq for KeyGesture {}
186impl std::hash::Hash for KeyGesture {
187    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
188        self.modifiers.ambit().hash(state);
189        self.key.hash(state);
190    }
191}
192impl KeyGesture {
193    /// New from modifiers and key.
194    pub fn new(modifiers: ModifiersState, key: GestureKey) -> Self {
195        KeyGesture { modifiers, key }
196    }
197
198    /// New key gesture without modifiers.
199    pub fn new_key(key: GestureKey) -> Self {
200        KeyGesture {
201            modifiers: ModifiersState::empty(),
202            key,
203        }
204    }
205
206    /// Gets if  [`GestureKey::is_valid`].
207    pub fn is_valid(&self) -> bool {
208        self.key.is_valid()
209    }
210}
211impl fmt::Debug for KeyGesture {
212    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
213        if f.alternate() {
214            f.debug_struct("KeyGesture")
215                .field("modifiers", &self.modifiers)
216                .field("key", &self.key)
217                .finish()
218        } else {
219            write!(f, "{self}")
220        }
221    }
222}
223impl fmt::Display for KeyGesture {
224    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
225        if self.modifiers.has_super() {
226            write!(f, "Super+")?
227        }
228        if self.modifiers.has_ctrl() {
229            write!(f, "Ctrl+")?
230        }
231        if self.modifiers.has_shift() {
232            write!(f, "Shift+")?
233        }
234        if self.modifiers.has_alt() {
235            write!(f, "Alt+")?
236        }
237
238        write!(f, "{}", self.key)
239    }
240}
241
242/// A modifier key press and release without any other key press in between.
243#[derive(Clone, Copy, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
244pub enum ModifierGesture {
245    /// Any of the Windows/Apple keys.
246    Super,
247    /// Any of the CTRL keys.
248    Ctrl,
249    /// Any of the SHIFT keys.
250    Shift,
251    /// Any of the ALT keys.
252    Alt,
253}
254impl fmt::Debug for ModifierGesture {
255    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
256        if f.alternate() {
257            write!(f, "ModifierGesture::")?;
258        }
259        write!(f, "{self}")
260    }
261}
262impl fmt::Display for ModifierGesture {
263    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
264        match self {
265            ModifierGesture::Super => write!(f, "Super"),
266            ModifierGesture::Ctrl => write!(f, "Ctrl"),
267            ModifierGesture::Shift => write!(f, "Shift"),
268            ModifierGesture::Alt => write!(f, "Alt"),
269        }
270    }
271}
272impl<'a> TryFrom<&'a Key> for ModifierGesture {
273    type Error = &'a Key;
274    fn try_from(value: &'a Key) -> Result<Self, Self::Error> {
275        match value {
276            Key::Alt | Key::AltGraph => Ok(ModifierGesture::Alt),
277            Key::Ctrl => Ok(ModifierGesture::Ctrl),
278            Key::Shift => Ok(ModifierGesture::Shift),
279            Key::Super => Ok(ModifierGesture::Super),
280            key => Err(key),
281        }
282    }
283}
284impl TryFrom<KeyCode> for ModifierGesture {
285    type Error = KeyCode;
286    fn try_from(value: KeyCode) -> Result<Self, Self::Error> {
287        match value {
288            KeyCode::AltLeft | KeyCode::AltRight => Ok(ModifierGesture::Alt),
289            KeyCode::CtrlLeft | KeyCode::CtrlRight => Ok(ModifierGesture::Ctrl),
290            KeyCode::ShiftLeft | KeyCode::ShiftRight => Ok(ModifierGesture::Shift),
291            KeyCode::SuperLeft | KeyCode::SuperRight => Ok(ModifierGesture::Super),
292            key => Err(key),
293        }
294    }
295}
296impl ModifierGesture {
297    /// Left modifier key.
298    pub fn left_key(&self) -> (KeyCode, Key) {
299        match self {
300            ModifierGesture::Super => (KeyCode::SuperLeft, Key::Super),
301            ModifierGesture::Ctrl => (KeyCode::CtrlLeft, Key::Ctrl),
302            ModifierGesture::Shift => (KeyCode::ShiftLeft, Key::Shift),
303            ModifierGesture::Alt => (KeyCode::AltLeft, Key::Alt),
304        }
305    }
306    /// To modifiers state.
307    pub fn modifiers_state(&self) -> ModifiersState {
308        match self {
309            ModifierGesture::Super => ModifiersState::SUPER,
310            ModifierGesture::Ctrl => ModifiersState::CTRL,
311            ModifierGesture::Shift => ModifiersState::SHIFT,
312            ModifierGesture::Alt => ModifiersState::ALT,
313        }
314    }
315}
316
317/// A sequence of two keyboard combinations.
318#[derive(Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
319pub struct KeyChord {
320    /// The first key gesture.
321    pub starter: KeyGesture,
322
323    /// The second key gesture.
324    pub complement: KeyGesture,
325}
326impl fmt::Debug for KeyChord {
327    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
328        if f.alternate() {
329            f.debug_struct("KeyChord")
330                .field("starter", &self.starter)
331                .field("complement", &self.complement)
332                .finish()
333        } else {
334            write!(f, "{self}")
335        }
336    }
337}
338impl fmt::Display for KeyChord {
339    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
340        write!(f, "{} {}", self.starter, self.complement)
341    }
342}
343
344/// Keyboard gesture or chord associated with a command.
345///
346/// See the [`shortcut!`] macro for declaring a shortcut.
347#[derive(Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
348pub enum Shortcut {
349    /// Key-press plus modifiers.
350    Gesture(KeyGesture),
351    /// Sequence of two key gestures.
352    Chord(KeyChord),
353    /// Modifier press and release.
354    Modifier(ModifierGesture),
355}
356impl fmt::Debug for Shortcut {
357    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
358        if f.alternate() {
359            match self {
360                Shortcut::Gesture(g) => f.debug_tuple("Shortcut::Gesture").field(g).finish(),
361                Shortcut::Chord(c) => f.debug_tuple("Shortcut::Chord").field(c).finish(),
362                Shortcut::Modifier(m) => f.debug_tuple("Shortcut::Modifier").field(m).finish(),
363            }
364        } else {
365            write!(f, "{self}")
366        }
367    }
368}
369impl fmt::Display for Shortcut {
370    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
371        match self {
372            Shortcut::Gesture(g) => fmt::Display::fmt(g, f),
373            Shortcut::Chord(c) => fmt::Display::fmt(c, f),
374            Shortcut::Modifier(m) => fmt::Display::fmt(m, f),
375        }
376    }
377}
378impl Shortcut {
379    /// Modifiers state required by shortcut.
380    pub fn modifiers_state(&self) -> ModifiersState {
381        match self {
382            Shortcut::Gesture(g) => g.modifiers,
383            Shortcut::Chord(c) => c.complement.modifiers,
384            Shortcut::Modifier(m) => m.modifiers_state(),
385        }
386    }
387
388    /// Gets if all [`KeyGesture::is_valid`].
389    pub fn is_valid(&self) -> bool {
390        match self {
391            Shortcut::Gesture(k) => k.is_valid(),
392            Shortcut::Chord(c) => c.starter.is_valid() && c.complement.is_valid(),
393            Shortcut::Modifier(_) => true,
394        }
395    }
396}
397impl_from_and_into_var! {
398    fn from(shortcut: Shortcut) -> Shortcuts {
399        Shortcuts(vec![shortcut])
400    }
401
402    fn from(key_gesture: KeyGesture) -> Shortcut {
403        Shortcut::Gesture(key_gesture)
404    }
405
406    fn from(key_chord: KeyChord) -> Shortcut {
407        Shortcut::Chord(key_chord)
408    }
409
410    fn from(modifier: ModifierGesture) -> Shortcut {
411        Shortcut::Modifier(modifier)
412    }
413
414    fn from(gesture_key: GestureKey) -> Shortcut {
415        KeyGesture::new_key(gesture_key).into()
416    }
417
418    fn from(gesture_key: GestureKey) -> Shortcuts {
419        Shortcuts(vec![gesture_key.into()])
420    }
421
422    fn from(key_gesture: KeyGesture) -> Shortcuts {
423        Shortcuts(vec![key_gesture.into()])
424    }
425
426    fn from(key_chord: KeyChord) -> Shortcuts {
427        Shortcuts(vec![key_chord.into()])
428    }
429
430    fn from(modifier: ModifierGesture) -> Shortcuts {
431        Shortcuts(vec![modifier.into()])
432    }
433
434    fn from(shortcuts: Vec<Shortcut>) -> Shortcuts {
435        Shortcuts(shortcuts)
436    }
437}
438impl<const N: usize> From<[Shortcut; N]> for Shortcuts {
439    fn from(a: [Shortcut; N]) -> Self {
440        Shortcuts(a.into())
441    }
442}
443impl<const N: usize> crate::var::IntoVar<Shortcuts> for [Shortcut; N] {
444    fn into_var(self) -> Var<Shortcuts> {
445        crate::var::const_var(self.into())
446    }
447}
448
449/// Multiple shortcuts.
450#[derive(Default, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
451pub struct Shortcuts(pub Vec<Shortcut>);
452impl Shortcuts {
453    /// New default (empty).
454    pub const fn new() -> Self {
455        Self(vec![])
456    }
457
458    /// Try to generate shortcuts that produce the `character`.
459    ///
460    /// Returns at least one shortcut or error the char back if it cannot
461    /// be generated by a single shortcut.
462    ///
463    /// Note chords are not generated. Caps lock is assumed to be off.
464    pub fn from_char(character: char) -> Result<Self, char> {
465        if character.is_control() {
466            Err(character)
467        } else {
468            Ok(Self(vec![Shortcut::Gesture(KeyGesture {
469                modifiers: ModifiersState::empty(),
470                key: GestureKey::Key(Key::Char(character)),
471            })]))
472        }
473    }
474
475    /// If the `shortcut` is present in the shortcuts.
476    pub fn contains(&self, shortcut: &Shortcut) -> bool {
477        self.0.contains(shortcut)
478    }
479}
480impl TryFrom<char> for Shortcuts {
481    type Error = char;
482
483    /// See [`from_char`](Self::from_char).
484    fn try_from(value: char) -> Result<Self, Self::Error> {
485        Shortcuts::from_char(value)
486    }
487}
488impl fmt::Debug for Shortcuts {
489    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
490        if f.alternate() {
491            f.debug_tuple("Shortcuts").field(&self.0).finish()
492        } else {
493            write!(f, "[")?;
494            if !self.0.is_empty() {
495                if let Shortcut::Chord(c) = &self.0[0] {
496                    write!(f, "({c:?})")?;
497                } else {
498                    write!(f, "{:?}", self.0[0])?;
499                }
500                for shortcut in &self.0[1..] {
501                    if let Shortcut::Chord(c) = shortcut {
502                        write!(f, ", ({c:?})")?;
503                    } else {
504                        write!(f, ", {shortcut:?}")?;
505                    }
506                }
507            }
508            write!(f, "]")
509        }
510    }
511}
512impl fmt::Display for Shortcuts {
513    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
514        if !self.0.is_empty() {
515            write!(f, "{}", self.0[0])?;
516            for shortcut in &self.0[1..] {
517                write!(f, " | {shortcut}")?;
518            }
519        }
520        Ok(())
521    }
522}
523impl std::ops::Deref for Shortcuts {
524    type Target = Vec<Shortcut>;
525
526    fn deref(&self) -> &Self::Target {
527        &self.0
528    }
529}
530impl std::ops::DerefMut for Shortcuts {
531    fn deref_mut(&mut self) -> &mut Self::Target {
532        &mut self.0
533    }
534}
535
536/// Shortcut, gesture parsing error.
537#[derive(Debug, Clone, PartialEq, Eq)]
538#[non_exhaustive]
539pub struct ParseError {
540    /// Error message, usually in the pattern "`{invalid-input}` is not a {shortcut/modifier}".
541    pub error: String,
542}
543impl ParseError {
544    /// New from any error message.
545    pub fn new(error: impl ToString) -> Self {
546        ParseError { error: error.to_string() }
547    }
548}
549impl fmt::Display for ParseError {
550    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
551        self.error.fmt(f)
552    }
553}
554impl std::error::Error for ParseError {}
555
556bitflags! {
557    /// Represents the current state of the keyboard modifiers.
558    ///
559    /// Each flag represents a modifier and is set if this modifier is active.
560    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, serde::Serialize, serde::Deserialize)]
561    #[serde(transparent)]
562    pub struct ModifiersState: u8 {
563        /// The left "shift" key.
564        const L_SHIFT = 0b0000_0001;
565        /// The right "shift" key.
566        const R_SHIFT = 0b0000_0010;
567        /// Any "shift" key.
568        const SHIFT = 0b0000_0011;
569
570        /// The left "control" key.
571        const L_CTRL = 0b0000_0100;
572        /// The right "control" key.
573        const R_CTRL = 0b0000_1000;
574        /// Any "control" key.
575        const CTRL = 0b0000_1100;
576
577        /// The left "alt" key.
578        const L_ALT = 0b0001_0000;
579        /// The right "alt" key.
580        const R_ALT = 0b0010_0000;
581        /// Any "alt" key.
582        const ALT = 0b0011_0000;
583
584        /// The left "logo" key.
585        const L_SUPER = 0b0100_0000;
586        /// The right "logo" key.
587        const R_SUPER = 0b1000_0000;
588        /// Any "logo" key.
589        ///
590        /// This is the "windows" key on PC and "command" key on Mac.
591        const SUPER = 0b1100_0000;
592    }
593}
594impl ModifiersState {
595    /// Returns `true` if any shift key is pressed.
596    pub fn has_shift(self) -> bool {
597        self.intersects(Self::SHIFT)
598    }
599    /// Returns `true` if any control key is pressed.
600    pub fn has_ctrl(self) -> bool {
601        self.intersects(Self::CTRL)
602    }
603    /// Returns `true` if any alt key is pressed.
604    pub fn has_alt(self) -> bool {
605        self.intersects(Self::ALT)
606    }
607    /// Returns `true` if any logo key is pressed.
608    pub fn has_super(self) -> bool {
609        self.intersects(Self::SUPER)
610    }
611
612    /// Returns `true` if only any flag in `part` is pressed.
613    pub fn is_only(self, part: ModifiersState) -> bool {
614        !self.is_empty() && (self - part).is_empty()
615    }
616
617    /// Returns `true` if only any shift key is pressed.
618    pub fn is_only_shift(self) -> bool {
619        self.is_only(ModifiersState::SHIFT)
620    }
621    /// Returns `true` if only any control key is pressed.
622    pub fn is_only_ctrl(self) -> bool {
623        self.is_only(ModifiersState::CTRL)
624    }
625    /// Returns `true` if only any alt key is pressed.
626    pub fn is_only_alt(self) -> bool {
627        self.is_only(ModifiersState::ALT)
628    }
629    /// Returns `true` if only any logo key is pressed.
630    pub fn is_only_super(self) -> bool {
631        self.is_only(ModifiersState::SUPER)
632    }
633
634    /// Removes `part` and returns if it was removed.
635    pub fn take(&mut self, part: ModifiersState) -> bool {
636        let r = self.intersects(part);
637        if r {
638            self.remove(part);
639        }
640        r
641    }
642
643    /// Removes `SHIFT` and returns if it was removed.
644    pub fn take_shift(&mut self) -> bool {
645        self.take(ModifiersState::SHIFT)
646    }
647
648    /// Removes `CTRL` and returns if it was removed.
649    pub fn take_ctrl(&mut self) -> bool {
650        self.take(ModifiersState::CTRL)
651    }
652
653    /// Removes `ALT` and returns if it was removed.
654    pub fn take_alt(&mut self) -> bool {
655        self.take(ModifiersState::ALT)
656    }
657
658    /// Removes `SUPER` and returns if it was removed.
659    pub fn take_super(&mut self) -> bool {
660        self.take(ModifiersState::SUPER)
661    }
662
663    /// Returns modifiers that set both left and right flags if any side is set in `self`.
664    pub fn ambit(self) -> Self {
665        let mut r = Self::empty();
666        if self.has_alt() {
667            r |= Self::ALT;
668        }
669        if self.has_ctrl() {
670            r |= Self::CTRL;
671        }
672        if self.has_shift() {
673            r |= Self::SHIFT;
674        }
675        if self.has_super() {
676            r |= Self::SUPER;
677        }
678        r
679    }
680
681    /// Returns only the alt flags in `self`.
682    pub fn into_alt(self) -> Self {
683        self & Self::ALT
684    }
685
686    /// Returns only the control flags in `self`.
687    pub fn into_ctrl(self) -> Self {
688        self & Self::CTRL
689    }
690
691    /// Returns only the shift flags in `self`.
692    pub fn into_shift(self) -> Self {
693        self & Self::SHIFT
694    }
695
696    /// Returns only the logo flags in `self`.
697    pub fn into_super(self) -> Self {
698        self & Self::SUPER
699    }
700
701    /// Modifier from `code`, returns empty if the key is not a modifier.
702    pub fn from_code(code: KeyCode) -> ModifiersState {
703        match code {
704            KeyCode::AltLeft => Self::L_ALT,
705            KeyCode::AltRight => Self::R_ALT,
706            KeyCode::CtrlLeft => Self::L_CTRL,
707            KeyCode::CtrlRight => Self::R_CTRL,
708            KeyCode::ShiftLeft => Self::L_SHIFT,
709            KeyCode::ShiftRight => Self::R_SHIFT,
710            KeyCode::SuperLeft => Self::L_SUPER,
711            KeyCode::SuperRight => Self::R_SUPER,
712            _ => Self::empty(),
713        }
714    }
715
716    /// Modifier from `key`, returns empty if the key is not a modifier.
717    pub fn from_key(key: Key) -> ModifiersState {
718        match key {
719            Key::Alt => Self::L_ALT,
720            Key::AltGraph => Self::R_ALT,
721            Key::Shift => Self::SHIFT,
722            Key::Ctrl => Self::CTRL,
723            Key::Super => Self::SUPER,
724            _ => Self::empty(),
725        }
726    }
727
728    /// All key codes that when pressed form the modifiers state.
729    ///
730    /// In case of multiple keys the order is `SUPER`, `CTRL`, `SHIFT`, `ALT`.
731    ///
732    /// In case both left and right keys are flagged for a modifier, the left key is used.
733    pub fn codes(self) -> Vec<KeyCode> {
734        let mut r = vec![];
735
736        if self.contains(Self::L_SUPER) {
737            r.push(KeyCode::SuperLeft);
738        } else if self.contains(Self::R_SUPER) {
739            r.push(KeyCode::SuperRight);
740        }
741
742        if self.contains(Self::L_CTRL) {
743            r.push(KeyCode::CtrlLeft);
744        } else if self.contains(Self::R_CTRL) {
745            r.push(KeyCode::CtrlRight);
746        }
747
748        if self.contains(Self::L_SHIFT) {
749            r.push(KeyCode::ShiftLeft);
750        } else if self.contains(Self::R_SHIFT) {
751            r.push(KeyCode::ShiftRight);
752        }
753
754        if self.contains(Self::L_ALT) {
755            r.push(KeyCode::AltLeft);
756        } else if self.contains(Self::R_ALT) {
757            r.push(KeyCode::AltRight);
758        }
759
760        r
761    }
762
763    /// All keys that when pressed form the modifiers state.
764    ///
765    /// In case of multiple keys the order is `SUPER`, `CTRL`, `SHIFT`, `ALT`.
766    pub fn keys(self) -> Vec<Key> {
767        let mut r = vec![];
768
769        if self.intersects(Self::SUPER) {
770            r.push(Key::Super);
771        }
772
773        if self.intersects(Self::CTRL) {
774            r.push(Key::Ctrl);
775        }
776
777        if self.intersects(Self::SHIFT) {
778            r.push(Key::Shift);
779        }
780
781        if self.contains(Self::R_ALT) {
782            r.push(Key::AltGraph);
783        } else if self.contains(Self::R_ALT) {
784            r.push(Key::Alt);
785        }
786
787        r
788    }
789}
790
791/// Adds the [`shortcut`] metadata.
792///
793/// If a command has a shortcut the `GestureManager` will invoke the command when the shortcut is pressed
794/// the command is enabled, if the command target is a widget it will also be focused. See the `GESTURES`
795/// service documentation for details on how shortcuts are resolved.
796///
797/// [`shortcut`]: CommandShortcutExt::shortcut
798pub trait CommandShortcutExt {
799    /// Gets a read-write variable that is zero-or-more shortcuts that invoke the command.
800    fn shortcut(self) -> CommandMetaVar<Shortcuts>;
801
802    /// Gets a read-only variable that is the display text for the first shortcut.
803    fn shortcut_txt(self) -> Var<Txt>
804    where
805        Self: Sized,
806    {
807        self.shortcut().map(|c| if c.is_empty() { Txt::from("") } else { c[0].to_txt() })
808    }
809
810    /// Gets a read-write variable that sets a filter for when the [`shortcut`] is valid.
811    ///
812    /// [`shortcut`]: CommandShortcutExt::shortcut
813    fn shortcut_filter(self) -> CommandMetaVar<ShortcutFilter>;
814
815    /// Sets the initial shortcuts.
816    fn init_shortcut(self, shortcut: impl Into<Shortcuts>) -> Self;
817
818    /// Sets the initial shortcut filters.
819    fn init_shortcut_filter(self, filter: impl Into<ShortcutFilter>) -> Self;
820}
821impl CommandShortcutExt for Command {
822    fn shortcut(self) -> CommandMetaVar<Shortcuts> {
823        self.with_meta(|m| m.get_var_or_default(*COMMAND_SHORTCUT_ID))
824    }
825
826    fn shortcut_filter(self) -> CommandMetaVar<ShortcutFilter> {
827        self.with_meta(|m| m.get_var_or_default(*COMMAND_SHORTCUT_FILTER_ID))
828    }
829
830    fn init_shortcut(self, shortcut: impl Into<Shortcuts>) -> Self {
831        self.with_meta(|m| m.init_var(*COMMAND_SHORTCUT_ID, shortcut.into()));
832        self
833    }
834
835    fn init_shortcut_filter(self, filter: impl Into<ShortcutFilter>) -> Self {
836        self.with_meta(|m| m.init_var(*COMMAND_SHORTCUT_FILTER_ID, filter.into()));
837        self
838    }
839}
840
841bitflags! {
842    /// Conditions that must be met for the shortcut to apply.
843    #[derive(Default, Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
844    #[serde(transparent)]
845    pub struct ShortcutFilter: u8 {
846        /// Shortcut only applies if the scope is enabled.
847        const ENABLED = 0b001;
848        /// Shortcut only applies if the scope is in the focused path.
849        const FOCUSED = 0b010;
850        /// Shortcut only applies if the command is enabled.
851        const CMD_ENABLED = 0b100;
852    }
853}
854
855static_id! {
856    static ref COMMAND_SHORTCUT_ID: CommandMetaVarId<Shortcuts>;
857    static ref COMMAND_SHORTCUT_FILTER_ID: CommandMetaVarId<ShortcutFilter>;
858}
859
860#[doc(hidden)]
861#[macro_export]
862macro_rules! __shortcut {
863    (-> + $Key:tt) => {
864        $crate::shortcut::KeyGesture {
865            key: $crate::__shortcut!(@key $Key),
866            modifiers: $crate::shortcut::ModifiersState::empty(),
867        }
868    };
869
870    (-> $($MODIFIER:ident)|+ + $Key:tt) => {
871        $crate::shortcut::KeyGesture {
872            key: $crate::__shortcut!(@key $Key),
873            modifiers: $($crate::shortcut::ModifiersState::$MODIFIER)|+,
874        }
875    };
876
877    (=> $($STARTER_MODIFIER:ident)|* + $StarterKey:tt, $($COMPLEMENT_MODIFIER:ident)|* + $ComplementKey:tt) => {
878        $crate::shortcut::KeyChord {
879            starter: $crate::__shortcut!(-> $($STARTER_MODIFIER)|* + $StarterKey),
880            complement: $crate::__shortcut!(-> $($COMPLEMENT_MODIFIER)|* + $ComplementKey)
881        }
882    };
883
884    (@key $Key:ident) => { $crate::shortcut::GestureKey::Key($crate::shortcut::Key::$Key) };
885    (@key $key_char:literal) => { $crate::shortcut::GestureKey::Key($crate::shortcut::Key::Char($key_char)) };
886}
887
888///<span data-del-macro-root></span> Creates a [`Shortcut`].
889///
890/// This macro input can be:
891///
892/// * A single [`ModifierGesture`] variant defines a [`Shortcut::Modifier`].
893/// * A single [`Key`] variant defines a [`Shortcut::Gesture`] without modifiers.
894/// * A single [`char`] literal that translates to a [`Key::Char`].
895/// * [`ModifiersState`] followed by `+` followed by a `Key` or `char` defines a gesture with modifiers. Modifier
896///   combinations must be joined by `|`.
897/// * A gesture followed by `,` followed by another gesture defines a [`Shortcut::Chord`].
898///
899/// Note that not all shortcuts can be declared with this macro, in particular there is no support for [`Key::Str`]
900/// and [`KeyCode`], these shortcuts must be declared manually. Also note that some keys are not recommended in shortcuts,
901/// in particular [`Key::is_modifier`] and [`Key::is_composition`] keys will not work right.
902///
903///
904/// # Examples
905///
906/// ```
907/// use zng_app::shortcut::{Shortcut, shortcut};
908///
909/// fn single_key() -> Shortcut {
910///     shortcut!(Enter)
911/// }
912///
913/// fn modified_key() -> Shortcut {
914///     shortcut!(CTRL + 'C')
915/// }
916///
917/// fn multi_modified_key() -> Shortcut {
918///     shortcut!(CTRL | SHIFT + 'C')
919/// }
920///
921/// fn chord() -> Shortcut {
922///     shortcut!(CTRL + 'E', 'A')
923/// }
924///
925/// fn modifier_release() -> Shortcut {
926///     shortcut!(Alt)
927/// }
928/// ```
929///
930/// [`Key`]: zng_view_api::keyboard::Key
931/// [`Key::Char`]: zng_view_api::keyboard::Key::Char
932/// [`Key::Str`]: zng_view_api::keyboard::Key::Str
933/// [`KeyCode`]: zng_view_api::keyboard::KeyCode
934/// [`Key::is_modifier`]: zng_view_api::keyboard::Key::is_modifier
935/// [`Key::is_composition`]: zng_view_api::keyboard::Key::is_composition
936#[macro_export]
937macro_rules! shortcut_macro {
938    (Super) => {
939        $crate::shortcut::Shortcut::Modifier($crate::shortcut::ModifierGesture::Super)
940    };
941    (Shift) => {
942        $crate::shortcut::Shortcut::Modifier($crate::shortcut::ModifierGesture::Shift)
943    };
944    (Ctrl) => {
945        $crate::shortcut::Shortcut::Modifier($crate::shortcut::ModifierGesture::Ctrl)
946    };
947    (Alt) => {
948        $crate::shortcut::Shortcut::Modifier($crate::shortcut::ModifierGesture::Alt)
949    };
950
951    ($Key:tt) => {
952        $crate::shortcut::Shortcut::Gesture($crate::__shortcut!(-> + $Key))
953    };
954    ($($MODIFIER:ident)|+ + $Key:tt) => {
955        $crate::shortcut::Shortcut::Gesture($crate::__shortcut!(-> $($MODIFIER)|+ + $Key))
956    };
957
958    ($StarterKey:tt, $ComplementKey:tt) => {
959        $crate::shortcut::Shortcut::Chord($crate::__shortcut!(=>
960            + $StarterKey,
961            + $ComplementKey
962        ))
963    };
964
965    ($StarterKey:tt, $($COMPLEMENT_MODIFIER:ident)|+ + $ComplementKey:tt) => {
966        $crate::shortcut::Shortcut::Chord($crate::__shortcut!(=>
967            + $StarterKey,
968            $(COMPLEMENT_MODIFIER)|* + $ComplementKey
969        ))
970    };
971
972    ($($STARTER_MODIFIER:ident)|+ + $StarterKey:tt, $ComplementKey:tt) => {
973        $crate::shortcut::Shortcut::Chord($crate::__shortcut!(=>
974            $($STARTER_MODIFIER)|* + $StarterKey,
975            + $ComplementKey
976        ))
977    };
978
979    ($($STARTER_MODIFIER:ident)|+ + $StarterKey:tt, $($COMPLEMENT_MODIFIER:ident)|+ + $ComplementKey:tt) => {
980        $crate::shortcut::Shortcut::Chord($crate::__shortcut!(=>
981            $($STARTER_MODIFIER)|* + $StarterKey,
982            $($COMPLEMENT_MODIFIER)|* + $ComplementKey
983        ))
984    };
985}
986#[doc(inline)]
987pub use crate::shortcut_macro as shortcut;