⎇ 3e2777540f992e839c6bbf93e21452062d183f66
crates/modules/mirada/mirada-brain/src/action.rs
Historia
Quién tocó qué
crudo
feat(mirada): mirada-brain — orquestador de escritorio del compositor
1//! Acciones de escritorio y su mapa de teclas por defecto.
2//!
3//! Una [`DesktopAction`] es una orden de alto nivel del usuario, ya
4//! desligada de la tecla concreta: el [`Desktop`](crate::Desktop) las
5//! aplica sin saber qué combinación las disparó.
6
7use mirada_layout::LayoutMode;
8
9/// Número de escritorios virtuales que mantiene el `Desktop`.
10pub const WORKSPACE_COUNT: usize = 9;
11
12/// Una orden de escritorio de alto nivel.
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum DesktopAction {
15 /// Mueve el foco a la ventana siguiente del escritorio activo.
16 FocusNext,
17 /// Mueve el foco a la ventana anterior.
18 FocusPrev,
19 /// Adelanta la ventana enfocada en el orden de teselado.
20 MoveForward,
21 /// Atrasa la ventana enfocada en el orden de teselado.
22 MoveBackward,
23 /// Cierra la ventana enfocada (cierre ordenado).
24 CloseFocused,
25 /// Pasa al siguiente modo de teselado.
26 CycleLayout,
27 /// Fija un modo de teselado concreto.
28 SetLayout(LayoutMode),
29 /// Activa el escritorio virtual `n` (índice 0-based).
30 SwitchWorkspace(usize),
31 /// Manda la ventana enfocada al escritorio virtual `n`.
32 SendToWorkspace(usize),
33 /// Apaga el compositor.
34 Quit,
35}
36
37/// Mapa de teclas por defecto, estilo *tiling WM* (modificador `Super`).
38///
39/// Las cadenas deben coincidir literalmente con las que el Cuerpo emite
40/// en [`BodyEvent::Keybind`](mirada_protocol::BodyEvent::Keybind); son
41/// también las que se registran con
42/// [`BrainCommand::GrabKeys`](mirada_protocol::BrainCommand::GrabKeys).
43pub fn default_keymap() -> Vec<(String, DesktopAction)> {
44 let mut map = vec![
45 ("Super+j".into(), DesktopAction::FocusNext),
46 ("Super+k".into(), DesktopAction::FocusPrev),
47 ("Super+Shift+j".into(), DesktopAction::MoveForward),
48 ("Super+Shift+k".into(), DesktopAction::MoveBackward),
49 ("Super+q".into(), DesktopAction::CloseFocused),
50 ("Super+space".into(), DesktopAction::CycleLayout),
51 ("Super+t".into(), DesktopAction::SetLayout(LayoutMode::MasterStack)),
52 ("Super+m".into(), DesktopAction::SetLayout(LayoutMode::Monocle)),
53 ("Super+g".into(), DesktopAction::SetLayout(LayoutMode::Grid)),
54 ("Super+c".into(), DesktopAction::SetLayout(LayoutMode::Columns)),
55 ("Super+Shift+e".into(), DesktopAction::Quit),
56 ];
57 // Un escritorio por dígito: `Super+1`..`Super+9` lo activan,
58 // `Super+Shift+1`.. mandan la ventana enfocada allí.
59 for n in 0..WORKSPACE_COUNT {
60 map.push((format!("Super+{}", n + 1), DesktopAction::SwitchWorkspace(n)));
61 map.push((
62 format!("Super+Shift+{}", n + 1),
63 DesktopAction::SendToWorkspace(n),
64 ));
65 }
66 map
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72
73 #[test]
74 fn keymap_has_no_duplicate_bindings() {
75 let map = default_keymap();
76 let mut keys: Vec<_> = map.iter().map(|(k, _)| k.clone()).collect();
77 keys.sort();
78 let unique = keys.len();
79 keys.dedup();
80 assert_eq!(keys.len(), unique, "hay un atajo repetido");
81 }
82
83 #[test]
84 fn keymap_covers_every_virtual_workspace() {
85 let map = default_keymap();
86 for n in 0..WORKSPACE_COUNT {
87 assert!(map
88 .iter()
89 .any(|(_, a)| *a == DesktopAction::SwitchWorkspace(n)));
90 assert!(map
91 .iter()
92 .any(|(_, a)| *a == DesktopAction::SendToWorkspace(n)));
93 }
94 }
95}