use core::{
num::NonZeroUsize,
pin::Pin,
task::{
Context,
Poll,
},
};
use alloc::vec::Vec;
use crate::{
debounce::{
DebounceState,
Debouncer,
State,
},
key::*,
matrix::Scan,
stateful::ScanStateful,
};
pub struct StatefulScanner<Sc, St, D> {
debouncer: Debouncer<Sc, St, D>,
per_group: NonZeroUsize,
num_groups: NonZeroUsize,
cur_group: usize,
}
pub type VecScanner<Sc, D> = StatefulScanner<Sc, Vec<Vec<DebounceState>>, D>;
impl<Sc, St, D> StatefulScanner<Sc, St, D>
where
Sc: Scan,
St: State<Sc>,
D: FnMut(),
{
pub fn new(scanner: Sc, debounce: usize, delay: D) -> Self {
Self::with_groups(scanner, debounce, 1, delay)
}
pub fn with_groups(scanner: Sc, debounce: usize, groups: usize, delay: D) -> Self {
StatefulScanner {
debouncer: Debouncer::new(scanner, true, debounce, delay),
per_group: NonZeroUsize::new(Sc::NPULL / groups)
.expect("cannot have more groups than lines to pull"),
num_groups: NonZeroUsize::new(groups).expect("cannot have zero scan groups"),
cur_group: 0,
}
}
}
impl<Sc, St, D> ScanStateful for StatefulScanner<Sc, St, D>
where
Sc: Scan + Unpin,
St: State<Sc> + Unpin,
D: FnMut() + Unpin,
{
fn poll_change(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<PhysKey>> {
let this = self.get_mut();
let offset = this.cur_group * this.per_group.get();
let end = if (this.cur_group + 1) == this.num_groups.get() {
Sc::NPULL
} else {
offset + this.per_group.get()
};
let debouncer = &mut this.debouncer;
for x in offset..end {
if let Some((y, state)) = debouncer.debounce_x(x) {
return Poll::Ready(Some(PhysKey {
pos: KeyPos {
x: x as u8,
y: y as u8,
},
state,
}));
}
}
this.cur_group += 1;
if this.cur_group == this.num_groups.get() {
this.cur_group = 0;
return Poll::Ready(None);
}
cx.waker().wake_by_ref();
Poll::Pending
}
}