smart_keymap/key/
caps_word.rs

1#![doc = include_str!("doc_de_caps_word.md")]
2
3use serde::Deserialize;
4
5use crate::input;
6use crate::key;
7use crate::keymap;
8
9/// Caps Word context.
10#[derive(Debug, Clone, Copy)]
11pub struct Context {
12    is_active: bool,
13}
14
15/// The default [Context].
16pub const DEFAULT_CONTEXT: Context = Context { is_active: false };
17
18impl Context {
19    /// Updates the context with the given event.
20    pub fn handle_event<E>(&mut self, event: key::Event<E>) -> key::KeyEvents<E>
21    where
22        Event: TryFrom<E>,
23        E: core::fmt::Debug + core::marker::Copy,
24    {
25        match event {
26            key::Event::Keymap(keymap::KeymapEvent::ResolvedKeyOutput {
27                key_output:
28                    key::KeyOutput {
29                        key_code: key::KeyUsage::Keyboard(key_code),
30                        key_modifiers,
31                    },
32                ..
33            }) if self.is_active => {
34                // CapsWord is deactivated for key presses other than:
35                //   - A-Z
36                //   - 0-9
37                //   - Backspace, Delete
38                //   - Minus, Underscore
39                let is_shifted = key_modifiers.has_modifiers(
40                    &key::KeyboardModifiers::LEFT_SHIFT.union(&key::KeyboardModifiers::RIGHT_SHIFT),
41                );
42                let exit_caps_word = match key_code {
43                    0x04..=0x1D => false,                // A-Z
44                    0x1E..=0x27 if !is_shifted => false, // 0-9
45                    0x2A => false,                       // Backspace
46                    0x2D => false,                       // `-` minus
47                    0x4C => false,                       // Delete
48                    0xE1 => false,                       // Left Shift
49                    0xE5 => false,                       // Right Shift
50                    0x00 => false,                       // No key code (modifier)
51                    _ => true,
52                };
53
54                if exit_caps_word {
55                    self.is_active = false;
56
57                    let key_code = 0xE1;
58                    let vk_ev = input::Event::VirtualKeyRelease {
59                        key_output: key::KeyOutput::from_key_code(key_code),
60                    };
61                    key::KeyEvents::event(key::Event::Input(vk_ev))
62                } else {
63                    key::KeyEvents::no_events()
64                }
65            }
66            key::Event::Key { key_event, .. } => {
67                if let Ok(ev) = key_event.try_into() {
68                    match ev {
69                        Event::EnableCapsWord => {
70                            self.is_active = true;
71
72                            let key_code = 0xE1;
73                            let vk_ev = input::Event::VirtualKeyPress {
74                                key_output: key::KeyOutput::from_key_code(key_code),
75                            };
76                            key::KeyEvents::event(key::Event::Input(vk_ev))
77                        }
78                        Event::DisableCapsWord => {
79                            self.is_active = false;
80
81                            let key_code = 0xE1;
82                            let vk_ev = input::Event::VirtualKeyRelease {
83                                key_output: key::KeyOutput::from_key_code(key_code),
84                            };
85                            key::KeyEvents::event(key::Event::Input(vk_ev))
86                        }
87                    }
88                } else {
89                    key::KeyEvents::no_events()
90                }
91            }
92            _ => key::KeyEvents::no_events(),
93        }
94    }
95}
96
97/// Caps Word events.
98#[derive(Debug, Clone, Copy, PartialEq)]
99pub enum Event {
100    /// Enables Caps Word.
101    EnableCapsWord,
102    /// Disables Caps Word.
103    DisableCapsWord,
104}
105
106/// A key for HID Keyboard usage codes.
107#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
108pub enum Key {
109    /// Enters/Exits CapsWord mode.
110    ToggleCapsWord,
111}
112
113impl Key {
114    /// Constructs a key with the given key_code.
115    pub const fn new() -> Self {
116        Key::ToggleCapsWord
117    }
118
119    /// Constructs a pressed key state
120    pub fn new_pressed_key(&self, context: &Context, keymap_index: u16) -> key::KeyEvents<Event> {
121        let key_event = match self {
122            Key::ToggleCapsWord => {
123                if context.is_active {
124                    Event::DisableCapsWord
125                } else {
126                    Event::EnableCapsWord
127                }
128            }
129        };
130        key::KeyEvents::event(key::Event::key_event(keymap_index, key_event))
131    }
132}
133
134impl key::Key for Key {
135    type Context = crate::init::Context;
136    type Event = crate::init::Event;
137    type PendingKeyState = crate::init::PendingKeyState;
138    type KeyState = crate::init::KeyState;
139
140    fn new_pressed_key(
141        &self,
142        context: &Self::Context,
143        key_path: key::KeyPath,
144    ) -> (
145        key::PressedKeyResult<Self::PendingKeyState, Self::KeyState>,
146        key::KeyEvents<Self::Event>,
147    ) {
148        let caps_word_context = context.into();
149        let keymap_index: u16 = key_path[0];
150        let pke = self.new_pressed_key(caps_word_context, keymap_index);
151        let pks = key::PressedKeyResult::Resolved(key::NoOpKeyState::new().into());
152        (pks, pke.into_events())
153    }
154
155    fn handle_event(
156        &self,
157        _pending_state: &mut Self::PendingKeyState,
158        _context: &Self::Context,
159        _key_path: key::KeyPath,
160        _event: key::Event<Self::Event>,
161    ) -> (
162        Option<key::PressedKeyResult<Self::PendingKeyState, Self::KeyState>>,
163        key::KeyEvents<Self::Event>,
164    ) {
165        panic!()
166    }
167
168    fn lookup(
169        &self,
170        _path: &[u16],
171    ) -> &dyn key::Key<
172        Context = Self::Context,
173        Event = Self::Event,
174        PendingKeyState = Self::PendingKeyState,
175        KeyState = Self::KeyState,
176    > {
177        self
178    }
179}