winit/platform_impl/linux/x11/util/
xmodmap.rs

1use std::collections::HashSet;
2use std::slice;
3
4use 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
13const 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)]
17pub struct ModifierKeymap {
18    // Maps keycodes to modifiers
19    modifiers: HashSet<XKeyCode>,
20}
21
22impl 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}