kbvm/xkb/
keymap.rs

1//! XKB keymaps.
2//!
3//! This module contains types representing the components of an XKB keymap.
4//!
5//! The entry point to this module is the [`Keymap`].
6
7mod format;
8mod from_lookup;
9mod from_resolved;
10pub mod iterators;
11#[cfg(test)]
12mod tests;
13mod to_builder;
14
15pub use crate::xkb::keymap::format::Formatter;
16use {
17    crate::{
18        builder::Redirect,
19        group::{GroupDelta, GroupIndex},
20        xkb::{
21            controls::ControlMask,
22            group::{GroupIdx, GroupMask},
23            group_component::GroupComponent,
24            indicator::IndicatorIdx,
25            keymap::{
26                actions::{
27                    ControlsLockAction, ControlsSetAction, GroupLatchAction, GroupLockAction,
28                    GroupSetAction, ModsLatchAction, ModsLockAction, ModsSetAction,
29                    RedirectKeyAction,
30                },
31                iterators::{Groups, Indicators, Keys, Levels, Mappings, VirtualModifiers},
32            },
33            level::Level,
34            mod_component::ModComponentMask,
35            radio_group::RadioGroup,
36            resolved::GroupsRedirect,
37        },
38        Components, ControlsMask, Keysym, ModifierIndex, ModifierMask,
39    },
40    hashbrown::DefaultHashBuilder,
41    indexmap::IndexMap,
42    smallvec::SmallVec,
43    std::sync::Arc,
44};
45#[expect(unused_imports)]
46use {
47    crate::{lookup::LookupTable, xkb::Context},
48    std::fmt::Display,
49};
50
51/// A fully-resolved XKB keymap.
52///
53/// This object is usually created from a [`Context`] but can also be created via
54/// [`LookupTable::to_xkb_keymap`].
55///
56/// # Creating a keymap from XKB source
57///
58/// ```xkb
59/// xkb_keymap {
60///     xkb_keycodes {
61///         <a> = 38;
62///         <leftshift> = 50;
63///     };
64///     xkb_symbols {
65///         key <a> {
66///             [ a, A ],
67///         };
68///         key <leftshift> {
69///             [ Shift_L ],
70///             [ SetMods(mods = Shift) ],
71///         };
72///     };
73/// };
74/// ```
75///
76/// ```no_run
77/// # use kbvm::xkb::Context;
78/// # use kbvm::xkb::diagnostic::WriteToLog;
79/// # const MAP: &str = "...";
80/// let context = Context::default();
81/// let keymap = context.keymap_from_bytes(WriteToLog, None, MAP.as_bytes()).unwrap();
82/// ```
83///
84/// # Creating a keymap from RMLVO names
85///
86/// ```
87/// # use kbvm::xkb::Context;
88/// # use kbvm::xkb::diagnostic::WriteToLog;
89/// # use kbvm::xkb::rmlvo::Group;
90/// let context = Context::default();
91/// let keymap = context.keymap_from_names(
92///     WriteToLog,
93///     None,
94///     None,
95///     Some(&[Group {
96///         layout: "de",
97///         variant: "neo",
98///     }]),
99///     None,
100/// );
101/// ```
102#[derive(Debug, PartialEq)]
103pub struct Keymap {
104    pub(crate) name: Option<Arc<String>>,
105    pub(crate) max_keycode: u32,
106    pub(crate) indicators: Vec<Indicator>,
107    pub(crate) keycodes: Vec<Keycode>,
108    pub(crate) types: Vec<Arc<KeyType>>,
109    pub(crate) virtual_modifiers: Vec<VirtualModifier>,
110    pub(crate) mod_maps: Vec<(ModifierIndex, ModMapValue)>,
111    pub(crate) group_names: Vec<(GroupIdx, Arc<String>)>,
112    pub(crate) keys: IndexMap<crate::Keycode, Key, DefaultHashBuilder>,
113}
114
115#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
116pub(crate) struct ModMapValue {
117    pub(crate) key_name: Arc<String>,
118    pub(crate) key_sym: Option<Keysym>,
119}
120
121/// An indicator.
122///
123/// # Example
124///
125/// ```xkb
126/// xkb_compat {
127///     indicator "Caps Lock" {
128///         modifiers = Lock;
129///         whichModState = Effective;
130///     };
131/// };
132/// ```
133#[derive(Debug, PartialEq)]
134pub struct Indicator {
135    pub(crate) virt: bool,
136    pub(crate) index: IndicatorIdx,
137    pub(crate) name: Arc<String>,
138    pub(crate) modifier_mask: ModifierMask,
139    pub(crate) group_mask: GroupMask,
140    pub(crate) controls: ControlMask,
141    pub(crate) mod_components: ModComponentMask,
142    pub(crate) group_component: GroupComponent,
143}
144
145/// An indicator matcher that determines if an indicator should be active.
146pub struct IndicatorMatcher {
147    mods_pressed: u32,
148    mods_latched: u32,
149    mods_locked: u32,
150    mods: u32,
151    group_pressed: bool,
152    group_not_pressed: bool,
153    group_latched: bool,
154    group_not_latched: bool,
155    group_locked: u32,
156    group: u32,
157    controls: u32,
158}
159
160#[derive(Debug, PartialEq)]
161pub(crate) struct Keycode {
162    pub(crate) name: Arc<String>,
163    pub(crate) keycode: crate::Keycode,
164}
165
166/// A virtual modifier.
167///
168/// # Example
169///
170/// ```xkb
171/// xkb_compat {
172///     virtual_modifiers V1 = 0x100;
173/// };
174/// ```
175#[derive(Debug, PartialEq)]
176pub struct VirtualModifier {
177    pub(crate) name: Arc<String>,
178    pub(crate) values: ModifierMask,
179}
180
181/// A key type.
182///
183/// # Example
184///
185/// ```xkb
186/// xkb_types {
187///     type "X" {
188///         modifiers = Shift+Mod1;
189///         map[Shift] = Level2;
190///         map[Mod1] = Level2;
191///     };
192/// };
193/// ```
194#[derive(Debug, PartialEq)]
195pub struct KeyType {
196    pub(crate) name: Arc<String>,
197    pub(crate) modifiers: ModifierMask,
198    pub(crate) mappings: Vec<KeyTypeMapping>,
199    pub(crate) level_names: Vec<(Level, Arc<String>)>,
200}
201
202/// A key-type mapping.
203///
204/// # Example
205///
206/// ```xkb
207/// xkb_types {
208///     type "X" {
209///         modifiers = Shift+Mod1;
210///         map[Shift] = Level2;
211///         map[Mod1] = Level2;
212///     };
213/// };
214/// ```
215///
216/// This object might refer to either `map[Shift]` or `map[Mod1]`.
217#[derive(Debug, PartialEq)]
218pub struct KeyTypeMapping {
219    pub(crate) modifiers: ModifierMask,
220    pub(crate) preserved: ModifierMask,
221    pub(crate) level: Level,
222}
223
224/// An XKB action.
225///
226/// # Example
227///
228/// ```xkb
229/// xkb_symbols {
230///     key <leftshift> {
231///         [ SetMods(mods = Shift) ],
232///     };
233/// };
234/// ```
235#[derive(Clone, Debug, PartialEq)]
236#[non_exhaustive]
237pub enum Action {
238    /// A `SetMods` action.
239    ModsSet(ModsSetAction),
240    /// A `LatchMods` action.
241    ModsLatch(ModsLatchAction),
242    /// A `LockMods` action.
243    ModsLock(ModsLockAction),
244    /// A `SetGroup` action.
245    GroupSet(GroupSetAction),
246    /// A `LatchGroup` action.
247    GroupLatch(GroupLatchAction),
248    /// A `LockGroup` action.
249    GroupLock(GroupLockAction),
250    /// A `RedirectKey` action.
251    RedirectKey(RedirectKeyAction),
252    /// A `SetControls` action.
253    ControlsSet(ControlsSetAction),
254    /// A `LockControls` action.
255    ControlsLock(ControlsLockAction),
256}
257
258/// The XKB actions supported by KBVM.
259pub mod actions {
260    use {
261        crate::{
262            xkb::{controls::ControlMask, group},
263            ModifierMask,
264        },
265        std::sync::Arc,
266    };
267
268    /// A `SetMods` action.
269    ///
270    /// # Example
271    ///
272    /// ```xkb
273    /// xkb_symbols {
274    ///     key <leftshift> {
275    ///         [ SetMods(mods = Shift) ],
276    ///     };
277    /// };
278    /// ```
279    #[derive(Clone, Debug, PartialEq)]
280    pub struct ModsSetAction {
281        pub(crate) clear_locks: bool,
282        pub(crate) modifiers: ModifierMask,
283    }
284
285    /// A `LatchMods` action.
286    ///
287    /// # Example
288    ///
289    /// ```xkb
290    /// xkb_symbols {
291    ///     key <leftshift> {
292    ///         [ LatchMods(mods = Shift) ],
293    ///     };
294    /// };
295    /// ```
296    #[derive(Clone, Debug, PartialEq)]
297    pub struct ModsLatchAction {
298        pub(crate) clear_locks: bool,
299        pub(crate) latch_to_lock: bool,
300        pub(crate) modifiers: ModifierMask,
301    }
302
303    /// A `LockMods` action.
304    ///
305    /// # Example
306    ///
307    /// ```xkb
308    /// xkb_symbols {
309    ///     key <leftshift> {
310    ///         [ LockMods(mods = Shift) ],
311    ///     };
312    /// };
313    /// ```
314    #[derive(Clone, Debug, PartialEq)]
315    pub struct ModsLockAction {
316        pub(crate) modifiers: ModifierMask,
317        pub(crate) lock: bool,
318        pub(crate) unlock: bool,
319    }
320
321    /// A `SetGroup` action.
322    ///
323    /// # Example
324    ///
325    /// ```xkb
326    /// xkb_symbols {
327    ///     key <compose> {
328    ///         [ SetGroup(group = +1) ],
329    ///     };
330    /// };
331    /// ```
332    #[derive(Clone, Debug, PartialEq)]
333    pub struct GroupSetAction {
334        pub(crate) group: group::GroupChange,
335        pub(crate) clear_locks: bool,
336    }
337
338    /// A `LatchGroup` action.
339    ///
340    /// # Example
341    ///
342    /// ```xkb
343    /// xkb_symbols {
344    ///     key <compose> {
345    ///         [ LatchGroup(group = +1) ],
346    ///     };
347    /// };
348    /// ```
349    #[derive(Clone, Debug, PartialEq)]
350    pub struct GroupLatchAction {
351        pub(crate) group: group::GroupChange,
352        pub(crate) clear_locks: bool,
353        pub(crate) latch_to_lock: bool,
354    }
355
356    /// A `LockGroup` action.
357    ///
358    /// # Example
359    ///
360    /// ```xkb
361    /// xkb_symbols {
362    ///     key <compose> {
363    ///         [ LockGroup(group = +1) ],
364    ///     };
365    /// };
366    /// ```
367    #[derive(Clone, Debug, PartialEq)]
368    pub struct GroupLockAction {
369        pub(crate) group: group::GroupChange,
370    }
371
372    /// A `RedirectKey` action.
373    ///
374    /// # Example
375    ///
376    /// ```xkb
377    /// xkb_symbols {
378    ///     key <a> {
379    ///         [ RedirectKey(key = b) ],
380    ///     };
381    /// };
382    /// ```
383    ///
384    /// # Implementation
385    ///
386    /// KBVM implements this action as follows:
387    ///
388    /// The new key code is emitted in `KeyDown` and `KeyUp` events instead of the
389    /// original key code.
390    ///
391    /// If the [`Self::modifier_mask`] of the action is not empty, then it additionally
392    /// modifies the components before and after the `KeyDown` and `KeyUp` events as
393    /// follows:
394    ///
395    /// - Before the event:
396    ///
397    ///   1. Save the pressed, latched, and locked modifiers.
398    ///   2. Set the latched and locked modifiers to 0.
399    ///   3. Set the pressed modifiers to the effective modifiers.
400    ///   4. Clear the modifiers from [`Self::mods_to_clear`] from the pressed modifiers.
401    ///   5. Set the modifiers from [`Self::mods_to_set`] in the pressed modifiers.
402    ///
403    /// - After the event:
404    ///
405    ///   1. Restore the pressed, latched, and locked modifiers.
406    #[derive(Clone, Debug, PartialEq)]
407    pub struct RedirectKeyAction {
408        pub(crate) key_name: Arc<String>,
409        pub(crate) keycode: crate::Keycode,
410        pub(crate) mods_to_set: ModifierMask,
411        pub(crate) mods_to_clear: ModifierMask,
412    }
413
414    /// A `SetControls` action.
415    ///
416    /// # Example
417    ///
418    /// ```xkb
419    /// xkb_symbols {
420    ///     key <leftshift> {
421    ///         [ SetControls(controls = Overlay1) ],
422    ///     };
423    /// };
424    /// ```
425    #[derive(Clone, Debug, PartialEq)]
426    pub struct ControlsSetAction {
427        pub(crate) controls: ControlMask,
428    }
429
430    /// A `LockControls` action.
431    ///
432    /// # Example
433    ///
434    /// ```xkb
435    /// xkb_symbols {
436    ///     key <leftshift> {
437    ///         [ LockControls(controls = Overlay1) ],
438    ///     };
439    /// };
440    /// ```
441    #[derive(Clone, Debug, PartialEq)]
442    pub struct ControlsLockAction {
443        pub(crate) controls: ControlMask,
444        pub(crate) lock: bool,
445        pub(crate) unlock: bool,
446    }
447}
448
449/// A group change performed by an [`Action`].
450pub enum GroupChange {
451    /// An absolute change of a group.
452    ///
453    /// # Example
454    ///
455    /// ```xkb
456    /// xkb_symbols {
457    ///     key <compose> {
458    ///         [ SetGroup(group = Group2) ],
459    ///     };
460    /// };
461    /// ```
462    Absolute(GroupIndex),
463    /// A relative change of a group.
464    ///
465    /// # Example
466    ///
467    /// ```xkb
468    /// xkb_symbols {
469    ///     key <compose> {
470    ///         [ SetGroup(group = +1) ],
471    ///     };
472    /// };
473    /// ```
474    Relative(GroupDelta),
475}
476
477/// A key.
478///
479/// # Example
480///
481/// ```xkb
482/// xkb_symbols {
483///     key <a> { [ a, A ] };
484/// };
485/// ```
486#[derive(Clone, Debug, PartialEq)]
487pub struct Key {
488    pub(crate) key_name: Arc<String>,
489    pub(crate) keycode: crate::Keycode,
490    pub(crate) groups: Vec<Option<KeyGroup>>,
491    pub(crate) repeat: bool,
492    pub(crate) behavior: Option<KeyBehavior>,
493    pub(crate) redirect: GroupsRedirect,
494}
495
496/// A key behavior.
497///
498/// # Example
499///
500/// ```xkb
501/// xkb_symbols {
502///     key <a> {
503///         locks = true,
504///         [ a, A ],
505///     };
506/// };
507/// ```
508///
509/// The key behavior is `KeyBehavior::Lock`.
510#[derive(Clone, Debug, PartialEq)]
511#[non_exhaustive]
512pub enum KeyBehavior {
513    /// The key locks.
514    Lock,
515    /// The key is affected by an overlay control.
516    Overlay(OverlayBehavior),
517    /// The key is affected by a radio-group control.
518    RadioGroup(RadioGroupBehavior),
519}
520
521/// The overlay that affects a key behavior.
522///
523/// # Example
524///
525/// ```xkb
526/// xkb_symbols {
527///     key <a> {
528///         overlay2 = <b>,
529///     };
530/// };
531/// ```
532///
533/// The overlay is `Overlay2`.
534#[derive(Copy, Clone, Debug, PartialEq)]
535#[non_exhaustive]
536pub enum KeyOverlay {
537    /// The first overlay.
538    Overlay1,
539    /// The second overlay.
540    Overlay2,
541}
542
543/// An overlay behavior.
544///
545/// # Example
546///
547/// ```xkb
548/// xkb_symbols {
549///     key <a> {
550///         overlay1 = <b>,
551///         [ a, A ],
552///     };
553/// };
554/// ```
555#[derive(Clone, Debug, PartialEq)]
556pub struct OverlayBehavior {
557    pub(crate) overlay: KeyOverlay,
558    pub(crate) key_name: Arc<String>,
559    pub(crate) keycode: crate::Keycode,
560}
561
562/// A radio-group behavior.
563///
564/// # Example
565///
566/// ```xkb
567/// xkb_symbols {
568///     key <a> {
569///         radiogroup = 1,
570///         [ a, A ],
571///     };
572/// };
573/// ```
574#[derive(Clone, Debug, PartialEq)]
575pub struct RadioGroupBehavior {
576    pub(crate) allow_none: bool,
577    pub(crate) radio_group: RadioGroup,
578}
579
580/// A key group.
581///
582/// # Example
583///
584/// ```xkb
585/// xkb_symbols {
586///     key <a> {
587///         [ a, A ],
588///         [ b, B ],
589///     };
590/// };
591/// ```
592///
593/// This object might refer to either `[ a, A ]` or `[ b, B ]`.
594#[derive(Clone, Debug, PartialEq)]
595pub struct KeyGroup {
596    pub(crate) key_type: Arc<KeyType>,
597    pub(crate) levels: Vec<KeyLevel>,
598}
599
600/// A key level.
601///
602/// # Example
603///
604/// ```xkb
605/// xkb_symbols {
606///     key <a> {
607///         symbols[Group1] = [ a,          A                    ],
608///         actions[Group1] = [ NoAction(), SetMods(mods = Mod1) ],
609///         symbols[Group2] = [ b,          B                    ],
610///     };
611/// };
612/// ```
613///
614/// This object might refer to any of
615///
616/// - `a`,
617/// - `A` / `SetMods(mods = Mod1)`,
618/// - `b`, or
619/// - `B`.
620#[derive(Clone, Debug, Default, PartialEq)]
621pub struct KeyLevel {
622    pub(crate) symbols: SmallVec<[Keysym; 1]>,
623    pub(crate) actions: SmallVec<[Action; 1]>,
624}
625
626impl Keymap {
627    /// Returns an iterator over the virtual modifiers of this map.
628    ///
629    /// Note that the real modifiers are not included in this iterator. The real modifiers
630    /// use the following hard-coded assignments:
631    ///
632    /// | name         | index | mask   |
633    /// | ------------ | ----- | ------ |
634    /// | Shift        | `0`   | `0x01` |
635    /// | Lock         | `1`   | `0x02` |
636    /// | Control      | `2`   | `0x04` |
637    /// | Mod1/Alt     | `3`   | `0x08` |
638    /// | Mod2/NumLock | `4`   | `0x10` |
639    /// | Mod3         | `5`   | `0x20` |
640    /// | Mod4/Logo    | `6`   | `0x40` |
641    /// | Mod5         | `7`   | `0x80` |
642    ///
643    /// # Example
644    ///
645    /// ```xkb
646    /// xkb_compat {
647    ///     virtual_modifiers A;
648    ///     virtual_modifiers B;
649    ///     virtual_modifiers C;
650    /// };
651    /// ```
652    ///
653    /// The iterator returns 3 elements, one for A, one for B, and one for C.
654    pub fn virtual_modifiers(&self) -> VirtualModifiers<'_> {
655        VirtualModifiers {
656            modifiers: self.virtual_modifiers.iter(),
657        }
658    }
659
660    /// Returns an iterator over the keys of this map.
661    ///
662    /// # Example
663    ///
664    /// ```xkb
665    /// xkb_symbols {
666    ///     key <a> { [ a, A ] };
667    ///     key <leftshift> { [ SetMods(mods = Shift) ] };
668    /// };
669    /// ```
670    ///
671    /// The iterator returns 2 elements, one for `<a>` and one for `<leftshift>`.
672    pub fn keys(&self) -> Keys<'_> {
673        Keys {
674            keys: self.keys.values(),
675        }
676    }
677
678    /// Returns an iterator over the indicators of this map.
679    ///
680    /// # Example
681    ///
682    /// ```xkb
683    /// xkb_compat {
684    ///     indicator "Caps Lock" {
685    ///         modifiers = Lock;
686    ///     };
687    ///     indicator "Num Lock" {
688    ///         modifiers = Mod2;
689    ///     };
690    /// };
691    /// ```
692    ///
693    /// The iterator returns 2 elements, one for `Caps Lock` and one for `Num Lock`.
694    pub fn indicators(&self) -> Indicators<'_> {
695        Indicators {
696            indicators: self.indicators.iter(),
697        }
698    }
699
700    /// Returns a type that can be used to format the map in XKB text format.
701    ///
702    /// # Warning
703    ///
704    /// When using this function to create a keymap for Xwayland, compositors should
705    /// enable both [`Formatter::lookup_only`] and [`Formatter::rename_long_keys`].
706    ///
707    /// `lookup_only` prevents key actions and key behaviors from being included in the
708    /// map. This works around a bug in Xwayland where Xwayland will execute the actions
709    /// and behaviors instead of only passing the key events to X clients.
710    ///
711    /// `rename_long_keys` is only necessary if the original keymap contains key names
712    /// that are longer than 4 bytes. Xwayland cannot handle such key names.
713    ///
714    /// # Example
715    ///
716    /// ```
717    /// # use kbvm::xkb::Keymap;
718    /// fn pretty_print_keymap(keymap: &Keymap) -> String {
719    ///     format!("{}\n", keymap.format())
720    /// }
721    /// ```
722    pub fn format(&self) -> Formatter<'_> {
723        Formatter {
724            keymap: self,
725            single_line: false,
726            lookup_only: false,
727            multiple_actions_per_level: false,
728            rename_long_keys: false,
729        }
730    }
731}
732
733impl Indicator {
734    pub(crate) fn dummy() -> Self {
735        Self {
736            virt: false,
737            index: IndicatorIdx::ONE,
738            name: Arc::new("DUMMY".to_string()),
739            modifier_mask: Default::default(),
740            group_mask: Default::default(),
741            controls: Default::default(),
742            mod_components: Default::default(),
743            group_component: Default::default(),
744        }
745    }
746}
747
748impl VirtualModifier {
749    pub(crate) fn dummy() -> Self {
750        Self {
751            name: Arc::new("Dummy".to_string()),
752            values: Default::default(),
753        }
754    }
755
756    /// Returns the name of the modifier.
757    ///
758    /// # Example
759    ///
760    /// ```xkb
761    /// xkb_compat {
762    ///     virtual_modifiers V1 = 0x100;
763    /// };
764    /// ```
765    ///
766    /// The function returns `"V1"`.
767    pub fn name(&self) -> &str {
768        &self.name
769    }
770
771    /// Returns the modifier mask that the modifier maps to.
772    ///
773    /// # Example 1
774    ///
775    /// ```xkb
776    /// xkb_compat {
777    ///     virtual_modifiers V1 = 0x100;
778    /// };
779    /// ```
780    ///
781    /// The function returns `0x100`.
782    ///
783    /// # Example 2
784    ///
785    /// ```xkb
786    /// xkb_compat {
787    ///     virtual_modifiers Alt;
788    ///
789    ///     interpret Alt_L {
790    ///         virtualmodifier = Alt;
791    ///     };
792    /// };
793    ///
794    /// xkb_symbols {
795    ///     key <leftalt> { [ Alt_L ] };
796    ///     modmap Mod1 { <leftalt> };
797    /// };
798    /// ```
799    ///
800    /// The function returns [`ModifierMask::MOD1`].
801    pub fn mask(&self) -> ModifierMask {
802        self.values
803    }
804}
805
806impl Key {
807    /// Returns the name of the key.
808    ///
809    /// # Example
810    ///
811    /// ```xkb
812    /// xkb_symbols {
813    ///     key <abcd> { [ a, A ] };
814    /// };
815    /// ```
816    ///
817    /// The function returns `abcd`.
818    pub fn name(&self) -> &str {
819        &self.key_name
820    }
821
822    /// Returns the keycode of the key.
823    ///
824    /// # Example
825    ///
826    /// ```xkb
827    /// xkb_keycodes {
828    ///     <a> = 38;
829    /// };
830    /// xkb_symbols {
831    ///     key <a> { [ a, A ] };
832    /// };
833    /// ```
834    ///
835    /// The function returns `38`.
836    pub fn keycode(&self) -> crate::Keycode {
837        self.keycode
838    }
839
840    /// Returns whether the key repeats.
841    ///
842    /// # Example
843    ///
844    /// ```xkb
845    /// xkb_symbols {
846    ///     key <a> {
847    ///         repeats = false,
848    ///         [ a, A ],
849    ///     };
850    /// };
851    /// ```
852    ///
853    /// The function returns `false`.
854    pub fn repeats(&self) -> bool {
855        self.repeat
856    }
857
858    /// Returns the group-redirect setting of this key.
859    ///
860    /// # Example
861    ///
862    /// ```xkb
863    /// xkb_symbols {
864    ///     key <a> {
865    ///         groupsClamp,
866    ///         [ a, A ],
867    ///     };
868    /// };
869    /// ```
870    ///
871    /// The function returns [`Redirect::Clamp`].
872    pub fn redirect(&self) -> Redirect {
873        self.redirect.to_redirect()
874    }
875
876    /// Returns the behavior of the key.
877    ///
878    /// # Example
879    ///
880    /// ```xkb
881    /// xkb_symbols {
882    ///     key <a> {
883    ///         locks = true,
884    ///         [ a, A ],
885    ///     };
886    /// };
887    /// ```
888    ///
889    /// The function returns `KeyBehavior::Lock`.
890    pub fn behavior(&self) -> Option<&KeyBehavior> {
891        self.behavior.as_ref()
892    }
893
894    /// Returns an iterator over the groups of this key.
895    ///
896    /// # Example 1
897    ///
898    /// ```xkb
899    /// xkb_symbols {
900    ///     key <a> {
901    ///         [ a, A ],
902    ///         [ b, B ],
903    ///     };
904    /// };
905    /// ```
906    ///
907    /// The iterator returns two elements, one for `[ a, A ]` and one for `[ b, B ]`.
908    ///
909    /// # Example 2
910    ///
911    /// ```xkb
912    /// xkb_symbols {
913    ///     key <a> {
914    ///         symbols[Group1] = [ a, A ],
915    ///         symbols[Group3] = [ b, B ],
916    ///     };
917    /// };
918    /// ```
919    ///
920    /// The iterator returns three elements:
921    ///
922    /// - `Some([ a, A ])`
923    /// - `None`
924    /// - `Some([ b, B ])`
925    pub fn groups(&self) -> Groups<'_> {
926        Groups {
927            groups: self.groups.iter(),
928        }
929    }
930}
931
932impl KeyGroup {
933    /// Returns the type of this group.
934    ///
935    /// # Example
936    ///
937    /// ```xkb
938    /// xkb_types {
939    ///     type "X" {
940    ///         modifiers = Shift;
941    ///         map[Shift] = Level2;
942    ///     };
943    /// };
944    /// xkb_symbols {
945    ///     key <a> {
946    ///         type[Group1] = "X";
947    ///         symbols[Group1] = [ a, A ],
948    ///     };
949    /// };
950    /// ```
951    ///
952    /// The function returns the `X` type.
953    pub fn ty(&self) -> &KeyType {
954        &self.key_type
955    }
956
957    /// Returns an iterator over the levels of this group.
958    ///
959    /// # Example
960    ///
961    /// ```xkb
962    /// xkb_symbols {
963    ///     key <a> {
964    ///         [ a, A ],
965    ///     };
966    /// };
967    /// ```
968    ///
969    /// The iterator returns two elements, one for `a` and one for `A`.
970    pub fn levels(&self) -> Levels<'_> {
971        Levels {
972            levels: self.levels.iter(),
973        }
974    }
975}
976
977impl KeyType {
978    /// Returns the modifier mask of this key type.
979    ///
980    /// Modifiers outside of this mask are completely ignored by this key type. That is,
981    /// they are masked out before considering which level to map to and are never
982    /// consumed.
983    ///
984    /// # Example
985    ///
986    /// ```xkb
987    /// xkb_types {
988    ///     type "X" {
989    ///         modifiers = Shift+Mod1;
990    ///         map[Shift] = Level2;
991    ///         map[Mod1] = Level2;
992    ///     };
993    /// };
994    /// ```
995    ///
996    /// The function returns [`ModifierMask::SHIFT | ModifierMask::MOD1`](ModifierMask).
997    pub fn mask(&self) -> ModifierMask {
998        self.modifiers
999    }
1000
1001    /// Returns an iterator over the mappings of this key type.
1002    ///
1003    /// Mappings that are not explicitly defined are not returned. Such mappings map to
1004    /// level 1 and consume all input modifiers.
1005    ///
1006    /// # Example
1007    ///
1008    /// ```xkb
1009    /// xkb_types {
1010    ///     type "X" {
1011    ///         modifiers = Shift+Mod1;
1012    ///         map[Shift] = Level2;
1013    ///         map[Mod1] = Level2;
1014    ///     };
1015    /// };
1016    /// ```
1017    ///
1018    /// The iterator returns one mapping for `map[Shift]` and one mapping for
1019    /// `map[Mod1]`.
1020    ///
1021    /// Note that no mappings are returned for `map[None]` and `map[Shift+Mod1]`.
1022    pub fn mappings(&self) -> Mappings<'_> {
1023        Mappings {
1024            mappings: self.mappings.iter(),
1025        }
1026    }
1027}
1028
1029impl KeyTypeMapping {
1030    /// Returns the modifier mask of this mapping.
1031    ///
1032    /// After masking with the [type mask](KeyType::mask), the effective modifiers must
1033    /// match this mask exactly for the mapping to be applicable.
1034    ///
1035    /// # Example
1036    ///
1037    /// ```xkb
1038    /// xkb_types {
1039    ///     type "X" {
1040    ///         modifiers = Shift+Mod1;
1041    ///         map[Shift] = Level2;
1042    ///         map[Mod1] = Level2;
1043    ///     };
1044    /// };
1045    /// ```
1046    ///
1047    /// If this mapping is `map[Shift]`, then this function returns
1048    /// [`ModifierMask::SHIFT`].
1049    pub fn mask(&self) -> ModifierMask {
1050        self.modifiers
1051    }
1052
1053    /// Returns the preserved modifiers of this mapping.
1054    ///
1055    /// If this mapping is applicable, then the preserved modifiers are not consumed by
1056    /// the mapping and might be used for keyboard shortcuts or keysym transformations.
1057    ///
1058    /// # Example
1059    ///
1060    /// ```xkb
1061    /// xkb_types {
1062    ///     type "X" {
1063    ///         modifiers = Control+Shift;
1064    ///         map[Control+Shift] = Level2;
1065    ///         preserve[Control+Shift] = Control;
1066    ///     };
1067    /// };
1068    /// ```
1069    ///
1070    /// If this mapping is `map[Control+Shift]`, then function returns
1071    /// [`ModifierMask::CONTROL`].
1072    pub fn preserved(&self) -> ModifierMask {
1073        self.modifiers & self.preserved
1074    }
1075
1076    /// Returns the consumed modifiers of this mapping.
1077    ///
1078    /// If this mapping is applicable, then the consumed modifiers should no longer be
1079    /// considered for keyboard shortcuts and keysym transformations.
1080    ///
1081    /// # Example
1082    ///
1083    /// ```xkb
1084    /// xkb_types {
1085    ///     type "X" {
1086    ///         modifiers = Control+Shift;
1087    ///         map[Control+Shift] = Level2;
1088    ///         preserve[Control+Shift] = Control;
1089    ///     };
1090    /// };
1091    /// ```
1092    ///
1093    /// If this mapping is `map[Control+Shift]`, then function returns
1094    /// [`ModifierMask::SHIFT`].
1095    pub fn consumed(&self) -> ModifierMask {
1096        self.modifiers & !self.preserved
1097    }
1098
1099    /// Returns the 0-based level that this mapping maps to.
1100    ///
1101    /// # Example
1102    ///
1103    /// ```xkb
1104    /// xkb_types {
1105    ///     type "X" {
1106    ///         modifiers = Shift;
1107    ///         map[Shift] = Level2;
1108    ///     };
1109    /// };
1110    /// ```
1111    ///
1112    /// If this mapping is `map[Shift]`, then function returns `1`.
1113    pub fn level(&self) -> usize {
1114        self.level.to_offset()
1115    }
1116}
1117
1118impl KeyLevel {
1119    /// Returns the symbols of this level.
1120    ///
1121    /// Note that returning more than 1 keysym is an extension that does not work for X
1122    /// applications.
1123    ///
1124    /// # Example
1125    ///
1126    /// ```xkb
1127    /// xkb_symbols {
1128    ///     key <a> {
1129    ///         [
1130    ///             a,
1131    ///             { A, B },
1132    ///         ],
1133    ///     };
1134    /// };
1135    /// ```
1136    ///
1137    /// If this object refers to the first level, then this function returns `&[syms::a]`.
1138    ///
1139    /// If this object refers to the second level, then this function returns
1140    /// `&[syms::A, syms::B]`.
1141    pub fn symbols(&self) -> &[Keysym] {
1142        &self.symbols
1143    }
1144
1145    /// Returns the actions of this level.
1146    ///
1147    /// # Example
1148    ///
1149    /// ```xkb
1150    /// xkb_symbols {
1151    ///     key <a> {
1152    ///         [
1153    ///             SetMods(mods = Mod1),
1154    ///             {
1155    ///                 SetMods(mods = Mod2),
1156    ///                 LockGroup(group = 2),
1157    ///             },
1158    ///         ],
1159    ///     };
1160    /// };
1161    /// ```
1162    ///
1163    /// If this object refers to the first level, then this function returns
1164    /// `&[SetMods(mods = Mod1)]`.
1165    ///
1166    /// If this object refers to the second level, then this function returns
1167    /// `&[SetMods(mods = Mod2), LockGroup(group = 2)]`.
1168    pub fn actions(&self) -> &[Action] {
1169        &self.actions
1170    }
1171}
1172
1173impl ModsSetAction {
1174    /// Returns whether this action has the `clearLocks` flag set.
1175    ///
1176    /// # Example
1177    ///
1178    /// ```xkb
1179    /// xkb_symbols {
1180    ///     key <leftshift> {
1181    ///         [ SetMods(mods = Shift, clearLocks) ],
1182    ///     };
1183    /// };
1184    /// ```
1185    ///
1186    /// The function returns `true`.
1187    pub fn clear_locks(&self) -> bool {
1188        self.clear_locks
1189    }
1190
1191    /// Returns the modifier mask of this action.
1192    ///
1193    /// # Example
1194    ///
1195    /// ```xkb
1196    /// xkb_symbols {
1197    ///     key <leftshift> {
1198    ///         [ SetMods(mods = Shift) ],
1199    ///     };
1200    /// };
1201    /// ```
1202    ///
1203    /// The function returns `Shift`.
1204    pub fn mask(&self) -> ModifierMask {
1205        self.modifiers
1206    }
1207}
1208
1209impl ModsLatchAction {
1210    /// Returns whether this action has the `clearLocks` flag set.
1211    ///
1212    /// # Example
1213    ///
1214    /// ```xkb
1215    /// xkb_symbols {
1216    ///     key <leftshift> {
1217    ///         [ LatchMods(mods = Shift, clearLocks) ],
1218    ///     };
1219    /// };
1220    /// ```
1221    ///
1222    /// The function returns `true`.
1223    pub fn clear_locks(&self) -> bool {
1224        self.clear_locks
1225    }
1226
1227    /// Returns whether this action has the `latchToLock` flag set.
1228    ///
1229    /// # Example
1230    ///
1231    /// ```xkb
1232    /// xkb_symbols {
1233    ///     key <leftshift> {
1234    ///         [ LatchMods(mods = Shift, latchToLock) ],
1235    ///     };
1236    /// };
1237    /// ```
1238    ///
1239    /// The function returns `true`.
1240    pub fn latch_to_lock(&self) -> bool {
1241        self.latch_to_lock
1242    }
1243
1244    /// Returns the modifier mask of this action.
1245    ///
1246    /// # Example
1247    ///
1248    /// ```xkb
1249    /// xkb_symbols {
1250    ///     key <leftshift> {
1251    ///         [ LatchMods(mods = Shift) ],
1252    ///     };
1253    /// };
1254    /// ```
1255    ///
1256    /// The function returns `Shift`.
1257    pub fn mask(&self) -> ModifierMask {
1258        self.modifiers
1259    }
1260}
1261
1262impl ModsLockAction {
1263    /// Returns whether this action will lock the modifiers.
1264    ///
1265    /// # Example
1266    ///
1267    /// ```xkb
1268    /// xkb_symbols {
1269    ///     key <leftshift> {
1270    ///         [ LockMods(mods = Shift, affect = unlock) ],
1271    ///     };
1272    /// };
1273    /// ```
1274    ///
1275    /// The function returns `false`.
1276    pub fn lock(&self) -> bool {
1277        self.lock
1278    }
1279
1280    /// Returns whether this action will unlock previously-locked modifiers.
1281    ///
1282    /// # Example
1283    ///
1284    /// ```xkb
1285    /// xkb_symbols {
1286    ///     key <leftshift> {
1287    ///         [ LockMods(mods = Shift, affect = lock) ],
1288    ///     };
1289    /// };
1290    /// ```
1291    ///
1292    /// The function returns `false`.
1293    pub fn unlock(&self) -> bool {
1294        self.unlock
1295    }
1296
1297    /// Returns the modifier mask of this action.
1298    ///
1299    /// # Example
1300    ///
1301    /// ```xkb
1302    /// xkb_symbols {
1303    ///     key <leftshift> {
1304    ///         [ LockMods(mods = Shift) ],
1305    ///     };
1306    /// };
1307    /// ```
1308    ///
1309    /// The function returns `Shift`.
1310    pub fn mask(&self) -> ModifierMask {
1311        self.modifiers
1312    }
1313}
1314
1315impl GroupSetAction {
1316    /// Returns whether this action has the `clearLocks` flag set.
1317    ///
1318    /// # Example
1319    ///
1320    /// ```xkb
1321    /// xkb_symbols {
1322    ///     key <compose> {
1323    ///         [ SetGroup(group = +1, clearLocks) ],
1324    ///     };
1325    /// };
1326    /// ```
1327    ///
1328    /// The function returns `true`.
1329    pub fn clear_locks(&self) -> bool {
1330        self.clear_locks
1331    }
1332
1333    /// Returns the group change of this action.
1334    ///
1335    /// # Example
1336    ///
1337    /// ```xkb
1338    /// xkb_symbols {
1339    ///     key <compose> {
1340    ///         [ SetGroup(group = -1) ],
1341    ///     };
1342    /// };
1343    /// ```
1344    ///
1345    /// The function returns `GroupChange::Relative(-1)`.
1346    pub fn group(&self) -> GroupChange {
1347        self.group.to_group_change()
1348    }
1349}
1350
1351impl GroupLatchAction {
1352    /// Returns whether this action has the `clearLocks` flag set.
1353    ///
1354    /// # Example
1355    ///
1356    /// ```xkb
1357    /// xkb_symbols {
1358    ///     key <compose> {
1359    ///         [ LatchGroup(group = +1, clearLocks) ],
1360    ///     };
1361    /// };
1362    /// ```
1363    ///
1364    /// The function returns `true`.
1365    pub fn clear_locks(&self) -> bool {
1366        self.clear_locks
1367    }
1368
1369    /// Returns whether this action has the `latchToLock` flag set.
1370    ///
1371    /// # Example
1372    ///
1373    /// ```xkb
1374    /// xkb_symbols {
1375    ///     key <compose> {
1376    ///         [ LatchGroup(group = +1, latchToLock) ],
1377    ///     };
1378    /// };
1379    /// ```
1380    ///
1381    /// The function returns `true`.
1382    pub fn latch_to_lock(&self) -> bool {
1383        self.latch_to_lock
1384    }
1385
1386    /// Returns the group change of this action.
1387    ///
1388    /// # Example
1389    ///
1390    /// ```xkb
1391    /// xkb_symbols {
1392    ///     key <compose> {
1393    ///         [ LatchGroup(group = -1) ],
1394    ///     };
1395    /// };
1396    /// ```
1397    ///
1398    /// The function returns `GroupChange::Relative(-1)`.
1399    pub fn group(&self) -> GroupChange {
1400        self.group.to_group_change()
1401    }
1402}
1403
1404impl GroupLockAction {
1405    /// Returns the group change of this action.
1406    ///
1407    /// # Example
1408    ///
1409    /// ```xkb
1410    /// xkb_symbols {
1411    ///     key <compose> {
1412    ///         [ LockGroup(group = -1) ],
1413    ///     };
1414    /// };
1415    /// ```
1416    ///
1417    /// The function returns `GroupChange::Relative(-1)`.
1418    pub fn group(&self) -> GroupChange {
1419        self.group.to_group_change()
1420    }
1421}
1422
1423impl RedirectKeyAction {
1424    /// Returns the name of the key that this action redirects to.
1425    ///
1426    /// # Example
1427    ///
1428    /// ```xkb
1429    /// xkb_symbols {
1430    ///     key <a> {
1431    ///         [ RedirectKey(key = <b>) ],
1432    ///     };
1433    /// };
1434    /// ```
1435    ///
1436    /// The function returns `"b"`.
1437    pub fn key_name(&self) -> &str {
1438        &self.key_name
1439    }
1440
1441    /// Returns the keycode of the key that this action redirects to.
1442    ///
1443    /// # Example
1444    ///
1445    /// ```xkb
1446    /// xkb_symbols {
1447    ///     key <a> {
1448    ///         [ RedirectKey(key = <b>) ],
1449    ///     };
1450    /// };
1451    /// ```
1452    ///
1453    /// The function returns the keycode of `<b>`.
1454    pub fn keycode(&self) -> crate::Keycode {
1455        self.keycode
1456    }
1457
1458    /// Returns the mods that will be set by this action.
1459    ///
1460    /// # Example
1461    ///
1462    /// ```xkb
1463    /// xkb_symbols {
1464    ///     key <a> {
1465    ///         [ RedirectKey(key = <b>, mods = Shift+Mod1) ],
1466    ///     };
1467    /// };
1468    /// ```
1469    ///
1470    /// The function returns `ModifierMask::SHIFT | ModifierMask::MOD1`.
1471    pub fn mods_to_set(&self) -> ModifierMask {
1472        self.mods_to_set
1473    }
1474
1475    /// Returns the mods that will be cleared by this action.
1476    ///
1477    /// # Example
1478    ///
1479    /// ```xkb
1480    /// xkb_symbols {
1481    ///     key <a> {
1482    ///         [ RedirectKey(key = <b>, clearMods = Shift+Mod1) ],
1483    ///     };
1484    /// };
1485    /// ```
1486    ///
1487    /// The function returns `ModifierMask::SHIFT | ModifierMask::MOD1`.
1488    pub fn mods_to_clear(&self) -> ModifierMask {
1489        self.mods_to_clear
1490    }
1491
1492    /// Returns the mods that are affected by this action.
1493    ///
1494    /// This is a shorthand for `self.mods_to_set() | self.mods_to_clear()`.
1495    pub fn modifier_mask(&self) -> ModifierMask {
1496        self.mods_to_set | self.mods_to_clear
1497    }
1498}
1499
1500impl ControlsSetAction {
1501    /// Returns the controls mask of this action.
1502    ///
1503    /// # Example
1504    ///
1505    /// ```xkb
1506    /// xkb_symbols {
1507    ///     key <leftshift> {
1508    ///         [ SetControls(mods = Overlay1) ],
1509    ///     };
1510    /// };
1511    /// ```
1512    ///
1513    /// The function returns the mask for `Overlay1`.
1514    pub fn mask(&self) -> ControlsMask {
1515        ControlsMask(self.controls.0 as u32)
1516    }
1517}
1518
1519impl ControlsLockAction {
1520    /// Returns whether this action will lock the controls.
1521    ///
1522    /// # Example
1523    ///
1524    /// ```xkb
1525    /// xkb_symbols {
1526    ///     key <leftshift> {
1527    ///         [ LockControls(controls = Overlay1, affect = unlock) ],
1528    ///     };
1529    /// };
1530    /// ```
1531    ///
1532    /// The function returns `false`.
1533    pub fn lock(&self) -> bool {
1534        self.lock
1535    }
1536
1537    /// Returns whether this action will unlock previously-locked controls.
1538    ///
1539    /// # Example
1540    ///
1541    /// ```xkb
1542    /// xkb_symbols {
1543    ///     key <leftshift> {
1544    ///         [ LockControls(controls = Overlay1, affect = lock) ],
1545    ///     };
1546    /// };
1547    /// ```
1548    ///
1549    /// The function returns `false`.
1550    pub fn unlock(&self) -> bool {
1551        self.unlock
1552    }
1553
1554    /// Returns the controls mask of this action.
1555    ///
1556    /// # Example
1557    ///
1558    /// ```xkb
1559    /// xkb_symbols {
1560    ///     key <leftshift> {
1561    ///         [ LockControls(mods = Overlay1) ],
1562    ///     };
1563    /// };
1564    /// ```
1565    ///
1566    /// The function returns the mask for `Overlay1`.
1567    pub fn mask(&self) -> ControlsMask {
1568        ControlsMask(self.controls.0 as u32)
1569    }
1570}
1571
1572impl OverlayBehavior {
1573    /// Returns the overlay that controls this behavior.
1574    ///
1575    /// # Example
1576    ///
1577    /// ```xkb
1578    /// xkb_symbols {
1579    ///     key <a> {
1580    ///         overlay2 = <b>,
1581    ///     };
1582    /// };
1583    /// ```
1584    ///
1585    /// The function returns `KeyOverlay::Overlay2`.
1586    pub fn overlay(&self) -> KeyOverlay {
1587        self.overlay
1588    }
1589
1590    /// Returns the name of the key that this behavior redirects to if the overlay is
1591    /// active.
1592    ///
1593    /// # Example
1594    ///
1595    /// ```xkb
1596    /// xkb_symbols {
1597    ///     key <a> {
1598    ///         overlay1 = <b>,
1599    ///     };
1600    /// };
1601    /// ```
1602    ///
1603    /// The function returns `"b"`.
1604    pub fn key_name(&self) -> &str {
1605        &self.key_name
1606    }
1607
1608    /// Returns the keycode of the key that this action redirects to if the overlay is
1609    /// active.
1610    ///
1611    /// # Example
1612    ///
1613    /// ```xkb
1614    /// xkb_symbols {
1615    ///     key <a> {
1616    ///         overlay1 = <b>,
1617    ///     };
1618    /// };
1619    /// ```
1620    ///
1621    /// The function returns the keycode of `<b>`.
1622    pub fn keycode(&self) -> crate::Keycode {
1623        self.keycode
1624    }
1625}
1626
1627impl RadioGroupBehavior {
1628    /// Returns whether pressing this key can release the pressed key.
1629    ///
1630    /// # Example
1631    ///
1632    /// ```xkb
1633    /// xkb_symbols {
1634    ///     key <a> {
1635    ///         allownone,
1636    ///         radiogroup = 1,
1637    ///     };
1638    /// };
1639    /// ```
1640    ///
1641    /// The function returns `true`.
1642    pub fn allow_none(&self) -> bool {
1643        self.allow_none
1644    }
1645
1646    /// Returns the group that this key belongs to. This is a value between 1 and 32.
1647    ///
1648    /// # Example
1649    ///
1650    /// ```xkb
1651    /// xkb_symbols {
1652    ///     key <a> {
1653    ///         radiogroup = 1,
1654    ///     };
1655    /// };
1656    /// ```
1657    ///
1658    /// The function returns `1`.
1659    pub fn group(&self) -> u32 {
1660        self.radio_group.raw()
1661    }
1662}
1663
1664impl Indicator {
1665    /// The name of the `Num Lock` indicator.
1666    pub const NUM_LOCK: &str = "Num Lock";
1667    /// The name of the `Caps Lock` indicator.
1668    pub const CAPS_LOCK: &str = "Caps Lock";
1669    /// The name of the `Scroll Lock` indicator.
1670    pub const SCROLL_LOCK: &str = "Scroll Lock";
1671    /// The name of the `Compose` indicator.
1672    pub const COMPOSE: &str = "Compose";
1673    /// The name of the `Kana` indicator.
1674    pub const KANA: &str = "Kana";
1675
1676    /// Returns the name of the indicator.
1677    ///
1678    /// # Example
1679    ///
1680    /// ```xkb
1681    /// xkb_compat {
1682    ///     indicator "Caps Lock" {
1683    ///         modifiers = Lock;
1684    ///         whichModState = Effective;
1685    ///     };
1686    /// };
1687    /// ```
1688    ///
1689    /// The function returns `"Caps Lock"`.
1690    pub fn name(&self) -> &str {
1691        &self.name
1692    }
1693
1694    /// Returns the matcher for the indicator.
1695    ///
1696    /// # Example
1697    ///
1698    /// ```xkb
1699    /// xkb_compat {
1700    ///     indicator "Caps Lock" {
1701    ///         modifiers = Lock;
1702    ///         whichModState = Effective;
1703    ///     };
1704    /// };
1705    /// ```
1706    ///
1707    /// The matcher will match if the effective group contains the Lock modifier.
1708    pub fn matcher(&self) -> IndicatorMatcher {
1709        macro_rules! mods {
1710            ($comp:ident) => {
1711                self.mod_components
1712                    .contains(ModComponentMask::$comp)
1713                    .then_some(self.modifier_mask.0)
1714                    .unwrap_or_default()
1715            };
1716        }
1717        macro_rules! group_flag {
1718            ($comp:ident, $tt:tt) => {
1719                self.group_component == GroupComponent::$comp
1720                && self.group_mask.0 $tt 0
1721            };
1722        }
1723        macro_rules! group_mask {
1724            ($comp:ident) => {
1725                (self.group_component == GroupComponent::$comp)
1726                    .then_some(self.group_mask.0)
1727                    .unwrap_or_default()
1728            };
1729        }
1730        IndicatorMatcher {
1731            mods_pressed: mods!(BASE),
1732            mods_latched: mods!(LATCHED),
1733            mods_locked: mods!(LOCKED),
1734            mods: mods!(EFFECTIVE),
1735            group_pressed: group_flag!(Base, !=),
1736            group_not_pressed: group_flag!(Base, ==),
1737            group_latched: group_flag!(Latched, !=),
1738            group_not_latched: group_flag!(Latched, ==),
1739            group_locked: group_mask!(Locked),
1740            group: group_mask!(Effective),
1741            controls: self.controls.0 as u32,
1742        }
1743    }
1744}
1745
1746impl IndicatorMatcher {
1747    /// Returns whether this indicator should be illuminated.
1748    pub fn matches(&self, components: &Components) -> bool {
1749        let mut res = 0;
1750        res |= self.mods_pressed & components.mods_pressed.0;
1751        res |= self.mods_latched & components.mods_latched.0;
1752        res |= self.mods_locked & components.mods_locked.0;
1753        res |= self.mods & components.mods.0;
1754        res |= (self.group_pressed & (components.group_pressed.0 != 0)) as u32;
1755        res |= (self.group_not_pressed & (components.group_pressed.0 == 0)) as u32;
1756        res |= (self.group_latched & (components.group_latched.0 != 0)) as u32;
1757        res |= (self.group_not_latched & (components.group_latched.0 == 0)) as u32;
1758        if components.group_locked.0 < u32::BITS {
1759            res |= self.group_locked & (1 << components.group_locked.0);
1760        }
1761        if components.group.0 < u32::BITS {
1762            res |= self.group & (1 << components.group.0);
1763        }
1764        res |= self.controls & components.controls.0;
1765        res != 0
1766    }
1767}