kbvm::lookup

Struct LookupTable

Source
pub struct LookupTable { /* private fields */ }
Expand description

A keysym lookup table.

This type allows looking up keysyms and characters generated by key-press events. It is created by calling Builder::build_lookup_table.

§Example

fn get_string(
    table: &LookupTable,
    group: GroupIndex,
    modifiers: ModifierMask,
    keycode: Keycode,
) -> String {
    table
        .lookup(group, modifiers, keycode)
        .into_iter()
        .flat_map(|p| p.char())
        .collect()
}

§Key Repeat

A key can be configured to repeat. In this case, the client should periodically emulate key-press events until the next repeating key is pressed or this key is released.

This property can be accessed with the Lookup::repeats function.

fn need_key_repeat_events(
    table: &LookupTable,
    group: GroupIndex,
    modifiers: ModifierMask,
    keycode: Keycode,
) -> bool {
    table
        .lookup(group, modifiers, keycode)
        .repeats()
}

§Consumed Modifiers

The lookup process might consume some of the input modifiers. These modifiers should be ignored when the produced keysyms are used in keyboard shortcuts.

This remaining modifiers can be accessed with the Lookup::remaining_mods function.

fn get_keysyms_for_shortcuts(
    table: &LookupTable,
    group: GroupIndex,
    modifiers: ModifierMask,
    keycode: Keycode,
) -> impl Iterator<Item = (ModifierMask, Keysym)> + use<'_> {
    let lookup = table.lookup(group, modifiers, keycode);
    lookup.into_iter().map(move |p| (lookup.remaining_mods(), p.keysym()))
}

§Caps Transformation

If the remaining modifiers contain the caps modifier, the keysym iterator will automatically perform caps transformation. That is, all keysyms will be replaced by their uppercase version.

This behavior can be disabled by using Lookup::with_caps_transform and Lookup::set_caps_transform.

fn disable_caps_transform(
    table: &LookupTable,
    group: GroupIndex,
    modifiers: ModifierMask,
    keycode: Keycode,
) -> impl Iterator<Item = KeysymProps> + use<'_> {
    table
        .lookup(group, modifiers, keycode)
        .with_caps_transform(false)
        .into_iter()
}

§Ctrl Transformation

If the remaining modifiers contain the ctrl modifier, the keysym iterator will automatically perform ctrl transformation. This transform only affects the produced characters but not the produced keysyms.

This behavior can be disabled by using Lookup::with_ctrl_transform and Lookup::set_ctrl_transform.

fn disable_ctrl_transform(
    table: &LookupTable,
    group: GroupIndex,
    modifiers: ModifierMask,
    keycode: Keycode,
) -> impl Iterator<Item = char> + use<'_> {
    table
        .lookup(group, modifiers, keycode)
        .with_ctrl_transform(false)
        .into_iter()
        .flat_map(|p| p.char())
}

Ctrl transformation applies the following modification:

let output = match input {
   b'@'..=b'~' => input & 0x1f,
   b' ' | b'2' => 0,
   b'3'..=b'7' => input - 0x1b,
   b'8' => 0x7f,
   b'/' => 0x1f,
   _ => input,
};

§Ctrl Transformation Fallback

If

  • the preconditions for ctrl transformation are met, and
  • the key press would otherwise produce a single keysym, and
  • that keysym has a value greater than 127, and
  • the key has another group that, when used with the same modifiers, would produce a single keysym less than or equal to 127,

then, instead of using the original keysym, the keysym form the first such group is used.

Caps and ctrl transformations are then applied to that keysym.

This is sometimes used to allow users of non-latin keyboard layouts to use latin keysyms in keyboard shortcuts.

This behavior can be disabled by using Lookup::with_ctrl_fallback and Lookup::set_ctrl_fallback.

fn disable_ctrl_fallback(
    table: &LookupTable,
    group: GroupIndex,
    modifiers: ModifierMask,
    keycode: Keycode,
) -> impl Iterator<Item = char> + use<'_> {
    table
        .lookup(group, modifiers, keycode)
        .with_ctrl_fallback(false)
        .into_iter()
        .flat_map(|p| p.char())
}

Implementations§

Source§

impl LookupTable

Source

pub fn lookup( &self, group: GroupIndex, mods: ModifierMask, keycode: Keycode, ) -> Lookup<'_>

Looks up the keysyms associated with a key press.

The group and mods should be the effective group and effective modifiers computed by the compositor.

In wayland, the effective modifiers are the bitwise OR of the pressed, latched, and locked modifiers. This can be managed with the Components type.

§Example

An application using the wayland-client crate might use this function as follows:

struct State {
    lookup_table: LookupTable,
    group: GroupIndex,
    mods: ModifierMask,
}

impl Dispatch<WlKeyboard, ()> for State {
    fn event(
        state: &mut State,
        _: &WlKeyboard,
        event: wl_keyboard::Event,
        _: &(),
        _: &Connection,
        _: &QueueHandle<State>,
    ) {
        use wl_keyboard::Event;
        match event {
            Event::Modifiers {
                mods_depressed, mods_latched, mods_locked, group, ..
            } => {
                state.group = GroupIndex(group);
                state.mods = ModifierMask(mods_depressed | mods_latched | mods_locked);
            }
            Event::Key { key, state: WEnum::Value(WlKeyState::Pressed), .. } => {
                let key = Keycode::from_evdev(key);
                for keysym in state.lookup_table.lookup(state.group, state.mods, key) {
                    println!("{keysym:?}");
                }
            }
            _ => { },
        }
    }
}
Source

pub fn effective_group( &self, group: GroupIndex, keycode: Keycode, ) -> Option<GroupIndex>

Returns the effective group that will be used for the keycode.

The group parameter should be the effective group computed by the compositor. This function will then return the effective group for the specific key.

These values can differ when the key has fewer groups than the maximum number of groups in the keymap. In this case, the effective group is calculated using the Redirect setting of the key.

Source

pub fn repeats(&self, keycode: Keycode) -> bool

Returns whether the key repeats.

Source§

impl LookupTable

Source

pub fn to_xkb_keymap(&self) -> Keymap

Creates a client-side XKB keymap from a lookup table.

The created keymap does not contain any actions. Clients trying to implement how-to-type logic will not be able to determine which key presses trigger which modifiers or groups.

The keymap will contain modmap entries mapping all keys producing Alt_L or Alt_R to Mod1.

§Example
let mut builder = Builder::default();
{
    let gt = GroupType::builder(ModifierMask::SHIFT)
        .map(ModifierMask::SHIFT, 1)
        .build();
    let mut gb = GroupBuilder::new(0, &gt);
    let mut level = LevelBuilder::new(0);
    level.keysyms(&[syms::a]);
    gb.add_level(level);
    let mut level = LevelBuilder::new(1);
    level.keysyms(&[syms::A]);
    gb.add_level(level);
    let mut key = KeyBuilder::new(Keycode::from_x11(9));
    key.repeats(true);
    key.add_group(gb);
    builder.add_key(key)
}
{
    let gt = GroupType::builder(ModifierMask::NONE).build();
    let mut level = LevelBuilder::new(0);
    level.keysyms(&[syms::Alt_L]);
    let mut gb = GroupBuilder::new(0, &gt);
    gb.add_level(level);
    let mut key = KeyBuilder::new(Keycode::from_x11(10));
    key.add_group(gb);
    builder.add_key(key)
}
let map = builder.build_lookup_table().to_xkb_keymap();
println!("{:#}", map.format());

Outputs

xkb_keymap {
    xkb_keycodes {
        minimum = 8;
        maximum = 255;

        indicator 1 = "DUMMY";

        <9> = 9;
        <10> = 10;
    };

    xkb_types {
        virtual_modifiers Dummy;

        type "type0" {
            modifiers = Shift;
            map[Shift] = Level2;
        };

        type "type1" {
            modifiers = None;
        };
    };

    xkb_compat {
        interpret VoidSymbol {
            repeat = false;
        };
    };

    xkb_symbols {
        modmap Mod1 { <10> };

        key.repeat = true;

        key <9> {
            type[Group1] = "type0",
            symbols[Group1] = [ a, A ]
        };
        key <10> {
            repeat = false,
            type[Group1] = "type1",
            symbols[Group1] = [ Alt_L ]
        };
    };
};

Trait Implementations§

Source§

impl Clone for LookupTable

Source§

fn clone(&self) -> LookupTable

Returns a copy of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for LookupTable

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dst: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dst. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.