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}
RKTK API Docs