use super::{XError, raw};
use crate::{Bitwise, Key, KeyDead, KeyMod, KeyMods, KeyPad, KeyState, is};
#[doc = crate::_doc_location!("sys/device/display/x11")]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) struct KeyRepeatFilter {
last_keycode: u8,
repeating: bool,
}
#[rustfmt::skip]
impl KeyRepeatFilter {
pub const fn new() -> Self { Self { last_keycode: 0, repeating: false } }
#[inline(always)]
pub fn filter(&mut self, keycode: u8, is_press: bool) -> KeyState {
if is_press {
is![self.repeating && self.last_keycode == keycode, return KeyState::Repeat];
self.last_keycode = keycode;
self.repeating = true;
KeyState::Press
} else {
self.repeating = false;
KeyState::Release
}
}
}
#[doc = crate::_doc_location!("sys/device/display/x11")]
#[derive(Debug)]
pub(crate) struct XkbKeyInfo {
pub(crate) semantic: Key,
pub(crate) physical: Key,
pub(crate) mods: KeyMods,
}
impl XkbKeyInfo {
#[inline(always)]
pub fn new(semantic: Key, physical: Key, mods: KeyMods) -> Self {
Self { semantic, physical, mods }
}
}
#[doc = crate::_doc_location!("sys/device/display/x11")]
#[derive(Debug)]
pub(crate) struct XkbState {
#[allow(dead_code, reason = "appears unused, but must outlive `keymap` and `state`")]
ctx: *mut raw::xkb_context,
keymap: *mut raw::xkb_keymap,
pub(crate) state: *mut raw::xkb_state,
}
#[rustfmt::skip]
impl XkbState {
pub fn new(conn: *mut raw::xcb_connection_t) -> Result<Self, XError> {
let ctx = unsafe { raw::xkb_context_new(0) };
is![ctx.is_null(), return Err(XError::ExtensionUnavailable("xkb-context"))];
let device_id = unsafe { raw::xkb_x11_get_core_keyboard_device_id(conn) };
is![device_id < 0, return Err(XError::ExtensionUnavailable("xkb-core-keyboard"))];
let keymap = unsafe { raw::xkb_x11_keymap_new_from_device(ctx, conn, device_id, 0) };
is![keymap.is_null(), return Err(XError::ExtensionUnavailable("xkb-keymap"))];
let state = unsafe { raw::xkb_x11_state_new_from_device(keymap, conn, device_id) };
if state.is_null() {
unsafe { raw::xkb_keymap_unref(keymap) };
return Err(XError::ExtensionUnavailable("xkb-state"));
}
Ok(Self { ctx, keymap, state })
}
pub fn update(&self, keycode: u8, dir: raw::xkb_key_direction ) {
unsafe { raw::xkb_state_update_key(self.state, keycode as u32, dir); }
}
pub fn translate_key(&self, keycode: u8, mods: u16) -> XkbKeyInfo {
XkbKeyInfo::new(self.key_semantic(keycode), self.key_physical(keycode), self.key_mods(mods))
}
pub fn key_mods(&self, xcb_modifiers: u16) -> KeyMods {
let (x, mut m) = (Bitwise(xcb_modifiers), KeyMods::empty());
is![x.is_set_mask(raw::XCB_MOD_MASK_SHIFT), m.set_shift()];
is![x.is_set_mask(raw::XCB_MOD_MASK_CONTROL), m.set_control()];
is![x.is_set_mask(raw::XCB_MOD_MASK_LOCK), m.set_caps_lock()];
is![x.is_set_mask(raw::XCB_MOD_MASK_1), m.set_alt()];
is![x.is_set_mask(raw::XCB_MOD_MASK_2), m.set_num_lock()];
is![x.is_set_mask(raw::XCB_MOD_MASK_4), m.set_super()];
is![x.is_set_mask(raw::XCB_MOD_MASK_4), m.set_alt_gr()];
m
}
#[inline(always)]
pub fn key_semantic(&self, keycode: u8) -> Key {
let sym = unsafe { raw::xkb_state_key_get_one_sym(self.state, keycode as u32) };
if let Some(key) = Self::map_special_keys(sym) { return key; }
let utf32 = unsafe { raw::xkb_state_key_get_utf32(self.state, keycode as u32) };
if utf32 != 0 {
#[cfg(any(feature = "safe_sys", not(feature = "unsafe_str")))]
return Key::Char(char::from_u32(utf32).expect("valid unicode scalar"));
#[cfg(all(not(feature = "safe_sys"), feature = "unsafe_str"))]
unsafe { return Key::Char(char::from_u32_unchecked(utf32)); }
}
Key::Unknown
}
#[inline(always)]
pub fn key_physical(&self, keycode: u8) -> Key {
let scancode = keycode.saturating_sub(8) as u32;
Self::map_scancode_to_key(scancode)
}
#[inline(always)]
const fn map_special_keys(sym: u32) -> Option<Key> {
let k = match sym {
raw::XKB_KEY_Return => Key::Enter,
raw::XKB_KEY_Tab => Key::Tab,
raw::XKB_KEY_BackSpace => Key::Backspace,
raw::XKB_KEY_Escape => Key::Escape,
raw::XKB_KEY_Delete => Key::Delete,
raw::XKB_KEY_KP_Delete => Key::Delete,
raw::XKB_KEY_Insert => Key::Insert,
raw::XKB_KEY_KP_Insert => Key::Insert,
raw::XKB_KEY_Left => Key::Left,
raw::XKB_KEY_Right => Key::Right,
raw::XKB_KEY_Up => Key::Up,
raw::XKB_KEY_Down => Key::Down,
raw::XKB_KEY_Home => Key::Home,
raw::XKB_KEY_End => Key::End,
raw::XKB_KEY_Page_Up => Key::PageUp,
raw::XKB_KEY_Page_Down => Key::PageDown,
raw::XKB_KEY_Num_Lock => Key::NumLock,
raw::XKB_KEY_Caps_Lock => Key::CapsLock,
raw::XKB_KEY_Scroll_Lock => Key::ScrollLock,
0xfe50 ..= 0xfe93 => Key::Dead(KeyDead::from_keysym(sym)),
raw::XKB_KEY_Shift_L => Key::Mod(KeyMod::LeftShift),
raw::XKB_KEY_Shift_R => Key::Mod(KeyMod::RightShift),
raw::XKB_KEY_Control_L => Key::Mod(KeyMod::LeftControl),
raw::XKB_KEY_Control_R => Key::Mod(KeyMod::RightControl),
raw::XKB_KEY_Alt_L => Key::Mod(KeyMod::LeftAlt),
raw::XKB_KEY_Alt_R => Key::Mod(KeyMod::RightAlt),
raw::XKB_KEY_Super_L => Key::Mod(KeyMod::LeftSuper),
raw::XKB_KEY_Super_R => Key::Mod(KeyMod::RightSuper),
0xfe03..=0xfe05 => Key::Mod(KeyMod::IsoLevel3Shift),
raw::XKB_KEY_Mode_switch => Key::Mod(KeyMod::AltGr),
0xfe11..=0xfe13 => Key::Mod(KeyMod::IsoLevel5Shift),
sym if (sym >= raw::XKB_KEY_F1 && sym <= raw::XKB_KEY_F35) => {
let n = (sym - raw::XKB_KEY_F1 + 1) as u8;
Key::Fn(n)
}
raw::XKB_KEY_KP_0 => Key::Pad(KeyPad::Num0),
raw::XKB_KEY_KP_1 => Key::Pad(KeyPad::Num1),
raw::XKB_KEY_KP_2 => Key::Pad(KeyPad::Num2),
raw::XKB_KEY_KP_3 => Key::Pad(KeyPad::Num3),
raw::XKB_KEY_KP_4 => Key::Pad(KeyPad::Num4),
raw::XKB_KEY_KP_5 => Key::Pad(KeyPad::Num5),
raw::XKB_KEY_KP_6 => Key::Pad(KeyPad::Num6),
raw::XKB_KEY_KP_7 => Key::Pad(KeyPad::Num7),
raw::XKB_KEY_KP_8 => Key::Pad(KeyPad::Num8),
raw::XKB_KEY_KP_9 => Key::Pad(KeyPad::Num9),
raw::XKB_KEY_KP_Add => Key::Pad(KeyPad::Add),
raw::XKB_KEY_KP_Subtract => Key::Pad(KeyPad::Subtract),
raw::XKB_KEY_KP_Multiply => Key::Pad(KeyPad::Multiply),
raw::XKB_KEY_KP_Divide => Key::Pad(KeyPad::Divide),
raw::XKB_KEY_KP_Enter => Key::Pad(KeyPad::Enter),
raw::XKB_KEY_KP_Equal => Key::Pad(KeyPad::Equal),
raw::XKB_KEY_KP_Separator => Key::Pad(KeyPad::Comma),
raw::XKB_KEY_KP_Decimal => Key::Pad(KeyPad::Decimal),
_ => return None,
};
Some(k)
}
#[inline(always)]
const fn map_scancode_to_key(sc: u32) -> Key {
raw::LUT_SCANCODE_TO_KEY[sc as usize]
}
}
impl Drop for XkbState {
fn drop(&mut self) {
unsafe {
raw::xkb_state_unref(self.state);
raw::xkb_keymap_unref(self.keymap);
}
}
}