tui_lib/tui_io/
input_parser.rs1use crate::tui_events::TuiEvents;
2
3use super::input_interface::InputInterfaceT;
4
5pub trait ParseInput: InputInterfaceT {
6 fn parse_input(&self, input_char: char) -> TuiEvents {
7 match input_char {
8 '\x1b' => {
9 return self.handle_escape_input_s1();
10 }
11 '\x7F' => {
12 return TuiEvents::Backspace;
13 }
14 '\n' | '\r' => {
15 return TuiEvents::Enter;
16 }
17 ' ' => {
18 return TuiEvents::Space;
19 }
20 '\t' => {
21 return TuiEvents::Tab;
22 }
23 _ => match input_char as u32 {
24 0x20..=0x7D => return TuiEvents::AsciiReadable(input_char),
25 0 => TuiEvents::Ignore,
26 1..=26 => return TuiEvents::Control((input_char as u8 + 0x40) as char),
27 _ => return TuiEvents::Other(input_char),
28 },
29 }
30 }
31 fn handle_escape_input_s1(&self) -> TuiEvents {
32 let input_char_option: Option<char> = self.read_raw_immediate();
33 let result = match input_char_option {
34 None => TuiEvents::Escape,
35 Some('[') => self.handle_escape_input_s2(),
36 Some(_) => TuiEvents::Error,
37 };
38 match result {
39 TuiEvents::Error | TuiEvents::Ignore => loop {
40 if let None = self.read_raw_immediate() {
41 return result;
42 };
43 },
44 _ => return result,
45 }
46 }
47
48 fn handle_escape_input_s2(&self) -> TuiEvents {
49 let input_char = self.read_raw_immediate();
50 return match input_char {
51 Some('A') => TuiEvents::UpArrow,
52 Some('B') => TuiEvents::DownArrow,
53 Some('C') => TuiEvents::RightArrow,
54 Some('D') => TuiEvents::LeftArrow,
55 Some('3') => {
56 if let Some('~') = self.read_raw_immediate() {
57 return TuiEvents::Delete;
58 }
59 TuiEvents::Error
60 }
61 Some('<') => self.handle_mouse_events(),
62 Some(_) | None => TuiEvents::Error,
63 };
64 }
65 fn handle_mouse_events(&self) -> TuiEvents {
66 return match self.read_raw_immediate() {
67 Some('0') => match self.get_coordinates() {
68 Some((coordinates, 'M')) => TuiEvents::LeftClick(coordinates),
69 Some((_, 'm')) => TuiEvents::Ignore,
70 None | Some(_) => TuiEvents::Error,
71 },
72 Some('1') => match self.get_coordinates() {
73 Some((coordinates, 'M')) => TuiEvents::MiddleClick(coordinates),
74 Some((_, 'm')) => TuiEvents::Ignore,
75 None | Some(_) => TuiEvents::Error,
76 },
77 Some('2') => match self.get_coordinates() {
78 Some((coordinates, 'M')) => TuiEvents::RightClick(coordinates),
79 Some((_, 'm')) => TuiEvents::Ignore,
80 None | Some(_) => TuiEvents::Error,
81 },
82 Some('3') => self.handle_mouse_move_event(),
83 Some('6') => self.handle_scroll_event(),
84 None | Some(_) => return TuiEvents::Error,
85 };
86 }
87
88 fn handle_mouse_move_event(&self) -> TuiEvents {
89 return match self.read_raw_immediate() {
90 Some('2') => match self.get_coordinates() {
91 Some((coordinates, 'M')) => TuiEvents::LeftDrag(coordinates),
92 Some(_) | None => TuiEvents::Error,
93 },
94 Some('3') => match self.get_coordinates() {
95 Some((coordinates, 'M')) => TuiEvents::MiddleDrag(coordinates),
96 Some(_) | None => TuiEvents::Error,
97 },
98 Some('4') => match self.get_coordinates() {
99 Some((coordinates, 'M')) => TuiEvents::RightDrag(coordinates),
100 Some(_) | None => TuiEvents::Error,
101 },
102 Some('5') => match self.get_coordinates() {
103 Some((coordinates, 'm')) => TuiEvents::MouseMove(coordinates),
104 Some(_) | None => TuiEvents::Error,
105 },
106 None | Some(_) => TuiEvents::Error,
107 };
108 }
109
110 fn handle_scroll_event(&self) -> TuiEvents {
111 return match self.read_raw_immediate() {
112 Some('4') => match self.get_coordinates() {
113 Some((coordinates, 'M')) => TuiEvents::ScrollUp(coordinates),
114 None | Some(_) => TuiEvents::Error,
115 },
116 Some('5') => match self.get_coordinates() {
117 Some((coordinates, 'M')) => TuiEvents::ScrollDown(coordinates),
118 None | Some(_) => TuiEvents::Error,
119 },
120 None | Some(_) => TuiEvents::Error,
121 };
122 }
123
124 fn get_u16(&self) -> Option<(u16, char)> {
125 let mut num = 0;
126 loop {
127 let next = self.read_raw_immediate()?;
128 match next as u16 {
129 0x30..=0x39 => {
130 let digit = next as u16 - 0x30;
131 if num > u16::MAX {
132 return None;
133 }
134 num *= 10;
135 if digit > u16::MAX - num {
136 return None;
137 }
138 num += digit;
139 }
140 _ => return Some((num, next)),
141 }
142 }
143 }
144
145 fn get_coordinates(&self) -> Option<((u16, u16), char)> {
146 let Some(';') = self.read_raw_immediate() else {
147 return None;
148 };
149 let Some((x, ';')) = self.get_u16() else {
150 return None;
151 };
152 return match self.get_u16() {
153 Some((y, c)) => Some(((x, y), c)),
154 None => None,
155 };
156 }
157}