rmk_q6_he_ansi/matrix/
layer_toggle.rs1use embassy_stm32::{exti::ExtiInput, mode::Async};
2use embassy_time::{Duration, Timer};
3use rmk::{event::KeyboardEvent, macros::input_device};
4
5#[derive(Copy, Clone)]
7pub struct MatrixPos {
8 pub col: u8,
10 pub row: u8,
12}
13
14#[input_device(publish = KeyboardEvent)]
16pub struct LayerToggle<'peripherals> {
17 debounce: Duration,
19 high_pos: MatrixPos,
21 last_level: Option<bool>,
23 low_pos: MatrixPos,
25 pending_release: Option<MatrixPos>,
27 pin: ExtiInput<'peripherals, Async>,
29}
30
31impl<'peripherals> LayerToggle<'peripherals> {
32 fn maybe_emit_for_level(&mut self, new_level: bool) -> Option<KeyboardEvent> {
34 if self.last_level == Some(new_level) {
35 return None;
36 }
37 self.last_level = Some(new_level);
38 Some(self.queue_tap(self.pos_for_level(new_level)))
39 }
40
41 #[must_use]
43 pub const fn new(
44 pin: ExtiInput<'peripherals, Async>,
45 high_pos: MatrixPos,
46 low_pos: MatrixPos,
47 debounce: Duration,
48 ) -> Self {
49 Self { pin, high_pos, low_pos, last_level: None, pending_release: None, debounce }
50 }
51
52 #[must_use]
54 pub const fn new_with_default_debounce(
55 pin: ExtiInput<'peripherals, Async>,
56 high_pos: MatrixPos,
57 low_pos: MatrixPos,
58 ) -> Self {
59 Self::new(pin, high_pos, low_pos, Duration::from_millis(15))
60 }
61
62 #[inline]
64 const fn pos_for_level(&self, level_high: bool) -> MatrixPos {
65 if level_high { self.high_pos } else { self.low_pos }
66 }
67
68 #[inline]
70 fn queue_tap(&mut self, pos: MatrixPos) -> KeyboardEvent {
71 self.pending_release = Some(pos);
72 KeyboardEvent::key(pos.row, pos.col, true)
73 }
74
75 async fn read_keyboard_event(&mut self) -> KeyboardEvent {
77 if let Some(pos) = self.pending_release.take() {
78 return KeyboardEvent::key(pos.row, pos.col, false);
79 }
80
81 if self.last_level.is_none() {
82 let level = self.pin.is_high();
83 self.last_level = Some(level);
84 return self.queue_tap(self.pos_for_level(level));
85 }
86
87 loop {
88 self.pin.wait_for_any_edge().await;
89 Timer::after(self.debounce).await;
90 let level = self.pin.is_high();
91
92 if let Some(evt) = self.maybe_emit_for_level(level) {
93 return evt;
94 }
95 }
96 }
97}