kbvm/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
//! KBVM is an implementation of the XKB specification and associated protocols.
//!
//! At its core, KBVM provides two types:
//!
//! - [`StateMachine`](state_machine::StateMachine), a compositor-side keyboard state
//!   machine.
//! - [`LookupTable`](lookup::LookupTable), a client-side lookup table that can be used
//!   to look up keysyms.
//!
//! These types can be created from XKB keymaps or RMLVO names by using an
//! [`xkb::Context`].
//!
//! Additionally, KBVM provides other tools from the XKB ecosystem:
//!
//! - [`ComposeTables`](xkb::compose::ComposeTable) can be created from XCompose files as
//!   a simple input method.
//! - XKB keymaps can be loaded from X11 connections via
//!   [integration](xkb::x11::KbvmX11Ext) with the x11rb crate.
//! - The RMLVO [registry](xkb::registry::Registry) can be loaded to display the available
//!   RMLVO names to users.
//!
//! While XKB keymaps can be used to create `StateMachines` and `LookupTables`, it is also
//! possible to created these objects manually with the [`Builder`](builder::Builder)
//! type. To retain compatibility with XKB, any `LookupTable` can be
//! [turned](lookup::LookupTable::to_xkb_keymap) into an XKB keymap.
//!
//! Manually created `StateMachines` allow you to run arbitrary logic when keys are
//! pressed and released. For example, you can use this logic to implement sticky keys,
//! radio groups, locked keys, key redirection, latching keys, etc.
//!
//! # The common compositor pattern
//!
//! If you are developing a wayland compositor, you might use this crate as follows:
//!
//! 1. For each seat, the user configures either an XKB map directly or a set of RMLVO
//!    names from which you have to create an XKB map.
//! 2. Either way, you use an [`xkb::Context`] and either
//!    [`keymap_from_bytes`](xkb::Context::keymap_from_bytes) or
//!    [`keymap_from_names`](xkb::Context::keymap_from_names) to create an
//!    [`xkb::Keymap`].
//! 3. You can format this keymap as a string by using
//!    [`Keymap::format`](xkb::Keymap::format). You send this keymap to clients via the
//!    `wl_keyboard.keymap` event.
//! 4. You then use [`Keymap::to_builder`](xkb::Keymap::to_builder) followed by
//!    [`Builder::build_state_machine`](builder::Builder::build_state_machine) to create
//!    a [`StateMachine`](state_machine::StateMachine).
//! 5. Whenever you receive a libinput key event, you feed it into the `StateMachine` with
//!    [`StateMachine::handle_key`](state_machine::StateMachine::handle_key). This in turn
//!    produces a number of [`Events`](state_machine::Event) that you forward to clients.
//!
//!    The `handle_key` documentation contains an example showing how to do this
//!    correctly.
//!
//! If you are also handling keyboard shortcuts in your compositor, you will likely also
//! want to create a `LookupTable` as described in the next section.
//!
//! # The common client pattern
//!
//! If you are developing a wayland client, you might use this crate as follows:
//!
//! 1. For each seat, you receive a keymap via the `wl_keyboard.keymap` event.
//! 2. You use an [`xkb::Context`] and
//!    [`keymap_from_bytes`](xkb::Context::keymap_from_bytes) to create an [`xkb::Keymap`]
//!    from the buffer from the event.
//! 3. You then use [`Keymap::to_builder`](xkb::Keymap::to_builder) followed by
//!    [`Builder::build_lookup_table`](builder::Builder::build_lookup_table) to create
//!    a [`LookupTable`](lookup::LookupTable).
//! 4. You create a [`Components`] object to store the active modifiers and group of the
//!    keyboard.
//! 5. Whenever you receive a `wl_keyboard.modifiers` event, you update the [`Components`]
//!    as shown in [`Components::update_effective`].
//! 6. Whenever you receive a `wl_keyboard.key` event for a key press, you use
//!    [`LookupTable::lookup`](lookup::LookupTable::lookup) to look up the keysyms
//!    produced by this event, using the effective modifiers and group from your
//!    [`Components`].

#![expect(
    clippy::collapsible_else_if,
    clippy::collapsible_if,
    clippy::field_reassign_with_default,
    clippy::should_implement_trait,
    clippy::assertions_on_constants,
    clippy::len_zero,
    clippy::manual_range_contains
)]

pub use {
    components::Components,
    controls::ControlsMask,
    group::{GroupDelta, GroupIndex},
    group_type::hidden::GroupType,
    keycode::Keycode,
    keysym::hidden::Keysym,
    modifier::hidden::{ModifierIndex, ModifierMask},
};

#[macro_use]
mod macros;
pub mod builder;
mod components;
mod config;
mod controls;
pub mod evdev;
mod from_bytes;
mod group;
pub mod group_type;
mod keycode;
pub mod keysym;
pub mod lookup;
pub mod modifier;
mod phf;
mod phf_map;
pub mod routine;
pub mod state_machine;
pub mod syms;
pub mod xkb;