mod format;
mod from_lookup;
mod from_resolved;
pub mod iterators;
#[cfg(test)]
mod tests;
mod to_builder;
pub use crate::xkb::keymap::format::Formatter;
use {
crate::{
Components, ControlsMask, Keysym, ModifierIndex, ModifierMask,
builder::Redirect,
group::{GroupDelta, GroupIndex},
xkb::{
controls::ControlMask,
group::{GroupIdx, GroupMask},
group_component::GroupComponent,
indicator::IndicatorIdx,
keymap::{
actions::{
ControlsLockAction, ControlsSetAction, GroupLatchAction, GroupLockAction,
GroupSetAction, ModsLatchAction, ModsLockAction, ModsSetAction,
RedirectKeyAction,
},
iterators::{Groups, Indicators, Keys, Levels, Mappings, VirtualModifiers},
},
level::Level,
mod_component::ModComponentMask,
radio_group::RadioGroup,
resolved::GroupsRedirect,
},
},
hashbrown::DefaultHashBuilder,
indexmap::IndexMap,
smallvec::SmallVec,
std::sync::Arc,
};
#[expect(unused_imports)]
use {
crate::{lookup::LookupTable, xkb::Context},
std::fmt::Display,
};
#[derive(Debug, PartialEq)]
pub struct Keymap {
pub(crate) name: Option<Arc<String>>,
pub(crate) max_keycode: u32,
pub(crate) indicators: Vec<Indicator>,
pub(crate) keycodes: Vec<Keycode>,
pub(crate) types: Vec<Arc<KeyType>>,
pub(crate) virtual_modifiers: Vec<VirtualModifier>,
pub(crate) mod_maps: Vec<(ModifierIndex, ModMapValue)>,
pub(crate) group_names: Vec<(GroupIdx, Arc<String>)>,
pub(crate) keys: IndexMap<crate::Keycode, Key, DefaultHashBuilder>,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) struct ModMapValue {
pub(crate) key_name: Arc<String>,
pub(crate) key_sym: Option<Keysym>,
}
#[derive(Debug, PartialEq)]
pub struct Indicator {
pub(crate) virt: bool,
pub(crate) index: IndicatorIdx,
pub(crate) name: Arc<String>,
pub(crate) modifier_mask: ModifierMask,
pub(crate) group_mask: GroupMask,
pub(crate) controls: ControlMask,
pub(crate) mod_components: ModComponentMask,
pub(crate) group_component: GroupComponent,
}
pub struct IndicatorMatcher {
mods_pressed: u32,
mods_latched: u32,
mods_locked: u32,
mods: u32,
group_pressed: bool,
group_not_pressed: bool,
group_latched: bool,
group_not_latched: bool,
group_locked: u32,
group: u32,
controls: u32,
}
#[derive(Debug, PartialEq)]
pub(crate) struct Keycode {
pub(crate) name: Arc<String>,
pub(crate) keycode: crate::Keycode,
}
#[derive(Debug, PartialEq)]
pub struct VirtualModifier {
pub(crate) name: Arc<String>,
pub(crate) values: ModifierMask,
}
#[derive(Debug, PartialEq)]
pub struct KeyType {
pub(crate) name: Arc<String>,
pub(crate) modifiers: ModifierMask,
pub(crate) mappings: Vec<KeyTypeMapping>,
pub(crate) level_names: Vec<(Level, Arc<String>)>,
}
#[derive(Debug, PartialEq)]
pub struct KeyTypeMapping {
pub(crate) modifiers: ModifierMask,
pub(crate) preserved: ModifierMask,
pub(crate) level: Level,
}
#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
pub enum Action {
ModsSet(ModsSetAction),
ModsLatch(ModsLatchAction),
ModsLock(ModsLockAction),
GroupSet(GroupSetAction),
GroupLatch(GroupLatchAction),
GroupLock(GroupLockAction),
RedirectKey(RedirectKeyAction),
ControlsSet(ControlsSetAction),
ControlsLock(ControlsLockAction),
}
pub mod actions {
use {
crate::{
ModifierMask,
xkb::{controls::ControlMask, group},
},
std::sync::Arc,
};
#[derive(Clone, Debug, PartialEq)]
pub struct ModsSetAction {
pub(crate) clear_locks: bool,
pub(crate) modifiers: ModifierMask,
}
#[derive(Clone, Debug, PartialEq)]
pub struct ModsLatchAction {
pub(crate) clear_locks: bool,
pub(crate) latch_to_lock: bool,
pub(crate) modifiers: ModifierMask,
}
#[derive(Clone, Debug, PartialEq)]
pub struct ModsLockAction {
pub(crate) modifiers: ModifierMask,
pub(crate) lock: bool,
pub(crate) unlock: bool,
}
#[derive(Clone, Debug, PartialEq)]
pub struct GroupSetAction {
pub(crate) group: group::GroupChange,
pub(crate) clear_locks: bool,
}
#[derive(Clone, Debug, PartialEq)]
pub struct GroupLatchAction {
pub(crate) group: group::GroupChange,
pub(crate) clear_locks: bool,
pub(crate) latch_to_lock: bool,
}
#[derive(Clone, Debug, PartialEq)]
pub struct GroupLockAction {
pub(crate) group: group::GroupChange,
}
#[derive(Clone, Debug, PartialEq)]
pub struct RedirectKeyAction {
pub(crate) key_name: Arc<String>,
pub(crate) keycode: crate::Keycode,
pub(crate) mods_to_set: ModifierMask,
pub(crate) mods_to_clear: ModifierMask,
}
#[derive(Clone, Debug, PartialEq)]
pub struct ControlsSetAction {
pub(crate) controls: ControlMask,
}
#[derive(Clone, Debug, PartialEq)]
pub struct ControlsLockAction {
pub(crate) controls: ControlMask,
pub(crate) lock: bool,
pub(crate) unlock: bool,
}
}
pub enum GroupChange {
Absolute(GroupIndex),
Relative(GroupDelta),
}
#[derive(Clone, Debug, PartialEq)]
pub struct Key {
pub(crate) key_name: Arc<String>,
pub(crate) keycode: crate::Keycode,
pub(crate) groups: Vec<Option<KeyGroup>>,
pub(crate) repeat: bool,
pub(crate) behavior: Option<KeyBehavior>,
pub(crate) redirect: GroupsRedirect,
}
#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
pub enum KeyBehavior {
Lock,
Overlay(OverlayBehavior),
RadioGroup(RadioGroupBehavior),
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[non_exhaustive]
pub enum KeyOverlay {
Overlay1,
Overlay2,
}
#[derive(Clone, Debug, PartialEq)]
pub struct OverlayBehavior {
pub(crate) overlay: KeyOverlay,
pub(crate) key_name: Arc<String>,
pub(crate) keycode: crate::Keycode,
}
#[derive(Clone, Debug, PartialEq)]
pub struct RadioGroupBehavior {
pub(crate) allow_none: bool,
pub(crate) radio_group: RadioGroup,
}
#[derive(Clone, Debug, PartialEq)]
pub struct KeyGroup {
pub(crate) key_type: Arc<KeyType>,
pub(crate) levels: Vec<KeyLevel>,
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct KeyLevel {
pub(crate) symbols: SmallVec<[Keysym; 1]>,
pub(crate) actions: SmallVec<[Action; 1]>,
}
impl Keymap {
pub fn virtual_modifiers(&self) -> VirtualModifiers<'_> {
VirtualModifiers {
modifiers: self.virtual_modifiers.iter(),
}
}
pub fn keys(&self) -> Keys<'_> {
Keys {
keys: self.keys.values(),
}
}
pub fn indicators(&self) -> Indicators<'_> {
Indicators {
indicators: self.indicators.iter(),
}
}
pub fn format(&self) -> Formatter<'_> {
Formatter {
keymap: self,
single_line: false,
lookup_only: false,
multiple_actions_per_level: false,
rename_long_keys: false,
}
}
}
impl Indicator {
pub(crate) fn dummy() -> Self {
Self {
virt: false,
index: IndicatorIdx::ONE,
name: Arc::new("DUMMY".to_string()),
modifier_mask: Default::default(),
group_mask: Default::default(),
controls: Default::default(),
mod_components: Default::default(),
group_component: Default::default(),
}
}
}
impl VirtualModifier {
pub(crate) fn dummy() -> Self {
Self {
name: Arc::new("Dummy".to_string()),
values: Default::default(),
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn mask(&self) -> ModifierMask {
self.values
}
}
impl Key {
pub fn name(&self) -> &str {
&self.key_name
}
pub fn keycode(&self) -> crate::Keycode {
self.keycode
}
pub fn repeats(&self) -> bool {
self.repeat
}
pub fn redirect(&self) -> Redirect {
self.redirect.to_redirect()
}
pub fn behavior(&self) -> Option<&KeyBehavior> {
self.behavior.as_ref()
}
pub fn groups(&self) -> Groups<'_> {
Groups {
groups: self.groups.iter(),
}
}
}
impl KeyGroup {
pub fn ty(&self) -> &KeyType {
&self.key_type
}
pub fn levels(&self) -> Levels<'_> {
Levels {
levels: self.levels.iter(),
}
}
}
impl KeyType {
pub fn mask(&self) -> ModifierMask {
self.modifiers
}
pub fn mappings(&self) -> Mappings<'_> {
Mappings {
mappings: self.mappings.iter(),
}
}
}
impl KeyTypeMapping {
pub fn mask(&self) -> ModifierMask {
self.modifiers
}
pub fn preserved(&self) -> ModifierMask {
self.modifiers & self.preserved
}
pub fn consumed(&self) -> ModifierMask {
self.modifiers & !self.preserved
}
pub fn level(&self) -> usize {
self.level.to_offset()
}
}
impl KeyLevel {
pub fn symbols(&self) -> &[Keysym] {
&self.symbols
}
pub fn actions(&self) -> &[Action] {
&self.actions
}
}
impl ModsSetAction {
pub fn clear_locks(&self) -> bool {
self.clear_locks
}
pub fn mask(&self) -> ModifierMask {
self.modifiers
}
}
impl ModsLatchAction {
pub fn clear_locks(&self) -> bool {
self.clear_locks
}
pub fn latch_to_lock(&self) -> bool {
self.latch_to_lock
}
pub fn mask(&self) -> ModifierMask {
self.modifiers
}
}
impl ModsLockAction {
pub fn lock(&self) -> bool {
self.lock
}
pub fn unlock(&self) -> bool {
self.unlock
}
pub fn mask(&self) -> ModifierMask {
self.modifiers
}
}
impl GroupSetAction {
pub fn clear_locks(&self) -> bool {
self.clear_locks
}
pub fn group(&self) -> GroupChange {
self.group.to_group_change()
}
}
impl GroupLatchAction {
pub fn clear_locks(&self) -> bool {
self.clear_locks
}
pub fn latch_to_lock(&self) -> bool {
self.latch_to_lock
}
pub fn group(&self) -> GroupChange {
self.group.to_group_change()
}
}
impl GroupLockAction {
pub fn group(&self) -> GroupChange {
self.group.to_group_change()
}
}
impl RedirectKeyAction {
pub fn key_name(&self) -> &str {
&self.key_name
}
pub fn keycode(&self) -> crate::Keycode {
self.keycode
}
pub fn mods_to_set(&self) -> ModifierMask {
self.mods_to_set
}
pub fn mods_to_clear(&self) -> ModifierMask {
self.mods_to_clear
}
pub fn modifier_mask(&self) -> ModifierMask {
self.mods_to_set | self.mods_to_clear
}
}
impl ControlsSetAction {
pub fn mask(&self) -> ControlsMask {
ControlsMask(self.controls.0 as u32)
}
}
impl ControlsLockAction {
pub fn lock(&self) -> bool {
self.lock
}
pub fn unlock(&self) -> bool {
self.unlock
}
pub fn mask(&self) -> ControlsMask {
ControlsMask(self.controls.0 as u32)
}
}
impl OverlayBehavior {
pub fn overlay(&self) -> KeyOverlay {
self.overlay
}
pub fn key_name(&self) -> &str {
&self.key_name
}
pub fn keycode(&self) -> crate::Keycode {
self.keycode
}
}
impl RadioGroupBehavior {
pub fn allow_none(&self) -> bool {
self.allow_none
}
pub fn group(&self) -> u32 {
self.radio_group.raw()
}
}
impl Indicator {
pub const NUM_LOCK: &str = "Num Lock";
pub const CAPS_LOCK: &str = "Caps Lock";
pub const SCROLL_LOCK: &str = "Scroll Lock";
pub const COMPOSE: &str = "Compose";
pub const KANA: &str = "Kana";
pub fn name(&self) -> &str {
&self.name
}
pub fn matcher(&self) -> IndicatorMatcher {
macro_rules! mods {
($comp:ident) => {
self.mod_components
.contains(ModComponentMask::$comp)
.then_some(self.modifier_mask.0)
.unwrap_or_default()
};
}
macro_rules! group_flag {
($comp:ident, $tt:tt) => {
self.group_component == GroupComponent::$comp
&& self.group_mask.0 $tt 0
};
}
macro_rules! group_mask {
($comp:ident) => {
(self.group_component == GroupComponent::$comp)
.then_some(self.group_mask.0)
.unwrap_or_default()
};
}
IndicatorMatcher {
mods_pressed: mods!(BASE),
mods_latched: mods!(LATCHED),
mods_locked: mods!(LOCKED),
mods: mods!(EFFECTIVE),
group_pressed: group_flag!(Base, !=),
group_not_pressed: group_flag!(Base, ==),
group_latched: group_flag!(Latched, !=),
group_not_latched: group_flag!(Latched, ==),
group_locked: group_mask!(Locked),
group: group_mask!(Effective),
controls: self.controls.0 as u32,
}
}
}
impl IndicatorMatcher {
pub fn matches(&self, components: &Components) -> bool {
let mut res = 0;
res |= self.mods_pressed & components.mods_pressed.0;
res |= self.mods_latched & components.mods_latched.0;
res |= self.mods_locked & components.mods_locked.0;
res |= self.mods & components.mods.0;
res |= (self.group_pressed & (components.group_pressed.0 != 0)) as u32;
res |= (self.group_not_pressed & (components.group_pressed.0 == 0)) as u32;
res |= (self.group_latched & (components.group_latched.0 != 0)) as u32;
res |= (self.group_not_latched & (components.group_latched.0 == 0)) as u32;
if components.group_locked.0 < u32::BITS {
res |= self.group_locked & (1 << components.group_locked.0);
}
if components.group.0 < u32::BITS {
res |= self.group & (1 << components.group.0);
}
res |= self.controls & components.controls.0;
res != 0
}
}