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 self.tap.new_pressed_key(context, key_path)
110 }
111 }
112 None => {
113 let (th_pks, sch_ev) = self.new_pending_key(th_ctx, key_path.clone());
115 let pk = key::PressedKeyResult::Pending(key_path, th_pks.into());
116 let pke = key::KeyEvents::scheduled_event(sch_ev.into_scheduled_event());
117 (pk, pke)
118 }
119 }
120 }
121
122 fn new_pending_key(
123 &self,
124 context: &Context,
125 key_path: key::KeyPath,
126 ) -> (PendingKeyState, key::ScheduledEvent<Event>) {
127 let keymap_index: u16 = key_path[0];
128 let timeout_ev = Event::TapHoldTimeout;
129 (
130 PendingKeyState::new(),
131 key::ScheduledEvent::after(
132 context.config.timeout,
133 key::Event::key_event(keymap_index, timeout_ev),
134 ),
135 )
136 }
137}
138
139impl<
140 K: key::Key<
141 Context = crate::init::Context,
142 Event = crate::init::Event,
143 PendingKeyState = crate::init::PendingKeyState,
144 KeyState = crate::init::KeyState,
145 >,
146 > key::Key for Key<K>
147{
148 type Context = crate::init::Context;
149 type Event = crate::init::Event;
150 type PendingKeyState = crate::init::PendingKeyState;
151 type KeyState = crate::init::KeyState;
152
153 fn new_pressed_key(
154 &self,
155 context: &Self::Context,
156 key_path: key::KeyPath,
157 ) -> (
158 key::PressedKeyResult<Self::PendingKeyState, Self::KeyState>,
159 key::KeyEvents<Self::Event>,
160 ) {
161 self.new_pressed_key(context, key_path.clone())
162 }
163
164 fn handle_event(
165 &self,
166 pending_state: &mut Self::PendingKeyState,
167 context: &Self::Context,
168 key_path: key::KeyPath,
169 event: key::Event<Self::Event>,
170 ) -> (
171 Option<key::PressedKeyResult<Self::PendingKeyState, Self::KeyState>>,
172 key::KeyEvents<Self::Event>,
173 ) {
174 let keymap_index = key_path[0];
175 let th_pks_res: Result<&mut PendingKeyState, _> = pending_state.try_into();
176 if let Ok(th_pks) = th_pks_res {
177 if let Ok(th_ev) = event.try_into_key_event(|e| e.try_into()) {
178 let th_state = th_pks.handle_event(context.into(), keymap_index, th_ev);
179 if let Some(th_state) = th_state {
180 let (i, nk) = match th_state {
181 key::tap_hold::TapHoldState::Tap => (0, &self.tap),
182 key::tap_hold::TapHoldState::Hold => (1, &self.hold),
183 };
184 let (pkr, pke) = nk.new_pressed_key(context, key_path);
185 let pkr = pkr.add_path_item(i);
187
188 (Some(pkr), pke)
189 } else {
190 (None, key::KeyEvents::no_events())
191 }
192 } else {
193 (None, key::KeyEvents::no_events())
194 }
195 } else {
196 (None, key::KeyEvents::no_events())
197 }
198 }
199
200 fn lookup(
201 &self,
202 path: &[u16],
203 ) -> &dyn key::Key<
204 Context = Self::Context,
205 Event = Self::Event,
206 PendingKeyState = Self::PendingKeyState,
207 KeyState = Self::KeyState,
208 > {
209 match path {
210 [] => self,
211 [0, path @ ..] => self.tap.lookup(path),
213 [1, path @ ..] => self.hold.lookup(path),
214 _ => panic!(),
215 }
216 }
217}
218
219#[derive(Debug, Clone, Copy, PartialEq)]
221pub struct Context {
222 config: Config,
223}
224
225pub const DEFAULT_CONTEXT: Context = Context::from_config(DEFAULT_CONFIG);
227
228impl Context {
229 pub const fn from_config(config: Config) -> Context {
231 Context { config }
232 }
233}
234
235#[derive(Debug, Clone, Copy, PartialEq)]
237pub enum TapHoldState {
238 Tap,
240 Hold,
242}
243
244#[derive(Debug, Clone, Copy, PartialEq)]
246pub enum Event {
247 TapHoldTimeout,
249}
250
251#[derive(Debug, Clone, PartialEq)]
253pub struct PendingKeyState {
254 other_pressed_keymap_index: Option<u16>,
256}
257
258impl PendingKeyState {
259 fn new() -> PendingKeyState {
261 PendingKeyState {
262 other_pressed_keymap_index: None,
263 }
264 }
265
266 fn hold_resolution(
269 &self,
270 interrupt_response: InterruptResponse,
271 keymap_index: u16,
272 event: key::Event<Event>,
273 ) -> Option<TapHoldState> {
274 match interrupt_response {
275 InterruptResponse::HoldOnKeyPress => {
276 match event {
277 key::Event::Input(input::Event::Press { .. }) => {
278 Some(TapHoldState::Hold)
280 }
281 key::Event::Input(input::Event::Release { keymap_index: ki }) => {
282 if keymap_index == ki {
283 Some(TapHoldState::Tap)
285 } else {
286 None
287 }
288 }
289 key::Event::Key {
290 key_event: Event::TapHoldTimeout,
291 ..
292 } => {
293 Some(TapHoldState::Hold)
295 }
296 _ => None,
297 }
298 }
299 InterruptResponse::HoldOnKeyTap => {
300 match event {
301 key::Event::Input(input::Event::Release { keymap_index: ki }) => {
302 if keymap_index == ki {
303 Some(TapHoldState::Tap)
305 } else if Some(ki) == self.other_pressed_keymap_index {
306 Some(TapHoldState::Hold)
308 } else {
309 None
310 }
311 }
312 key::Event::Key {
313 key_event: Event::TapHoldTimeout,
314 ..
315 } => {
316 Some(TapHoldState::Hold)
318 }
319 _ => None,
320 }
321 }
322 InterruptResponse::Ignore => {
323 match event {
324 key::Event::Input(input::Event::Release { keymap_index: ki }) => {
325 if keymap_index == ki {
326 Some(TapHoldState::Tap)
328 } else {
329 None
330 }
331 }
332 key::Event::Key {
333 key_event: Event::TapHoldTimeout,
334 ..
335 } => {
336 Some(TapHoldState::Hold)
338 }
339 _ => None,
340 }
341 }
342 }
343 }
344
345 pub fn handle_event(
347 &mut self,
348 context: &Context,
349 keymap_index: u16,
350 event: key::Event<Event>,
351 ) -> Option<TapHoldState> {
352 if let key::Event::Input(input::Event::Press { keymap_index: ki }) = event {
355 self.other_pressed_keymap_index = Some(ki);
356 }
357
358 let Context { config, .. } = context;
360 self.hold_resolution(config.interrupt_response, keymap_index, event)
361 }
362}