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 | modifers: 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.modifers.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.modifers.clear(); |
52 | for key in keys { |
53 | self.modifers.insert(*key); |
54 | } |
55 | } |
56 | } |
57 | |