summaryrefslogtreecommitdiff
path: root/src/keys.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/keys.rs')
-rw-r--r--src/keys.rs99
1 files changed, 46 insertions, 53 deletions
diff --git a/src/keys.rs b/src/keys.rs
index 07dfb40..21217b0 100644
--- a/src/keys.rs
+++ b/src/keys.rs
@@ -1,6 +1,6 @@
-use std::process::Command;
+use std::ops::RangeInclusive;
-use crate::{error::*, WM};
+use crate::{config::KEYBINDS, error::*, WM};
use xcb::{
x::{
GetKeyboardMapping, GetKeyboardMappingReply, GetModifierMapping, GrabKey, GrabMode,
@@ -11,8 +11,8 @@ use xcb::{
use xkeysym::{KeyCode, Keysym, RawKeyCode};
impl WM<'_> {
- /// Handles a key press event by dispatching according to [`self::KEYBINDS`]
- pub(crate) fn handle_key_press(&mut self, e: KeyPressEvent) -> Result<()> {
+ /// 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
};
@@ -27,8 +27,8 @@ impl WM<'_> {
Ok(())
}
- /// Handles a mapping notify event by updating our keyboard setup if needed.
- pub(crate) fn handle_mapping_notify(&mut self, e: MappingNotifyEvent) -> Result<()> {
+ /// Update our keyboard info when the mapping changes.
+ pub fn handle_mapping_notify(&mut self, e: MappingNotifyEvent) -> Result<()> {
if e.request() == Mapping::Keyboard {
self.grab_keys()?;
}
@@ -36,8 +36,8 @@ impl WM<'_> {
Ok(())
}
- /// Grab all keys specified by [`self::KEYBINDS`], ensuring we get events for them.
- pub(crate) fn grab_keys(&mut self) -> Result<()> {
+ /// 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)?;
@@ -81,9 +81,14 @@ impl WM<'_> {
/// Cached information about our keyboard layout.
pub struct KeyboardInfo {
- min_keycode: RawKeyCode,
- max_keycode: RawKeyCode,
+ /// 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,
}
@@ -99,20 +104,22 @@ impl KeyboardInfo {
}))?;
let mut this = Self {
- min_keycode: min_keycode as u32,
- max_keycode: max_keycode as u32,
+ keycodes: min_keycode as RawKeyCode..=max_keycode as RawKeyCode,
numlock_mask: ModMask::empty(),
mapping,
};
- let numlock_keycode = this.keysym_to_keycode(Keysym::Num_Lock)?;
+ 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 has unrecognised modifier");
+ ModMask::from_bits(1 << i).expect("x11 returned unrecognised modifier");
}
}
}
@@ -120,18 +127,16 @@ impl KeyboardInfo {
Ok(this)
}
- /// Get the modifier mask being used for numlock, which varies.
+ /// 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(crate) fn iter_keycodes_keysyms(&self) -> impl Iterator<Item = (KeyCode, Keysym)> + '_ {
+ pub fn iter_keycodes_keysyms(&self) -> impl Iterator<Item = (KeyCode, Keysym)> + '_ {
(0..self.mapping.keysyms_per_keycode())
- .flat_map(|shift| {
- (self.min_keycode..self.max_keycode).map(move |keycode| (shift, keycode))
- })
+ .flat_map(|shift| self.keycodes.clone().map(move |keycode| (shift, keycode)))
.flat_map(|(shift, keycode)| -> Option<_> {
Some((
keycode.into(),
@@ -140,21 +145,21 @@ impl KeyboardInfo {
})
}
- /// Lookup the first keycode which has the given keysym
- pub(crate) fn keysym_to_keycode(&self, keysym: Keysym) -> Result<KeyCode> {
+ /// 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.min_keycode..self.max_keycode {
- if self.mapping.keysyms()[(keycode as usize - self.min_keycode as usize)
+ 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 Ok(keycode.into());
+ return Some(keycode.into());
}
}
}
- Ok(KeyCode::new(0))
+ None
}
/// Lookup the keysym in the given column for the given keycode
@@ -162,43 +167,22 @@ impl KeyboardInfo {
xkeysym::keysym(
keycode,
col,
- self.min_keycode.into(),
+ (*self.keycodes.start()).into(),
self.mapping.keysyms_per_keycode(),
self.mapping.keysyms(),
)
}
}
-/// A bound key
+/// A key bound to some action
pub struct Keybind {
- modifiers: ModMask,
- key: Keysym,
- action: &'static dyn Fn(&mut WM<'_>),
-}
-
-impl std::fmt::Debug for Keybind {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.debug_struct("Keybind")
- .field("modifiers", &self.modifiers)
- .field("key", &self.key)
- .finish()
- }
+ pub modifiers: ModMask,
+ pub key: Keysym,
+ pub action: &'static dyn Fn(&mut WM<'_>),
}
-/// A set of keybinds. Currently, there is only one instance of this defined statically: [`self::KEYBINDS`].
-pub struct Keybinds(&'static [Keybind]);
-
-/// The keybinds to use.
-const KEYBINDS: Keybinds = Keybinds(&[Keybind {
- modifiers: ModMask::CONTROL,
- key: Keysym::t,
- action: &|_| {
- // TODO: disown this process, probably using another way to spawn commands
- if let Err(e) = Command::new("xterm").spawn() {
- dbg!(e);
- }
- },
-}]);
+/// A set of keybinds. Currently, there is only one instance of this defined statically: [`crate::config::KEYBINDS`].
+pub struct Keybinds(pub &'static [Keybind]);
impl Keybinds {
/// Get an iterator over all bound keys
@@ -216,3 +200,12 @@ impl Keybinds {
}
}
}
+
+impl std::fmt::Debug for Keybind {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("Keybind")
+ .field("modifiers", &self.modifiers)
+ .field("key", &self.key)
+ .finish()
+ }
+}