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