use core::hash::{Hash, Hasher};
use bitflags::bitflags;
use crate::Event;
#[derive(Debug, PartialOrd, Ord, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct KeyEvent {
pub code: KeyCode,
pub modifiers: KeyModifiers,
pub kind: KeyEventKind,
pub state: KeyEventState,
}
impl KeyEvent {
pub const fn new(code: KeyCode) -> Self {
Self {
code,
modifiers: KeyModifiers::empty(),
kind: KeyEventKind::Press,
state: KeyEventState::empty(),
}
}
pub const fn modifiers(mut self, modifiers: KeyModifiers) -> Self {
self.modifiers = modifiers;
self
}
pub const fn kind(mut self, kind: KeyEventKind) -> Self {
self.kind = kind;
self
}
pub const fn state(mut self, state: KeyEventState) -> Self {
self.state = state;
self
}
pub fn normalize_case(mut self) -> Self {
let c = match self.code {
KeyCode::Char(c) => c,
_ => return self,
};
if c.is_ascii_uppercase() {
self.modifiers.insert(KeyModifiers::SHIFT);
} else if self.modifiers.contains(KeyModifiers::SHIFT) {
self.code = KeyCode::Char(c.to_ascii_uppercase());
}
self
}
}
impl PartialEq for KeyEvent {
fn eq(&self, other: &Self) -> bool {
let Self {
code: lhs_code,
modifiers: lhs_modifiers,
kind: lhs_kind,
state: lhs_state,
} = self.normalize_case();
let Self {
code: rhs_code,
modifiers: rhs_modifiers,
kind: rhs_kind,
state: rhs_state,
} = other.normalize_case();
(lhs_code == rhs_code)
&& (lhs_modifiers == rhs_modifiers)
&& (lhs_kind == rhs_kind)
&& (lhs_state == rhs_state)
}
}
impl Eq for KeyEvent {}
impl Hash for KeyEvent {
fn hash<H: Hasher>(&self, hash_state: &mut H) {
let Self {
code,
modifiers,
kind,
state,
} = self.normalize_case();
code.hash(hash_state);
modifiers.hash(hash_state);
kind.hash(hash_state);
state.hash(hash_state);
}
}
#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Copy, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ModifierDirection {
Left,
Right,
Unknown,
}
#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Copy, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum KeyCode {
Backspace,
Enter,
Left,
Right,
Up,
Down,
Home,
End,
PageUp,
PageDown,
Tab,
Delete,
Insert,
F(u8),
Char(char),
Esc,
CapsLock,
ScrollLock,
NumLock,
PrintScreen,
Pause,
Menu,
KeypadBegin,
Media(MediaKeyCode),
Modifier(ModifierKeyCode, ModifierDirection),
}
bitflags! {
#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Copy, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(transparent))]
pub struct KeyModifiers: u8 {
const NONE = 0;
const SHIFT = 1;
const ALT = 1<<1;
const CTRL = 1<<2;
const SUPER = 1<<3;
const HYPER = 1<<4;
const META = 1<<5;
}
}
pub const SHIFT: KeyModifiers = KeyModifiers::SHIFT;
pub const ALT: KeyModifiers = KeyModifiers::ALT;
pub const CTRL: KeyModifiers = KeyModifiers::CTRL;
pub const SUPER: KeyModifiers = KeyModifiers::SUPER;
pub const HYPER: KeyModifiers = KeyModifiers::HYPER;
pub const META: KeyModifiers = KeyModifiers::META;
#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Copy, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum KeyEventKind {
Press,
Repeat,
Release,
}
#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Copy, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum MediaKeyCode {
Play,
Pause,
PlayPause,
Reverse,
Stop,
FastForward,
Rewind,
TrackNext,
TrackPrevious,
Record,
LowerVolume,
RaiseVolume,
MuteVolume,
}
#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Copy, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ModifierKeyCode {
Shift,
Control,
Alt,
Super,
Hyper,
Meta,
IsoLevel3Shift,
IsoLevel5Shift,
}
bitflags! {
#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Copy, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(transparent))]
pub struct KeyEventState: u8 {
const NONE = 0;
const KEYPAD = 1;
const CAPS_LOCK = 1<<1;
const NUM_LOCK = 1<<2;
}
}
pub const KEYPAD: KeyEventState = KeyEventState::KEYPAD;
pub const CAPS_LOCK: KeyEventState = KeyEventState::CAPS_LOCK;
pub const NUM_LOCK: KeyEventState = KeyEventState::NUM_LOCK;
impl From<KeyCode> for KeyEvent {
fn from(code: KeyCode) -> Self {
Self {
code,
modifiers: KeyModifiers::empty(),
kind: KeyEventKind::Press,
state: KeyEventState::empty(),
}
}
}
impl From<KeyEvent> for Event {
fn from(value: KeyEvent) -> Self {
Self::Key(value)
}
}
#[macro_export]
macro_rules! key {
($state:pat, $mods:pat, $code:pat) => {
$crate::KeyEvent {
code: $code,
modifiers: $mods,
state: $state,
..
}
};
($mods:pat, $code:pat) => {
$crate::KeyEvent {
code: $code,
modifiers: $mods,
..
}
};
($code:pat) => {
$crate::KeyEvent {
code: $code,
modifiers: $crate::KeyModifiers::NONE,
..
}
};
}
#[macro_export]
macro_rules! modifiers {
($($key_mod:tt),+) => {
$crate::KeyModifiers::from_bits_retain($($key_mod.bits())|+)
};
}
#[macro_export]
macro_rules! states {
($($state:tt),+) => {
$crate::KeyEventState::from_bits_retain($($state.bits())|+)
};
}