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                if self.deboune_only_pressed {
42                    return event.pressed;
43                } else {
44                    return true;
45                }
46            }
47        self.last[event.row as usize][event.col as usize] = Some(now);
48        false
49    }
50}
51
52#[cfg(test)]
53mod tests {
54    use embassy_time::{Duration, Instant};
55    use rktk::drivers::interface::{debounce::DebounceDriver as _, keyscan::KeyChangeEvent};
56
57    use super::EagerDebounceDriver;
58
59    #[test]
60    fn eager_debouncer_only_pressed() {
61        // PRESS    Accepted
62        // 5ms
63        // RELEASE  Maybe chatter but accepted
64        // 3ms
65        // PRESS    Ignored
66        // ...
67        // 92ms
68        // ...
69        // PRESS    Accepted
70
71        let mut d = EagerDebounceDriver::new(Duration::from_millis(10), true);
72
73        assert!(
74            !d.should_ignore_event(
75                &KeyChangeEvent {
76                    row: 0,
77                    col: 0,
78                    pressed: true,
79                },
80                Instant::from_millis(0),
81            ),
82            "Key press event should not be ignored"
83        );
84
85        assert!(
86            !d.should_ignore_event(
87                &KeyChangeEvent {
88                    row: 0,
89                    col: 0,
90                    pressed: false,
91                },
92                Instant::from_millis(5),
93            ),
94            "Key release event before debounce_time should not be ignored"
95        );
96
97        assert!(
98            d.should_ignore_event(
99                &KeyChangeEvent {
100                    row: 0,
101                    col: 0,
102                    pressed: true,
103                },
104                Instant::from_millis(8),
105            ),
106            "Key press event before debounce_time should be ignored"
107        );
108
109        assert!(
110            !d.should_ignore_event(
111                &KeyChangeEvent {
112                    row: 0,
113                    col: 0,
114                    pressed: true,
115                },
116                Instant::from_millis(100),
117            ),
118            "Key press event after debounce_time should not be ignored"
119        );
120    }
121}