rustphone/src/keypad.rs
2023-09-11 22:22:20 +02:00

187 lines
4 KiB
Rust

use arrayvec::ArrayVec;
const NB_KEYS: usize = 21;
/// Key repeat max delay (ms)
const REPEAT_DELAY: u64 = 500;
pub type KeyEvents = ArrayVec<KeyEvent, 4>;
pub struct Keypad {
last_key: Option<(Key, u64, u8)>,
pressed: [bool; NB_KEYS],
}
impl Default for Keypad {
fn default() -> Self {
Self {
last_key: None,
pressed: [false; NB_KEYS],
}
}
}
impl Keypad {
pub fn update(&mut self) -> KeyEvents {
self.get_keys()
.into_iter()
.zip(self.pressed.iter_mut())
.zip(0u8..)
.filter_map(|((new_pressed, old_pressed), key)| {
let mut repeats = 0;
let event_type = match (*old_pressed, new_pressed) {
(true, true) => KeyEventType::Down,
(true, false) => {
*old_pressed = new_pressed;
KeyEventType::Released
}
(false, true) => {
*old_pressed = new_pressed;
'count_repeats: {
if let Some((last_key, last_when, last_repeats)) = &mut self.last_key {
if *last_key as u8 == key {
let now = crate::time::millis();
if now.wrapping_sub(*last_when) < REPEAT_DELAY {
*last_repeats = last_repeats.saturating_add(1);
} else {
*last_repeats = 1;
}
repeats = *last_repeats;
*last_when = now;
break 'count_repeats;
}
}
self.last_key =
Some((Key::from_u8_unchecked(key), crate::time::millis(), 1));
}
KeyEventType::Pressed
}
(false, false) => return None,
};
Some(KeyEvent {
key: Key::from_u8_unchecked(key),
event_type,
repeats,
})
})
.collect()
}
#[cfg(feature = "simulator")]
fn get_keys(&self) -> [bool; NB_KEYS] {
use embedded_graphics_simulator::sdl2::Keycode;
use embedded_graphics_simulator::SimulatorEvent;
let mut keys = [false; NB_KEYS];
crate::display::window_mut()
.events()
.filter_map(|event| match event {
SimulatorEvent::KeyDown { keycode, .. } => match keycode {
Keycode::Num0 | Keycode::Kp0 => Some(Key::D0),
Keycode::Num1 | Keycode::Kp1 => Some(Key::D1),
Keycode::Num2 | Keycode::Kp2 => Some(Key::D2),
Keycode::Num3 | Keycode::Kp3 => Some(Key::D3),
Keycode::Num4 | Keycode::Kp4 => Some(Key::D4),
Keycode::Num5 | Keycode::Kp5 => Some(Key::D5),
Keycode::Num6 | Keycode::Kp6 => Some(Key::D6),
Keycode::Num7 | Keycode::Kp7 => Some(Key::D7),
Keycode::Num8 | Keycode::Kp8 => Some(Key::D8),
Keycode::Num9 | Keycode::Kp9 => Some(Key::D9),
Keycode::KpEnter | Keycode::Return => Some(Key::Enter),
Keycode::Asterisk => Some(Key::Asterisk),
Keycode::Hash | Keycode::KpHash => Some(Key::Hash),
// TODO more
_ => None,
},
SimulatorEvent::Quit => std::process::exit(0),
_ => None,
})
.for_each(|key| keys[key as usize] = true);
keys
}
#[cfg(not(feature = "simulator"))]
fn get_keys(&self) -> [bool; NB_KEYS] {
[false; NB_KEYS]
}
}
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum Key {
D0 = 0,
D1 = 1,
D2 = 2,
D3 = 3,
D4 = 4,
D5 = 5,
D6 = 6,
D7 = 7,
D8 = 8,
D9 = 9,
Enter = 10,
OptionRight = 11,
OptionLeft = 12,
Left = 13,
Right = 14,
Top = 15,
Down = 16,
Asterisk = 17,
Hash = 18,
PickUp = 19,
HangUp = 20,
}
impl Key {
fn from_u8_unchecked(key: u8) -> Self {
unsafe { core::mem::transmute(key) }
}
}
pub struct KeyEvent {
pub event_type: KeyEventType,
pub key: Key,
pub repeats: u8,
}
impl KeyEvent {
pub fn get_char(&self, key_input_mode: KeyInputMode) -> Option<char> {
use Key::*;
match key_input_mode {
KeyInputMode::Digit => match self.key {
D0 => Some('0'),
D1 => Some('1'),
D2 => Some('2'),
D3 => Some('3'),
D4 => Some('4'),
D5 => Some('5'),
D6 => Some('6'),
D7 => Some('7'),
D8 => Some('8'),
D9 => Some('9'),
Asterisk => Some('*'),
Hash => Some('#'),
_ => None,
},
_ => {
None /* TODO */
}
}
}
}
//ncb1 upz2 tdk3
//eow4 lqh5 age6
//sfx7 rmj8 ivy9
#[derive(Eq, PartialEq)]
pub enum KeyEventType {
Pressed,
Down,
Released,
}
pub enum KeyInputMode {
Digit,
Alpha,
}