requestty_ui/events/
termion.rs1use std::{
2 convert::{TryFrom, TryInto},
3 fmt,
4 io::{self, stdin, Stdin},
5};
6
7use termion::{
8 event,
9 input::{self, TermRead},
10};
11
12use super::EventIterator;
13
14#[cfg_attr(docsrs, doc(cfg(feature = "termion")))]
16pub struct TermionEvents {
17 events: input::Keys<Stdin>,
18}
19
20struct Dash;
21
22impl fmt::Debug for Dash {
23 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24 f.write_str("_")
25 }
26}
27
28impl fmt::Debug for TermionEvents {
29 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30 f.debug_struct("TermionEvents")
31 .field("events", &Dash)
32 .finish()
33 }
34}
35
36impl TermionEvents {
37 pub fn new() -> Self {
39 Self {
40 events: stdin().keys(),
41 }
42 }
43}
44
45impl Default for TermionEvents {
46 fn default() -> Self {
47 Self::new()
48 }
49}
50
51impl EventIterator for TermionEvents {
52 fn next_event(&mut self) -> io::Result<super::KeyEvent> {
53 let e = self
54 .events
55 .next()
56 .expect("TermionEvents ran out of user input!?")?;
57 e.try_into()
58 }
59}
60
61impl TryFrom<event::Key> for super::KeyEvent {
62 type Error = io::Error;
63
64 fn try_from(key: event::Key) -> io::Result<super::KeyEvent> {
65 let key = match key {
66 event::Key::Backspace => super::KeyCode::Backspace.into(),
67 event::Key::Left => super::KeyCode::Left.into(),
68 event::Key::Right => super::KeyCode::Right.into(),
69 event::Key::Up => super::KeyCode::Up.into(),
70 event::Key::Down => super::KeyCode::Down.into(),
71 event::Key::Home => super::KeyCode::Home.into(),
72 event::Key::End => super::KeyCode::End.into(),
73 event::Key::PageUp => super::KeyCode::PageUp.into(),
74 event::Key::PageDown => super::KeyCode::PageDown.into(),
75 event::Key::BackTab => super::KeyCode::BackTab.into(),
76 event::Key::Delete => super::KeyCode::Delete.into(),
77 event::Key::Insert => super::KeyCode::Insert.into(),
78 event::Key::F(n) => super::KeyCode::F(n).into(),
79 event::Key::Char('\n') => super::KeyCode::Enter.into(),
80 event::Key::Char('\t') => super::KeyCode::Tab.into(),
81 event::Key::Char(c) => super::KeyCode::Char(c).into(),
82 event::Key::Alt(c) => parse_char(c, super::KeyModifiers::ALT)?,
83 event::Key::Ctrl(c) => parse_char(c, super::KeyModifiers::CONTROL)?,
84 event::Key::Null => super::KeyCode::Null.into(),
85 event::Key::Esc => super::KeyCode::Esc.into(),
86 _ => unreachable!(),
87 };
88
89 Ok(key)
90 }
91}
92
93fn parse_char(mut c: char, mut modifiers: super::KeyModifiers) -> io::Result<super::KeyEvent> {
94 let code = loop {
95 if c as u32 >= 256 {
96 break super::KeyCode::Char(c);
97 }
98
99 let k = match event::parse_event(c as u8, &mut std::iter::empty())? {
100 event::Event::Key(k) => k,
101 _ => match char::try_from(c as u32) {
102 Ok(c) => break super::KeyCode::Char(c),
103 Err(_) => {
104 return Err(io::Error::new(
105 io::ErrorKind::Other,
106 "Could not parse an event",
107 ))
108 }
109 },
110 };
111
112 match k {
113 event::Key::Backspace => break super::KeyCode::Backspace,
114 event::Key::Left => break super::KeyCode::Left,
115 event::Key::Right => break super::KeyCode::Right,
116 event::Key::Up => break super::KeyCode::Up,
117 event::Key::Down => break super::KeyCode::Down,
118 event::Key::Home => break super::KeyCode::Home,
119 event::Key::End => break super::KeyCode::End,
120 event::Key::PageUp => break super::KeyCode::PageUp,
121 event::Key::PageDown => break super::KeyCode::PageDown,
122 event::Key::BackTab => break super::KeyCode::BackTab,
123 event::Key::Delete => break super::KeyCode::Delete,
124 event::Key::Insert => break super::KeyCode::Insert,
125 event::Key::F(n) => break super::KeyCode::F(n),
126 event::Key::Char('\n') => break super::KeyCode::Enter,
127 event::Key::Char('\t') => break super::KeyCode::Tab,
128 event::Key::Char(c @ 'A'..='Z') => {
129 modifiers |= super::KeyModifiers::SHIFT;
130 break super::KeyCode::Char(c);
131 }
132 event::Key::Char(c) => break super::KeyCode::Char(c),
133 event::Key::Alt(new_c) => {
134 modifiers |= super::KeyModifiers::ALT;
135 c = new_c
136 }
137 event::Key::Ctrl(new_c) => {
138 modifiers |= super::KeyModifiers::CONTROL;
139 c = new_c
140 }
141 event::Key::Null => break super::KeyCode::Null,
142 event::Key::Esc => break super::KeyCode::Esc,
143 _ => unreachable!(),
144 }
145 };
146
147 Ok(super::KeyEvent::new(code, modifiers))
148}