| 1 | use std::collections::HashSet; |
| 2 | use std::slice; |
| 3 | |
| 4 | use x11_dl::xlib::{KeyCode as XKeyCode, XModifierKeymap}; |
| 5 | |
| 6 | // Offsets within XModifierKeymap to each set of keycodes. |
| 7 | // We are only interested in Shift, Control, Alt, and Logo. |
| 8 | // |
| 9 | // There are 8 sets total. The order of keycode sets is: |
| 10 | // Shift, Lock, Control, Mod1 (Alt), Mod2, Mod3, Mod4 (Logo), Mod5 |
| 11 | // |
| 12 | // https://tronche.com/gui/x/xlib/input/XSetModifierMapping.html |
| 13 | const NUM_MODS: usize = 8; |
| 14 | |
| 15 | /// Track which keys are modifiers, so we can properly replay them when they were filtered. |
| 16 | #[derive (Debug, Default)] |
| 17 | pub struct ModifierKeymap { |
| 18 | // Maps keycodes to modifiers |
| 19 | modifiers: HashSet<XKeyCode>, |
| 20 | } |
| 21 | |
| 22 | impl ModifierKeymap { |
| 23 | pub fn new() -> ModifierKeymap { |
| 24 | ModifierKeymap::default() |
| 25 | } |
| 26 | |
| 27 | pub fn is_modifier(&self, keycode: XKeyCode) -> bool { |
| 28 | self.modifiers.contains(&keycode) |
| 29 | } |
| 30 | |
| 31 | pub fn reload_from_x_connection(&mut self, xconn: &super::XConnection) { |
| 32 | unsafe { |
| 33 | let keymap = (xconn.xlib.XGetModifierMapping)(xconn.display); |
| 34 | |
| 35 | if keymap.is_null() { |
| 36 | return; |
| 37 | } |
| 38 | |
| 39 | self.reset_from_x_keymap(&*keymap); |
| 40 | |
| 41 | (xconn.xlib.XFreeModifiermap)(keymap); |
| 42 | } |
| 43 | } |
| 44 | |
| 45 | fn reset_from_x_keymap(&mut self, keymap: &XModifierKeymap) { |
| 46 | let keys_per_mod = keymap.max_keypermod as usize; |
| 47 | |
| 48 | let keys = unsafe { |
| 49 | slice::from_raw_parts(keymap.modifiermap as *const _, keys_per_mod * NUM_MODS) |
| 50 | }; |
| 51 | self.modifiers.clear(); |
| 52 | for key in keys { |
| 53 | self.modifiers.insert(*key); |
| 54 | } |
| 55 | } |
| 56 | } |
| 57 | |