rmk_q1_pro_iso/matrix/
layer_toggle.rs1use core::hint::cold_path;
2use embassy_stm32::{exti::ExtiInput, mode::Async};
3use embassy_time::{Duration, Timer};
4use rmk::{event::KeyboardEvent, macros::input_device};
5
6#[derive(Copy, Clone)]
7pub struct MatrixPos {
9 pub col: u8,
11 pub row: u8,
13}
14
15#[input_device(publish = KeyboardEvent)]
17pub struct LayerToggle<'peripherals> {
18 debounce: Duration,
20 high_pos: MatrixPos,
22 last_level: Option<bool>,
24 low_pos: MatrixPos,
26 pending_release: Option<MatrixPos>,
28 pin: ExtiInput<'peripherals, Async>,
30}
31
32impl<'peripherals> LayerToggle<'peripherals> {
33 fn maybe_emit_for_level(&mut self, new_level: bool) -> Option<KeyboardEvent> {
35 if self.last_level == Some(new_level) {
36 return None;
37 }
38 self.last_level = Some(new_level);
39 Some(self.queue_tap(self.pos_for_level(new_level)))
40 }
41
42 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 pub const fn new_with_default_debounce(
54 pin: ExtiInput<'peripherals, Async>,
55 high_pos: MatrixPos,
56 low_pos: MatrixPos,
57 ) -> Self {
58 Self::new(pin, high_pos, low_pos, Duration::from_millis(15))
59 }
60
61 #[inline]
62 const fn pos_for_level(&self, level_high: bool) -> MatrixPos {
64 if level_high { self.high_pos } else { self.low_pos }
65 }
66
67 #[inline]
68 fn queue_tap(&mut self, pos: MatrixPos) -> KeyboardEvent {
70 self.pending_release = Some(pos);
71 KeyboardEvent::key(pos.row, pos.col, true)
72 }
73
74 async fn read_keyboard_event(&mut self) -> KeyboardEvent {
76 if let Some(pos) = self.pending_release.take() {
77 cold_path();
78 return KeyboardEvent::key(pos.row, pos.col, false);
79 }
80
81 if self.last_level.is_none() {
82 cold_path();
83 let level = self.pin.is_high();
84 self.last_level = Some(level);
85 return self.queue_tap(self.pos_for_level(level));
86 }
87
88 loop {
89 self.pin.wait_for_any_edge().await;
90 Timer::after(self.debounce).await;
91 let level = self.pin.is_high();
92
93 if let Some(evt) = self.maybe_emit_for_level(level) {
94 return evt;
95 }
96 }
97 }
98}