use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct KeyMod(pub u8);
impl KeyMod {
pub const SHIFT: KeyMod = KeyMod(1 << 0);
pub const ALT: KeyMod = KeyMod(1 << 1);
pub const CTRL: KeyMod = KeyMod(1 << 2);
pub const META: KeyMod = KeyMod(1 << 3);
pub const HYPER: KeyMod = KeyMod(1 << 4);
pub const SUPER: KeyMod = KeyMod(1 << 5);
pub const CAPS_LOCK: KeyMod = KeyMod(1 << 6);
pub const NUM_LOCK: KeyMod = KeyMod(1 << 7);
pub fn contains(&self, flag: KeyMod) -> bool {
(self.0 & flag.0) != 0
}
}
pub const KEY_UP: char = '\u{E000}';
pub const KEY_DOWN: char = '\u{E001}';
pub const KEY_RIGHT: char = '\u{E002}';
pub const KEY_LEFT: char = '\u{E003}';
pub const KEY_HOME: char = '\u{E004}';
pub const KEY_END: char = '\u{E005}';
pub const KEY_PG_UP: char = '\u{E006}';
pub const KEY_PG_DOWN: char = '\u{E007}';
pub const KEY_ENTER: char = '\r';
pub const KEY_TAB: char = '\t';
pub const KEY_BACKSPACE: char = '\u{007F}';
pub const KEY_ESCAPE: char = '\u{001B}';
pub const KEY_SPACE: char = ' ';
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Key {
pub text: String,
pub mod_keys: KeyMod,
pub code: char,
pub shifted_code: Option<char>,
pub base_code: Option<char>,
pub is_repeat: bool,
}
impl Key {
pub fn new(code: char, text: &str, mod_keys: KeyMod) -> Self {
Self {
text: text.to_string(),
mod_keys,
code,
shifted_code: None,
base_code: None,
is_repeat: false,
}
}
pub fn string(&self) -> String {
if self.code == ' ' {
"space".to_string()
} else if !self.text.is_empty() {
self.text.clone()
} else {
self.keystroke()
}
}
pub fn keystroke(&self) -> String {
let mut parts: Vec<String> = Vec::new();
if self.mod_keys.contains(KeyMod::CTRL) {
parts.push("ctrl".to_string());
}
if self.mod_keys.contains(KeyMod::ALT) {
parts.push("alt".to_string());
}
if self.mod_keys.contains(KeyMod::SHIFT) {
parts.push("shift".to_string());
}
if self.mod_keys.contains(KeyMod::META) {
parts.push("meta".to_string());
}
let name = match self.code {
KEY_UP => "up".to_string(),
KEY_DOWN => "down".to_string(),
KEY_RIGHT => "right".to_string(),
KEY_LEFT => "left".to_string(),
KEY_HOME => "home".to_string(),
KEY_END => "end".to_string(),
KEY_PG_UP => "pgup".to_string(),
KEY_PG_DOWN => "pgdown".to_string(),
KEY_ENTER => "enter".to_string(),
KEY_TAB => "tab".to_string(),
KEY_BACKSPACE => "backspace".to_string(),
KEY_ESCAPE => "esc".to_string(),
' ' => "space".to_string(),
c => c.to_string(),
};
if parts.is_empty() {
name
} else {
parts.push(name);
parts.join("+")
}
}
}
impl fmt::Display for Key {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.string())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct KeyPressMsg(pub Key);
impl fmt::Display for KeyPressMsg {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0.string())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct KeyReleaseMsg(pub Key);
impl fmt::Display for KeyReleaseMsg {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0.string())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum KeyMsg {
Press(KeyPressMsg),
Release(KeyReleaseMsg),
}
impl KeyMsg {
pub fn key(&self) -> &Key {
match self {
KeyMsg::Press(k) => &k.0,
KeyMsg::Release(k) => &k.0,
}
}
}
impl fmt::Display for KeyMsg {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.key().string())
}
}