veridian_kernel/desktop/desktop_ext/
shortcuts.rs1#[cfg(feature = "alloc")]
6use alloc::{collections::BTreeMap, vec::Vec};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
10pub struct ModifierMask(pub u8);
11
12impl ModifierMask {
13 pub const NONE: Self = Self(0);
14 pub const CTRL: Self = Self(1 << 0);
15 pub const ALT: Self = Self(1 << 1);
16 pub const SUPER: Self = Self(1 << 2);
17 pub const SHIFT: Self = Self(1 << 3);
18
19 pub fn has(self, modifier: Self) -> bool {
21 (self.0 & modifier.0) == modifier.0
22 }
23
24 pub fn combine(self, other: Self) -> Self {
26 Self(self.0 | other.0)
27 }
28
29 pub fn remove(self, modifier: Self) -> Self {
31 Self(self.0 & !modifier.0)
32 }
33
34 pub fn is_empty(self) -> bool {
36 self.0 == 0
37 }
38}
39
40pub type KeyCode = u8;
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45pub enum ShortcutAction {
46 LaunchLauncher,
48 LaunchTerminal,
50 LaunchFileManager,
52 CloseWindow,
54 MinimizeWindow,
56 MaximizeWindow,
58 ToggleFullscreen,
60 SwitchWorkspace(u8),
62 MoveToWorkspace(u8),
64 SwitchNextWindow,
66 SwitchPrevWindow,
68 Screenshot,
70 ScreenshotWindow,
72 LockScreen,
74 Logout,
76 SnapLeft,
78 SnapRight,
80 Copy,
82 Paste,
84 Cut,
86 Undo,
88 Redo,
90 Custom(u16),
92}
93
94#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
96pub enum ShortcutPriority {
97 System = 3,
99 Desktop = 2,
101 Application = 1,
103 #[default]
105 User = 0,
106}
107
108#[derive(Debug, Clone, Copy, PartialEq, Eq)]
110pub struct KeyBinding {
111 pub modifiers: ModifierMask,
113 pub key: KeyCode,
115 pub action: ShortcutAction,
117 pub priority: ShortcutPriority,
119 pub enabled: bool,
121}
122
123impl KeyBinding {
124 pub fn new(modifiers: ModifierMask, key: KeyCode, action: ShortcutAction) -> Self {
126 Self {
127 modifiers,
128 key,
129 action,
130 priority: ShortcutPriority::User,
131 enabled: true,
132 }
133 }
134
135 pub fn with_priority(mut self, priority: ShortcutPriority) -> Self {
137 self.priority = priority;
138 self
139 }
140
141 pub fn matches(&self, modifiers: ModifierMask, key: KeyCode) -> bool {
143 self.enabled && self.modifiers == modifiers && self.key == key
144 }
145}
146
147const MAX_SHORTCUTS: usize = 128;
149
150#[derive(Debug)]
152#[cfg(feature = "alloc")]
153pub struct ShortcutManager {
154 bindings: Vec<KeyBinding>,
156 enabled: bool,
158 next_id: u32,
160 id_map: BTreeMap<u32, usize>,
162}
163
164#[cfg(feature = "alloc")]
165impl Default for ShortcutManager {
166 fn default() -> Self {
167 Self::new()
168 }
169}
170
171#[cfg(feature = "alloc")]
172impl ShortcutManager {
173 pub fn new() -> Self {
175 let mut mgr = Self {
176 bindings: Vec::new(),
177 enabled: true,
178 next_id: 0,
179 id_map: BTreeMap::new(),
180 };
181 mgr.register_defaults();
182 mgr
183 }
184
185 fn register_defaults(&mut self) {
187 self.register(
189 KeyBinding::new(ModifierMask::ALT, 0x0F, ShortcutAction::SwitchNextWindow)
190 .with_priority(ShortcutPriority::System),
191 );
192 self.register(
194 KeyBinding::new(
195 ModifierMask(ModifierMask::CTRL.0 | ModifierMask::ALT.0),
196 0x26,
197 ShortcutAction::LockScreen,
198 )
199 .with_priority(ShortcutPriority::System),
200 );
201 self.register(
203 KeyBinding::new(ModifierMask::SUPER, 0xDB, ShortcutAction::LaunchLauncher)
204 .with_priority(ShortcutPriority::Desktop),
205 );
206 self.register(
208 KeyBinding::new(ModifierMask::CTRL, 0x2E, ShortcutAction::Copy)
209 .with_priority(ShortcutPriority::Application),
210 );
211 self.register(
213 KeyBinding::new(ModifierMask::CTRL, 0x2F, ShortcutAction::Paste)
214 .with_priority(ShortcutPriority::Application),
215 );
216 self.register(
218 KeyBinding::new(ModifierMask::CTRL, 0x2D, ShortcutAction::Cut)
219 .with_priority(ShortcutPriority::Application),
220 );
221 self.register(
223 KeyBinding::new(ModifierMask::ALT, 0x3E, ShortcutAction::CloseWindow)
224 .with_priority(ShortcutPriority::Desktop),
225 );
226 self.register(
228 KeyBinding::new(ModifierMask::NONE, 0xB7, ShortcutAction::Screenshot)
229 .with_priority(ShortcutPriority::System),
230 );
231 }
232
233 pub fn register(&mut self, binding: KeyBinding) -> u32 {
235 let id = self.next_id;
236 self.next_id += 1;
237
238 if self.bindings.len() < MAX_SHORTCUTS {
239 self.id_map.insert(id, self.bindings.len());
240 self.bindings.push(binding);
241 }
242
243 id
244 }
245
246 pub fn unregister(&mut self, id: u32) -> bool {
248 if let Some(&index) = self.id_map.get(&id) {
249 if index < self.bindings.len() {
250 self.bindings.remove(index);
251 self.id_map.remove(&id);
252 let mut new_map = BTreeMap::new();
254 for (&k, &v) in &self.id_map {
255 if v > index {
256 new_map.insert(k, v - 1);
257 } else {
258 new_map.insert(k, v);
259 }
260 }
261 self.id_map = new_map;
262 return true;
263 }
264 }
265 false
266 }
267
268 pub fn process_key(&self, modifiers: ModifierMask, key: KeyCode) -> Option<ShortcutAction> {
271 if !self.enabled {
272 return None;
273 }
274
275 self.bindings
276 .iter()
277 .filter(|b| b.matches(modifiers, key))
278 .max_by_key(|b| b.priority)
279 .map(|b| b.action)
280 }
281
282 pub fn set_enabled(&mut self, enabled: bool) {
284 self.enabled = enabled;
285 }
286
287 pub fn is_enabled(&self) -> bool {
289 self.enabled
290 }
291
292 pub fn binding_count(&self) -> usize {
294 self.bindings.len()
295 }
296
297 pub fn bindings_for_action(&self, action: ShortcutAction) -> Vec<&KeyBinding> {
299 self.bindings
300 .iter()
301 .filter(|b| b.action == action)
302 .collect()
303 }
304
305 pub fn set_binding_enabled(&mut self, id: u32, enabled: bool) -> bool {
307 if let Some(&index) = self.id_map.get(&id) {
308 if let Some(binding) = self.bindings.get_mut(index) {
309 binding.enabled = enabled;
310 return true;
311 }
312 }
313 false
314 }
315}