Skip to main content

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