Skip to main content
RKTK API Docs RKTK Home Repo

rktk_drivers_common/magnetic/
rapid_trigger.rs

1#[derive(Debug, Clone, Copy)]
2pub struct RapidTriggerState {
3    last_val: u16,
4    max_val: u16,
5    min_val: u16,
6    pressed: bool,
7}
8
9impl RapidTriggerState {
10    #[allow(clippy::new_without_default)]
11    pub const fn new() -> Self {
12        Self { last_val: 0, max_val: 0, min_val: 0, pressed: false }
13    }
14
15    /// Updates the state with a new travel distance and returns whether the key state changed.
16    ///
17    /// # Arguments
18    /// * `val`: Physical travel distance in 0.01mm units (e.g., 0-400 for 0-4.0mm).
19    /// * `press_dist`: Threshold to trigger press when moving down (in 0.01mm).
20    /// * `release_dist`: Threshold to trigger release when moving up (in 0.01mm).
21    /// * `top_deadzone`: Initial travel distance required before activating rapid trigger (in 0.01mm).
22    pub fn update(
23        &mut self,
24        val: u16,
25        press_dist: u16,
26        release_dist: u16,
27        top_deadzone: u16,
28    ) -> Option<bool> {
29        // Top deadzone: if physical travel distance is less than the configured deadzone, force release/unpressed state.
30        // This is standard for magnetic switches to filter out top-of-travel key mechanical play and electronic noise.
31        if val < top_deadzone {
32            if self.pressed {
33                self.pressed = false;
34                self.min_val = val;
35                self.max_val = 0;
36                self.last_val = val;
37                return Some(false);
38            }
39            self.min_val = val;
40            self.max_val = 0;
41            self.last_val = val;
42            return None;
43        }
44
45        let changed = if !self.pressed {
46            if val > self.min_val.saturating_add(press_dist) {
47                self.pressed = true;
48                self.max_val = val;
49                Some(true)
50            } else {
51                if val < self.min_val {
52                    self.min_val = val;
53                }
54                None
55            }
56        } else {
57            if val < self.max_val.saturating_sub(release_dist) {
58                self.pressed = false;
59                self.min_val = val;
60                Some(false)
61            } else {
62                if val > self.max_val {
63                    self.max_val = val;
64                }
65                None
66            }
67        };
68
69        self.last_val = val;
70        changed
71    }
72}