1#![expect(dead_code)]
2use core::ascii::Char;
3
4use defmt::Format;
5
6use crate::{Key, held_key::HeldKey};
7mod case;
8pub use case::*;
9mod pending;
10pub use pending::*;
11
12#[derive(Debug, PartialEq, Format, Copy, Clone)]
13pub enum Event {
14 Tentative(Char),
15 Decided(Char),
16 Case(Case),
17 ShowSpecialCharacters,
18}
19
20impl Event {
21 fn decide(self) -> Option<Self> {
22 match self {
23 Self::Tentative(c) => Some(Self::Decided(c)),
24 _ => None,
25 }
26 }
27
28 fn next_char(self) -> Option<Self> {
29 match self {
30 Self::Tentative(c) => {
31 let result = match c {
32 Char::CapitalA => Char::CapitalB,
33 Char::CapitalB => Char::CapitalC,
34 Char::CapitalC => Char::CapitalA,
35 Char::CapitalD => Char::CapitalE,
36 Char::CapitalE => Char::CapitalF,
37 Char::CapitalF => Char::CapitalD,
38 Char::CapitalG => Char::CapitalH,
39 Char::CapitalH => Char::CapitalI,
40 Char::CapitalI => Char::CapitalG,
41 Char::CapitalJ => Char::CapitalK,
42 Char::CapitalK => Char::CapitalL,
43 Char::CapitalL => Char::CapitalJ,
44 Char::CapitalM => Char::CapitalN,
45 Char::CapitalN => Char::CapitalO,
46 Char::CapitalO => Char::CapitalM,
47 Char::CapitalP => Char::CapitalQ,
48 Char::CapitalQ => Char::CapitalR,
49 Char::CapitalR => Char::CapitalS,
50 Char::CapitalS => Char::CapitalP,
51 Char::CapitalT => Char::CapitalU,
52 Char::CapitalU => Char::CapitalV,
53 Char::CapitalV => Char::CapitalT,
54 Char::CapitalW => Char::CapitalX,
55 Char::CapitalX => Char::CapitalY,
56 Char::CapitalY => Char::CapitalZ,
57 Char::CapitalZ => Char::CapitalW,
58 Char::SmallA => Char::SmallB,
59 Char::SmallB => Char::SmallC,
60 Char::SmallC => Char::SmallA,
61 Char::SmallD => Char::SmallE,
62 Char::SmallE => Char::SmallF,
63 Char::SmallF => Char::SmallD,
64 Char::SmallG => Char::SmallH,
65 Char::SmallH => Char::SmallI,
66 Char::SmallI => Char::SmallG,
67 Char::SmallJ => Char::SmallK,
68 Char::SmallK => Char::SmallL,
69 Char::SmallL => Char::SmallJ,
70 Char::SmallM => Char::SmallN,
71 Char::SmallN => Char::SmallO,
72 Char::SmallO => Char::SmallM,
73 Char::SmallP => Char::SmallQ,
74 Char::SmallQ => Char::SmallR,
75 Char::SmallR => Char::SmallS,
76 Char::SmallS => Char::SmallP,
77 Char::SmallT => Char::SmallU,
78 Char::SmallU => Char::SmallV,
79 Char::SmallV => Char::SmallT,
80 Char::SmallW => Char::SmallX,
81 Char::SmallX => Char::SmallY,
82 Char::SmallY => Char::SmallZ,
83 Char::SmallZ => Char::SmallW,
84 Char::Digit1 => Char::Digit2,
85 Char::Digit2 => Char::Digit3,
86 Char::Digit3 => Char::Digit4,
87 Char::Digit4 => Char::Digit5,
88 Char::Digit5 => Char::Digit6,
89 Char::Digit6 => Char::Digit7,
90 Char::Digit7 => Char::Digit8,
91 Char::Digit8 => Char::Digit9,
92 Char::Digit9 => Char::Digit0,
93 Char::Digit0 => Char::Digit1,
94 e => e,
95 };
96 Some(Self::Tentative(result))
97 }
98 _ => None,
99 }
100 }
101}
102
103#[derive(Debug)]
104pub struct Last {
105 held_key_event: Option<crate::held_key::Event>,
106 event: Option<Event>,
107}
108
109impl Last {
110 fn new() -> Self {
111 Self {
112 held_key_event: None,
113 event: None,
114 }
115 }
116
117 fn clear(&mut self) {
118 self.held_key_event = None;
119 self.event = None;
120 }
121
122 fn set_held_key_event(
123 &mut self,
124 held_key_event: Option<crate::held_key::Event>,
125 ) -> Option<crate::held_key::Event> {
126 let result = self.held_key_event.clone();
127 self.held_key_event = held_key_event;
128 result
129 }
130
131 fn set_event(&mut self, event: Option<Event>) -> Option<Event> {
132 let result = self.event;
133 self.event = event;
134 result
135 }
136}
137
138#[derive(Debug)]
139pub struct MultiTap {
140 case_state: CaseState,
141 last: Last,
142 pending: Pending<Event>,
143 held_key: HeldKey,
144 duration: u64,
145}
146
147impl MultiTap {
148 pub fn new(duration: u64) -> Self {
149 let case_state = CaseState::new(Case::Lower);
150 let mut pending = Pending::new();
151 pending.enqueue(Event::Case(case_state.case()));
152
153 Self {
154 case_state,
155 last: Last::new(),
156 pending,
157 held_key: HeldKey::new(15000, 5000),
158 duration,
159 }
160 }
161
162 fn case(&self) -> Case {
163 self.case_state.case()
164 }
165
166 pub async fn event(&mut self, keypad: &mut impl crate::Keypad) -> Option<Event> {
167 if let Some(pending) = self.pending.dequeue() {
168 self.last.set_event(Some(pending));
169 return Some(pending);
170 }
171
172 let key = self.held_key.event(keypad).await;
173 let last_key = self.last.set_held_key_event(key.clone());
174
175 let result = match key {
176 Some(crate::held_key::Event::Down(Key::Asterisk)) => Some(Event::ShowSpecialCharacters),
177 Some(crate::held_key::Event::Down(Key::Hash)) => {
178 self.case_state.cycle_case();
179 Some(Event::Case(self.case()))
180 }
181 Some(crate::held_key::Event::Down(Key::Cancel)) => {
182 Some(Event::Decided(core::ascii::Char::Backspace))
183 }
184 Some(crate::held_key::Event::Delay(Key::Hash)) => {
185 self.case_state.enable_numeric_case();
186 Some(Event::Case(self.case()))
187 }
188 Some(crate::held_key::Event::Delay(Key::Cancel)) => None,
189 Some(crate::held_key::Event::Delay(d)) => {
190 self.last.clear();
191 Some(Event::Decided(digit(d)))
192 }
193 Some(crate::held_key::Event::Down(ref now)) => {
194 if key == last_key {
195 self.last.event.unwrap().next_char()
196 } else if last_key.is_some() {
197 let result = self.last.event.unwrap().decide();
198 self.pending
199 .enqueue(Event::Tentative(lowercase(now.clone().into())));
200 result
201 } else {
202 Some(Event::Tentative(lowercase(now.clone().into())))
203 }
204 }
205 None | Some(crate::held_key::Event::Repeat(_)) => None,
206 };
207
208 self.last.set_event(result);
209 result
210 }
211}
212
213fn digit(k: crate::Key) -> Char {
214 match k {
215 crate::Key::One => core::ascii::Char::Digit1,
216 crate::Key::Two => core::ascii::Char::Digit2,
217 crate::Key::Three => core::ascii::Char::Digit3,
218 crate::Key::Four => core::ascii::Char::Digit4,
219 crate::Key::Five => core::ascii::Char::Digit5,
220 crate::Key::Six => core::ascii::Char::Digit6,
221 crate::Key::Seven => core::ascii::Char::Digit7,
222 crate::Key::Eight => core::ascii::Char::Digit8,
223 crate::Key::Nine => core::ascii::Char::Digit9,
224 crate::Key::Zero => core::ascii::Char::Digit0,
225 _ => core::ascii::Char::Digit0,
226 }
227}
228
229fn lowercase(c: Char) -> Char {
230 match c {
231 core::ascii::Char::CapitalA => core::ascii::Char::SmallA,
232 core::ascii::Char::CapitalB => core::ascii::Char::SmallB,
233 core::ascii::Char::CapitalC => core::ascii::Char::SmallC,
234 core::ascii::Char::CapitalD => core::ascii::Char::SmallD,
235 core::ascii::Char::CapitalE => core::ascii::Char::SmallE,
236 core::ascii::Char::CapitalF => core::ascii::Char::SmallF,
237 core::ascii::Char::CapitalG => core::ascii::Char::SmallG,
238 core::ascii::Char::CapitalH => core::ascii::Char::SmallH,
239 core::ascii::Char::CapitalI => core::ascii::Char::SmallI,
240 core::ascii::Char::CapitalJ => core::ascii::Char::SmallJ,
241 core::ascii::Char::CapitalK => core::ascii::Char::SmallK,
242 core::ascii::Char::CapitalL => core::ascii::Char::SmallL,
243 core::ascii::Char::CapitalM => core::ascii::Char::SmallM,
244 core::ascii::Char::CapitalN => core::ascii::Char::SmallN,
245 core::ascii::Char::CapitalO => core::ascii::Char::SmallO,
246 core::ascii::Char::CapitalP => core::ascii::Char::SmallP,
247 core::ascii::Char::CapitalQ => core::ascii::Char::SmallQ,
248 core::ascii::Char::CapitalR => core::ascii::Char::SmallR,
249 core::ascii::Char::CapitalS => core::ascii::Char::SmallS,
250 core::ascii::Char::CapitalT => core::ascii::Char::SmallT,
251 core::ascii::Char::CapitalU => core::ascii::Char::SmallU,
252 core::ascii::Char::CapitalV => core::ascii::Char::SmallV,
253 core::ascii::Char::CapitalW => core::ascii::Char::SmallW,
254 core::ascii::Char::CapitalX => core::ascii::Char::SmallX,
255 core::ascii::Char::CapitalY => core::ascii::Char::SmallY,
256 core::ascii::Char::CapitalZ => core::ascii::Char::SmallZ,
257 t => t,
258 }
259}
260
261#[cfg(test)]
262mod test {
263 use futures_executor::block_on;
264
265 #[test]
266 fn test_tentative() {
267 block_on(async {
268 let mut keypad = crate::test::Keypad::new(&[crate::KeyEvent::Down(crate::Key::Two)]);
269 let mut multitap = super::MultiTap::new(1000);
270 assert_eq!(
271 multitap.event(&mut keypad).await,
272 Some(super::Event::Case(super::Case::Lower))
273 );
274 assert_eq!(
275 multitap.event(&mut keypad).await,
276 Some(super::Event::Tentative(core::ascii::Char::SmallA))
277 );
278 });
279 }
280
281 #[test]
282 fn test_tentative_next() {
283 block_on(async {
284 let mut keypad = crate::test::Keypad::new(&[
285 crate::KeyEvent::Down(crate::Key::Two),
286 crate::KeyEvent::Down(crate::Key::Two),
287 ]);
288 let mut multitap = super::MultiTap::new(1000);
289 assert_eq!(
290 multitap.event(&mut keypad).await,
291 Some(super::Event::Case(super::Case::Lower))
292 );
293 assert_eq!(
294 multitap.event(&mut keypad).await,
295 Some(super::Event::Tentative(core::ascii::Char::SmallA))
296 );
297 assert_eq!(
298 multitap.event(&mut keypad).await,
299 Some(super::Event::Tentative(core::ascii::Char::SmallB))
300 );
301 });
302 }
303
304 #[test]
305 fn test_decided_by_timeout() {}
306
307 #[test]
308 fn test_hold_for_number() {}
309
310 #[test]
311 fn test_decided_by_other() {
312 block_on(async {
313 let mut keypad = crate::test::Keypad::new(&[
314 crate::KeyEvent::Down(crate::Key::Two),
315 crate::KeyEvent::Down(crate::Key::Three),
316 ]);
317 let mut multitap = super::MultiTap::new(1000);
318 assert_eq!(
319 multitap.event(&mut keypad).await,
320 Some(super::Event::Case(super::Case::Lower))
321 );
322 assert_eq!(
323 multitap.event(&mut keypad).await,
324 Some(super::Event::Tentative(core::ascii::Char::SmallA))
325 );
326 assert_eq!(
327 multitap.event(&mut keypad).await,
328 Some(super::Event::Decided(core::ascii::Char::SmallA))
329 );
330 assert_eq!(
331 multitap.event(&mut keypad).await,
332 Some(super::Event::Tentative(core::ascii::Char::SmallD))
333 );
334 });
335 }
336}