use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KeyEventType {
KeyDown,
KeyUp,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct Modifiers {
pub shift: bool,
pub ctrl: bool,
pub alt: bool,
pub meta: bool,
}
impl Modifiers {
pub const NONE: Modifiers = Modifiers {
shift: false,
ctrl: false,
alt: false,
meta: false,
};
pub fn any(&self) -> bool {
self.shift || self.ctrl || self.alt || self.meta
}
pub fn command_or_ctrl(&self) -> bool {
#[cfg(target_os = "macos")]
{
self.meta
}
#[cfg(not(target_os = "macos"))]
{
self.ctrl
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum KeyCode {
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
Digit0,
Digit1,
Digit2,
Digit3,
Digit4,
Digit5,
Digit6,
Digit7,
Digit8,
Digit9,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
F11,
F12,
ArrowUp,
ArrowDown,
ArrowLeft,
ArrowRight,
Home,
End,
PageUp,
PageDown,
Backspace,
Delete,
Enter,
Tab,
Space,
Escape,
ShiftLeft,
ShiftRight,
ControlLeft,
ControlRight,
AltLeft,
AltRight,
MetaLeft,
MetaRight,
Minus,
Equal,
BracketLeft,
BracketRight,
Backslash,
Semicolon,
Quote,
Comma,
Period,
Slash,
Backquote,
Unknown,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct KeyEvent {
pub key_code: KeyCode,
pub text: String,
pub modifiers: Modifiers,
pub event_type: KeyEventType,
}
impl KeyEvent {
pub fn new(
key_code: KeyCode,
text: impl Into<String>,
modifiers: Modifiers,
event_type: KeyEventType,
) -> Self {
Self {
key_code,
text: text.into(),
modifiers,
event_type,
}
}
pub fn key_down(key_code: KeyCode, text: impl Into<String>) -> Self {
Self::new(key_code, text, Modifiers::NONE, KeyEventType::KeyDown)
}
pub fn key_down_with_modifiers(
key_code: KeyCode,
text: impl Into<String>,
modifiers: Modifiers,
) -> Self {
Self::new(key_code, text, modifiers, KeyEventType::KeyDown)
}
pub fn is_key_down(&self) -> bool {
self.event_type == KeyEventType::KeyDown
}
pub fn is_key_up(&self) -> bool {
self.event_type == KeyEventType::KeyUp
}
pub fn has_text(&self) -> bool {
!self.text.is_empty()
}
}
impl fmt::Display for KeyEvent {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"KeyEvent({:?}, text=\"{}\", {:?})",
self.key_code, self.text, self.event_type
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn key_event_creation() {
let event = KeyEvent::key_down(KeyCode::A, "a");
assert_eq!(event.key_code, KeyCode::A);
assert_eq!(event.text, "a");
assert!(event.is_key_down());
assert!(event.has_text());
}
#[test]
fn key_event_with_modifiers() {
let modifiers = Modifiers {
shift: true,
ctrl: false,
alt: false,
meta: false,
};
let event = KeyEvent::key_down_with_modifiers(KeyCode::A, "A", modifiers);
assert_eq!(event.text, "A");
assert!(event.modifiers.shift);
}
#[test]
fn backspace_has_no_text() {
let event = KeyEvent::key_down(KeyCode::Backspace, "");
assert!(!event.has_text());
}
#[test]
fn modifiers_any() {
assert!(!Modifiers::NONE.any());
assert!(Modifiers {
shift: true,
..Modifiers::NONE
}
.any());
}
}