use crate::cmd::{ModeStatus, RequestColor};
use crate::Token;
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum TokenOrEvent<'a> {
Event(Event),
Token(Token<'a>),
}
impl TokenOrEvent<'_> {
pub const fn is_token(&self) -> bool {
matches!(*self, TokenOrEvent::Token(_))
}
pub const fn is_event(&self) -> bool {
matches!(*self, TokenOrEvent::Event(_))
}
pub fn as_event(&self) -> Option<Event> {
match *self {
TokenOrEvent::Event(event) => Some(event),
_ => None,
}
}
pub fn map_event<R, F>(&self, op: F) -> Option<R>
where
F: FnOnce(Event) -> R,
{
match *self {
TokenOrEvent::Event(event) => Some(op(event)),
_ => None,
}
}
pub fn map_either<R, Fe, Ft>(self, map_event: Fe, map_token: Ft) -> Option<R>
where
Fe: FnOnce(Event) -> Option<R>,
Ft: FnOnce(Token<'_>) -> Option<R>,
{
match self {
TokenOrEvent::Event(event) => map_event(event),
TokenOrEvent::Token(token) => map_token(token),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Event {
Key(KeyEvent),
Mouse(MouseEvent),
Window(WindowEvent),
Cursor(CursorEvent),
Color(ColorEvent),
Mode(ModeStatus),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct MouseEvent {
pub kind: MouseEventKind,
pub modifiers: Modifiers,
pub column: u16,
pub row: u16,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MouseEventKind {
Press(MouseButton),
Drag(MouseButton),
Release(MouseButton),
Move,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MouseButton {
Left,
Middle,
Right,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct KeyEvent {
pub kind: KeyEventKind,
pub modifiers: Modifiers,
pub key: Key,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum KeyEventKind {
Press,
Repeat,
Release,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum Modifier {
Shift = 0x01,
Option = 0x02,
Control = 0x04,
Command = 0x08,
Extra1 = 0x10,
Extra2 = 0x20,
CapsLock = 0x40,
NumLock = 0x80,
Keypad = 0x100,
}
impl Modifier {
const fn successor(&self) -> Option<Self> {
use Modifier::*;
Some(match *self {
Shift => Option,
Option => Control,
Control => Command,
Command => Extra1,
Extra1 => Extra2,
Extra2 => CapsLock,
CapsLock => NumLock,
NumLock => Keypad,
Keypad => return None,
})
}
}
impl From<Modifier> for Modifiers {
fn from(value: Modifier) -> Self {
Self(value as u16)
}
}
impl<M: Into<Modifiers>> core::ops::Add<M> for Modifier {
type Output = Modifiers;
fn add(self, rhs: M) -> Self::Output {
Modifiers::combine(self as u16, rhs.into().0)
}
}
impl<M: Into<Modifiers>> core::ops::Add<M> for Modifiers {
type Output = Modifiers;
fn add(self, rhs: M) -> Self::Output {
Self::combine(self.0, rhs.into().0)
}
}
impl<M: Into<Modifiers>> core::ops::AddAssign<M> for Modifiers {
fn add_assign(&mut self, rhs: M) {
*self = Self::combine(self.0, rhs.into().0)
}
}
impl<M: Into<Modifiers>> core::ops::Sub<M> for Modifier {
type Output = Modifiers;
fn sub(self, rhs: M) -> Self::Output {
Modifiers(self as u16 & !rhs.into().0)
}
}
impl<M: Into<Modifiers>> core::ops::Sub<M> for Modifiers {
type Output = Modifiers;
fn sub(self, rhs: M) -> Self::Output {
Self(self.0 & !rhs.into().0)
}
}
impl<M: Into<Modifiers>> core::ops::SubAssign<M> for Modifiers {
fn sub_assign(&mut self, rhs: M) {
*self = Self(self.0 & !rhs.into().0)
}
}
#[derive(Clone, Copy, Default, PartialEq, Eq)]
pub struct Modifiers(u16);
impl Modifiers {
fn combine(left: u16, right: u16) -> Self {
Self(left | right)
}
pub fn from_escape(code: u16) -> Option<Self> {
let code = code.saturating_sub(1);
if code <= (u8::MAX as u16) {
Some(Self(code))
} else {
None
}
}
pub const fn is_empty(&self) -> bool {
self.0 == 0
}
pub const fn len(&self) -> usize {
self.0.count_ones() as usize
}
pub fn has(&self, modifier: Modifier) -> bool {
self.0 & modifier as u16 != 0
}
pub fn modifiers(&self) -> ModifierIter {
ModifierIter {
modifiers: *self,
cursor: None,
remaining: self.len(),
}
}
}
impl core::fmt::Debug for Modifiers {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_set().entries(self.modifiers()).finish()
}
}
#[derive(Debug)]
pub struct ModifierIter {
modifiers: Modifiers,
cursor: Option<Modifier>,
remaining: usize,
}
impl Iterator for ModifierIter {
type Item = Modifier;
fn next(&mut self) -> Option<Self::Item> {
loop {
let modifier = match self.cursor {
None => Modifier::Shift,
Some(Modifier::NumLock) => return None,
Some(modifier) => modifier
.successor()
.expect("with no-successor case already handled, successor must exist"),
};
self.cursor = Some(modifier);
if self.modifiers.has(modifier) {
self.remaining -= 1;
return Some(modifier);
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining, Some(self.remaining))
}
}
impl ExactSizeIterator for ModifierIter {
fn len(&self) -> usize {
self.remaining
}
}
impl core::iter::FusedIterator for ModifierIter {}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum Key {
Escape,
Enter,
Tab,
Backspace,
Insert,
Delete,
Left,
Right,
Up,
Down,
PageUp,
PageDown,
Home,
End,
CapsLock,
ScrollLock,
NumLock,
PrintScreen,
Pause,
Menu,
KeypadBegin,
F(u8),
Media(MediaKey),
Mod(ModifierKey),
Char(char),
}
impl Key {
pub fn with_ss3(byte: u8) -> Option<Self> {
use Key::*;
let key = match byte {
b' ' => Char(' '),
b'A' => Up,
b'B' => Down,
b'C' => Right,
b'D' => Left,
b'E' => KeypadBegin,
b'F' => End,
b'H' => Home,
b'I' => Tab,
b'M' => Enter,
b'P' => F(1),
b'Q' => F(2),
b'R' => F(3),
b'S' => F(4),
b'X' => Char('='),
b'j' => Char('*'),
b'k' => Char('+'),
b'l' => Char(','),
b'm' => Char('-'),
b'n' => Char('.'),
b'o' => Char('/'),
b'p' => Char('0'),
b'q' => Char('1'),
b'r' => Char('2'),
b's' => Char('3'),
b't' => Char('4'),
b'u' => Char('5'),
b'v' => Char('6'),
b'w' => Char('7'),
b'x' => Char('8'),
b'y' => Char('9'),
_ => return None,
};
Some(key)
}
pub fn with_function_key(code: u8) -> Option<Self> {
use Key::*;
let key = match code {
1 => Home,
2 => Insert,
3 => Delete,
4 => End,
5 => PageUp,
6 => PageDown,
7 => Left, 8 => Down, 9 => Up,
10 => Right,
11..=15 => F(code - 10), 17..=21 => F(code - 11), 23..=26 => F(code - 12), 28..=29 => F(code - 13), 31..=34 => F(code - 14), _ => return None,
};
Some(key)
}
pub fn with_csi_u(code: u16) -> Option<(Self, Modifiers)> {
use Key::*;
let key = match code {
9 => Tab,
13 => Enter,
27 => Escape,
127 => Backspace,
57_358 => CapsLock,
57_359 => ScrollLock,
57_360 => NumLock,
57_361 => PrintScreen,
57_362 => Pause,
57_363 => Menu,
57_376..=57_398 => F((code - 57_376) as u8 + 13),
57_399..=57_408 => Char((b'0' + (code - 57_399) as u8) as char),
57_409 => Char('.'),
57_410 => Char('/'),
57_411 => Char('*'),
57_412 => Char('-'),
57_413 => Char('+'),
57_414 => Enter,
57_415 => Char('='),
57_416 => Char(','),
57_417 => Left,
57_418 => Right,
57_419 => Up,
57_420 => Down,
57_421 => PageUp,
57_422 => PageDown,
57_423 => Home,
57_424 => End,
57_425 => Insert,
57_426 => Delete,
57_427 => KeypadBegin,
57_428..=57_440 => Media(MediaKey::with_csi_u(code)?),
57_441..=57_452 => Mod(ModifierKey::with_csi_u(code)?),
_ => return None,
};
let modifiers = if (57_399..=57_427).contains(&code) {
self::Modifier::Keypad.into()
} else {
Modifiers::default()
};
Some((key, modifiers))
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum MediaKey {
Play,
Pause,
PlayPause,
Reverse,
Stop,
FastForward,
Rewind,
NextTrack,
PreviousTrack,
Record,
LowerVolume,
RaiseVolume,
MuteVolume,
}
impl MediaKey {
pub fn with_csi_u(code: u16) -> Option<Self> {
use MediaKey::*;
let key = match code {
57_428 => Play,
57_429 => Pause,
57_430 => PlayPause,
57_431 => Reverse,
57_432 => Stop,
57_433 => FastForward,
57_434 => Rewind,
57_435 => NextTrack,
57_436 => PreviousTrack,
57_437 => Record,
57_438 => LowerVolume,
57_439 => RaiseVolume,
57_440 => MuteVolume,
_ => return None,
};
Some(key)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum ModifierKey {
LeftShift,
LeftControl,
LeftOption,
LeftCommand,
LeftExtra1,
LeftExtra2,
RightShift,
RightControl,
RightOption,
RightCommand,
RightExtra1,
RightExtra2,
}
impl ModifierKey {
pub fn with_csi_u(code: u16) -> Option<Self> {
use ModifierKey::*;
let key = match code {
57_441 => LeftShift,
57_442 => LeftControl,
57_443 => LeftOption,
57_444 => LeftCommand,
57_445 => LeftExtra1,
57_446 => LeftExtra2,
57_447 => RightShift,
57_448 => RightControl,
57_449 => RightOption,
57_450 => RightCommand,
57_451 => RightExtra1,
57_452 => RightExtra2,
_ => return None,
};
Some(key)
}
pub fn as_modifier(&self) -> Modifier {
use ModifierKey::*;
match *self {
LeftShift => Modifier::Shift,
LeftControl => Modifier::Control,
LeftOption => Modifier::Option,
LeftCommand => Modifier::Command,
LeftExtra1 => Modifier::Extra1,
LeftExtra2 => Modifier::Extra2,
RightShift => Modifier::Shift,
RightControl => Modifier::Control,
RightOption => Modifier::Option,
RightCommand => Modifier::Command,
RightExtra1 => Modifier::Extra1,
RightExtra2 => Modifier::Extra2,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct WindowEvent {
pub columns: u16,
pub rows: u16,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct CursorEvent {
pub column: u16,
pub row: u16,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ColorEvent {
pub kind: RequestColor,
pub value: [(u16, u16); 3],
}