1#![doc = include_str!("doc_de_tap_hold.md")]
2
3use core::fmt::Debug;
4
5use serde::Deserialize;
6
7use crate::input;
8use crate::key;
9use crate::keymap;
10
11#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
13pub enum InterruptResponse {
14 Ignore,
17 HoldOnKeyPress,
19 HoldOnKeyTap,
22}
23
24#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
26pub struct Config {
27 #[serde(default = "default_timeout")]
29 pub timeout: u16,
30
31 #[serde(default = "default_interrupt_response")]
33 pub interrupt_response: InterruptResponse,
34
35 pub required_idle_time: Option<u16>,
41}
42
43fn default_timeout() -> u16 {
44 DEFAULT_CONFIG.timeout
45}
46
47fn default_interrupt_response() -> InterruptResponse {
48 DEFAULT_CONFIG.interrupt_response
49}
50
51pub const DEFAULT_CONFIG: Config = Config {
53 timeout: 200,
54 interrupt_response: InterruptResponse::Ignore,
55 required_idle_time: None,
56};
57
58impl Default for Config {
59 fn default() -> Self {
61 DEFAULT_CONFIG
62 }
63}
64
65#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
67pub struct Key<K: key::Key> {
68 pub tap: K,
70 pub hold: K,
72}
73
74impl<K: key::Key> Key<K> {
75 pub const fn new(tap: K, hold: K) -> Key<K> {
77 Key { tap, hold }
78 }
79}
80
81impl<K: key::Key> Key<K> {
82 fn new_pressed_key(
83 &self,
84 context: &K::Context,
85 key_path: key::KeyPath,
86 ) -> (
87 key::PressedKeyResult<K::PendingKeyState, K::KeyState>,
88 key::KeyEvents<K::Event>,
89 )
90 where
91 for<'ctx> &'ctx K::Context: Into<&'ctx Context>,
92 for<'ctx> &'ctx K::Context: Into<&'ctx keymap::KeymapContext>,
93 Event: Into<K::Event>,
94 PendingKeyState: Into<K::PendingKeyState>,
95 {
96 let th_ctx: &Context = context.into();
97 match th_ctx.config.required_idle_time {
98 Some(required_idle_time) => {
99 let km_ctx: &keymap::KeymapContext = context.into();
100 if km_ctx.idle_time_ms >= required_idle_time as u32 {
101 let (th_pks, sch_ev) = self.new_pending_key(th_ctx, key_path.clone());
103 let pk = key::PressedKeyResult::Pending(key_path, th_pks.into());
104 let pke = key::KeyEvents::scheduled_event(sch_ev.into_scheduled_event());
105 (pk, pke)
106 } else {
107 let tap_key_path = key_path.append_path_item(0);
111 (
112 key::PressedKeyResult::NewPressedKey(key::NewPressedKey::key_path(
113 tap_key_path,
114 )),
115 key::KeyEvents::no_events(),
116 )
117 }
118 }
119 None => {
120 let (th_pks, sch_ev) = self.new_pending_key(th_ctx, key_path.clone());
122 let pk = key::PressedKeyResult::Pending(key_path, th_pks.into());
123 let pke = key::KeyEvents::scheduled_event(sch_ev.into_scheduled_event());
124 (pk, pke)
125 }
126 }
127 }
128
129 fn new_pending_key(
130 &self,
131 context: &Context,
132 key_path: key::KeyPath,
133 ) -> (PendingKeyState, key::ScheduledEvent<Event>) {
134 let keymap_index: u16 = key_path.keymap_index();
135 let timeout_ev = Event::TapHoldTimeout;
136 (
137 PendingKeyState::new(),
138 key::ScheduledEvent::after(
139 context.config.timeout,
140 key::Event::key_event(keymap_index, timeout_ev),
141 ),
142 )
143 }
144}
145
146impl<
147 K: key::Key<
148 Context = crate::init::Context,
149 Event = crate::init::Event,
150 PendingKeyState = crate::init::PendingKeyState,
151 KeyState = crate::init::KeyState,
152 >,
153 > key::Key for Key<K>
154{
155 type Context = crate::init::Context;
156 type Event = crate::init::Event;
157 type PendingKeyState = crate::init::PendingKeyState;
158 type KeyState = crate::init::KeyState;
159
160 fn new_pressed_key(
161 &self,
162 context: &Self::Context,
163 key_path: key::KeyPath,
164 ) -> (
165 key::PressedKeyResult<Self::PendingKeyState, Self::KeyState>,
166 key::KeyEvents<Self::Event>,
167 ) {
168 self.new_pressed_key(context, key_path.clone())
169 }
170
171 fn handle_event(
172 &self,
173 pending_state: &mut Self::PendingKeyState,
174 context: &Self::Context,
175 key_path: key::KeyPath,
176 event: key::Event<Self::Event>,
177 ) -> (Option<key::NewPressedKey>, key::KeyEvents<Self::Event>) {
178 let keymap_index = key_path.keymap_index();
179 let th_pks_res: Result<&mut PendingKeyState, _> = pending_state.try_into();
180 if let Ok(th_pks) = th_pks_res {
181 if let Ok(th_ev) = event.try_into_key_event(|e| e.try_into()) {
182 let th_state = th_pks.handle_event(context.into(), keymap_index, th_ev);
183 if let Some(th_state) = th_state {
184 let i = match th_state {
185 key::tap_hold::TapHoldState::Tap => 0,
186 key::tap_hold::TapHoldState::Hold => 1,
187 };
188 let new_key_path = key_path.append_path_item(i);
190
191 (
192 Some(key::NewPressedKey::key_path(new_key_path)),
193 key::KeyEvents::no_events(),
194 )
195 } else {
196 (None, key::KeyEvents::no_events())
197 }
198 } else {
199 (None, key::KeyEvents::no_events())
200 }
201 } else {
202 (None, key::KeyEvents::no_events())
203 }
204 }
205
206 fn lookup(
207 &self,
208 path: &[u16],
209 ) -> &dyn key::Key<
210 Context = Self::Context,
211 Event = Self::Event,
212 PendingKeyState = Self::PendingKeyState,
213 KeyState = Self::KeyState,
214 > {
215 match path {
216 [] => self,
217 [0, path @ ..] => self.tap.lookup(path),
219 [1, path @ ..] => self.hold.lookup(path),
220 _ => panic!(),
221 }
222 }
223}
224
225#[derive(Debug, Clone, Copy, PartialEq)]
227pub struct Context {
228 config: Config,
229}
230
231pub const DEFAULT_CONTEXT: Context = Context::from_config(DEFAULT_CONFIG);
233
234impl Context {
235 pub const fn from_config(config: Config) -> Context {
237 Context { config }
238 }
239}
240
241#[derive(Debug, Clone, Copy, PartialEq)]
243pub enum TapHoldState {
244 Tap,
246 Hold,
248}
249
250#[derive(Debug, Clone, Copy, PartialEq)]
252pub enum Event {
253 TapHoldTimeout,
255}
256
257#[derive(Debug, Clone, PartialEq)]
259pub struct PendingKeyState {
260 other_pressed_keymap_index: Option<u16>,
262}
263
264impl PendingKeyState {
265 fn new() -> PendingKeyState {
267 PendingKeyState {
268 other_pressed_keymap_index: None,
269 }
270 }
271
272 fn hold_resolution(
275 &self,
276 interrupt_response: InterruptResponse,
277 keymap_index: u16,
278 event: key::Event<Event>,
279 ) -> Option<TapHoldState> {
280 match interrupt_response {
281 InterruptResponse::HoldOnKeyPress => {
282 match event {
283 key::Event::Input(input::Event::Press { .. }) => {
284 Some(TapHoldState::Hold)
286 }
287 key::Event::Input(input::Event::Release { keymap_index: ki }) => {
288 if keymap_index == ki {
289 Some(TapHoldState::Tap)
291 } else {
292 None
293 }
294 }
295 key::Event::Key {
296 key_event: Event::TapHoldTimeout,
297 ..
298 } => {
299 Some(TapHoldState::Hold)
301 }
302 _ => None,
303 }
304 }
305 InterruptResponse::HoldOnKeyTap => {
306 match event {
307 key::Event::Input(input::Event::Release { keymap_index: ki }) => {
308 if keymap_index == ki {
309 Some(TapHoldState::Tap)
311 } else if Some(ki) == self.other_pressed_keymap_index {
312 Some(TapHoldState::Hold)
314 } else {
315 None
316 }
317 }
318 key::Event::Key {
319 key_event: Event::TapHoldTimeout,
320 ..
321 } => {
322 Some(TapHoldState::Hold)
324 }
325 _ => None,
326 }
327 }
328 InterruptResponse::Ignore => {
329 match event {
330 key::Event::Input(input::Event::Release { keymap_index: ki }) => {
331 if keymap_index == ki {
332 Some(TapHoldState::Tap)
334 } else {
335 None
336 }
337 }
338 key::Event::Key {
339 key_event: Event::TapHoldTimeout,
340 ..
341 } => {
342 Some(TapHoldState::Hold)
344 }
345 _ => None,
346 }
347 }
348 }
349 }
350
351 pub fn handle_event(
353 &mut self,
354 context: &Context,
355 keymap_index: u16,
356 event: key::Event<Event>,
357 ) -> Option<TapHoldState> {
358 if let key::Event::Input(input::Event::Press { keymap_index: ki }) = event {
361 self.other_pressed_keymap_index = Some(ki);
362 }
363
364 let Context { config, .. } = context;
366 self.hold_resolution(config.interrupt_response, keymap_index, event)
367 }
368}