tuyere 0.1.0

A powerful TUI framework based on The Elm Architecture 🔮
Documentation
//! Keyboard input types.

use crossterm::event::{KeyCode, KeyModifiers as CrosstermModifiers};

/// A keyboard key.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Key {
    /// A character key.
    Char(char),
    /// Function key (F1-F12).
    F(u8),
    /// Backspace key.
    Backspace,
    /// Enter/Return key.
    Enter,
    /// Left arrow key.
    Left,
    /// Right arrow key.
    Right,
    /// Up arrow key.
    Up,
    /// Down arrow key.
    Down,
    /// Home key.
    Home,
    /// End key.
    End,
    /// Page Up key.
    PageUp,
    /// Page Down key.
    PageDown,
    /// Tab key.
    Tab,
    /// Backtab (Shift+Tab).
    BackTab,
    /// Delete key.
    Delete,
    /// Insert key.
    Insert,
    /// Escape key.
    Esc,
    /// Caps Lock key.
    CapsLock,
    /// Scroll Lock key.
    ScrollLock,
    /// Num Lock key.
    NumLock,
    /// Print Screen key.
    PrintScreen,
    /// Pause key.
    Pause,
    /// Menu key.
    Menu,
    /// Null (no key).
    Null,
}

impl Key {
    /// Check if this is the escape key.
    #[must_use]
    pub const fn is_esc(&self) -> bool {
        matches!(self, Key::Esc)
    }

    /// Check if this is the enter key.
    #[must_use]
    pub const fn is_enter(&self) -> bool {
        matches!(self, Key::Enter)
    }

    /// Check if this is a character key.
    #[must_use]
    pub const fn is_char(&self) -> bool {
        matches!(self, Key::Char(_))
    }

    /// Get the character if this is a character key.
    #[must_use]
    pub const fn char(&self) -> Option<char> {
        match self {
            Key::Char(c) => Some(*c),
            _ => None,
        }
    }

    /// Check if this key matches a character.
    #[must_use]
    pub fn matches(&self, c: char) -> bool {
        matches!(self, Key::Char(k) if *k == c)
    }

    /// Check if this key matches any of the given characters.
    #[must_use]
    pub fn matches_any(&self, chars: &[char]) -> bool {
        match self {
            Key::Char(c) => chars.contains(c),
            _ => false,
        }
    }
}

impl From<KeyCode> for Key {
    fn from(code: KeyCode) -> Self {
        match code {
            KeyCode::Char(c) => Key::Char(c),
            KeyCode::F(n) => Key::F(n),
            KeyCode::Backspace => Key::Backspace,
            KeyCode::Enter => Key::Enter,
            KeyCode::Left => Key::Left,
            KeyCode::Right => Key::Right,
            KeyCode::Up => Key::Up,
            KeyCode::Down => Key::Down,
            KeyCode::Home => Key::Home,
            KeyCode::End => Key::End,
            KeyCode::PageUp => Key::PageUp,
            KeyCode::PageDown => Key::PageDown,
            KeyCode::Tab => Key::Tab,
            KeyCode::BackTab => Key::BackTab,
            KeyCode::Delete => Key::Delete,
            KeyCode::Insert => Key::Insert,
            KeyCode::Esc => Key::Esc,
            KeyCode::CapsLock => Key::CapsLock,
            KeyCode::ScrollLock => Key::ScrollLock,
            KeyCode::NumLock => Key::NumLock,
            KeyCode::PrintScreen => Key::PrintScreen,
            KeyCode::Pause => Key::Pause,
            KeyCode::Menu => Key::Menu,
            KeyCode::Null => Key::Null,
            _ => Key::Null,
        }
    }
}

/// Key modifiers (Ctrl, Alt, Shift).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct KeyModifiers {
    /// Shift key is pressed.
    pub shift: bool,
    /// Control key is pressed.
    pub ctrl: bool,
    /// Alt key is pressed.
    pub alt: bool,
    /// Super/Meta/Windows key is pressed.
    pub super_key: bool,
}

impl KeyModifiers {
    /// No modifiers.
    pub const NONE: Self = Self {
        shift: false,
        ctrl: false,
        alt: false,
        super_key: false,
    };

    /// Shift modifier.
    pub const SHIFT: Self = Self {
        shift: true,
        ctrl: false,
        alt: false,
        super_key: false,
    };

    /// Control modifier.
    pub const CTRL: Self = Self {
        shift: false,
        ctrl: true,
        alt: false,
        super_key: false,
    };

    /// Alt modifier.
    pub const ALT: Self = Self {
        shift: false,
        ctrl: false,
        alt: true,
        super_key: false,
    };

    /// Check if any modifier is pressed.
    #[must_use]
    pub const fn any(&self) -> bool {
        self.shift || self.ctrl || self.alt || self.super_key
    }

    /// Check if no modifier is pressed.
    #[must_use]
    pub const fn none(&self) -> bool {
        !self.any()
    }
}

impl From<CrosstermModifiers> for KeyModifiers {
    fn from(mods: CrosstermModifiers) -> Self {
        Self {
            shift: mods.contains(CrosstermModifiers::SHIFT),
            ctrl: mods.contains(CrosstermModifiers::CONTROL),
            alt: mods.contains(CrosstermModifiers::ALT),
            super_key: mods.contains(CrosstermModifiers::SUPER),
        }
    }
}