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}