1use vt100::{
2 MouseProtocolEncoding,
3 Parser,
4};
5
6pub(crate) fn check_for_terminal_queries(data: &[u8], parser: &Parser) -> Vec<Vec<u8>> {
10 let mut responses = Vec::new();
11
12 if data.windows(4).any(|w| w == b"\x1b[6n") {
14 let (row, col) = parser.screen().cursor_position();
15 let response = format!("\x1b[{};{}R", row + 1, col + 1);
16 responses.push(response.into_bytes());
17 }
18
19 if data.windows(5).any(|w| w == b"\x1b[?6n") {
21 let (row, col) = parser.screen().cursor_position();
22 let response = format!("\x1b[?{};{}R", row + 1, col + 1);
23 responses.push(response.into_bytes());
24 }
25
26 if data.windows(4).any(|w| w == b"\x1b[5n") {
28 responses.push(b"\x1b[0n".to_vec());
29 }
30
31 if data.windows(3).any(|w| w == b"\x1b[c") || data.windows(4).any(|w| w == b"\x1b[0c") {
33 responses.push(b"\x1b[?62;22c".to_vec());
34 }
35
36 if data.windows(4).any(|w| w == b"\x1b>c") || data.windows(5).any(|w| w == b"\x1b>0c") {
38 responses.push(b"\x1b[>0;0;0c".to_vec());
39 }
40
41 responses
42}
43
44#[derive(Debug, Clone, Copy, PartialEq)]
46pub enum TerminalMouseButton {
47 Left,
48 Middle,
49 Right,
50}
51
52impl TerminalMouseButton {
53 fn code(self) -> u8 {
55 match self {
56 Self::Left => 0,
57 Self::Middle => 1,
58 Self::Right => 2,
59 }
60 }
61}
62
63pub fn encode_mouse_press(
65 row: usize,
66 col: usize,
67 button: TerminalMouseButton,
68 encoding: MouseProtocolEncoding,
69) -> String {
70 match encoding {
71 MouseProtocolEncoding::Sgr => {
72 let sgr_row = row.saturating_add(1);
73 let sgr_col = col.saturating_add(1);
74 format!("\x1b[<{};{};{}M", button.code(), sgr_col, sgr_row)
75 }
76 _ => {
77 let button_byte = button.code().saturating_add(32);
78 let col_byte = col.saturating_add(1).min(255) as u8;
79 let row_byte = row.saturating_add(1).min(255) as u8;
80 format!(
81 "\x1b[M{}{}{}",
82 button_byte as char, col_byte as char, row_byte as char
83 )
84 }
85 }
86}
87
88pub fn encode_mouse_release(
90 row: usize,
91 col: usize,
92 button: TerminalMouseButton,
93 encoding: MouseProtocolEncoding,
94) -> String {
95 match encoding {
96 MouseProtocolEncoding::Sgr => {
97 let sgr_row = row.saturating_add(1);
99 let sgr_col = col.saturating_add(1);
100 format!("\x1b[<{};{};{}m", button.code(), sgr_col, sgr_row)
101 }
102 _ => {
103 let button_byte = 35u8; let col_byte = col.saturating_add(1).min(255) as u8;
106 let row_byte = row.saturating_add(1).min(255) as u8;
107 format!(
108 "\x1b[M{}{}{}",
109 button_byte as char, col_byte as char, row_byte as char
110 )
111 }
112 }
113}
114
115pub fn encode_mouse_move(
122 row: usize,
123 col: usize,
124 button: Option<TerminalMouseButton>,
125 encoding: MouseProtocolEncoding,
126) -> String {
127 let code = match button {
129 Some(b) => b.code() + 32,
130 None => 3 + 32, };
132
133 match encoding {
134 MouseProtocolEncoding::Sgr => {
135 let sgr_row = row.saturating_add(1);
136 let sgr_col = col.saturating_add(1);
137 format!("\x1b[<{};{};{}M", code, sgr_col, sgr_row)
138 }
139 _ => {
140 let button_byte = code.saturating_add(32);
141 let col_byte = col.saturating_add(1).min(255) as u8;
142 let row_byte = row.saturating_add(1).min(255) as u8;
143 format!(
144 "\x1b[M{}{}{}",
145 button_byte as char, col_byte as char, row_byte as char
146 )
147 }
148 }
149}
150
151pub fn encode_wheel_event(
155 row: usize,
156 col: usize,
157 delta_y: f64,
158 encoding: MouseProtocolEncoding,
159) -> String {
160 match encoding {
162 MouseProtocolEncoding::Sgr => {
163 let button = if delta_y > 0.0 { 64 } else { 65 };
164 let sgr_row = row.saturating_add(1);
165 let sgr_col = col.saturating_add(1);
166 format!("\x1b[<{};{};{}M", button, sgr_col, sgr_row)
168 }
169 _ => {
171 let button_byte = if delta_y > 0.0 { 96u8 } else { 97u8 };
176 let col_byte = col.saturating_add(1).min(255) as u8;
177 let row_byte = row.saturating_add(1).min(255) as u8;
178 format!(
179 "\x1b[M{}{}{}",
180 button_byte as char, col_byte as char, row_byte as char
181 )
182 }
183 }
184}