mod state;
use crate::{
key::*,
matrix::Scan,
};
pub use self::state::{
DebounceState,
State,
};
pub struct Debouncer<Sc, St, D> {
scanner: Sc,
state: St,
threshold: usize,
quick: bool,
delay: D,
}
impl<Sc, St, D> Debouncer<Sc, St, D>
where
Sc: Scan,
St: State<Sc>,
D: FnMut(),
{
pub fn new(scanner: Sc, quick: bool, threshold: usize, delay: D) -> Self {
Debouncer {
scanner,
threshold,
quick,
state: St::init(),
delay,
}
}
pub fn debounce_x(&mut self, x: usize) -> Option<(usize, KeyState)> {
let mut found = None;
self.scanner.pull(x);
(self.delay)();
for y in 0..Sc::NREAD {
if let Some(change) = self.debounce(x, y) {
found = Some((y, change.into()));
break;
}
}
self.scanner.release(x);
found
}
fn debounce(&mut self, x: usize, y: usize) -> Option<bool> {
if self.quick {
self.debounce_quick(x, y)
} else {
self.debounce_slow(x, y)
}
}
fn debounce_quick(&mut self, x: usize, y: usize) -> Option<bool> {
let state = self.state.get_state(x, y);
match state {
DebounceState::Steady(last_steady) => {
let last_read = self.scanner.read(y);
if last_steady != last_read {
self.state.set_state(
x,
y,
DebounceState::Bouncing {
last_steady,
last_read,
ctr: 0,
},
);
}
None
}
DebounceState::Bouncing {
last_steady,
last_read,
ctr,
} => {
if ctr >= self.threshold {
let current = self.scanner.read(y);
if current == last_read {
self.state.set_state(x, y, DebounceState::Steady(current));
Some(current)
} else {
self.state
.set_state(x, y, DebounceState::Steady(last_steady));
None
}
} else {
self.state.set_state(
x,
y,
DebounceState::Bouncing {
last_steady,
last_read,
ctr: ctr + 1,
},
);
None
}
}
}
}
fn debounce_slow(&mut self, x: usize, y: usize) -> Option<bool> {
let state = self.state.get_state(x, y);
let current = self.scanner.read(y);
match state {
DebounceState::Steady(last_steady) => {
if current != last_steady {
self.state.set_state(
x,
y,
DebounceState::Bouncing {
last_steady,
last_read: current,
ctr: 0,
},
);
}
None
}
DebounceState::Bouncing {
last_steady,
last_read,
mut ctr,
} => {
if current == last_read {
if ctr >= self.threshold {
self.state.set_state(x, y, DebounceState::Steady(current));
Some(current)
} else {
ctr += 1;
self.state.set_state(
x,
y,
DebounceState::Bouncing {
last_steady,
last_read,
ctr,
},
);
None
}
} else {
self.state.set_state(
x,
y,
DebounceState::Bouncing {
last_steady,
last_read: current,
ctr: 0,
},
);
None
}
}
}
}
pub fn change_alg(&mut self, quick: bool) {
self.quick = quick;
}
}