summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortcmal <me@aria.rip>2024-06-04 22:06:07 +0100
committertcmal <me@aria.rip>2024-06-04 22:06:07 +0100
commite993ab6e41738c50eb64fc644be1bf49ca069f78 (patch)
treedd46335627f1910e2d71353074929ab2bec96986
parent543c0e4c1f4f20b1d987c91d610e869e1f68ecf4 (diff)
grab all keys when needed
-rw-r--r--src/keys.rs119
-rw-r--r--src/main.rs2
2 files changed, 117 insertions, 4 deletions
diff --git a/src/keys.rs b/src/keys.rs
index 6cf28a6..08dd056 100644
--- a/src/keys.rs
+++ b/src/keys.rs
@@ -1,12 +1,125 @@
use crate::{error::*, WM};
-use xcb::x::{KeyPressEvent, MappingNotifyEvent};
+use xcb::x::{
+ GetKeyboardMapping, GetModifierMapping, GrabKey, GrabMode, KeyPressEvent, Keycode, Keysym,
+ Mapping, MappingNotifyEvent, ModMask, UngrabKey, GRAB_ANY,
+};
+
+// https://github.com/D-Programming-Deimos/libX11/blob/master/c/X11/keysymdef.h
+const KEYSYM_NUMLOCK: Keysym = 0xff7f;
impl WM<'_> {
pub(crate) fn handle_key_press(&mut self, e: KeyPressEvent) -> Result<()> {
- todo!()
+ dbg!(e);
+
+ Ok(())
}
pub(crate) fn handle_mapping_notify(&mut self, e: MappingNotifyEvent) -> Result<()> {
- todo!()
+ if e.request() == Mapping::Keyboard {
+ self.grabkeys()?;
+ }
+
+ Ok(())
+ }
+
+ pub(crate) fn grabkeys(&self) -> Result<()> {
+ let numlock_mask = self.get_numlock_mask()?;
+
+ // ungrab all keys
+ self.conn.send_request(&UngrabKey {
+ key: GRAB_ANY,
+ grab_window: self.root,
+ modifiers: ModMask::ANY,
+ });
+
+ // go through keymap and grab what we need
+ let (min_keycode, max_keycode) = (
+ self.conn.get_setup().min_keycode(),
+ self.conn.get_setup().max_keycode(),
+ );
+ let mapping = self
+ .conn
+ .wait_for_reply(self.conn.send_request(&GetKeyboardMapping {
+ first_keycode: min_keycode,
+ count: max_keycode - min_keycode + 1,
+ }))?;
+
+ for shift in 0..mapping.keysyms_per_keycode() {
+ for keycode in min_keycode..max_keycode {
+ let keysym = mapping.keysyms()
+ [(shift as usize * mapping.keysyms_per_keycode() as usize + keycode as usize)];
+ if true {
+ // todo: is bound
+ // grab key with any combination of modifiers
+ for modmask in [
+ ModMask::empty(),
+ ModMask::LOCK,
+ numlock_mask,
+ numlock_mask | ModMask::LOCK,
+ ] {
+ self.conn.send_request(&GrabKey {
+ grab_window: self.root,
+ key: keycode,
+ modifiers: modmask,
+ owner_events: true,
+ pointer_mode: GrabMode::Async,
+ keyboard_mode: GrabMode::Async,
+ });
+ }
+ }
+ }
+ }
+
+ // ensure all requests succeeded
+ self.conn.flush()?;
+
+ Ok(())
+ }
+
+ pub(crate) fn get_numlock_mask(&self) -> Result<ModMask> {
+ let map = self
+ .conn
+ .wait_for_reply(self.conn.send_request(&GetModifierMapping {}))?;
+ let numlock_keycode = self.keysym_to_keycode(KEYSYM_NUMLOCK)?;
+
+ let keypermod = map.keycodes().len() / 8;
+ for i in 0..8 {
+ for j in 0..keypermod {
+ if map.keycodes()[(i * keypermod + j) as usize] == numlock_keycode {
+ return Ok(ModMask::from_bits(1 << i).expect("x11 has unrecognised modifier"));
+ }
+ }
+ }
+
+ // todo: is this ok?
+ return Ok(ModMask::empty());
+ }
+
+ pub(crate) fn keysym_to_keycode(&self, keysym: Keysym) -> Result<Keycode> {
+ let (min_keycode, max_keycode) = (
+ self.conn.get_setup().min_keycode(),
+ self.conn.get_setup().max_keycode(),
+ );
+ let mapping = self
+ .conn
+ .wait_for_reply(self.conn.send_request(&GetKeyboardMapping {
+ first_keycode: min_keycode,
+ count: max_keycode - min_keycode + 1,
+ }))?;
+
+ // todo: apparently there's an optimisation here https://github.com/ArcherPergande/xcbkeys/blob/main/xcbkeys.h
+ for shift in 0..mapping.keysyms_per_keycode() {
+ for keycode in min_keycode..max_keycode {
+ if mapping.keysyms()
+ [keycode as usize * mapping.keysyms_per_keycode() as usize + shift as usize]
+ == keysym
+ {
+ return Ok(keycode);
+ }
+ }
+ }
+
+ // todo: is this right?
+ return Ok(0);
}
}
diff --git a/src/main.rs b/src/main.rs
index c2b32a0..f61f422 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -89,7 +89,7 @@ impl WM<'_> {
],
}))?;
- // TODO: grab keys
+ self.grabkeys()?;
// TODO: reset focus