1use crate::keycode::KeyCode;
13use crate::modifier::ModifierCombination;
14
15#[derive(Clone, Copy, Debug, serde::Serialize, serde::Deserialize)]
17#[cfg_attr(feature = "defmt", derive(defmt::Format))]
18#[derive(postcard::experimental::max_size::MaxSize)]
19pub struct EncoderAction {
20 clockwise: KeyAction,
21 counter_clockwise: KeyAction,
22}
23
24impl Default for EncoderAction {
25 fn default() -> Self {
26 Self {
27 clockwise: KeyAction::No,
28 counter_clockwise: KeyAction::No,
29 }
30 }
31}
32
33impl EncoderAction {
34 pub const fn new(clockwise: KeyAction, counter_clockwise: KeyAction) -> Self {
36 Self {
37 clockwise,
38 counter_clockwise,
39 }
40 }
41
42 pub fn set_clockwise(&mut self, clockwise: KeyAction) {
44 self.clockwise = clockwise;
45 }
46
47 pub fn set_counter_clockwise(&mut self, counter_clockwise: KeyAction) {
49 self.counter_clockwise = counter_clockwise;
50 }
51
52 pub fn clockwise(&self) -> KeyAction {
54 self.clockwise
55 }
56
57 pub fn counter_clockwise(&self) -> KeyAction {
59 self.counter_clockwise
60 }
61}
62
63#[derive(Clone, Copy, Debug, PartialEq, Eq)]
65#[cfg_attr(feature = "defmt", derive(defmt::Format))]
66#[repr(u8)]
67pub enum MorseMode {
68 PermissiveHold,
72 HoldOnOtherPress,
74 Normal,
76}
77
78#[derive(PartialEq, Eq, Clone, Copy, Debug, serde::Serialize, serde::Deserialize)]
81#[cfg_attr(feature = "defmt", derive(defmt::Format))]
82#[derive(postcard::experimental::max_size::MaxSize)]
83pub struct MorseProfile(u32);
84
85impl MorseProfile {
86 pub const fn const_default() -> Self {
87 Self(0)
88 }
89
90 pub fn unilateral_tap(self) -> Option<bool> {
92 match self.0 & 0x0000_C000 {
93 0x0000_C000 => Some(true),
94 0x0000_8000 => Some(false),
95 _ => None,
96 }
97 }
98
99 pub const fn with_unilateral_tap(self, b: Option<bool>) -> Self {
100 Self(
101 (self.0 & 0xFFFF_3FFF)
102 | match b {
103 Some(true) => 0x0000_C000,
104 Some(false) => 0x0000_8000,
105 None => 0,
106 },
107 )
108 }
109
110 pub fn mode(self) -> Option<MorseMode> {
119 match self.0 & 0xC000_0000 {
120 0xC000_0000 => Some(MorseMode::Normal),
121 0x8000_0000 => Some(MorseMode::HoldOnOtherPress),
122 0x4000_0000 => Some(MorseMode::PermissiveHold),
123 _ => None,
124 }
125 }
126
127 pub const fn with_mode(self, m: Option<MorseMode>) -> Self {
128 Self(
129 (self.0 & 0x3FFF_FFFF)
130 | match m {
131 Some(MorseMode::Normal) => 0xC000_0000,
132 Some(MorseMode::HoldOnOtherPress) => 0x8000_0000,
133 Some(MorseMode::PermissiveHold) => 0x4000_0000,
134 None => 0,
135 },
136 )
137 }
138
139 pub fn hold_timeout_ms(self) -> Option<u16> {
142 let t = (self.0 & 0x3FFF) as u16;
144 if t == 0 { None } else { Some(t) }
145 }
146
147 pub const fn with_hold_timeout_ms(self, t: Option<u16>) -> Self {
148 if let Some(t) = t {
149 Self((self.0 & 0xFFFF_C000) | (t as u32 & 0x3FFF))
150 } else {
151 Self(self.0 & 0xFFFF_C000)
152 }
153 }
154
155 pub const fn set_hold_timeout_ms(&mut self, t: u16) {
156 self.0 = (self.0 & 0xFFFF_C000) | (t as u32 & 0x3FFF)
157 }
158
159 pub const fn set_gap_timeout_ms(&mut self, t: u16) {
160 self.0 = (self.0 & 0xC000_FFFF) | ((t as u32 & 0x3FFF) << 16)
161 }
162
163 pub fn gap_timeout_ms(self) -> Option<u16> {
166 let t = ((self.0 >> 16) & 0x3FFF) as u16;
168 if t == 0 { None } else { Some(t) }
169 }
170
171 pub const fn with_gap_timeout_ms(self, t: Option<u16>) -> Self {
172 if let Some(t) = t {
173 Self((self.0 & 0xC000_FFFF) | ((t as u32 & 0x3FFF) << 16))
174 } else {
175 Self(self.0 & 0xC000_FFFF)
176 }
177 }
178
179 pub const fn new(
180 unilateral_tap: Option<bool>,
181 mode: Option<MorseMode>,
182 hold_timeout_ms: Option<u16>,
183 gap_timeout_ms: Option<u16>,
184 ) -> Self {
185 let mut v = 0u32;
186 if let Some(t) = hold_timeout_ms {
187 v = (t & 0x3FFF) as u32;
189 }
190
191 if let Some(t) = gap_timeout_ms {
192 v |= ((t & 0x3FFF) as u32) << 16;
194 }
195
196 if let Some(b) = unilateral_tap {
197 v |= if b { 0x0000_C000 } else { 0x0000_8000 };
198 }
199
200 if let Some(m) = mode {
201 v |= match m {
202 MorseMode::Normal => 0xC000_0000,
203 MorseMode::HoldOnOtherPress => 0x8000_0000,
204 MorseMode::PermissiveHold => 0x4000_0000,
205 };
206 }
207
208 MorseProfile(v)
209 }
210}
211
212impl Default for MorseProfile {
213 fn default() -> Self {
214 MorseProfile::const_default()
215 }
216}
217
218impl From<u32> for MorseProfile {
219 fn from(v: u32) -> Self {
220 MorseProfile(v)
221 }
222}
223
224impl From<MorseProfile> for u32 {
225 fn from(val: MorseProfile) -> Self {
226 val.0
227 }
228}
229
230#[derive(Debug, Copy, Clone, Eq, serde::Serialize, serde::Deserialize)]
233#[cfg_attr(feature = "defmt", derive(defmt::Format))]
234#[derive(postcard::experimental::max_size::MaxSize)]
235pub enum KeyAction {
236 No,
238 Transparent,
240 Single(Action),
242 Tap(Action),
244 TapHold(Action, Action, MorseProfile),
246
247 Morse(u8),
249}
250
251impl KeyAction {
252 pub fn to_action(self) -> Action {
255 match self {
256 KeyAction::Single(a) | KeyAction::Tap(a) => a,
257 _ => Action::No,
258 }
259 }
260
261 pub fn is_morse(&self) -> bool {
264 matches!(self, KeyAction::TapHold(_, _, _) | KeyAction::Morse(_))
265 }
266
267 pub fn is_empty(&self) -> bool {
268 matches!(self, KeyAction::No)
269 }
270}
271
272impl PartialEq for KeyAction {
275 fn eq(&self, other: &Self) -> bool {
276 match (self, other) {
277 (KeyAction::No, KeyAction::No) => true,
278 (KeyAction::Transparent, KeyAction::Transparent) => true,
279 (KeyAction::Single(a), KeyAction::Single(b)) => a == b,
280 (KeyAction::Tap(a), KeyAction::Tap(b)) => a == b,
281 (KeyAction::TapHold(a, b, _), KeyAction::TapHold(c, d, _)) => a == c && b == d,
282 (KeyAction::Morse(a), KeyAction::Morse(b)) => a == b,
283 _ => false,
284 }
285 }
286}
287
288#[derive(Debug, Copy, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
290#[cfg_attr(feature = "defmt", derive(defmt::Format))]
291#[derive(postcard::experimental::max_size::MaxSize)]
292pub enum Action {
293 No,
295 Transparent,
297 Key(KeyCode),
299 Modifier(ModifierCombination),
301 KeyWithModifier(KeyCode, ModifierCombination),
303 LayerOn(u8),
305 LayerOnWithModifier(u8, ModifierCombination),
307 LayerOff(u8),
309 LayerToggle(u8),
311 DefaultLayer(u8),
313 LayerToggleOnly(u8),
315 TriggerMacro(u8),
322 OneShotLayer(u8),
324 OneShotModifier(ModifierCombination),
326 OneShotKey(KeyCode),
328}
329
330#[cfg(test)]
331mod tests {
332 use super::*;
333
334 #[test]
335 fn test_morse_profile_timeout_setters() {
336 let mut profile = MorseProfile::new(Some(true), Some(MorseMode::PermissiveHold), Some(1000), Some(2000));
338
339 assert_eq!(profile.hold_timeout_ms(), Some(1000));
341 assert_eq!(profile.gap_timeout_ms(), Some(2000));
342 assert_eq!(profile.unilateral_tap(), Some(true));
343 assert_eq!(profile.mode(), Some(MorseMode::PermissiveHold));
344
345 profile.set_hold_timeout_ms(1500);
347 assert_eq!(profile.hold_timeout_ms(), Some(1500));
348 assert_eq!(profile.gap_timeout_ms(), Some(2000));
349 assert_eq!(profile.unilateral_tap(), Some(true));
350 assert_eq!(profile.mode(), Some(MorseMode::PermissiveHold));
351
352 profile.set_gap_timeout_ms(2500);
354 assert_eq!(profile.hold_timeout_ms(), Some(1500));
355 assert_eq!(profile.gap_timeout_ms(), Some(2500));
356 assert_eq!(profile.unilateral_tap(), Some(true));
357 assert_eq!(profile.mode(), Some(MorseMode::PermissiveHold));
358
359 profile.set_hold_timeout_ms(0x3FFF);
361 profile.set_gap_timeout_ms(0x3FFF);
362 assert_eq!(profile.hold_timeout_ms(), Some(0x3FFF));
363 assert_eq!(profile.gap_timeout_ms(), Some(0x3FFF));
364 assert_eq!(profile.unilateral_tap(), Some(true));
365 assert_eq!(profile.mode(), Some(MorseMode::PermissiveHold));
366
367 profile.set_hold_timeout_ms(0);
369 profile.set_gap_timeout_ms(0);
370 assert_eq!(profile.hold_timeout_ms(), None);
371 assert_eq!(profile.gap_timeout_ms(), None);
372 assert_eq!(profile.unilateral_tap(), Some(true));
373 assert_eq!(profile.mode(), Some(MorseMode::PermissiveHold));
374 }
375}