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
// ------------------------------------------------------------------------
/// Convert stdin to specific keypresses
fn read_key(&mut self) -> Option<EditorKey<char>> {
/*
TODO: Read 1 byte by default, and read additional bytes
if the first byte is an escape character, to resolve the
unintentional input throttling
*/
// --------------------------------------------------------------------
// Match single character
// --------------------------------------------------------------------
let stdin = io::stdin();
let stdin = stdin.lock();
let mut in_str = String::new();
let mut buffer = BufReader::with_capacity(4, stdin);
buffer.read_to_string(&mut in_str).unwrap();
let mut br = BufReader::with_capacity(5, stdin);
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![];
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 {
'\x08' => Backspace,
'\x7f' => Backspace,
'\x1b' => Escape,
'\r' => Enter,
_ => OtherKey(char),
});
}
// Since we matched Escape earlier, if the input is empty,
// this must be the escape key
if input.is_empty() {
return None;
return Some(Escape);
}
if input[0].eq(&Escape) {
match input.len() {
5 => {
// Escape code of the form `^[[NM~`
if input[4].eq(&OtherKey('~')) {
let action = match (input[2].unwrap(), input[3].unwrap()) {
('1', '5') => Function('5'),
('1', '7') => Function('6'),
('1', '8') => Function('7'),
('1', '9') => Function('8'),
('2', '0') => Function('9'),
('2', '1') => Function('X'), // F10
('2', '4') => Function('T'), // F12
match input.len() {
4 => {
// Escape code of the form `^[[NM~`
if input[3].eq(&OtherKey('~')) {
let action = match (input[1].unwrap(), input[2].unwrap()) {
('1', '5') => Function('5'),
('1', '7') => Function('6'),
('1', '8') => Function('7'),
('1', '9') => Function('8'),
('2', '0') => Function('9'),
('2', '1') => Function('X'), // F10
('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,
};
return Some(action);
}
}
4 => {
// Escape code of the form `^[[N~`
if input[3].eq(&OtherKey('~')) {
let action = match input[2].unwrap() {
'1' => HomeKey,
'3' => DeleteKey,
'4' => EndKey,
'5' => PageUp,
'6' => PageDown,
'7' => HomeKey,
'8' => EndKey,
_ => input[2], // Escape,
// Escape code of the form `^[OX`
OtherKey('O') => {
let action = match input[1].unwrap() {
'H' => HomeKey,
'F' => EndKey,
'P' => Function('1'),
'Q' => Function('2'),
'R' => Function('3'),
'S' => Function('4'),
_ => Escape,
};
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
@ -344,6 +381,7 @@ impl Editor {
self.cursor_x = self.rows[self.cursor_y].chars.len();
}
}
Function(_) => (),
OtherKey(c) => {
if c.is_ascii_control() {
if c == ctrl_key('q') {
@ -373,7 +411,6 @@ impl Editor {
self.insert_char(c);
}
}
_ => (),
};
self.quit_times = KILO_QUIT_TIMES;