xkbcommon_rs/rust_xkbcommon/rust_xkbcommon.rs
1//based on xkbcommon.h
2/*
3 * Copyright 1985, 1987, 1990, 1998 The Open Group
4 * Copyright 2008 Dan Nicholson
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *
23 * Except as contained in this notice, the names of the authors or their
24 * institutions shall not be used in advertising or otherwise to promote the
25 * sale, use or other dealings in this Software without prior written
26 * authorization from the authors.
27 */
28
29/************************************************************
30 * Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
31 *
32 * Permission to use, copy, modify, and distribute this
33 * software and its documentation for any purpose and without
34 * fee is hereby granted, provided that the above copyright
35 * notice appear in all copies and that both that copyright
36 * notice and this permission notice appear in supporting
37 * documentation, and that the name of Silicon Graphics not be
38 * used in advertising or publicity pertaining to distribution
39 * of the software without specific prior written permission.
40 * Silicon Graphics makes no representation about the suitability
41 * of this software for any purpose. It is provided "as is"
42 * without any express or implied warranty.
43 *
44 * SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
45 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
46 * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
47 * GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
48 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
49 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
50 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
51 * THE USE OR PERFORMANCE OF THIS SOFTWARE.
52 *
53 ********************************************************/
54
55/*
56 * Copyright © 2009-2012 Daniel Stone
57 * Copyright © 2012 Intel Corporation
58 * Copyright © 2012 Ran Benita
59 * Copyright © 2024 wysiwys
60 *
61 * Permission is hereby granted, free of charge, to any person obtaining a
62 * copy of this software and associated documentation files (the "Software"),
63 * to deal in the Software without restriction, including without limitation
64 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
65 * and/or sell copies of the Software, and to permit persons to whom the
66 * Software is furnished to do so, subject to the following conditions:
67 *
68 * The above copyright notice and this permission notice (including the next
69 * paragraph) shall be included in all copies or substantial portions of the
70 * Software.
71 *
72 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
73 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
74 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
75 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
76 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
77 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
78 * DEALINGS IN THE SOFTWARE.
79 *
80 * Author: Daniel Stone <daniel@fooishbar.org>
81 */
82
83pub(crate) use crate::keycode::Keycode;
84
85pub(crate) use xkeysym::Keysym;
86
87/// A number used to represent a physical key on a keyboard.
88///
89/// A standard PC-compatible keyboard might have 102 keys.
90/// An appropriate keymap would assign each of them a keycode,
91/// by which the user should refer to the key throughout
92/// the library.
93///
94/// Historically, the X11 protocol, and consequently the
95/// XKB protocol, assigned only 8 bits for keycodes.
96/// This limits the number of different keys that can be
97/// used simultaneously in a single keymap to 256
98/// (disregarding other limitations). This library does not
99/// share this limit.
100///
101/// Corresponds to `xkb_keycode_t`
102pub type RawKeycode = u32;
103
104impl From<Keycode> for u32 {
105 fn from(val: Keycode) -> Self {
106 val.0
107 }
108}
109
110impl From<u32> for Keycode {
111 fn from(raw: u32) -> Self {
112 Self(raw)
113 }
114}
115impl Keycode {
116 pub fn new(raw: u32) -> Self {
117 Self(raw)
118 }
119
120 pub fn raw(&self) -> u32 {
121 self.0
122 }
123}
124
125/// Corresponds to `xkb_layout_index_t`
126pub type LayoutIndex = usize;
127
128/// Corresponds to `xkb_layout_mask_t`
129pub type LayoutMask = u32;
130
131/// Corresponds to `xkb_level_index_t`
132pub type LevelIndex = usize;
133
134/// Corresponds to `xkb_mod_index_t`
135pub type ModIndex = usize;
136
137/// Corresponds to `xkb_mod_mask_t`
138pub type ModMask = u32;
139
140/// Corresponds to `xkb_led_index_t`
141pub type LedIndex = usize;
142
143/// Corresponds to `xkb_led_mask_t`
144pub type LedMask = u32;
145
146pub(crate) const XKB_KEYCODE_INVALID: RawKeycode = 0xffffffff;
147//pub(crate) const XKB_LAYOUT_INVALID: LayoutIndex = 0xffffffff;
148//pub(crate) const XKB_LEVEL_INVALID: LevelIndex = 0xffffffff;
149pub(crate) const XKB_MOD_INVALID: ModIndex = 0xffffffff;
150//pub(crate) const XKB_LED_INVALID: LedIndex = 0xffffffff;
151
152pub const XKB_KEYCODE_MAX: RawKeycode = 0xffffffff - 1;
153pub const XKB_KEYSYM_MAX: u32 = 0x1fffffff;
154
155impl Keycode {
156 pub fn is_legal_ext(&self) -> bool {
157 self.0 <= XKB_KEYCODE_MAX
158 }
159
160 pub fn is_legal_x11(&self) -> bool {
161 self.0 >= 8 && self.0 <= 255
162 }
163}
164
165#[derive(Clone, Debug)]
166pub struct RuleNames
167// xkb_rule_names
168{
169 /// The rules file to use. The rules file describes how to interpret the values of the model,
170 /// layout, variant, and options fields.
171 ///
172 /// If `None` or the empty string `""`, a default value is used.
173 /// If the `XKB_DEFAULT_RULES` environment variable is set, it is used as the default.
174 /// Otherwise, the system default is used.
175 ///
176 pub rules: Option<String>,
177
178 /// The keyboard model by which to interpret keycodes and LEDs.
179 ///
180 /// If `None` or the empty string `""`, a default value is used.
181 /// If the `XKB_DEFAULT_MODEL` environment variable is set, it is used as the default.
182 /// Otherwise the system default is used.
183 ///
184 ///
185 pub model: Option<String>,
186
187 /// A comma-separated list of layouts (languages) to include in the keymap.
188 ///
189 /// If `None` or the empty string `""`, a default value is used.
190 /// If the `XKB_DEFAULT_LAYOUT` environment variable is set, it is used as the default.
191 /// Otherwise, the system default is used.
192 pub layout: Option<String>,
193
194 /// A comma-separated list of variants, one per layout, which may modify or augment the
195 /// respective layout in various ways.
196 ///
197 /// Generally, this should either be empty or have the same number of values as the number of
198 /// layouts. You may use empty values as in `"intl,,neo"`.
199 ///
200 /// If `None` or the empty string `""`, and a default value is also used for the layout, a
201 /// default value is used. Otherwise, no variant is used.
202 ///
203 /// If the `XKB_DEFAULT_VARIANT` environment variable is set, it is used as the default.
204 /// Otherwise, the system default is used.
205 pub variant: Option<String>,
206
207 /// A comma-separated list of options, through which the user specifies non-layout related
208 /// preferences, like which key combinations are used for switching layouts, or which key is
209 /// the Compose key.
210 ///
211 /// If the `XKB_DEFAULT_OPTIONS` environment variable is set, it is used as the default.
212 /// Otherwise, the system default is used.
213 pub options: Option<String>,
214}
215
216impl RuleNames {
217 pub fn new(rules: &str, model: &str, layout: &str, variant: &str, options: &str) -> Self {
218 Self {
219 rules: match rules {
220 "" => None,
221 s => Some(s.into()),
222 },
223 model: match model {
224 "" => None,
225 s => Some(s.into()),
226 },
227 layout: match layout {
228 "" => None,
229 s => Some(s.into()),
230 },
231 variant: match variant {
232 "" => None,
233 s => Some(s.into()),
234 },
235 options: match options {
236 "" => None,
237 s => Some(s.into()),
238 },
239 }
240 }
241
242 pub(crate) fn empty() -> Self {
243 Self {
244 rules: None,
245 model: None,
246 layout: None,
247 variant: None,
248 options: None,
249 }
250 }
251}
252
253bitflags::bitflags! {
254 pub struct KeysymFlags: u8 {
255 /// Do not apply any flags
256 const NO_FLAGS = 0;
257 /// Find keysym by case-insensitive search
258 const CASE_INSENSITIVE = (1 << 0);
259 }
260}
261
262impl TryFrom<u8> for KeysymFlags {
263 type Error = &'static str;
264
265 fn try_from(u: u8) -> Result<Self, Self::Error> {
266 match u {
267 0 => Ok(KeysymFlags::NO_FLAGS),
268 1 => Ok(KeysymFlags::CASE_INSENSITIVE),
269 _ => Err("no such flags"),
270 }
271 }
272}
273
274bitflags::bitflags! {
275 /// Flags for context creation.
276pub struct ContextFlags: u32 {
277 /// Do not apply any context flags.
278 const NO_FLAGS = 0;
279
280 /// Create this context with an empty include path.
281 const NO_DEFAULT_INCLUDES = (1 << 0);
282
283 /// Don't take RMLVO names from the environment.
284 const NO_ENVIRONMENT_NAMES = (1 << 1);
285 /// Disable the use of secure_getenv for this context,
286 /// so that privileged processes can use environment variables.
287 /// Client uses at their own risk.
288 /// TODO: Not implemented
289 const NO_SECURE_GETENV = (1 << 2);
290 }
291}
292
293impl From<u32> for ContextFlags {
294 fn from(bits: u32) -> Self {
295 Self::from_bits_truncate(bits)
296 }
297}
298
299/*
300pub enum LogLevel {
301 CRITICAL = 10,
302 ERROR = 20,
303 WARNING = 30,
304 INFO = 40,
305 DEBUG = 50
306}
307*/
308
309bitflags::bitflags! {
310 #[derive(Clone, Debug)]
311 /// Flags for keymap compilation.
312 pub struct CompileFlags: u32 {
313 const NO_FLAGS = 0;
314 }
315}
316
317impl From<CompileFlags> for u32 {
318 fn from(val: CompileFlags) -> Self {
319 val.bits()
320 }
321}
322
323impl TryFrom<u32> for CompileFlags {
324 type Error = ();
325
326 fn try_from(u: u32) -> Result<Self, Self::Error> {
327 CompileFlags::from_bits(u).ok_or(())
328 }
329}
330
331/// The possible keymap formats. Currently, only `TextV1` is supported.
332#[repr(u32)]
333#[derive(Clone, Copy, Debug, PartialEq)]
334pub enum KeymapFormat {
335 /// The current/classic XKB format, as generated by `xkbcomp -xkb`.
336 TextV1 = 1,
337 OriginalFormat = 0xffff_ffff,
338}
339
340impl From<KeymapFormat> for u32 {
341 fn from(val: KeymapFormat) -> Self {
342 val as u32
343 }
344}
345
346impl TryFrom<u32> for KeymapFormat {
347 type Error = &'static str;
348
349 fn try_from(u: u32) -> Result<Self, Self::Error> {
350 if u == 1 {
351 Ok(KeymapFormat::TextV1)
352 } else if u == 0xffff_ffff {
353 Ok(KeymapFormat::OriginalFormat)
354 } else {
355 Err("Invalid keymap format")
356 }
357 }
358}
359
360pub(crate) trait KeymapFormatType: Into<KeymapFormat> {}
361
362#[derive(Clone, Copy, Debug, PartialEq)]
363pub(crate) struct TextV1;
364#[derive(Clone, Copy, Debug, PartialEq)]
365pub(crate) struct OriginalFormat;
366
367impl From<TextV1> for KeymapFormat {
368 fn from(_: TextV1) -> Self {
369 KeymapFormat::TextV1
370 }
371}
372impl KeymapFormatType for TextV1 {}
373impl From<OriginalFormat> for KeymapFormat {
374 fn from(_: OriginalFormat) -> Self {
375 KeymapFormat::OriginalFormat
376 }
377}
378impl KeymapFormatType for OriginalFormat {}
379
380/// Specifies the direction of key (press/release)
381#[derive(PartialEq, Clone, Copy, Debug)]
382pub enum KeyDirection {
383 /// The key was released.
384 Up,
385 /// The key was pressed.
386 Down,
387}
388
389bitflags::bitflags! {
390 #[derive(Copy,Clone, Eq, PartialEq, Debug)]
391/// Modifier and layout types for state objects.
392///
393/// This enum is bitmaskable. E.g.
394/// `StateComponent::MODS_DEPRESSED | StateComponent::MODS_LATCHED` is valid to exclude locked
395/// modifiers.
396///
397/// In XKB, the `DEPRESSED` components are also known as 'base'.
398 pub struct StateComponent: u16 {
399 /// Depressed modifiers, i.e. a key is physically holding them.
400 const MODS_DEPRESSED = (1 << 0);
401 /// Latched modifiers, i.e. will be unset after the next non-modifier key press.
402 const MODS_LATCHED = (1 << 1);
403 /// Locked modifiers, i.e. will be unset after the key provoking the lock has been pressed
404 /// again.
405 const MODS_LOCKED = (1 << 2);
406 /// Effective modifiers, i.e. currently active and affect key
407 /// processing (derived from the other state components).
408 /// Use this unless you explicitly care how the state came about.
409 const MODS_EFFECTIVE = (1 << 3);
410 /** Depressed layout, i.e. a key is physically holding it. */
411 const LAYOUT_DEPRESSED = (1 << 4);
412 /** Latched layout, i.e. will be unset after the next non-modifier key press. */
413 const LAYOUT_LATCHED = (1 << 5);
414 /** Locked layout, i.e. will be unset after the key provoking the lock
415 * has been pressed again. */
416 const LAYOUT_LOCKED = (1 << 6);
417 /** Effective layout, i.e. currently active and affects key processing
418 * (derived from the other state components).
419 * Use this unless you explicitly care how the state came about. */
420 const LAYOUT_EFFECTIVE = (1 << 7);
421 /** LEDs (derived from the other state components). */
422 const LEDS = (1 << 8);
423 }
424}
425
426impl From<StateComponent> for i64 {
427 fn from(val: StateComponent) -> Self {
428 val.bits() as i64
429 }
430}
431
432impl TryFrom<i64> for StateComponent {
433 type Error = &'static str;
434
435 fn try_from(i: i64) -> Result<Self, Self::Error> {
436 let u = match i.try_into() {
437 Err(_) => return Err("Could not convert from i64"),
438 Ok(u) => u,
439 };
440 match Self::from_bits(u) {
441 None => Err("Could not convert to StateComponent"),
442 Some(a) => Ok(a),
443 }
444 }
445}
446
447bitflags::bitflags! {
448 #[derive(Copy,Clone)]
449pub struct StateMatch: u32 {
450 /// Returns true if any of the modifiers are active
451 const ANY = (1 << 0);
452 /// Returns true if all of the modifiers are active
453 const ALL = (1 << 1);
454 /// Makes matching non-exclusive, i.e. will not return false if a modifier not specified in the
455 /// arguments is active.
456 const NON_EXCLUSIVE = (1 << 16);
457}}
458
459pub enum ConsumedMode {
460 /// This is the mode defined in the XKB specification and used by libX11.
461 ///
462 /// A modifier is consumed if and only if it *may affect* key translation.
463 ///
464 /// For example, if `Control+Alt+<Backspace>` produces some assigned keysym,
465 /// then, when pressing just `<Backspace>`, `Control` and `Alt` are consumed, even though they
466 /// are not active, since if they had been active they would have affected key translation.
467 Xkb,
468
469 /// This is the mode used by the GTK+ toolkit.
470 ///
471 ///
472 Gtk,
473}
474
475#[cfg(test)]
476mod tests {
477
478 use super::*;
479
480 #[test]
481 fn test_keysym_0() {
482 assert_eq!(Keysym::from(0), xkeysym::NO_SYMBOL);
483 }
484}