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}