1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
//! Debouncer definition. //! //! When pressed, switches don't give a clear state change: they //! bounce. A debouncer filter these bounces. The current //! implementation validate the state change when the state is stable //! during a configurable number of update. 5 ms is the recommended //! duration for keyboard switches. use crate::layout::Event; use core::convert::TryInto; use either::Either::*; /// The debouncer type. pub struct Debouncer<T> { cur: T, new: T, since: u16, nb_bounce: u16, } impl<T> Debouncer<T> { /// Create a new debouncer. /// /// `cur` and `new` corresponds to the initial state, they should /// be equal at start. taking the 2 states allow `new` to be a /// `const fn` and allow non clonable types to be used. /// /// `nb_bounce` correspond to the number of update with same state /// needed to validate the new state. pub const fn new(cur: T, new: T, nb_bounce: u16) -> Self { Self { cur, new, since: 0, nb_bounce, } } } impl<T: PartialEq> Debouncer<T> { /// Gets the current state. pub fn get(&self) -> &T { &self.cur } /// Updates the current state. Returns `true` if the state changes. pub fn update(&mut self, new: T) -> bool { if self.cur == new { self.since = 0; return false; } if self.new != new { self.new = new; self.since = 1; } else { self.since += 1; } if self.since > self.nb_bounce { core::mem::swap(&mut self.cur, &mut self.new); self.since = 0; true } else { false } } /// Iterates on the `Event`s generated by the update. /// /// `T` must be some kind of array of array of bool. /// /// Panics if the coordinates doesn't fit in a `(u8, u8)`. /// /// # Example /// /// ``` /// use keyberon::debounce::Debouncer; /// use keyberon::layout::Event; /// let mut debouncer = Debouncer::new( /// [[false, false], [false, false]], /// [[false, false], [false, false]], /// 2, /// ); /// /// // no changes /// assert_eq!(0, debouncer.events([[false, false], [false, false]]).count()); /// /// // `(0, 1)` pressed, but debouncer is filtering /// assert_eq!(0, debouncer.events([[false, true], [false, false]]).count()); /// assert_eq!(0, debouncer.events([[false, true], [false, false]]).count()); /// /// // `(0, 1)` stable enough, event appear. /// assert_eq!( /// vec![Event::Press(0, 1)], /// debouncer.events([[false, true], [false, false]]).collect::<Vec<_>>(), /// ); /// ``` pub fn events<'a, U>(&'a mut self, new: T) -> impl Iterator<Item = Event> + 'a where &'a T: IntoIterator<Item = U>, U: IntoIterator<Item = &'a bool>, U::IntoIter: 'a, { if self.update(new) { Left( self.new .into_iter() .zip(self.cur.into_iter()) .enumerate() .flat_map(move |(i, (o, n))| { o.into_iter().zip(n.into_iter()).enumerate().filter_map( move |(j, bools)| match bools { (false, true) => { Some(Event::Press(i.try_into().unwrap(), j.try_into().unwrap())) } (true, false) => Some(Event::Release( i.try_into().unwrap(), j.try_into().unwrap(), )), _ => None, }, ) }), ) } else { Right(core::iter::empty()) } } }