зеркало из
https://github.com/glebtv/tui-textarea.git
synced 2026-09-08 00:15:50 +03:00
move Input backends support to respective modules in input/
Этот коммит содержится в:
325
src/input.rs
325
src/input.rs
@@ -1,325 +0,0 @@
|
|||||||
#[cfg(any(feature = "crossterm", feature = "tuirs-crossterm"))]
|
|
||||||
use crate::crossterm::event::{
|
|
||||||
Event as CrosstermEvent, KeyCode, KeyEvent, KeyEventKind, KeyModifiers, MouseEvent,
|
|
||||||
MouseEventKind as CrosstermMouseEventKind,
|
|
||||||
};
|
|
||||||
#[cfg(feature = "arbitrary")]
|
|
||||||
use arbitrary::Arbitrary;
|
|
||||||
#[cfg(any(feature = "termion", feature = "tuirs-termion"))]
|
|
||||||
use termion::event::{Event as TermionEvent, Key as TermionKey, MouseEvent as TermionMouseEvent};
|
|
||||||
#[cfg(feature = "termwiz")]
|
|
||||||
use termwiz::input::{
|
|
||||||
InputEvent as TermwizInputEvent, KeyEvent as TermwizKeyEvent,
|
|
||||||
MouseButtons as TermwizMouseButtons, MouseEvent as TermwizMouseEvent, PixelMouseEvent,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Backend-agnostic key input kind.
|
|
||||||
///
|
|
||||||
/// This type is marked as `#[non_exhaustive]` since more keys may be supported in the future.
|
|
||||||
#[non_exhaustive]
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
|
||||||
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
|
|
||||||
pub enum Key {
|
|
||||||
/// Normal letter key input.
|
|
||||||
Char(char),
|
|
||||||
/// F1, F2, F3, ... keys.
|
|
||||||
F(u8),
|
|
||||||
Backspace,
|
|
||||||
Enter,
|
|
||||||
Left,
|
|
||||||
Right,
|
|
||||||
Up,
|
|
||||||
Down,
|
|
||||||
Tab,
|
|
||||||
Delete,
|
|
||||||
Home,
|
|
||||||
End,
|
|
||||||
PageUp,
|
|
||||||
PageDown,
|
|
||||||
Esc,
|
|
||||||
/// Virtual key to scroll down by mouse
|
|
||||||
MouseScrollDown,
|
|
||||||
/// Virtual key to scroll up by mouse
|
|
||||||
MouseScrollUp,
|
|
||||||
/// An invalid key input (this key is always ignored by [`TextArea`](crate::TextArea)).
|
|
||||||
Null,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Backend-agnostic key input type.
|
|
||||||
///
|
|
||||||
/// When `crossterm`, `termion`, `termwiz` features are enabled, converting respective key input types into this
|
|
||||||
/// `Input` type is defined.
|
|
||||||
/// ```no_run
|
|
||||||
/// use tui_textarea::{TextArea, Input, Key};
|
|
||||||
/// use crossterm::event::{Event, read};
|
|
||||||
///
|
|
||||||
/// let event = read().unwrap();
|
|
||||||
///
|
|
||||||
/// // `Input::from` can convert backend-native event into `Input`
|
|
||||||
/// let input = Input::from(event.clone());
|
|
||||||
/// // or `Into::into`
|
|
||||||
/// let input: Input = event.clone().into();
|
|
||||||
/// // Conversion from `KeyEvent` value is also available
|
|
||||||
/// if let Event::Key(key) = event {
|
|
||||||
/// let input = Input::from(key);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Creating `Input` instance directly can cause backend-agnostic input as follows.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use tui_textarea::{TextArea, Input, Key};
|
|
||||||
///
|
|
||||||
/// let mut textarea = TextArea::default();
|
|
||||||
///
|
|
||||||
/// // Input Ctrl+A
|
|
||||||
/// textarea.input(Input {
|
|
||||||
/// key: Key::Char('a'),
|
|
||||||
/// ctrl: true,
|
|
||||||
/// alt: false,
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
|
|
||||||
pub struct Input {
|
|
||||||
/// Typed key.
|
|
||||||
pub key: Key,
|
|
||||||
/// Ctrl modifier key. `true` means Ctrl key was pressed.
|
|
||||||
pub ctrl: bool,
|
|
||||||
/// Alt modifier key. `true` means Alt key was pressed.
|
|
||||||
pub alt: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Input {
|
|
||||||
/// The default input is [`Key::Null`] without pressing any modifier keys, which means invalid input.
|
|
||||||
fn default() -> Self {
|
|
||||||
Input {
|
|
||||||
key: Key::Null,
|
|
||||||
ctrl: false,
|
|
||||||
alt: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(feature = "crossterm", feature = "tuirs-crossterm"))]
|
|
||||||
impl From<CrosstermEvent> for Input {
|
|
||||||
/// Convert [`crossterm::event::Event`] to [`Input`].
|
|
||||||
fn from(event: CrosstermEvent) -> Self {
|
|
||||||
match event {
|
|
||||||
CrosstermEvent::Key(key) if key.kind != KeyEventKind::Release => Self::from(key),
|
|
||||||
CrosstermEvent::Mouse(mouse) => Self::from(mouse),
|
|
||||||
_ => Self::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(feature = "crossterm", feature = "tuirs-crossterm"))]
|
|
||||||
impl From<KeyEvent> for Input {
|
|
||||||
/// Convert [`crossterm::event::KeyEvent`] to [`Input`].
|
|
||||||
fn from(key: KeyEvent) -> Self {
|
|
||||||
let ctrl = key.modifiers.contains(KeyModifiers::CONTROL);
|
|
||||||
let alt = key.modifiers.contains(KeyModifiers::ALT);
|
|
||||||
let key = match key.code {
|
|
||||||
KeyCode::Char(c) => Key::Char(c),
|
|
||||||
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::Tab => Key::Tab,
|
|
||||||
KeyCode::Delete => Key::Delete,
|
|
||||||
KeyCode::Home => Key::Home,
|
|
||||||
KeyCode::End => Key::End,
|
|
||||||
KeyCode::PageUp => Key::PageUp,
|
|
||||||
KeyCode::PageDown => Key::PageDown,
|
|
||||||
KeyCode::Esc => Key::Esc,
|
|
||||||
KeyCode::F(x) => Key::F(x),
|
|
||||||
_ => Key::Null,
|
|
||||||
};
|
|
||||||
Self { key, ctrl, alt }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(feature = "crossterm", feature = "tuirs-crossterm"))]
|
|
||||||
impl From<MouseEvent> for Input {
|
|
||||||
/// Convert [`crossterm::event::MouseEvent`] to [`Input`].
|
|
||||||
fn from(mouse: MouseEvent) -> Self {
|
|
||||||
let key = match mouse.kind {
|
|
||||||
CrosstermMouseEventKind::ScrollDown => Key::MouseScrollDown,
|
|
||||||
CrosstermMouseEventKind::ScrollUp => Key::MouseScrollUp,
|
|
||||||
_ => return Self::default(),
|
|
||||||
};
|
|
||||||
let ctrl = mouse.modifiers.contains(KeyModifiers::CONTROL);
|
|
||||||
let alt = mouse.modifiers.contains(KeyModifiers::ALT);
|
|
||||||
Self { key, ctrl, alt }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(feature = "termion", feature = "tuirs-termion"))]
|
|
||||||
impl From<TermionEvent> for Input {
|
|
||||||
/// Convert [`termion::event::Event`] to [`Input`].
|
|
||||||
fn from(event: TermionEvent) -> Self {
|
|
||||||
match event {
|
|
||||||
TermionEvent::Key(key) => Self::from(key),
|
|
||||||
TermionEvent::Mouse(mouse) => Self::from(mouse),
|
|
||||||
_ => Self::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(feature = "termion", feature = "tuirs-termion"))]
|
|
||||||
impl From<TermionKey> for Input {
|
|
||||||
/// Convert [`termion::event::Key`] to [`Input`].
|
|
||||||
fn from(key: TermionKey) -> Self {
|
|
||||||
use TermionKey::*;
|
|
||||||
|
|
||||||
let mut ctrl = false;
|
|
||||||
let mut alt = false;
|
|
||||||
let key = match key {
|
|
||||||
Char('\n' | '\r') => Key::Enter,
|
|
||||||
Char(c) => Key::Char(c),
|
|
||||||
Ctrl(c) => {
|
|
||||||
ctrl = true;
|
|
||||||
Key::Char(c)
|
|
||||||
}
|
|
||||||
Alt(c) => {
|
|
||||||
alt = true;
|
|
||||||
Key::Char(c)
|
|
||||||
}
|
|
||||||
Backspace => Key::Backspace,
|
|
||||||
Left => Key::Left,
|
|
||||||
Right => Key::Right,
|
|
||||||
Up => Key::Up,
|
|
||||||
Down => Key::Down,
|
|
||||||
Home => Key::Home,
|
|
||||||
End => Key::End,
|
|
||||||
PageUp => Key::PageUp,
|
|
||||||
PageDown => Key::PageDown,
|
|
||||||
BackTab => Key::Tab,
|
|
||||||
Delete => Key::Delete,
|
|
||||||
Esc => Key::Esc,
|
|
||||||
F(x) => Key::F(x),
|
|
||||||
_ => Key::Null,
|
|
||||||
};
|
|
||||||
|
|
||||||
Input { key, ctrl, alt }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(feature = "termion", feature = "tuirs-termion"))]
|
|
||||||
impl From<TermionMouseEvent> for Input {
|
|
||||||
/// Convert [`termion::event::MouseEvent`] to [`Input`].
|
|
||||||
fn from(mouse: TermionMouseEvent) -> Self {
|
|
||||||
use termion::event::MouseButton;
|
|
||||||
let key = match mouse {
|
|
||||||
TermionMouseEvent::Press(MouseButton::WheelUp, ..) => Key::MouseScrollUp,
|
|
||||||
TermionMouseEvent::Press(MouseButton::WheelDown, ..) => Key::MouseScrollDown,
|
|
||||||
_ => return Self::default(),
|
|
||||||
};
|
|
||||||
Self {
|
|
||||||
key,
|
|
||||||
ctrl: false,
|
|
||||||
alt: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "termwiz")]
|
|
||||||
impl From<TermwizInputEvent> for Input {
|
|
||||||
/// Convert [`termwiz::input::InputEvent`] to [`Input`].
|
|
||||||
fn from(input: TermwizInputEvent) -> Self {
|
|
||||||
match input {
|
|
||||||
TermwizInputEvent::Key(key) => Self::from(key),
|
|
||||||
TermwizInputEvent::Mouse(mouse) => Self::from(mouse),
|
|
||||||
TermwizInputEvent::PixelMouse(mouse) => Self::from(mouse),
|
|
||||||
_ => Self::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "termwiz")]
|
|
||||||
impl From<TermwizKeyEvent> for Input {
|
|
||||||
/// Convert [`termwiz::input::KeyEvent`] to [`Input`].
|
|
||||||
fn from(key: TermwizKeyEvent) -> Self {
|
|
||||||
use termwiz::input::{KeyCode, Modifiers};
|
|
||||||
|
|
||||||
let TermwizKeyEvent { key, modifiers } = key;
|
|
||||||
let key = match key {
|
|
||||||
KeyCode::Char(c) => Key::Char(c),
|
|
||||||
KeyCode::Backspace => Key::Backspace,
|
|
||||||
KeyCode::Tab => Key::Tab,
|
|
||||||
KeyCode::Enter => Key::Enter,
|
|
||||||
KeyCode::Escape => Key::Esc,
|
|
||||||
KeyCode::PageUp => Key::PageUp,
|
|
||||||
KeyCode::PageDown => Key::PageDown,
|
|
||||||
KeyCode::End => Key::End,
|
|
||||||
KeyCode::Home => Key::Home,
|
|
||||||
KeyCode::LeftArrow => Key::Left,
|
|
||||||
KeyCode::RightArrow => Key::Right,
|
|
||||||
KeyCode::UpArrow => Key::Up,
|
|
||||||
KeyCode::DownArrow => Key::Down,
|
|
||||||
KeyCode::Delete => Key::Delete,
|
|
||||||
KeyCode::Function(x) => Key::F(x),
|
|
||||||
_ => Key::Null,
|
|
||||||
};
|
|
||||||
let ctrl = modifiers.contains(Modifiers::CTRL);
|
|
||||||
let alt = modifiers.contains(Modifiers::ALT);
|
|
||||||
|
|
||||||
Self { key, ctrl, alt }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "termwiz")]
|
|
||||||
impl From<TermwizMouseButtons> for Key {
|
|
||||||
/// Convert [`termwiz::input::MouseButtons`] to [`Key`].
|
|
||||||
fn from(buttons: TermwizMouseButtons) -> Self {
|
|
||||||
if buttons.contains(TermwizMouseButtons::VERT_WHEEL) {
|
|
||||||
if buttons.contains(TermwizMouseButtons::WHEEL_POSITIVE) {
|
|
||||||
Key::MouseScrollUp
|
|
||||||
} else {
|
|
||||||
Key::MouseScrollDown
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Key::Null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "termwiz")]
|
|
||||||
impl From<TermwizMouseEvent> for Input {
|
|
||||||
/// Convert [`termwiz::input::MouseEvent`] to [`Input`].
|
|
||||||
fn from(mouse: TermwizMouseEvent) -> Self {
|
|
||||||
use termwiz::input::Modifiers;
|
|
||||||
|
|
||||||
let TermwizMouseEvent {
|
|
||||||
mouse_buttons,
|
|
||||||
modifiers,
|
|
||||||
..
|
|
||||||
} = mouse;
|
|
||||||
let key = Key::from(mouse_buttons);
|
|
||||||
let ctrl = modifiers.contains(Modifiers::CTRL);
|
|
||||||
let alt = modifiers.contains(Modifiers::ALT);
|
|
||||||
|
|
||||||
Self { key, ctrl, alt }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "termwiz")]
|
|
||||||
impl From<PixelMouseEvent> for Input {
|
|
||||||
/// Convert [`termwiz::input::PixelMouseEvent`] to [`Input`].
|
|
||||||
fn from(mouse: PixelMouseEvent) -> Self {
|
|
||||||
use termwiz::input::Modifiers;
|
|
||||||
|
|
||||||
let PixelMouseEvent {
|
|
||||||
mouse_buttons,
|
|
||||||
modifiers,
|
|
||||||
..
|
|
||||||
} = mouse;
|
|
||||||
let key = Key::from(mouse_buttons);
|
|
||||||
let ctrl = modifiers.contains(Modifiers::CTRL);
|
|
||||||
let alt = modifiers.contains(Modifiers::ALT);
|
|
||||||
|
|
||||||
Self { key, ctrl, alt }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
56
src/input/crossterm.rs
Обычный файл
56
src/input/crossterm.rs
Обычный файл
@@ -0,0 +1,56 @@
|
|||||||
|
use super::{Input, Key};
|
||||||
|
use crate::crossterm::event::{
|
||||||
|
Event, KeyCode, KeyEvent, KeyEventKind, KeyModifiers, MouseEvent, MouseEventKind,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl From<Event> for Input {
|
||||||
|
/// Convert [`crossterm::event::Event`] to [`Input`].
|
||||||
|
fn from(event: Event) -> Self {
|
||||||
|
match event {
|
||||||
|
Event::Key(key) if key.kind != KeyEventKind::Release => Self::from(key),
|
||||||
|
Event::Mouse(mouse) => Self::from(mouse),
|
||||||
|
_ => Self::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<KeyEvent> for Input {
|
||||||
|
/// Convert [`crossterm::event::KeyEvent`] to [`Input`].
|
||||||
|
fn from(key: KeyEvent) -> Self {
|
||||||
|
let ctrl = key.modifiers.contains(KeyModifiers::CONTROL);
|
||||||
|
let alt = key.modifiers.contains(KeyModifiers::ALT);
|
||||||
|
let key = match key.code {
|
||||||
|
KeyCode::Char(c) => Key::Char(c),
|
||||||
|
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::Tab => Key::Tab,
|
||||||
|
KeyCode::Delete => Key::Delete,
|
||||||
|
KeyCode::Home => Key::Home,
|
||||||
|
KeyCode::End => Key::End,
|
||||||
|
KeyCode::PageUp => Key::PageUp,
|
||||||
|
KeyCode::PageDown => Key::PageDown,
|
||||||
|
KeyCode::Esc => Key::Esc,
|
||||||
|
KeyCode::F(x) => Key::F(x),
|
||||||
|
_ => Key::Null,
|
||||||
|
};
|
||||||
|
Self { key, ctrl, alt }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<MouseEvent> for Input {
|
||||||
|
/// Convert [`crossterm::event::MouseEvent`] to [`Input`].
|
||||||
|
fn from(mouse: MouseEvent) -> Self {
|
||||||
|
let key = match mouse.kind {
|
||||||
|
MouseEventKind::ScrollDown => Key::MouseScrollDown,
|
||||||
|
MouseEventKind::ScrollUp => Key::MouseScrollUp,
|
||||||
|
_ => return Self::default(),
|
||||||
|
};
|
||||||
|
let ctrl = mouse.modifiers.contains(KeyModifiers::CONTROL);
|
||||||
|
let alt = mouse.modifiers.contains(KeyModifiers::ALT);
|
||||||
|
Self { key, ctrl, alt }
|
||||||
|
}
|
||||||
|
}
|
||||||
105
src/input/mod.rs
Обычный файл
105
src/input/mod.rs
Обычный файл
@@ -0,0 +1,105 @@
|
|||||||
|
#[cfg(any(feature = "crossterm", feature = "tuirs-crossterm"))]
|
||||||
|
mod crossterm;
|
||||||
|
#[cfg(any(feature = "termion", feature = "tuirs-termion"))]
|
||||||
|
mod termion;
|
||||||
|
#[cfg(feature = "termwiz")]
|
||||||
|
mod termwiz;
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary")]
|
||||||
|
use arbitrary::Arbitrary;
|
||||||
|
|
||||||
|
/// Backend-agnostic key input kind.
|
||||||
|
///
|
||||||
|
/// This type is marked as `#[non_exhaustive]` since more keys may be supported in the future.
|
||||||
|
#[non_exhaustive]
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
|
||||||
|
pub enum Key {
|
||||||
|
/// Normal letter key input
|
||||||
|
Char(char),
|
||||||
|
/// F1, F2, F3, ... keys
|
||||||
|
F(u8),
|
||||||
|
/// Backspace key
|
||||||
|
Backspace,
|
||||||
|
/// Enter or return key
|
||||||
|
Enter,
|
||||||
|
/// Left arrow key
|
||||||
|
Left,
|
||||||
|
/// Right arrow key
|
||||||
|
Right,
|
||||||
|
/// Up arrow key
|
||||||
|
Up,
|
||||||
|
/// Down arrow key
|
||||||
|
Down,
|
||||||
|
/// Tab key
|
||||||
|
Tab,
|
||||||
|
/// Delete key
|
||||||
|
Delete,
|
||||||
|
/// Home key
|
||||||
|
Home,
|
||||||
|
/// End key
|
||||||
|
End,
|
||||||
|
/// Page up key
|
||||||
|
PageUp,
|
||||||
|
/// Page down key
|
||||||
|
PageDown,
|
||||||
|
/// Escape key
|
||||||
|
Esc,
|
||||||
|
/// Virtual key to scroll down by mouse
|
||||||
|
MouseScrollDown,
|
||||||
|
/// Virtual key to scroll up by mouse
|
||||||
|
MouseScrollUp,
|
||||||
|
/// An invalid key input (this key is always ignored by [`TextArea`](crate::TextArea))
|
||||||
|
Null,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Key {
|
||||||
|
fn default() -> Self {
|
||||||
|
Key::Null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Backend-agnostic key input type.
|
||||||
|
///
|
||||||
|
/// When `crossterm`, `termion`, `termwiz` features are enabled, converting respective key input types into this
|
||||||
|
/// `Input` type is defined.
|
||||||
|
/// ```no_run
|
||||||
|
/// use tui_textarea::{TextArea, Input, Key};
|
||||||
|
/// use crossterm::event::{Event, read};
|
||||||
|
///
|
||||||
|
/// let event = read().unwrap();
|
||||||
|
///
|
||||||
|
/// // `Input::from` can convert backend-native event into `Input`
|
||||||
|
/// let input = Input::from(event.clone());
|
||||||
|
/// // or `Into::into`
|
||||||
|
/// let input: Input = event.clone().into();
|
||||||
|
/// // Conversion from `KeyEvent` value is also available
|
||||||
|
/// if let Event::Key(key) = event {
|
||||||
|
/// let input = Input::from(key);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Creating `Input` instance directly can cause backend-agnostic input as follows.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use tui_textarea::{TextArea, Input, Key};
|
||||||
|
///
|
||||||
|
/// let mut textarea = TextArea::default();
|
||||||
|
///
|
||||||
|
/// // Input Ctrl+A
|
||||||
|
/// textarea.input(Input {
|
||||||
|
/// key: Key::Char('a'),
|
||||||
|
/// ctrl: true,
|
||||||
|
/// alt: false,
|
||||||
|
/// });
|
||||||
|
/// ```
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
|
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
|
||||||
|
pub struct Input {
|
||||||
|
/// Typed key.
|
||||||
|
pub key: Key,
|
||||||
|
/// Ctrl modifier key. `true` means Ctrl key was pressed.
|
||||||
|
pub ctrl: bool,
|
||||||
|
/// Alt modifier key. `true` means Alt key was pressed.
|
||||||
|
pub alt: bool,
|
||||||
|
}
|
||||||
68
src/input/termion.rs
Обычный файл
68
src/input/termion.rs
Обычный файл
@@ -0,0 +1,68 @@
|
|||||||
|
use super::{Input, Key};
|
||||||
|
use termion::event::{Event, Key as KeyEvent, MouseEvent};
|
||||||
|
|
||||||
|
impl From<Event> for Input {
|
||||||
|
/// Convert [`termion::event::Event`] to [`Input`].
|
||||||
|
fn from(event: Event) -> Self {
|
||||||
|
match event {
|
||||||
|
Event::Key(key) => Self::from(key),
|
||||||
|
Event::Mouse(mouse) => Self::from(mouse),
|
||||||
|
_ => Self::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<KeyEvent> for Input {
|
||||||
|
/// Convert [`termion::event::Key`] to [`Input`].
|
||||||
|
fn from(key: KeyEvent) -> Self {
|
||||||
|
use KeyEvent::*;
|
||||||
|
|
||||||
|
let mut ctrl = false;
|
||||||
|
let mut alt = false;
|
||||||
|
let key = match key {
|
||||||
|
Char('\n' | '\r') => Key::Enter,
|
||||||
|
Char(c) => Key::Char(c),
|
||||||
|
Ctrl(c) => {
|
||||||
|
ctrl = true;
|
||||||
|
Key::Char(c)
|
||||||
|
}
|
||||||
|
Alt(c) => {
|
||||||
|
alt = true;
|
||||||
|
Key::Char(c)
|
||||||
|
}
|
||||||
|
Backspace => Key::Backspace,
|
||||||
|
Left => Key::Left,
|
||||||
|
Right => Key::Right,
|
||||||
|
Up => Key::Up,
|
||||||
|
Down => Key::Down,
|
||||||
|
Home => Key::Home,
|
||||||
|
End => Key::End,
|
||||||
|
PageUp => Key::PageUp,
|
||||||
|
PageDown => Key::PageDown,
|
||||||
|
BackTab => Key::Tab,
|
||||||
|
Delete => Key::Delete,
|
||||||
|
Esc => Key::Esc,
|
||||||
|
F(x) => Key::F(x),
|
||||||
|
_ => Key::Null,
|
||||||
|
};
|
||||||
|
|
||||||
|
Input { key, ctrl, alt }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<MouseEvent> for Input {
|
||||||
|
/// Convert [`termion::event::MouseEvent`] to [`Input`].
|
||||||
|
fn from(mouse: MouseEvent) -> Self {
|
||||||
|
use termion::event::MouseButton;
|
||||||
|
let key = match mouse {
|
||||||
|
MouseEvent::Press(MouseButton::WheelUp, ..) => Key::MouseScrollUp,
|
||||||
|
MouseEvent::Press(MouseButton::WheelDown, ..) => Key::MouseScrollDown,
|
||||||
|
_ => return Self::default(),
|
||||||
|
};
|
||||||
|
Self {
|
||||||
|
key,
|
||||||
|
ctrl: false,
|
||||||
|
alt: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
96
src/input/termwiz.rs
Обычный файл
96
src/input/termwiz.rs
Обычный файл
@@ -0,0 +1,96 @@
|
|||||||
|
use super::{Input, Key};
|
||||||
|
use termwiz::input::{InputEvent, KeyEvent, MouseButtons, MouseEvent, PixelMouseEvent};
|
||||||
|
|
||||||
|
impl From<InputEvent> for Input {
|
||||||
|
/// Convert [`termwiz::input::InputEvent`] to [`Input`].
|
||||||
|
fn from(input: InputEvent) -> Self {
|
||||||
|
match input {
|
||||||
|
InputEvent::Key(key) => Self::from(key),
|
||||||
|
InputEvent::Mouse(mouse) => Self::from(mouse),
|
||||||
|
InputEvent::PixelMouse(mouse) => Self::from(mouse),
|
||||||
|
_ => Self::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<KeyEvent> for Input {
|
||||||
|
/// Convert [`termwiz::input::KeyEvent`] to [`Input`].
|
||||||
|
fn from(key: KeyEvent) -> Self {
|
||||||
|
use termwiz::input::{KeyCode, Modifiers};
|
||||||
|
|
||||||
|
let KeyEvent { key, modifiers } = key;
|
||||||
|
let key = match key {
|
||||||
|
KeyCode::Char(c) => Key::Char(c),
|
||||||
|
KeyCode::Backspace => Key::Backspace,
|
||||||
|
KeyCode::Tab => Key::Tab,
|
||||||
|
KeyCode::Enter => Key::Enter,
|
||||||
|
KeyCode::Escape => Key::Esc,
|
||||||
|
KeyCode::PageUp => Key::PageUp,
|
||||||
|
KeyCode::PageDown => Key::PageDown,
|
||||||
|
KeyCode::End => Key::End,
|
||||||
|
KeyCode::Home => Key::Home,
|
||||||
|
KeyCode::LeftArrow => Key::Left,
|
||||||
|
KeyCode::RightArrow => Key::Right,
|
||||||
|
KeyCode::UpArrow => Key::Up,
|
||||||
|
KeyCode::DownArrow => Key::Down,
|
||||||
|
KeyCode::Delete => Key::Delete,
|
||||||
|
KeyCode::Function(x) => Key::F(x),
|
||||||
|
_ => Key::Null,
|
||||||
|
};
|
||||||
|
let ctrl = modifiers.contains(Modifiers::CTRL);
|
||||||
|
let alt = modifiers.contains(Modifiers::ALT);
|
||||||
|
|
||||||
|
Self { key, ctrl, alt }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<MouseButtons> for Key {
|
||||||
|
/// Convert [`termwiz::input::MouseButtons`] to [`Key`].
|
||||||
|
fn from(buttons: MouseButtons) -> Self {
|
||||||
|
if buttons.contains(MouseButtons::VERT_WHEEL) {
|
||||||
|
if buttons.contains(MouseButtons::WHEEL_POSITIVE) {
|
||||||
|
Key::MouseScrollUp
|
||||||
|
} else {
|
||||||
|
Key::MouseScrollDown
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Key::Null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<MouseEvent> for Input {
|
||||||
|
/// Convert [`termwiz::input::MouseEvent`] to [`Input`].
|
||||||
|
fn from(mouse: MouseEvent) -> Self {
|
||||||
|
use termwiz::input::Modifiers;
|
||||||
|
|
||||||
|
let MouseEvent {
|
||||||
|
mouse_buttons,
|
||||||
|
modifiers,
|
||||||
|
..
|
||||||
|
} = mouse;
|
||||||
|
let key = Key::from(mouse_buttons);
|
||||||
|
let ctrl = modifiers.contains(Modifiers::CTRL);
|
||||||
|
let alt = modifiers.contains(Modifiers::ALT);
|
||||||
|
|
||||||
|
Self { key, ctrl, alt }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<PixelMouseEvent> for Input {
|
||||||
|
/// Convert [`termwiz::input::PixelMouseEvent`] to [`Input`].
|
||||||
|
fn from(mouse: PixelMouseEvent) -> Self {
|
||||||
|
use termwiz::input::Modifiers;
|
||||||
|
|
||||||
|
let PixelMouseEvent {
|
||||||
|
mouse_buttons,
|
||||||
|
modifiers,
|
||||||
|
..
|
||||||
|
} = mouse;
|
||||||
|
let key = Key::from(mouse_buttons);
|
||||||
|
let ctrl = modifiers.contains(Modifiers::CTRL);
|
||||||
|
let alt = modifiers.contains(Modifiers::ALT);
|
||||||
|
|
||||||
|
Self { key, ctrl, alt }
|
||||||
|
}
|
||||||
|
}
|
||||||
Ссылка в новой задаче
Block a user