keybindings_parser/
lib.rs

1mod masks;
2pub use masks::ModMask;
3
4#[derive(Debug)]
5pub struct Keybindings {
6    binds: Vec<Keybinding>,
7    ghost_modifiers: ModMask,
8    key_delimiter: char,
9}
10
11impl Keybindings {
12    pub fn new(key_delimiter: char, ghost_modifiers: ModMask) -> Self {
13        Self {
14            binds: Vec::new(),
15            ghost_modifiers,
16            key_delimiter,
17        }
18    }
19}
20
21impl Default for Keybindings {
22    fn default() -> Self {
23        Self {
24            binds: Vec::new(),
25            ghost_modifiers: ModMask::MOD2 | ModMask::MOD5 | ModMask::CAPS_LOCK,
26            key_delimiter: '+',
27        }
28    }
29}
30
31pub struct Keybinding {
32    origin: String,
33    modifier: ModMask,
34    key: u32, // keysym
35    action: Box<dyn KeyAction>,
36}
37
38impl Keybinding {
39    pub fn modifier(&self) -> ModMask {
40        self.modifier
41    }
42    pub fn key(&self) -> u32 {
43        self.key
44    }
45    pub fn action(&self) -> &dyn KeyAction {
46        self.action.as_ref()
47    }
48    pub fn origin(&self) -> &str {
49        &self.origin
50    }
51}
52
53impl std::fmt::Debug for Keybinding {
54    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55        f.debug_struct("Keybinding")
56            .field("modifier", &self.modifier)
57            .field("key", &self.key)
58            .finish()
59    }
60}
61
62impl Keybindings {
63    pub fn add(
64        &mut self,
65        human_key_string: &str,
66        action: Box<dyn KeyAction>,
67    ) -> Result<(), Box<dyn std::error::Error>> {
68        if self.binds.iter().any(|x| x.origin == human_key_string) {
69            return Err("duplicate keybinding")?;
70        }
71        let mut parts: Vec<&str> = human_key_string
72            .split(self.key_delimiter)
73            .map(|x| x.trim())
74            .collect();
75        let mut keymod = ModMask::NONE;
76
77        let key = match parts.pop() {
78            Some(k) => k.to_string(),
79            None => return Err("no key provided")?,
80        };
81
82        let (strict, lazy) = (
83            keysymdefs::get_item_by_name(&key),
84            keysymdefs::get_item_by_cleared_name(&key),
85        );
86
87        let mut key = 0u32;
88        if let Some(lazy) = lazy {
89            key = lazy.keysym();
90        }
91        if let Some(strict) = strict {
92            key = strict.keysym();
93        }
94        if key == 0 {
95            return Err("Key not found".to_string())?;
96        }
97
98        while let Some(m) = parts.pop() {
99            keymod |= match m.to_lowercase().as_str() {
100                "super" | "mod4" | "win" | "windows" | "cmd" | "command" => ModMask::MOD4,
101                "alt" | "mod1" | "meta" | "alt_l" | "alt_r" | "meta_l" | "meta_r" => ModMask::MOD1,
102                "alt_gr" | "mod3" | "altgr" | "meta_gr" | "metagr" => ModMask::MOD3,
103                "ctrl" | "control" | "ctrl_l" | "ctrl_r" => ModMask::CONTROL,
104                "shift" | "shift_l" | "shift_r" => ModMask::SHIFT,
105                _ => return Err("invalid modifier")?,
106            }
107        }
108
109        self.binds.push(Keybinding {
110            origin: human_key_string.to_string(),
111            modifier: keymod,
112            key,
113            action,
114        });
115
116        Ok(())
117    }
118
119    pub fn handle(&self, modifiers: ModMask, keysym: u32) -> Option<&Keybinding> {
120        let find = self.binds.iter().find(|k| {
121            (k.modifier | self.ghost_modifiers) == (modifiers | self.ghost_modifiers)
122                && k.key == keysym
123        })?;
124        Some(find)
125    }
126}
127
128pub trait KeyAction {
129    fn run(&self) -> Result<(), Box<dyn std::error::Error>>;
130}