xkbcommon_rs/
lib.rs

1#![allow(warnings)]
2// Includes comments and exports from include/xkbcommon/xkbcommon.h
3/*
4 * Copyright 1985, 1987, 1990, 1998  The Open Group
5 * Copyright 2008  Dan Nicholson
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Except as contained in this notice, the names of the authors or their
25 * institutions shall not be used in advertising or otherwise to promote the
26 * sale, use or other dealings in this Software without prior written
27 * authorization from the authors.
28 */
29
30/************************************************************
31 * Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
32 *
33 * Permission to use, copy, modify, and distribute this
34 * software and its documentation for any purpose and without
35 * fee is hereby granted, provided that the above copyright
36 * notice appear in all copies and that both that copyright
37 * notice and this permission notice appear in supporting
38 * documentation, and that the name of Silicon Graphics not be
39 * used in advertising or publicity pertaining to distribution
40 * of the software without specific prior written permission.
41 * Silicon Graphics makes no representation about the suitability
42 * of this software for any purpose. It is provided "as is"
43 * without any express or implied warranty.
44 *
45 * SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
46 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
47 * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
48 * GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
49 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
50 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
51 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
52 * THE USE OR PERFORMANCE OF THIS SOFTWARE.
53 *
54 ********************************************************/
55
56/*
57 * Copyright © 2009-2012 Daniel Stone
58 * Copyright © 2012 Intel Corporation
59 * Copyright © 2012 Ran Benita
60 * Copyright © 2024 wysiwys
61 *
62 * Permission is hereby granted, free of charge, to any person obtaining a
63 * copy of this software and associated documentation files (the "Software"),
64 * to deal in the Software without restriction, including without limitation
65 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
66 * and/or sell copies of the Software, and to permit persons to whom the
67 * Software is furnished to do so, subject to the following conditions:
68 *
69 * The above copyright notice and this permission notice (including the next
70 * paragraph) shall be included in all copies or substantial portions of the
71 * Software.
72 *
73 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
74 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
75 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
76 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
77 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
78 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
79 * DEALINGS IN THE SOFTWARE.
80 *
81 * Author: Daniel Stone <daniel@fooishbar.org>
82 */
83
84//!
85//! A port of `libxkbcommon` version `1.7.0` in safe Rust.
86//!
87//! ### Use in Wayland client
88//! This crate is intended for use within a Wayland client written in Rust. It provides `Send + Sync` implementations of [Keymap] and [State].
89//!
90//!
91//!
92//! ### Example
93//!
94//! To set up the keymap/state on the Wayland client side:
95//! ```rust
96//! use xkbcommon_rs::*;
97//!
98//! let keymap = Keymap::new_from_string(
99//!     Context::new(0).unwrap(),
100//!     string, /* Read from the OwnedFd provided by the Wayland compositor */
101//!     KeymapFormat::TextV1,
102//!     0).unwrap();
103//!
104//! let mut state = State::new(keymap);
105//!
106//! ```
107//!
108//! To get keysyms and update the state on the client side:
109//!
110//!
111//! ```rust
112//! // Get syms before updating state
113//! let sym = state.key_get_one_sym(keycode)?;
114//!
115//! // Update state with the parameters provided by the wl_keyboard::Event::Modifiers{..} event
116//! state.update_mask(
117//!     mods_depressed, mods_latched, mods_locked,
118//!     0, 0, group as usize);
119//! ```
120//!
121//! For more information on using [State::update_mask()] in a Wayland client, please see <https://wayland-book.com/seat/keyboard.html>.
122//!
123//! # Server state and client state
124//! The `xkb_state` API is used by two distinct actors in most window-system architectures:
125//! 1. A *server* - for example, a Wayland compositor, and X11 server, or an evdev listener.
126//!
127//! Servers maintain the XKB state for a device according to input events from the device, such as
128//! key presses and releases, and out-of-band events from the user, like UI layout switchers.
129//!
130//! 2. A *client* - for example, a Wayland client, an X11 client.
131//!
132//! Clients do not listen to input from the device; instead, whenever the server state changes, the
133//! server state serializes the state and notifies the clients that the state has changed; the
134//! clients then update the state from the serialization.
135//!
136//! Some entry points in the `xkb_state` API are only meant for servers and some are only meant for
137//! clients, and the two should generally not be mixed.
138//!
139//!
140//! # Environment variables
141//!
142//! As in `libxkbcommon`, the user may set some environment variables which affect the library:
143//!
144//! `XKB_CONFIG_ROOT`, `XKB_CONFIG_EXTRA_PATH`, `XDG_CONFIG_DIR`, `HOME` - see [include-path].
145//! `XKB_DEFAULT_RULES`, `XKB_DEFAULT_MODEL`, `XKB_DEFAULT_LAYOUT`, `XKB_DEFAULT_VARIANT`,
146//! `XKB_DEFAULT_OPTIONS` - see [xkb_keymap::RuleNames].
147//!
148#![cfg_attr(docsrs, feature(doc_auto_cfg))]
149#![allow(clippy::module_inception)]
150#![allow(clippy::unwrap_or_default)]
151#![allow(clippy::absurd_extreme_comparisons)]
152#![crate_name = "xkbcommon_rs"]
153#![forbid(unsafe_code)]
154
155mod keysyms_utf;
156
157// generated in project 26
158// TODO: migrate over to build.rs
159mod keysyms_generated_phf;
160
161mod keysyms;
162
163mod atom;
164mod context;
165mod errors;
166mod keymap;
167mod message_codes;
168mod state;
169
170mod rust_xkbcommon;
171mod xkbcomp;
172
173mod parser_utils;
174mod utils;
175
176mod text;
177mod utf8;
178
179mod config;
180
181pub mod error {
182    //! Various error types for the crate.
183
184    pub use super::errors::{context, keymap, state};
185}
186pub mod xkb_context {
187    //! The module containing the [Keymap](crate::Keymap)'s [Context] struct and its associated options.
188    //!
189    //! The [Context] contains general library data and state, and is passed to a Keymap's
190    //! constructor.
191    //! ### Usage
192    //! ```rust
193    //! let context = Context::new(0).unwrap();
194    //! ```
195    //! The [Context] is passed to a Keymap's constructor to initialize the keymap.
196    /// A [Keymap](crate::Keymap)'s context object.
197    ///
198    /// The context contains various general data and state, like include paths.
199    ///
200    /// ### Differences from libxkbcommon
201    /// In `libxkbcommon`, multiple objects may share one context. This feature has yet to be implemented in this crate, so for now each [Keymap](crate::Keymap) has its own [Context], which is not shared by other keymaps.
202    ///
203    pub use super::context::Context;
204
205    pub use super::rust_xkbcommon::ContextFlags;
206}
207pub use xkb_context::Context;
208
209pub mod xkb_keymap {
210
211    //! The module containing the [Keymap] struct and its associated options and metadata.
212    //!
213    //! The keymap is initialized from e.g. a string representation of the keymap passed by the
214    //! Wayland server.
215    //!
216    //! ### Creating a [Keymap]
217    //! ```rust
218    //! let keymap = Keymap::new_from_string(
219    //!     context,
220    //!     string, /* Read from the OwnedFd provided by the Wayland compositor */
221    //!     KeymapFormat::TextV1,
222    //!     0 // compile flags
223    //! ).unwrap();
224    //! ```
225    //! It is standard to pass [KeymapFormat::TextV1] and `0` or
226    //! `CompileFlags::empty()` to this function.
227    //!
228    //! A keymap can also be generated from RMLVO:
229    //! ```rust
230    //! let keymap = Keymap::new_from_names(
231    //!     context,
232    //!     Some(rmlvo),
233    //!     0 // compile flags
234    //! ).unwrap();
235    //!
236    //! ```
237    //! ### Creating a [State](crate::State) from a [Keymap]
238    //! ```rust
239    //! let mut state = State::new(keymap);
240    //! ```
241
242    /// An immutable representation of a keymap compiled from an XKB file. Used by the
243    /// [State](crate::State) struct.
244    ///
245    /// The keymap object holds all of the static keyboard information obtained from compiling XKB
246    /// files.
247    ///
248    /// A keymap is immutable after it is created.
249    /// If you need to change it, you must create a new one.
250    pub use super::keymap::Keymap;
251
252    pub use super::rust_xkbcommon::CompileFlags;
253
254    /// An alternative format that can be used to initialize a [Keymap]. RMLVO = Rules, Model,
255    /// Layout, Variant, Options
256    ///
257    /// You should prefer passing `None` to [Keymap::new_from_names()] instead of choosing your own defaults.
258    pub use super::rust_xkbcommon::RuleNames;
259
260    pub use super::rust_xkbcommon::KeymapFormat;
261}
262pub use xkb_keymap::Keymap;
263pub use xkb_keymap::KeymapFormat;
264
265pub mod xkb_state {
266    //! The module containing the [State] and its associated metadata and options.
267    //! ### Creating a [State] from a [Keymap](crate::Keymap)
268    //! ```rust
269    //! let mut state = State::new(keymap);
270    //! ```
271    //! ### Use in a Wayland client
272    //! To update the [State] on the Wayland client side, use the functions enabled by the `client`
273    //! feature. For example, in Cargo.toml:
274    //! ```toml
275    //! [dependencies]
276    //! xkbcommon-rs = { version = "0.1.1", features = ["client"] }
277    //! ```
278    //! Then to update the state based on data passed by the compositor:
279    //! ```rust
280    //! // Get syms before updating state
281    //! let sym = state.key_get_one_sym(keycode)?;
282    //!
283    //! // Update state with the parameters provided by the wl_keyboard::Event::Modifiers{..} event
284    //! state.update_mask(
285    //!     mods_depressed, mods_latched, mods_locked,
286    //!     0, 0, group as usize);
287    //! ```
288    //!
289    /// Keyboard state object.
290    ///
291    /// ### Creating a [State] from a [Keymap](crate::Keymap)
292    /// ```rust
293    /// let mut state = State::new(keymap);
294    /// ```
295    /// State objects contain the active state of a keyboard
296    /// (or keyboards), such
297    /// as the currently effective layout and the active modifiers.
298    /// It acts as a simple state machine, wherein key presses
299    /// and releases are the input, and key symbols (keysyms) are the output.
300    ///
301    /// ### Usage in Wayland
302    /// On the Wayland client side, a local keyboard State is maintained by the client, which is
303    /// updated to reflect changes in the compositor's state. These changes are communicated over
304    /// the Wayland protocol. To update the client's [State] to reflect these changes, the
305    /// functions in the `client` feature are used.
306    pub use super::state::State;
307
308    pub use super::rust_xkbcommon::KeyDirection;
309    /// Index of a keyboard layout.
310    ///
311    /// The layout index is a state component which determines which <em>keyboard layout</em> is
312    /// active. These may be different alphabets, different key arrangements, etc.
313    ///
314    /// Layout indices are consecutive. The first layout has index 0.
315    ///
316    /// Each layout is not required to have a name, and the names are not guaranteed to be unique
317    /// (though they are usually provided and unique).
318    /// Therefore, it is not safe to use the name as a unique identifier for a layout.
319    /// Layout names are case-sensitive.
320    ///
321    /// Layout names are specified in the layout's definition,
322    /// for example "English (US)". These are different from the
323    /// (conventionally) short names which are used to locate the layout,
324    /// for example "us" or "us(intl)". These names are not present
325    /// in a compiled keymap.
326    ///
327    /// If the user selects layouts from a list generated from the XKB registry (using libxkbregistry
328    /// or directly), it is recommended to store it along with the keymap.
329    ///
330    /// Layouts are also called "groups" by XKB.
331    ///
332    pub use super::rust_xkbcommon::LayoutIndex;
333
334    /// A mask of layout indices.
335    pub use super::rust_xkbcommon::LayoutMask;
336
337    /// Index of a shift level.
338    ///
339    pub use super::rust_xkbcommon::LevelIndex;
340
341    /// Index of a modifier.
342    ///
343    pub use super::rust_xkbcommon::ModIndex;
344
345    /// A mask of modifier indices.
346    ///
347    pub use super::rust_xkbcommon::ModMask;
348
349    /// Index of a keyboard LED.
350    ///
351    pub use super::rust_xkbcommon::LedIndex;
352
353    /// A mask of LED indices.
354    ///
355    pub use super::rust_xkbcommon::LedMask;
356
357    pub use super::rust_xkbcommon::names::*;
358    /// Consumed modifiers mode.
359    ///
360    /// There are several possible methods for deciding which modifiers are consumed and which are not,
361    /// each applicable for different systems or situations. The mode selects the method to use.
362    ///
363    /// Keep in mind that in all methods the keymap may decide to "preserve" a modifier, meaning it is
364    /// not reported as consumed even if it would have otherwise.
365    pub use super::rust_xkbcommon::ConsumedMode;
366
367    pub use super::rust_xkbcommon::StateComponent;
368
369    pub use super::rust_xkbcommon::StateMatch;
370
371    pub use super::keymap::XKB_MAX_GROUPS;
372}
373pub use xkb_state::State;
374
375/// A [Keycode](crate::keycode::Keycode) is a number used to represent a physical key on a keyboard.
376///
377/// A standard PC-compatible keyboard might have 102 keys.
378/// An appropriate keymap would assign each of them a keycode,
379/// by which the user should refer to the key throughout the library.
380///
381/// Historically, the X11 protocol, and consequentially the XKB protocol,
382/// assign only 8 bits for keycodes. This limits the number of different keys
383/// that can be used simultaneously in a single keymap to 256
384/// (disregarding other limitations). This library does not share this limit;
385/// keycodes beyond 255 ('extended keycodes') are not treated specially.
386/// Keymaps and applications which are compatible with X11
387/// should not use these keycodes.
388///
389/// The values of specific keycodes are determined by the keymap and the underlying input system.
390/// For example, with an X11-compatible keymap
391/// and Linux evdev scan codes (see [evdev::Key](https://docs.rs/evdev/latest/evdev/struct.Key.html)), a fixed offset is used:
392///
393/// ```
394/// use evdev::Key;
395/// let keycode_A = Keycode::new(Key::KEY_A + 8);
396/// ```
397///
398/// The keymap defines a canonical name for each key, plus possible aliases.
399/// Historically, the XKB protocol restricts these names to at most 4 (ASCII) characters,
400/// but this library does not share this limit.
401pub mod keycode {
402    //! The [Keycode](crate::keycode::Keycode) struct, which is used to update the [State].
403    //!
404    //! ### Usage in [State]:
405    //! ```rust
406    //! state.update_key(keycode_A, KeyDirection::Down);
407    //! state.update_key(keycode_A, KeyDirection::Up);
408    //!
409    //! ```
410    pub use super::rust_xkbcommon::RawKeycode;
411
412    /// A wrapper struct for [RawKeycode].
413    ///
414    #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq)]
415    pub struct Keycode(pub RawKeycode);
416}
417
418// parser generated in build.rs
419mod lexer;
420mod lexer_utils;
421use lalrpop_util::lalrpop_mod;
422lalrpop_mod!(pub(crate) parser);
423
424// keywords list generated in build.rs
425mod keywords;
426
427/// Additional constants and functions for [`xkeysym`] keysyms
428pub mod keysym {
429    /// Re-export of [`xkeysym::NO_SYMBOL`]:
430    pub use xkeysym::NO_SYMBOL;
431
432    /*
433    /// Re-export of [`xkeysym::Keysym`]
434    ///
435    /// A keycode is a number used to represent the symbols generated from a key on a keyboard.
436    ///
437    /// A key, represented by a keycode, may generate different symbols
438    /// according to keyboard state. For example, on a QWERTY keyboard,
439    /// pressing the key labeled \<A\> generates the symbol 'a'. If the shift key is held, it generates
440    /// the symbol  ‘α’.  And so on.
441    ///
442    /// Each such symbol is represented by a *keysym* (short for "key symbol").
443    /// Note that keysyms are somewhat more general, in that they can also represent
444    /// some "function", such as "Left" or "Right" for the arrow keys.
445    /// For more information, see Appendix A ["KEYSYM
446    /// Encoding"](https://www.x.org/releases/X11R7.7/doc/xproto/x11protocol.html#keysym_encoding) of the X Window System
447    /// Protocol.
448    ///
449    /// Keysym names are case-sensitive.
450    ///
451    pub use xkeysym::Keysym;
452
453    */
454    /// Get the name of a keysym.
455    ///
456    /// For a description of how keysyms are named, see [xkeysym::Keysym].
457    ///
458    pub use super::keysyms::keysym_get_name;
459
460    /// Determines whether a keysym is a keypad symbol.
461    pub use super::keysyms::keysym_is_keypad;
462
463    /// Determines whether a keysym is lowercase.
464    pub use super::keysyms::keysym_is_lower;
465
466    /// Determines whether a keysym is a modifier.
467    pub use super::keysyms::keysym_is_modifier;
468
469    /// Determines whether a keysym is uppercase.
470    pub use super::keysyms::keysym_is_upper;
471
472    /// Converts a keysym to its lowercase representation.
473    pub use super::keysyms::keysym_to_lower;
474
475    /// Converts a keysym to its uppercase representation.
476    pub use super::keysyms::keysym_to_upper;
477
478    /// The flags for [keysym_from_name()].
479    pub use super::rust_xkbcommon::KeysymFlags;
480
481    /// Get a keysym from its name.
482    ///
483    /// # Arguments
484    /// * `name`: The name of a keysym. See remarks in [keysym_get_name()];
485    /// this function will accept any name returned by that function.
486    /// * `flags`: A set of flags controlling how the search is done. If invalid flags are passed, this
487    /// will fail with `None`.
488    ///
489    /// If you use the [KeysymFlags::CASE_INSENSITIVE] flag and two keysym names differ only by case,
490    /// then the lower-case keysym is returned. For instance, for `KEY_a` and `KEY_A`, this function
491    /// would return `KEY_a` for the case-insensitive search. If this functionality is needed, it is
492    /// recommended to first call this function without this flag; and if that fails, only then to try
493    /// with this flag, while possibly warning the user he had misspelled the name, and might get wrong
494    /// results.
495    pub use super::keysyms::keysym_from_name;
496    /// Maximum keysym value
497    ///
498    pub use super::rust_xkbcommon::XKB_KEYSYM_MAX;
499}
500
501#[cfg(test)]
502pub(crate) mod test;
503
504#[cfg(test)]
505macro_rules! log_init {
506    () => {
507        use simplelog::*;
508
509        // Only initialize logger if not already initialized
510        let _ = TermLogger::init(
511            LevelFilter::Debug,
512            Config::default(),
513            TerminalMode::Mixed,
514            ColorChoice::Auto,
515        );
516    };
517}
518#[cfg(test)]
519pub(crate) use log_init;