use std::ops::{BitOr, BitOrAssign};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct KeyEvent {
code: KeyCode,
modifiers: KeyModifiers,
kind: KeyEventKind,
}
impl KeyEvent {
pub fn new(code: KeyCode) -> Self {
Self {
code,
modifiers: KeyModifiers::empty(),
kind: KeyEventKind::Press,
}
}
pub fn kind(mut self, kind: KeyEventKind) -> Self {
self.kind = kind;
self
}
pub fn modifier(mut self, modifier: KeyModifiers) -> Self {
self.modifiers.insert(modifier);
self
}
pub fn code(&self) -> KeyCode {
self.code
}
pub fn modifiers(&self) -> KeyModifiers {
self.modifiers
}
pub fn kind_value(&self) -> KeyEventKind {
self.kind
}
}
impl From<crossterm::event::KeyEvent> for KeyEvent {
fn from(event: crossterm::event::KeyEvent) -> Self {
Self {
code: event.code.into(),
modifiers: event.modifiers.into(),
kind: event.kind.into(),
}
}
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KeyCode {
Char(char),
Enter,
Backspace,
Delete,
Left,
Right,
Up,
Down,
Home,
End,
Tab,
BackTab,
Esc,
PageUp,
PageDown,
Unsupported,
}
impl From<crossterm::event::KeyCode> for KeyCode {
fn from(code: crossterm::event::KeyCode) -> Self {
match code {
crossterm::event::KeyCode::Backspace => Self::Backspace,
crossterm::event::KeyCode::Enter => Self::Enter,
crossterm::event::KeyCode::Left => Self::Left,
crossterm::event::KeyCode::Right => Self::Right,
crossterm::event::KeyCode::Up => Self::Up,
crossterm::event::KeyCode::Down => Self::Down,
crossterm::event::KeyCode::Home => Self::Home,
crossterm::event::KeyCode::End => Self::End,
crossterm::event::KeyCode::PageUp => Self::PageUp,
crossterm::event::KeyCode::PageDown => Self::PageDown,
crossterm::event::KeyCode::Tab => Self::Tab,
crossterm::event::KeyCode::BackTab => Self::BackTab,
crossterm::event::KeyCode::Delete => Self::Delete,
crossterm::event::KeyCode::Char(ch) => Self::Char(ch),
crossterm::event::KeyCode::Esc => Self::Esc,
_ => Self::Unsupported,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct KeyModifiers(u8);
impl KeyModifiers {
pub const SHIFT: Self = Self(1 << 0);
pub const ALT: Self = Self(1 << 1);
pub const CONTROL: Self = Self(1 << 2);
pub const SUPER: Self = Self(1 << 3);
pub const META: Self = Self(1 << 4);
pub const HYPER: Self = Self(1 << 5);
pub const fn empty() -> Self {
Self(0)
}
pub fn is_empty(self) -> bool {
self.0 == 0
}
pub fn contains(self, other: Self) -> bool {
self.0 & other.0 == other.0
}
pub fn intersects(self, other: Self) -> bool {
self.0 & other.0 != 0
}
pub fn with(mut self, other: Self) -> Self {
self.insert(other);
self
}
fn insert(&mut self, other: Self) {
self.0 |= other.0;
}
}
impl BitOr for KeyModifiers {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
Self(self.0 | rhs.0)
}
}
impl BitOrAssign for KeyModifiers {
fn bitor_assign(&mut self, rhs: Self) {
self.insert(rhs);
}
}
impl From<crossterm::event::KeyModifiers> for KeyModifiers {
fn from(modifiers: crossterm::event::KeyModifiers) -> Self {
let mut mapped = Self::empty();
if modifiers.contains(crossterm::event::KeyModifiers::SHIFT) {
mapped.insert(Self::SHIFT);
}
if modifiers.contains(crossterm::event::KeyModifiers::ALT) {
mapped.insert(Self::ALT);
}
if modifiers.contains(crossterm::event::KeyModifiers::CONTROL) {
mapped.insert(Self::CONTROL);
}
if modifiers.contains(crossterm::event::KeyModifiers::SUPER) {
mapped.insert(Self::SUPER);
}
if modifiers.contains(crossterm::event::KeyModifiers::META) {
mapped.insert(Self::META);
}
if modifiers.contains(crossterm::event::KeyModifiers::HYPER) {
mapped.insert(Self::HYPER);
}
mapped
}
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KeyEventKind {
Press,
Repeat,
Release,
}
impl From<crossterm::event::KeyEventKind> for KeyEventKind {
fn from(kind: crossterm::event::KeyEventKind) -> Self {
match kind {
crossterm::event::KeyEventKind::Press => Self::Press,
crossterm::event::KeyEventKind::Repeat => Self::Repeat,
crossterm::event::KeyEventKind::Release => Self::Release,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KeyOutcome {
Changed,
Unchanged,
Submit,
Ignored,
}