dracon-terminal-engine 1.1.17

A next-generation terminal compositor engine for Rust. Z-indexed layers, TrueColor, SGR mouse, Kitty keyboard, and drop-in Ratatui support.
Documentation
use std::borrow::Cow;

use crate::input::event as rt;

pub use crate::contracts::{
    InputEvent as Event, KeyCode, KeyEvent, KeyEventKind, KeyModifiers, MediaKeyCode,
    ModifierKeyCode, MouseButton, MouseEvent, MouseEventKind, UiEvent, UiResize,
};

pub fn from_runtime_event(event: rt::Event) -> Event {
    match event {
        rt::Event::Key(key) => Event::Key(from_runtime_key_event(key)),
        rt::Event::Mouse(me) => Event::Mouse(from_runtime_mouse_event(me)),
        rt::Event::Resize(w, h) => Event::Resize(w, h),
        rt::Event::Paste(s) => Event::Paste(s),
        rt::Event::FocusGained => Event::FocusGained,
        rt::Event::FocusLost => Event::FocusLost,
        rt::Event::Unsupported(bytes) => Event::Unsupported(bytes),
    }
}

pub fn to_runtime_event(event: &Event) -> rt::Event {
    match event {
        Event::Key(key) => rt::Event::Key(to_runtime_key_event(*key)),
        Event::Mouse(me) => rt::Event::Mouse(to_runtime_mouse_event(*me)),
        Event::Resize(w, h) => rt::Event::Resize(*w, *h),
        Event::Paste(s) => rt::Event::Paste(s.clone()),
        Event::FocusGained => rt::Event::FocusGained,
        Event::FocusLost => rt::Event::FocusLost,
        Event::Unsupported(bytes) => rt::Event::Unsupported(bytes.clone()),
    }
}

pub fn to_ui_event(event: &Event) -> Option<UiEvent> {
    match event {
        Event::Resize(width, height) => Some(UiEvent::Resize(UiResize {
            width: *width,
            height: *height,
        })),
        Event::Key(key) => Some(UiEvent::Key {
            key: Cow::Owned(format_key(key)),
        }),
        _ => None,
    }
}

fn from_runtime_key_event(key: rt::KeyEvent) -> KeyEvent {
    KeyEvent {
        code: from_runtime_key_code(key.code),
        modifiers: from_runtime_key_modifiers(key.modifiers),
        kind: from_runtime_key_kind(key.kind),
    }
}

fn to_runtime_key_event(key: KeyEvent) -> rt::KeyEvent {
    rt::KeyEvent {
        code: to_runtime_key_code(key.code),
        modifiers: to_runtime_key_modifiers(key.modifiers),
        kind: to_runtime_key_kind(key.kind),
    }
}

fn from_runtime_key_kind(kind: rt::KeyEventKind) -> KeyEventKind {
    match kind {
        rt::KeyEventKind::Press => KeyEventKind::Press,
        rt::KeyEventKind::Repeat => KeyEventKind::Repeat,
        rt::KeyEventKind::Release => KeyEventKind::Release,
    }
}

fn to_runtime_key_kind(kind: KeyEventKind) -> rt::KeyEventKind {
    match kind {
        KeyEventKind::Press => rt::KeyEventKind::Press,
        KeyEventKind::Repeat => rt::KeyEventKind::Repeat,
        KeyEventKind::Release => rt::KeyEventKind::Release,
    }
}

fn from_runtime_key_code(code: rt::KeyCode) -> KeyCode {
    match code {
        rt::KeyCode::Backspace => KeyCode::Backspace,
        rt::KeyCode::Enter => KeyCode::Enter,
        rt::KeyCode::Left => KeyCode::Left,
        rt::KeyCode::Right => KeyCode::Right,
        rt::KeyCode::Up => KeyCode::Up,
        rt::KeyCode::Down => KeyCode::Down,
        rt::KeyCode::Home => KeyCode::Home,
        rt::KeyCode::End => KeyCode::End,
        rt::KeyCode::PageUp => KeyCode::PageUp,
        rt::KeyCode::PageDown => KeyCode::PageDown,
        rt::KeyCode::Tab => KeyCode::Tab,
        rt::KeyCode::BackTab => KeyCode::BackTab,
        rt::KeyCode::Delete => KeyCode::Delete,
        rt::KeyCode::Insert => KeyCode::Insert,
        rt::KeyCode::F(n) => KeyCode::F(n),
        rt::KeyCode::Char(c) => KeyCode::Char(c),
        rt::KeyCode::Null => KeyCode::Null,
        rt::KeyCode::Esc => KeyCode::Esc,
        rt::KeyCode::CapsLock => KeyCode::CapsLock,
        rt::KeyCode::ScrollLock => KeyCode::ScrollLock,
        rt::KeyCode::NumLock => KeyCode::NumLock,
        rt::KeyCode::PrintScreen => KeyCode::PrintScreen,
        rt::KeyCode::Pause => KeyCode::Pause,
        rt::KeyCode::Menu => KeyCode::Menu,
        rt::KeyCode::KeypadBegin => KeyCode::KeypadBegin,
        rt::KeyCode::Media(m) => KeyCode::Media(from_runtime_media_key(m)),
        rt::KeyCode::Modifier(m) => KeyCode::Modifier(from_runtime_modifier_key(m)),
    }
}

fn to_runtime_key_code(code: KeyCode) -> rt::KeyCode {
    match code {
        KeyCode::Backspace => rt::KeyCode::Backspace,
        KeyCode::Enter => rt::KeyCode::Enter,
        KeyCode::Left => rt::KeyCode::Left,
        KeyCode::Right => rt::KeyCode::Right,
        KeyCode::Up => rt::KeyCode::Up,
        KeyCode::Down => rt::KeyCode::Down,
        KeyCode::Home => rt::KeyCode::Home,
        KeyCode::End => rt::KeyCode::End,
        KeyCode::PageUp => rt::KeyCode::PageUp,
        KeyCode::PageDown => rt::KeyCode::PageDown,
        KeyCode::Tab => rt::KeyCode::Tab,
        KeyCode::BackTab => rt::KeyCode::BackTab,
        KeyCode::Delete => rt::KeyCode::Delete,
        KeyCode::Insert => rt::KeyCode::Insert,
        KeyCode::F(n) => rt::KeyCode::F(n),
        KeyCode::Char(c) => rt::KeyCode::Char(c),
        KeyCode::Null => rt::KeyCode::Null,
        KeyCode::Esc => rt::KeyCode::Esc,
        KeyCode::CapsLock => rt::KeyCode::CapsLock,
        KeyCode::ScrollLock => rt::KeyCode::ScrollLock,
        KeyCode::NumLock => rt::KeyCode::NumLock,
        KeyCode::PrintScreen => rt::KeyCode::PrintScreen,
        KeyCode::Pause => rt::KeyCode::Pause,
        KeyCode::Menu => rt::KeyCode::Menu,
        KeyCode::KeypadBegin => rt::KeyCode::KeypadBegin,
        KeyCode::Media(m) => rt::KeyCode::Media(to_runtime_media_key(m)),
        KeyCode::Modifier(m) => rt::KeyCode::Modifier(to_runtime_modifier_key(m)),
    }
}

fn from_runtime_media_key(code: rt::MediaKeyCode) -> MediaKeyCode {
    match code {
        rt::MediaKeyCode::Play => MediaKeyCode::Play,
        rt::MediaKeyCode::Pause => MediaKeyCode::Pause,
        rt::MediaKeyCode::PlayPause => MediaKeyCode::PlayPause,
        rt::MediaKeyCode::Reverse => MediaKeyCode::Reverse,
        rt::MediaKeyCode::Stop => MediaKeyCode::Stop,
        rt::MediaKeyCode::FastForward => MediaKeyCode::FastForward,
        rt::MediaKeyCode::Rewind => MediaKeyCode::Rewind,
        rt::MediaKeyCode::TrackNext => MediaKeyCode::TrackNext,
        rt::MediaKeyCode::TrackPrevious => MediaKeyCode::TrackPrevious,
        rt::MediaKeyCode::Record => MediaKeyCode::Record,
        rt::MediaKeyCode::LowerVolume => MediaKeyCode::LowerVolume,
        rt::MediaKeyCode::RaiseVolume => MediaKeyCode::RaiseVolume,
        rt::MediaKeyCode::MuteVolume => MediaKeyCode::MuteVolume,
    }
}

fn to_runtime_media_key(code: MediaKeyCode) -> rt::MediaKeyCode {
    match code {
        MediaKeyCode::Play => rt::MediaKeyCode::Play,
        MediaKeyCode::Pause => rt::MediaKeyCode::Pause,
        MediaKeyCode::PlayPause => rt::MediaKeyCode::PlayPause,
        MediaKeyCode::Reverse => rt::MediaKeyCode::Reverse,
        MediaKeyCode::Stop => rt::MediaKeyCode::Stop,
        MediaKeyCode::FastForward => rt::MediaKeyCode::FastForward,
        MediaKeyCode::Rewind => rt::MediaKeyCode::Rewind,
        MediaKeyCode::TrackNext => rt::MediaKeyCode::TrackNext,
        MediaKeyCode::TrackPrevious => rt::MediaKeyCode::TrackPrevious,
        MediaKeyCode::Record => rt::MediaKeyCode::Record,
        MediaKeyCode::LowerVolume => rt::MediaKeyCode::LowerVolume,
        MediaKeyCode::RaiseVolume => rt::MediaKeyCode::RaiseVolume,
        MediaKeyCode::MuteVolume => rt::MediaKeyCode::MuteVolume,
    }
}

fn from_runtime_modifier_key(code: rt::ModifierKeyCode) -> ModifierKeyCode {
    match code {
        rt::ModifierKeyCode::LeftShift => ModifierKeyCode::LeftShift,
        rt::ModifierKeyCode::LeftControl => ModifierKeyCode::LeftControl,
        rt::ModifierKeyCode::LeftAlt => ModifierKeyCode::LeftAlt,
        rt::ModifierKeyCode::LeftSuper => ModifierKeyCode::LeftSuper,
        rt::ModifierKeyCode::LeftHyper => ModifierKeyCode::LeftHyper,
        rt::ModifierKeyCode::LeftMeta => ModifierKeyCode::LeftMeta,
        rt::ModifierKeyCode::RightShift => ModifierKeyCode::RightShift,
        rt::ModifierKeyCode::RightControl => ModifierKeyCode::RightControl,
        rt::ModifierKeyCode::RightAlt => ModifierKeyCode::RightAlt,
        rt::ModifierKeyCode::RightSuper => ModifierKeyCode::RightSuper,
        rt::ModifierKeyCode::RightHyper => ModifierKeyCode::RightHyper,
        rt::ModifierKeyCode::RightMeta => ModifierKeyCode::RightMeta,
        rt::ModifierKeyCode::IsoLevel3Shift => ModifierKeyCode::IsoLevel3Shift,
        rt::ModifierKeyCode::IsoLevel5Shift => ModifierKeyCode::IsoLevel5Shift,
    }
}

fn to_runtime_modifier_key(code: ModifierKeyCode) -> rt::ModifierKeyCode {
    match code {
        ModifierKeyCode::LeftShift => rt::ModifierKeyCode::LeftShift,
        ModifierKeyCode::LeftControl => rt::ModifierKeyCode::LeftControl,
        ModifierKeyCode::LeftAlt => rt::ModifierKeyCode::LeftAlt,
        ModifierKeyCode::LeftSuper => rt::ModifierKeyCode::LeftSuper,
        ModifierKeyCode::LeftHyper => rt::ModifierKeyCode::LeftHyper,
        ModifierKeyCode::LeftMeta => rt::ModifierKeyCode::LeftMeta,
        ModifierKeyCode::RightShift => rt::ModifierKeyCode::RightShift,
        ModifierKeyCode::RightControl => rt::ModifierKeyCode::RightControl,
        ModifierKeyCode::RightAlt => rt::ModifierKeyCode::RightAlt,
        ModifierKeyCode::RightSuper => rt::ModifierKeyCode::RightSuper,
        ModifierKeyCode::RightHyper => rt::ModifierKeyCode::RightHyper,
        ModifierKeyCode::RightMeta => rt::ModifierKeyCode::RightMeta,
        ModifierKeyCode::IsoLevel3Shift => rt::ModifierKeyCode::IsoLevel3Shift,
        ModifierKeyCode::IsoLevel5Shift => rt::ModifierKeyCode::IsoLevel5Shift,
    }
}

fn from_runtime_key_modifiers(m: rt::KeyModifiers) -> KeyModifiers {
    KeyModifiers::from_bits_retain(m.bits())
}

fn to_runtime_key_modifiers(m: KeyModifiers) -> rt::KeyModifiers {
    rt::KeyModifiers::from_bits_retain(m.bits())
}

fn from_runtime_mouse_event(me: rt::MouseEvent) -> MouseEvent {
    MouseEvent {
        kind: from_runtime_mouse_kind(me.kind),
        column: me.column,
        row: me.row,
        modifiers: from_runtime_key_modifiers(me.modifiers),
    }
}

fn to_runtime_mouse_event(me: MouseEvent) -> rt::MouseEvent {
    rt::MouseEvent {
        kind: to_runtime_mouse_kind(me.kind),
        column: me.column,
        row: me.row,
        modifiers: to_runtime_key_modifiers(me.modifiers),
    }
}

fn from_runtime_mouse_kind(kind: rt::MouseEventKind) -> MouseEventKind {
    match kind {
        rt::MouseEventKind::Down(b) => MouseEventKind::Down(from_runtime_mouse_button(b)),
        rt::MouseEventKind::Up(b) => MouseEventKind::Up(from_runtime_mouse_button(b)),
        rt::MouseEventKind::Drag(b) => MouseEventKind::Drag(from_runtime_mouse_button(b)),
        rt::MouseEventKind::Moved => MouseEventKind::Moved,
        rt::MouseEventKind::ScrollDown => MouseEventKind::ScrollDown,
        rt::MouseEventKind::ScrollUp => MouseEventKind::ScrollUp,
        rt::MouseEventKind::ScrollLeft => MouseEventKind::ScrollLeft,
        rt::MouseEventKind::ScrollRight => MouseEventKind::ScrollRight,
    }
}

fn to_runtime_mouse_kind(kind: MouseEventKind) -> rt::MouseEventKind {
    match kind {
        MouseEventKind::Down(b) => rt::MouseEventKind::Down(to_runtime_mouse_button(b)),
        MouseEventKind::Up(b) => rt::MouseEventKind::Up(to_runtime_mouse_button(b)),
        MouseEventKind::Drag(b) => rt::MouseEventKind::Drag(to_runtime_mouse_button(b)),
        MouseEventKind::Moved => rt::MouseEventKind::Moved,
        MouseEventKind::ScrollDown => rt::MouseEventKind::ScrollDown,
        MouseEventKind::ScrollUp => rt::MouseEventKind::ScrollUp,
        MouseEventKind::ScrollLeft => rt::MouseEventKind::ScrollLeft,
        MouseEventKind::ScrollRight => rt::MouseEventKind::ScrollRight,
    }
}

fn from_runtime_mouse_button(button: rt::MouseButton) -> MouseButton {
    match button {
        rt::MouseButton::Left => MouseButton::Left,
        rt::MouseButton::Right => MouseButton::Right,
        rt::MouseButton::Middle => MouseButton::Middle,
        rt::MouseButton::Back => MouseButton::Back,
        rt::MouseButton::Forward => MouseButton::Forward,
        rt::MouseButton::Other(v) => MouseButton::Other(v),
    }
}

fn to_runtime_mouse_button(button: MouseButton) -> rt::MouseButton {
    match button {
        MouseButton::Left => rt::MouseButton::Left,
        MouseButton::Right => rt::MouseButton::Right,
        MouseButton::Middle => rt::MouseButton::Middle,
        MouseButton::Back => rt::MouseButton::Back,
        MouseButton::Forward => rt::MouseButton::Forward,
        MouseButton::Other(v) => rt::MouseButton::Other(v),
    }
}

fn format_key(key: &KeyEvent) -> String {
    let mut out = String::new();

    if key.modifiers.contains(KeyModifiers::CONTROL) {
        out.push_str("ctrl+");
    }
    if key.modifiers.contains(KeyModifiers::ALT) {
        out.push_str("alt+");
    }
    if key.modifiers.contains(KeyModifiers::SHIFT) {
        out.push_str("shift+");
    }
    if key.modifiers.contains(KeyModifiers::SUPER) {
        out.push_str("super+");
    }
    if key.modifiers.contains(KeyModifiers::HYPER) {
        out.push_str("hyper+");
    }
    if key.modifiers.contains(KeyModifiers::META) {
        out.push_str("meta+");
    }

    out.push_str(match key.code {
        KeyCode::Backspace => "backspace",
        KeyCode::Enter => "enter",
        KeyCode::Left => "left",
        KeyCode::Right => "right",
        KeyCode::Up => "up",
        KeyCode::Down => "down",
        KeyCode::Home => "home",
        KeyCode::End => "end",
        KeyCode::PageUp => "page_up",
        KeyCode::PageDown => "page_down",
        KeyCode::Tab => "tab",
        KeyCode::BackTab => "backtab",
        KeyCode::Delete => "delete",
        KeyCode::Insert => "insert",
        KeyCode::Null => "null",
        KeyCode::Esc => "esc",
        KeyCode::CapsLock => "caps_lock",
        KeyCode::ScrollLock => "scroll_lock",
        KeyCode::NumLock => "num_lock",
        KeyCode::PrintScreen => "print_screen",
        KeyCode::Pause => "pause",
        KeyCode::Menu => "menu",
        KeyCode::KeypadBegin => "keypad_begin",
        KeyCode::Char(c) => return format!("{out}{c}"),
        KeyCode::F(n) => return format!("{out}f{n}"),
        KeyCode::Media(media) => return format!("{out}media::{media:?}"),
        KeyCode::Modifier(modifier) => return format!("{out}modifier::{modifier:?}"),
    });

    match key.kind {
        KeyEventKind::Press => out.push_str(":press"),
        KeyEventKind::Repeat => out.push_str(":repeat"),
        KeyEventKind::Release => out.push_str(":release"),
    }

    out
}