Rework input logic to remove throttling

This commit is contained in:
Timothy Warren 2019-09-03 11:48:40 -04:00
parent dd9166d465
commit ae74513e88
1 changed files with 113 additions and 76 deletions

View File

@ -122,107 +122,144 @@ impl Editor {
// Terminal // Terminal
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/// Convert stdin to specific keypresses
fn read_key(&mut self) -> Option<EditorKey<char>> { fn read_key(&mut self) -> Option<EditorKey<char>> {
/* // --------------------------------------------------------------------
TODO: Read 1 byte by default, and read additional bytes // Match single character
if the first byte is an escape character, to resolve the // --------------------------------------------------------------------
unintentional input throttling
*/
let stdin = io::stdin(); let stdin = io::stdin();
let stdin = stdin.lock(); let stdin = stdin.lock();
let mut in_str = String::new(); let mut br = BufReader::with_capacity(5, stdin);
let mut buffer = BufReader::with_capacity(4, stdin);
buffer.read_to_string(&mut in_str).unwrap(); let mut first_read = [0; 1];
br.read_exact(&mut first_read);
let first_str = String::from_utf8(first_read.to_vec());
if first_str.is_err() {
return None;
}
let first_str = first_str.unwrap();
// Read the first character, if it isn't escape, just return it
let mut chars = first_str.chars();
let char = chars.next();
if char.is_none() {
return None;
}
let char = char.unwrap();
match char {
'\0' => return None,
'\x1b' => (),
'\x08' => return Some(Backspace),
'\x7f' => return Some(Backspace),
'\r' => return Some(Enter),
c => return Some(OtherKey(c)),
}
// --------------------------------------------------------------------
// Match escape sequence
// --------------------------------------------------------------------
let mut seq = [0;4];
br.read_exact(&mut seq);
let seq_str = String::from_utf8(seq.to_vec());
// On error, just continue the input loop
if seq_str.is_err() {
return None;
}
let seq_str = seq_str.unwrap();
let mut input: Vec<EditorKey<char>> = vec![]; let mut input: Vec<EditorKey<char>> = vec![];
for char in in_str.chars() { for char in seq_str.chars() {
// Since the fixed array is always filled, there
// will be null characters. Ignore these.
if char == '\0' {
continue;
}
input.push(match char { input.push(match char {
'\x08' => Backspace,
'\x7f' => Backspace,
'\x1b' => Escape, '\x1b' => Escape,
'\r' => Enter,
_ => OtherKey(char), _ => OtherKey(char),
}); });
} }
// Since we matched Escape earlier, if the input is empty,
// this must be the escape key
if input.is_empty() { if input.is_empty() {
return None; return Some(Escape);
} }
if input[0].eq(&Escape) { match input.len() {
match input.len() { 4 => {
5 => { // Escape code of the form `^[[NM~`
// Escape code of the form `^[[NM~` if input[3].eq(&OtherKey('~')) {
if input[4].eq(&OtherKey('~')) { let action = match (input[1].unwrap(), input[2].unwrap()) {
let action = match (input[2].unwrap(), input[3].unwrap()) { ('1', '5') => Function('5'),
('1', '5') => Function('5'), ('1', '7') => Function('6'),
('1', '7') => Function('6'), ('1', '8') => Function('7'),
('1', '8') => Function('7'), ('1', '9') => Function('8'),
('1', '9') => Function('8'), ('2', '0') => Function('9'),
('2', '0') => Function('9'), ('2', '1') => Function('X'), // F10
('2', '1') => Function('X'), // F10 ('2', '4') => Function('T'), // F12
('2', '4') => Function('T'), // F12 _ => Escape,
};
return Some(action);
}
}
3 => {
// Escape code of the form `^[[N~`
if input[2].eq(&OtherKey('~')) {
let action = match input[1].unwrap() {
'1' => HomeKey,
'3' => DeleteKey,
'4' => EndKey,
'5' => PageUp,
'6' => PageDown,
'7' => HomeKey,
'8' => EndKey,
_ => input[1], // Escape,
};
return Some(action);
}
}
2 => {
match input[0] {
// Escape code of the form `^[[X`
OtherKey('[') => {
let action = match input[1].unwrap() {
'A' => ArrowUp,
'B' => ArrowDown,
'C' => ArrowRight,
'D' => ArrowLeft,
'H' => HomeKey,
'F' => EndKey,
// Eh, just return escape otherwise
_ => Escape, _ => Escape,
}; };
return Some(action); return Some(action);
} }
} // Escape code of the form `^[OX`
4 => { OtherKey('O') => {
// Escape code of the form `^[[N~` let action = match input[1].unwrap() {
if input[3].eq(&OtherKey('~')) { 'H' => HomeKey,
let action = match input[2].unwrap() { 'F' => EndKey,
'1' => HomeKey, 'P' => Function('1'),
'3' => DeleteKey, 'Q' => Function('2'),
'4' => EndKey, 'R' => Function('3'),
'5' => PageUp, 'S' => Function('4'),
'6' => PageDown, _ => Escape,
'7' => HomeKey,
'8' => EndKey,
_ => input[2], // Escape,
}; };
return Some(action); return Some(action);
} }
_ => return Some(Escape),
} }
3 => {
match input[1] {
// Escape code of the form `^[[X`
OtherKey('[') => {
let action = match input[2].unwrap() {
'A' => ArrowUp,
'B' => ArrowDown,
'C' => ArrowRight,
'D' => ArrowLeft,
'H' => HomeKey,
'F' => EndKey,
// Eh, just return escape otherwise
_ => input[2], //Escape,
};
return Some(action);
}
// Escape code of the form `^[OX`
OtherKey('O') => {
let action = match input[2].unwrap() {
'H' => HomeKey,
'F' => EndKey,
'P' => Function('1'),
'Q' => Function('2'),
'R' => Function('3'),
'S' => Function('4'),
_ => input[2], //Escape,
};
return Some(action);
}
_ => return Some(input[1]),
}
}
_ => return Some(input[0]),
} }
_ => return Some(input[0]),
} }
// If the character doesn't match any escape sequences, just // If the character doesn't match any escape sequences, just
@ -344,6 +381,7 @@ impl Editor {
self.cursor_x = self.rows[self.cursor_y].chars.len(); self.cursor_x = self.rows[self.cursor_y].chars.len();
} }
} }
Function(_) => (),
OtherKey(c) => { OtherKey(c) => {
if c.is_ascii_control() { if c.is_ascii_control() {
if c == ctrl_key('q') { if c == ctrl_key('q') {
@ -373,7 +411,6 @@ impl Editor {
self.insert_char(c); self.insert_char(c);
} }
} }
_ => (),
}; };
self.quit_times = KILO_QUIT_TIMES; self.quit_times = KILO_QUIT_TIMES;