summaryrefslogtreecommitdiff
path: root/src/keys.rs
diff options
context:
space:
mode:
authortcmal <me@aria.rip>2024-06-21 19:13:12 +0100
committertcmal <me@aria.rip>2024-06-21 19:13:12 +0100
commit475253b7bcfd03a932c4b7efd969b3d2bf155035 (patch)
tree44789ce271d14c89cbff777e75f1e9ab6e1a5e64 /src/keys.rs
parentc3e98e34ed7d42ef4271339de88f7131e7647442 (diff)
refactor connection-related stuff out, make things a bit cleaner
Diffstat (limited to 'src/keys.rs')
-rw-r--r--src/keys.rs198
1 files changed, 50 insertions, 148 deletions
diff --git a/src/keys.rs b/src/keys.rs
index 21217b0..08cd46d 100644
--- a/src/keys.rs
+++ b/src/keys.rs
@@ -1,177 +1,79 @@
-use std::ops::RangeInclusive;
-
-use crate::{config::KEYBINDS, error::*, WM};
-use xcb::{
- x::{
- GetKeyboardMapping, GetKeyboardMappingReply, GetModifierMapping, GrabKey, GrabMode,
- KeyPressEvent, Mapping, MappingNotifyEvent, ModMask, UngrabKey, GRAB_ANY,
- },
- Connection,
+use crate::{config::KEYBINDS, conn_info::Connection, error::Result, WM};
+use xcb::x::{
+ GrabKey, GrabMode, KeyPressEvent, Mapping, MappingNotifyEvent, ModMask, UngrabKey, GRAB_ANY,
};
-use xkeysym::{KeyCode, Keysym, RawKeyCode};
+use xkeysym::Keysym;
impl WM<'_> {
/// Dispatch the given keypress event according to [`self::KEYBINDS`]
- pub fn handle_key_press(&mut self, e: KeyPressEvent) -> Result<()> {
- let Some(sym) = self.keyboard_state.keycode_to_keysym(e.detail().into(), 0) else {
- return Ok(()); // probably not bound
+ pub fn handle_key_press(&mut self, e: &KeyPressEvent) {
+ let Some(sym) = self
+ .conn
+ .keyboard_state
+ .keycode_to_keysym(e.detail().into(), 0)
+ else {
+ return; // probably not bound
};
KEYBINDS.dispatch(
self,
sym,
ModMask::from_bits_truncate(e.state().bits())
- .difference(self.keyboard_state.numlock_mask() | ModMask::LOCK),
+ .difference(self.conn.keyboard_state.numlock_mask() | ModMask::LOCK),
);
-
- Ok(())
}
/// Update our keyboard info when the mapping changes.
- pub fn handle_mapping_notify(&mut self, e: MappingNotifyEvent) -> Result<()> {
+ pub fn handle_mapping_notify(&mut self, e: &MappingNotifyEvent) -> Result<()> {
if e.request() == Mapping::Keyboard {
- self.grab_keys()?;
+ grab_keys(&mut self.conn)?;
}
Ok(())
}
-
- /// Refresh our keyboard info, and ensure that we get events for bound keys.
- pub fn grab_keys(&mut self) -> Result<()> {
- // Refresh keyboard state
- self.keyboard_state = KeyboardInfo::new_with(self.conn)?;
-
- // Ungrab all keys
- self.conn.send_request(&UngrabKey {
- key: GRAB_ANY,
- grab_window: self.root,
- modifiers: ModMask::ANY,
- });
-
- // Bind all of the keycodes which have keysyms we see in our binds.
- for (keycode, keysym) in self.keyboard_state.iter_keycodes_keysyms() {
- for bind in KEYBINDS.binds() {
- if bind.key == keysym {
- // grab key with any combination of modifiers
- for modmask in [
- ModMask::empty(),
- ModMask::LOCK,
- self.keyboard_state.numlock_mask(),
- self.keyboard_state.numlock_mask() | ModMask::LOCK,
- ] {
- self.conn.send_request(&GrabKey {
- grab_window: self.root,
- key: keycode.raw() as u8,
- modifiers: bind.modifiers | modmask,
- owner_events: true,
- pointer_mode: GrabMode::Async,
- keyboard_mode: GrabMode::Async,
- });
- }
- }
- }
- }
-
- // Ensure all requests succeeded
- self.conn.flush()?;
-
- Ok(())
- }
-}
-
-/// Cached information about our keyboard layout.
-pub struct KeyboardInfo {
- /// The range of keycodes used
- keycodes: RangeInclusive<RawKeyCode>,
-
- /// The ModMask corresponding to NumLock.
- /// This varies sometimes, and we need to know to ignore it.
- numlock_mask: ModMask,
-
- /// The mapping from keycodes to (multiple) key symbols
- mapping: GetKeyboardMappingReply,
}
-impl KeyboardInfo {
- /// Query information about the keyboard layout from the given connection.
- pub fn new_with(conn: &Connection) -> Result<Self> {
- let min_keycode = conn.get_setup().min_keycode();
- let max_keycode = conn.get_setup().max_keycode();
-
- let mapping = conn.wait_for_reply(conn.send_request(&GetKeyboardMapping {
- first_keycode: min_keycode,
- count: max_keycode - min_keycode + 1,
- }))?;
-
- let mut this = Self {
- keycodes: min_keycode as RawKeyCode..=max_keycode as RawKeyCode,
- numlock_mask: ModMask::empty(),
- mapping,
- };
-
- let Some(numlock_keycode) = this.keysym_to_keycode(Keysym::Num_Lock) else {
- // No numlock button, so no modmask for numlock
- return Ok(this);
- };
- let mod_map = conn.wait_for_reply(conn.send_request(&GetModifierMapping {}))?;
- let keypermod = mod_map.keycodes().len() / 8;
- for i in 0..8 {
- for j in 0..keypermod {
- if mod_map.keycodes()[i * keypermod + j] as u32 == numlock_keycode.raw() {
- this.numlock_mask =
- ModMask::from_bits(1 << i).expect("x11 returned unrecognised modifier");
+/// Refresh our keyboard info, and ensure that we get events for bound keys.
+fn grab_keys(conn: &mut Connection<'_>) -> Result<()> {
+ // Refresh keyboard state
+ conn.refresh_keyboard_info()?;
+
+ // Ungrab all keys
+ conn.send_request(&UngrabKey {
+ key: GRAB_ANY,
+ grab_window: conn.root(),
+ modifiers: ModMask::ANY,
+ });
+
+ // Bind all of the keycodes which have keysyms we see in our binds.
+ for (keycode, keysym) in conn.keyboard_state.iter_keycodes_keysyms() {
+ for bind in KEYBINDS.binds() {
+ if bind.key == keysym {
+ // grab key with any combination of modifiers
+ for modmask in [
+ ModMask::empty(),
+ ModMask::LOCK,
+ conn.keyboard_state.numlock_mask(),
+ conn.keyboard_state.numlock_mask() | ModMask::LOCK,
+ ] {
+ conn.send_request(&GrabKey {
+ grab_window: conn.root(),
+ #[allow(clippy::cast_possible_truncation)]
+ key: keycode.raw() as u8,
+ modifiers: bind.modifiers | modmask,
+ owner_events: true,
+ pointer_mode: GrabMode::Async,
+ keyboard_mode: GrabMode::Async,
+ });
}
}
}
-
- Ok(this)
- }
-
- /// Get the modifier mask being used for numlock
- pub fn numlock_mask(&self) -> ModMask {
- self.numlock_mask
}
- /// Iterate over all keycodes and their bound keysyms.
- /// This is likely to contain duplicate pairs.
- pub fn iter_keycodes_keysyms(&self) -> impl Iterator<Item = (KeyCode, Keysym)> + '_ {
- (0..self.mapping.keysyms_per_keycode())
- .flat_map(|shift| self.keycodes.clone().map(move |keycode| (shift, keycode)))
- .flat_map(|(shift, keycode)| -> Option<_> {
- Some((
- keycode.into(),
- self.keycode_to_keysym(keycode.into(), shift)?,
- ))
- })
- }
-
- /// Lookup the first keycode which has the given keysym in any column
- pub(crate) fn keysym_to_keycode(&self, keysym: Keysym) -> Option<KeyCode> {
- for shift in 0..self.mapping.keysyms_per_keycode() {
- for keycode in self.keycodes.clone() {
- if self.mapping.keysyms()[(keycode as usize - *self.keycodes.start() as usize)
- * self.mapping.keysyms_per_keycode() as usize
- + shift as usize]
- == keysym.raw()
- {
- return Some(keycode.into());
- }
- }
- }
-
- None
- }
+ // Ensure all requests succeeded
+ conn.flush()?;
- /// Lookup the keysym in the given column for the given keycode
- pub fn keycode_to_keysym(&self, keycode: KeyCode, col: u8) -> Option<Keysym> {
- xkeysym::keysym(
- keycode,
- col,
- (*self.keycodes.start()).into(),
- self.mapping.keysyms_per_keycode(),
- self.mapping.keysyms(),
- )
- }
+ Ok(())
}
/// A key bound to some action
@@ -206,6 +108,6 @@ impl std::fmt::Debug for Keybind {
f.debug_struct("Keybind")
.field("modifiers", &self.modifiers)
.field("key", &self.key)
- .finish()
+ .finish_non_exhaustive()
}
}