xkbcommon_rs/xkbcomp/
vmod.rs

1// based on vmod.c
2/************************************************************
3 * Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
4 *
5 * Permission to use, copy, modify, and distribute this
6 * software and its documentation for any purpose and without
7 * fee is hereby granted, provided that the above copyright
8 * notice appear in all copies and that both that copyright
9 * notice and this permission notice appear in supporting
10 * documentation, and that the name of Silicon Graphics not be
11 * used in advertising or publicity pertaining to distribution
12 * of the software without specific prior written permission.
13 * Silicon Graphics makes no representation about the suitability
14 * of this software for any purpose. It is provided "as is"
15 * without any express or implied warranty.
16 *
17 * SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
18 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
19 * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
20 * GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
21 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
22 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
23 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
24 * THE USE OR PERFORMANCE OF THIS SOFTWARE.
25 *
26 ********************************************************/
27/*
28 * Copyright © 2024 wysiwys
29 *
30 * Permission is hereby granted, free of charge, to any person obtaining a
31 * copy of this software and associated documentation files (the "Software"),
32 * to deal in the Software without restriction, including without limitation
33 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
34 * and/or sell copies of the Software, and to permit persons to whom the
35 * Software is furnished to do so, subject to the following conditions:
36 *
37 * The above copyright notice and this permission notice (including the next
38 * paragraph) shall be included in all copies or substantial portions of the
39 * Software.
40 *
41 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
43 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
44 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
45 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
46 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
47 * DEALINGS IN THE SOFTWARE.
48 *
49 */
50use super::ast::*;
51
52use crate::context::Context;
53use crate::errors::*;
54use crate::keymap::{Mod, ModSet, ModType, XKB_MAX_MODS};
55
56impl ModSet {
57    pub(super) fn handle_vmod_def(
58        &mut self,
59        ctx: &Context,
60        stmt: VModDef,
61        mut merge: MergeMode,
62    ) -> Result<(), HandleVModError> {
63        let mods = self.clone();
64
65        if merge == MergeMode::Default {
66            merge = stmt.merge;
67        }
68
69        let mut mapping = match stmt.value {
70            None => 0,
71            Some(value) =>
72            // This is a statement such as 'virtualModifiers NumLock = Mod1';
73            // it sets the vmod-to-real-mod[s] mapping directly instead of going through
74            // modifier_map or some such.
75            {
76                value
77                    .resolve_mod_mask(ctx, ModType::REAL, self)
78                    .ok_or_else(|| {
79                        log::error!(
80                            "{:?}: Declaration of {:?} ignored",
81                            XkbMessageCode::NoId,
82                            ctx.xkb_atom_text(stmt.name)
83                        );
84                        HandleVModError::CouldNotResolveModMask
85                    })?
86            }
87        };
88
89        for _mod in self.mods.iter_mut() {
90            if _mod.name == stmt.name {
91                if _mod.mod_type != ModType::VIRT {
92                    let name = ctx.atom_text(_mod.name);
93                    log::error!("{:?}: Can't add a virtual modifier named \"{:?}\"; there is already a non-virtual modifier with this name! Ignored",
94                        XkbMessageCode::NoId,
95                        name
96                    );
97
98                    return Err(HandleVModError::ExistingRealModHasName(
99                        name.expect("Mod has no name").into(),
100                    ));
101                }
102                if _mod.mapping == mapping {
103                    return Ok(());
104                }
105                if _mod.mapping != 0 {
106                    let (_use, ignore) = match merge {
107                        MergeMode::Override => (mapping, _mod.mapping),
108                        _ => (_mod.mapping, mapping),
109                    };
110
111                    log::warn!("{:?}: Virtual modifier {:?} defined multiple times; Using {:?}, ignoring {:?}",
112                        XkbMessageCode::NoId,
113                        ctx.xkb_atom_text(stmt.name),
114                        ctx.mod_mask_text(&mods, _use),
115                        ctx.mod_mask_text(&mods, ignore)
116                    );
117
118                    mapping = _use;
119                }
120
121                _mod.mapping = mapping;
122                return Ok(());
123            }
124        }
125
126        if self.mods.len() >= XKB_MAX_MODS {
127            let err = XkbMessageCode::NoId;
128            log::error!(
129                "{:?}:: Too many modifiers defined (maximum {})",
130                err,
131                XKB_MAX_MODS
132            );
133            return Err(HandleVModError::TooManyModifiersDefined);
134        }
135
136        self.mods.push(Mod {
137            name: stmt.name,
138            mod_type: ModType::VIRT,
139            mapping,
140        });
141
142        Ok(())
143    }
144}