Skip to main content
RKTK API Docs RKTK Home Repo

rktk_drivers_common/
debounce.rs

1//! Debounce driver implementations.
2
3use rktk::{
4    config::CONST_CONFIG,
5    drivers::interface::debounce::{DebounceDriver, KeyChangeEvent},
6};
7
8/// Debounce driver that implements `Eager debouncing`
9///
10/// Debounces key using "eager debouncing" strategy.
11/// Ignores all events related to a key for a certain period of time after that event is reported.
12/// ref: [Debouncing | ZMK](https://zmk.dev/docs/features/debouncing#eager-debouncing)
13pub struct EagerDebounceDriver {
14    last: [[Option<embassy_time::Instant>; CONST_CONFIG.keyboard.cols as usize];
15        CONST_CONFIG.keyboard.rows as usize],
16    debounce_time: embassy_time::Duration,
17    deboune_only_pressed: bool,
18}
19
20impl EagerDebounceDriver {
21    /// Create a new `EagerDebounceDriver` instance.
22    ///
23    /// # Arguments
24    /// * debounce_time - The debounce time.
25    /// * deboune_only_pressed - If true, only debounce pressed events.
26    pub const fn new(debounce_time: embassy_time::Duration, deboune_only_pressed: bool) -> Self {
27        Self {
28            last: [[None; CONST_CONFIG.keyboard.cols as usize];
29                CONST_CONFIG.keyboard.rows as usize],
30            debounce_time,
31            deboune_only_pressed,
32        }
33    }
34}
35
36impl DebounceDriver for EagerDebounceDriver {
37    fn should_ignore_event(&mut self, event: &KeyChangeEvent, now: embassy_time::Instant) -> bool {
38        let last = self.last[event.row as usize][event.col as usize];
39        if let Some(last) = last
40            && now - last < self.debounce_time
41        {
42            if self.deboune_only_pressed {
43                return event.pressed;
44            } else {
45                return true;
46            }
47        }
48        self.last[event.row as usize][event.col as usize] = Some(now);
49        false
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use embassy_time::{Duration, Instant};
56    use rktk::drivers::interface::{debounce::DebounceDriver as _, keyscan::KeyChangeEvent};
57
58    use super::EagerDebounceDriver;
59
60    #[test]
61    fn eager_debouncer_only_pressed() {
62        // PRESS    Accepted
63        // 5ms
64        // RELEASE  Maybe chatter but accepted
65        // 3ms
66        // PRESS    Ignored
67        // ...
68        // 92ms
69        // ...
70        // PRESS    Accepted
71
72        let mut d = EagerDebounceDriver::new(Duration::from_millis(10), true);
73
74        assert!(
75            !d.should_ignore_event(
76                &KeyChangeEvent { row: 0, col: 0, pressed: true },
77                Instant::from_millis(0),
78            ),
79            "Key press event should not be ignored"
80        );
81
82        assert!(
83            !d.should_ignore_event(
84                &KeyChangeEvent { row: 0, col: 0, pressed: false },
85                Instant::from_millis(5),
86            ),
87            "Key release event before debounce_time should not be ignored"
88        );
89
90        assert!(
91            d.should_ignore_event(
92                &KeyChangeEvent { row: 0, col: 0, pressed: true },
93                Instant::from_millis(8),
94            ),
95            "Key press event before debounce_time should be ignored"
96        );
97
98        assert!(
99            !d.should_ignore_event(
100                &KeyChangeEvent { row: 0, col: 0, pressed: true },
101                Instant::from_millis(100),
102            ),
103            "Key press event after debounce_time should not be ignored"
104        );
105    }
106}