Skip to main content

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