smart_keymap/key/
caps_word.rs

1use core::fmt::Debug;
2use core::marker::PhantomData;
3
4use serde::Deserialize;
5
6use crate::input;
7use crate::key;
8use crate::keymap;
9
10/// Reference for a caps word key.
11#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
12pub struct Ref(pub Key);
13
14/// Caps Word context.
15#[derive(Debug, Clone, Copy)]
16pub struct Context {
17    is_active: bool,
18}
19
20impl Context {
21    /// Constructs a new [Context].
22    pub const fn new() -> Self {
23        Context { is_active: false }
24    }
25
26    /// Updates the context with the given event.
27    fn handle_event(&mut self, event: key::Event<Event>) -> key::KeyEvents<Event> {
28        match event {
29            key::Event::Keymap(keymap::KeymapEvent::ResolvedKeyOutput {
30                key_output:
31                    key::KeyOutput {
32                        key_code: key::KeyUsage::Keyboard(key_code),
33                        key_modifiers,
34                    },
35                ..
36            }) if self.is_active => {
37                // CapsWord is deactivated for key presses other than:
38                //   - A-Z
39                //   - 0-9
40                //   - Backspace, Delete
41                //   - Minus, Underscore
42                let is_shifted = key_modifiers.has_modifiers(
43                    &key::KeyboardModifiers::LEFT_SHIFT.union(&key::KeyboardModifiers::RIGHT_SHIFT),
44                );
45                let exit_caps_word = match key_code {
46                    0x04..=0x1D => false,                // A-Z
47                    0x1E..=0x27 if !is_shifted => false, // 0-9
48                    0x2A => false,                       // Backspace
49                    0x2D => false,                       // `-` minus
50                    0x4C => false,                       // Delete
51                    0xE1 => false,                       // Left Shift
52                    0xE5 => false,                       // Right Shift
53                    0x00 => false,                       // No key code (modifier)
54                    _ => true,
55                };
56
57                if exit_caps_word {
58                    self.is_active = false;
59
60                    let key_code = 0xE1;
61                    let vk_ev = input::Event::VirtualKeyRelease {
62                        key_output: key::KeyOutput::from_key_code(key_code),
63                    };
64                    key::KeyEvents::event(key::Event::Input(vk_ev))
65                } else {
66                    key::KeyEvents::no_events()
67                }
68            }
69            key::Event::Key { key_event, .. } => match key_event {
70                Event::EnableCapsWord => {
71                    self.is_active = true;
72
73                    let key_code = 0xE1;
74                    let vk_ev = input::Event::VirtualKeyPress {
75                        key_output: key::KeyOutput::from_key_code(key_code),
76                    };
77                    key::KeyEvents::event(key::Event::Input(vk_ev))
78                }
79                Event::DisableCapsWord => {
80                    self.is_active = false;
81
82                    let key_code = 0xE1;
83                    let vk_ev = input::Event::VirtualKeyRelease {
84                        key_output: key::KeyOutput::from_key_code(key_code),
85                    };
86                    key::KeyEvents::event(key::Event::Input(vk_ev))
87                }
88            },
89            _ => key::KeyEvents::no_events(),
90        }
91    }
92}
93
94impl key::Context for Context {
95    type Event = Event;
96
97    fn handle_event(&mut self, event: key::Event<Self::Event>) -> key::KeyEvents<Self::Event> {
98        self.handle_event(event)
99    }
100}
101
102/// Caps Word events.
103#[derive(Debug, Clone, Copy, PartialEq)]
104pub enum Event {
105    /// Enables Caps Word.
106    EnableCapsWord,
107    /// Disables Caps Word.
108    DisableCapsWord,
109}
110
111/// A key for HID Keyboard usage codes.
112#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
113pub enum Key {
114    /// Enters/Exits CapsWord mode.
115    ToggleCapsWord,
116}
117
118impl Key {
119    /// Constructs a key with the given key_code.
120    pub const fn new() -> Self {
121        Key::ToggleCapsWord
122    }
123
124    /// Constructs a pressed key state
125    pub fn new_pressed_key(&self, context: &Context, keymap_index: u16) -> key::KeyEvents<Event> {
126        let key_event = match self {
127            Key::ToggleCapsWord => {
128                if context.is_active {
129                    Event::DisableCapsWord
130                } else {
131                    Event::EnableCapsWord
132                }
133            }
134        };
135        key::KeyEvents::event(key::Event::key_event(keymap_index, key_event))
136    }
137}
138
139impl Default for Key {
140    fn default() -> Self {
141        Self::new()
142    }
143}
144
145/// The pending key state type for caps word keys. (No pending state).
146#[derive(Debug, Clone, Copy, PartialEq)]
147pub struct PendingKeyState;
148
149/// Key state used by [System].
150#[derive(Debug, Clone, Copy, PartialEq)]
151pub struct KeyState;
152
153/// The [key::System] implementation for caps word keys.
154#[derive(Debug, Clone, Copy, PartialEq)]
155pub struct System<R>(PhantomData<R>);
156
157impl<R> System<R> {
158    /// Constructs a new [System] with the given key data.
159    pub const fn new() -> Self {
160        Self(PhantomData)
161    }
162}
163
164impl<R> Default for System<R> {
165    fn default() -> Self {
166        Self::new()
167    }
168}
169
170impl<R: Debug> key::System<R> for System<R> {
171    type Ref = Ref;
172    type Context = Context;
173    type Event = Event;
174    type PendingKeyState = PendingKeyState;
175    type KeyState = KeyState;
176
177    fn new_pressed_key(
178        &self,
179        keymap_index: u16,
180        context: &Self::Context,
181        Ref(key): Ref,
182    ) -> (
183        key::PressedKeyResult<R, Self::PendingKeyState, Self::KeyState>,
184        key::KeyEvents<Self::Event>,
185    ) {
186        let pke = key.new_pressed_key(context, keymap_index);
187        let pkr = key::PressedKeyResult::NewPressedKey(key::NewPressedKey::NoOp);
188        (pkr, pke.into_events())
189    }
190
191    fn update_pending_state(
192        &self,
193        _pending_state: &mut Self::PendingKeyState,
194        _keymap_index: u16,
195        _context: &Self::Context,
196        _key_ref: Ref,
197        _event: key::Event<Self::Event>,
198    ) -> (Option<key::NewPressedKey<R>>, key::KeyEvents<Self::Event>) {
199        panic!()
200    }
201
202    fn update_state(
203        &self,
204        _key_state: &mut Self::KeyState,
205        _ref: &Self::Ref,
206        _context: &Self::Context,
207        _keymap_index: u16,
208        _event: key::Event<Self::Event>,
209    ) -> key::KeyEvents<Self::Event> {
210        panic!()
211    }
212
213    fn key_output(
214        &self,
215        _key_ref: &Self::Ref,
216        _key_state: &Self::KeyState,
217    ) -> Option<key::KeyOutput> {
218        panic!()
219    }
220}
221
222#[cfg(test)]
223mod tests {
224    use super::*;
225
226    #[test]
227    fn test_sizeof_ref() {
228        assert_eq!(0, core::mem::size_of::<Ref>());
229    }
230
231    #[test]
232    fn test_sizeof_event() {
233        assert_eq!(1, core::mem::size_of::<Event>());
234    }
235}