pub type InputKey = &'static str;
macro_rules! with_key_codes {
($callback:ident) => {
$callback! {
Backquote, Backslash, BracketLeft, BracketRight, Comma, Digit0, Digit1, Digit2, Digit3, Digit4, Digit5,
Digit6, Digit7, Digit8, Digit9, Equal, IntlBackslash, IntlRo, IntlYen, KeyA, KeyB, KeyC, KeyD, KeyE, KeyF,
KeyG, KeyH, KeyI, KeyJ, KeyK, KeyL, KeyM, KeyN, KeyO, KeyP, KeyQ, KeyR, KeyS, KeyT, KeyU, KeyV, KeyW, KeyX,
KeyY, KeyZ, Minus, Period, Quote, Semicolon, Slash, AltLeft, AltRight, Backspace, CapsLock, ContextMenu,
ControlLeft, ControlRight, Enter, ShiftLeft, ShiftRight, Space, Tab, Convert, KanaMode, Lang1, Lang2,
Lang3, Lang4, Lang5, NonConvert, Delete, End, Help, Home, Insert, PageDown, PageUp, ArrowDown, ArrowLeft,
ArrowRight, ArrowUp, NumLock, Numpad0, Numpad1, Numpad2, Numpad3, Numpad4, Numpad5, Numpad6, Numpad7,
Numpad8, Numpad9, NumpadAdd, NumpadBackspace, NumpadClear, NumpadClearEntry, NumpadComma, NumpadDecimal,
NumpadDivide, NumpadEnter, NumpadEqual, NumpadHash, NumpadMemoryAdd, NumpadMemoryClear,
NumpadMemoryRecall, NumpadMemoryStore, NumpadMemorySubtract, NumpadMultiply, NumpadParenLeft,
NumpadParenRight, NumpadStar, NumpadSubtract, Escape, Fn, FnLock, PrintScreen, ScrollLock, Pause,
BrowserBack, BrowserFavorites, BrowserForward, BrowserHome, BrowserRefresh, BrowserSearch, BrowserStop,
Eject, LaunchApp1, LaunchApp2, LaunchMail, MediaPlayPause, MediaSelect, MediaStop, MediaTrackNext,
MediaTrackPrevious, Power, Sleep, AudioVolumeDown, AudioVolumeMute, AudioVolumeUp, WakeUp, Hyper,
Turbo, Abort, Resume, Suspend, Again, Copy, Cut, Find, Open, Paste, Props, Select, Undo, Hiragana,
Katakana, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17, F18, F19, F20,
F21, F22, F23, F24, F25, F26, F27, F28, F29, F30, F31, F32, F33, F34, F35
}
};
}
pub(crate) use with_key_codes;
macro_rules! key_code_names {
($($code:ident),*) => { &[$(stringify!($code),)* "MetaLeft", "MetaRight"] };
}
pub const KEY_CODES: &[InputKey] = with_key_codes!(key_code_names);
pub fn key_name(code: &str) -> InputKey {
KEY_CODES.iter().copied().find(|k| *k == code).unwrap_or("Unknown")
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
pub struct Modifiers {
pub shift: bool,
pub ctrl: bool,
pub alt: bool,
pub meta: bool,
}
impl Modifiers {
pub fn from_bits(bits: u32) -> Self {
Self { shift: bits & 1 != 0, ctrl: bits & 2 != 0, alt: bits & 4 != 0, meta: bits & 8 != 0 }
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum KeyKind {
Down,
Up,
Char,
}
#[derive(Default, Debug)]
pub struct Keyboard {
pub modifiers: Modifiers,
pressed: Vec<InputKey>,
}
impl Keyboard {
pub fn is_shift_pressed(&self) -> bool {
self.modifiers.shift
}
pub fn is_control_pressed(&self) -> bool {
self.modifiers.ctrl || self.modifiers.meta
}
pub fn is_alt_pressed(&self) -> bool {
self.modifiers.alt
}
pub fn is_pressed(&self, key: &str) -> bool {
self.pressed.iter().any(|k| *k == key)
}
pub(crate) fn apply(&mut self, kind: KeyKind, key: InputKey, modifiers: Modifiers) {
self.modifiers = modifiers;
match kind {
KeyKind::Down if !self.is_pressed(key) => self.pressed.push(key),
KeyKind::Up => self.pressed.retain(|k| *k != key),
_ => {}
}
}
pub(crate) fn reset(&mut self) {
self.pressed.clear();
self.modifiers = Modifiers::default();
}
}
#[derive(Clone, Copy, Debug)]
pub struct KeyEvent<'a> {
pub kind: KeyKind,
pub key: InputKey,
pub text: &'a str,
pub repeat: bool,
pub keyboard: &'a Keyboard,
}
impl KeyEvent<'_> {
pub fn modifiers(&self) -> Modifiers {
self.keyboard.modifiers
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
pub enum Cursor {
#[default]
Default,
Pointer,
Text,
}