1 use std::{collections::HashMap, slice};
2 
3 use super::*;
4 
5 use crate::event::{ElementState, ModifiersState};
6 
7 // Offsets within XModifierKeymap to each set of keycodes.
8 // We are only interested in Shift, Control, Alt, and Logo.
9 //
10 // There are 8 sets total. The order of keycode sets is:
11 //     Shift, Lock, Control, Mod1 (Alt), Mod2, Mod3, Mod4 (Logo), Mod5
12 //
13 // https://tronche.com/gui/x/xlib/input/XSetModifierMapping.html
14 const SHIFT_OFFSET: usize = 0;
15 const CONTROL_OFFSET: usize = 2;
16 const ALT_OFFSET: usize = 3;
17 const LOGO_OFFSET: usize = 6;
18 const NUM_MODS: usize = 8;
19 
20 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
21 pub enum Modifier {
22     Alt,
23     Ctrl,
24     Shift,
25     Logo,
26 }
27 
28 #[derive(Debug, Default)]
29 pub struct ModifierKeymap {
30     // Maps keycodes to modifiers
31     keys: HashMap<ffi::KeyCode, Modifier>,
32 }
33 
34 #[derive(Clone, Debug, Default)]
35 pub struct ModifierKeyState {
36     // Contains currently pressed modifier keys and their corresponding modifiers
37     keys: HashMap<ffi::KeyCode, Modifier>,
38     state: ModifiersState,
39 }
40 
41 impl ModifierKeymap {
new() -> ModifierKeymap42     pub fn new() -> ModifierKeymap {
43         ModifierKeymap::default()
44     }
45 
get_modifier(&self, keycode: ffi::KeyCode) -> Option<Modifier>46     pub fn get_modifier(&self, keycode: ffi::KeyCode) -> Option<Modifier> {
47         self.keys.get(&keycode).cloned()
48     }
49 
reset_from_x_connection(&mut self, xconn: &XConnection)50     pub fn reset_from_x_connection(&mut self, xconn: &XConnection) {
51         unsafe {
52             let keymap = (xconn.xlib.XGetModifierMapping)(xconn.display);
53 
54             if keymap.is_null() {
55                 panic!("failed to allocate XModifierKeymap");
56             }
57 
58             self.reset_from_x_keymap(&*keymap);
59 
60             (xconn.xlib.XFreeModifiermap)(keymap);
61         }
62     }
63 
reset_from_x_keymap(&mut self, keymap: &ffi::XModifierKeymap)64     pub fn reset_from_x_keymap(&mut self, keymap: &ffi::XModifierKeymap) {
65         let keys_per_mod = keymap.max_keypermod as usize;
66 
67         let keys = unsafe {
68             slice::from_raw_parts(keymap.modifiermap as *const _, keys_per_mod * NUM_MODS)
69         };
70 
71         self.keys.clear();
72 
73         self.read_x_keys(keys, SHIFT_OFFSET, keys_per_mod, Modifier::Shift);
74         self.read_x_keys(keys, CONTROL_OFFSET, keys_per_mod, Modifier::Ctrl);
75         self.read_x_keys(keys, ALT_OFFSET, keys_per_mod, Modifier::Alt);
76         self.read_x_keys(keys, LOGO_OFFSET, keys_per_mod, Modifier::Logo);
77     }
78 
read_x_keys( &mut self, keys: &[ffi::KeyCode], offset: usize, keys_per_mod: usize, modifier: Modifier, )79     fn read_x_keys(
80         &mut self,
81         keys: &[ffi::KeyCode],
82         offset: usize,
83         keys_per_mod: usize,
84         modifier: Modifier,
85     ) {
86         let start = offset * keys_per_mod;
87         let end = start + keys_per_mod;
88 
89         for &keycode in &keys[start..end] {
90             if keycode != 0 {
91                 self.keys.insert(keycode, modifier);
92             }
93         }
94     }
95 }
96 
97 impl ModifierKeyState {
update_keymap(&mut self, mods: &ModifierKeymap)98     pub fn update_keymap(&mut self, mods: &ModifierKeymap) {
99         self.keys.retain(|k, v| {
100             if let Some(m) = mods.get_modifier(*k) {
101                 *v = m;
102                 true
103             } else {
104                 false
105             }
106         });
107 
108         self.reset_state();
109     }
110 
update_state( &mut self, state: &ModifiersState, except: Option<Modifier>, ) -> Option<ModifiersState>111     pub fn update_state(
112         &mut self,
113         state: &ModifiersState,
114         except: Option<Modifier>,
115     ) -> Option<ModifiersState> {
116         let mut new_state = *state;
117 
118         match except {
119             Some(Modifier::Alt) => new_state.set(ModifiersState::ALT, self.state.alt()),
120             Some(Modifier::Ctrl) => new_state.set(ModifiersState::CTRL, self.state.ctrl()),
121             Some(Modifier::Shift) => new_state.set(ModifiersState::SHIFT, self.state.shift()),
122             Some(Modifier::Logo) => new_state.set(ModifiersState::LOGO, self.state.logo()),
123             None => (),
124         }
125 
126         if self.state == new_state {
127             None
128         } else {
129             self.keys.retain(|_k, v| get_modifier(&new_state, *v));
130             self.state = new_state;
131             Some(new_state)
132         }
133     }
134 
modifiers(&self) -> ModifiersState135     pub fn modifiers(&self) -> ModifiersState {
136         self.state
137     }
138 
key_event(&mut self, state: ElementState, keycode: ffi::KeyCode, modifier: Modifier)139     pub fn key_event(&mut self, state: ElementState, keycode: ffi::KeyCode, modifier: Modifier) {
140         match state {
141             ElementState::Pressed => self.key_press(keycode, modifier),
142             ElementState::Released => self.key_release(keycode),
143         }
144     }
145 
key_press(&mut self, keycode: ffi::KeyCode, modifier: Modifier)146     pub fn key_press(&mut self, keycode: ffi::KeyCode, modifier: Modifier) {
147         self.keys.insert(keycode, modifier);
148 
149         set_modifier(&mut self.state, modifier, true);
150     }
151 
key_release(&mut self, keycode: ffi::KeyCode)152     pub fn key_release(&mut self, keycode: ffi::KeyCode) {
153         if let Some(modifier) = self.keys.remove(&keycode) {
154             if self.keys.values().find(|&&m| m == modifier).is_none() {
155                 set_modifier(&mut self.state, modifier, false);
156             }
157         }
158     }
159 
reset_state(&mut self)160     fn reset_state(&mut self) {
161         let mut new_state = ModifiersState::default();
162 
163         for &m in self.keys.values() {
164             set_modifier(&mut new_state, m, true);
165         }
166 
167         self.state = new_state;
168     }
169 }
170 
get_modifier(state: &ModifiersState, modifier: Modifier) -> bool171 fn get_modifier(state: &ModifiersState, modifier: Modifier) -> bool {
172     match modifier {
173         Modifier::Alt => state.alt(),
174         Modifier::Ctrl => state.ctrl(),
175         Modifier::Shift => state.shift(),
176         Modifier::Logo => state.logo(),
177     }
178 }
179 
set_modifier(state: &mut ModifiersState, modifier: Modifier, value: bool)180 fn set_modifier(state: &mut ModifiersState, modifier: Modifier, value: bool) {
181     match modifier {
182         Modifier::Alt => state.set(ModifiersState::ALT, value),
183         Modifier::Ctrl => state.set(ModifiersState::CTRL, value),
184         Modifier::Shift => state.set(ModifiersState::SHIFT, value),
185         Modifier::Logo => state.set(ModifiersState::LOGO, value),
186     }
187 }
188