Merge pull request #122 from snaggen/keyboard_refactor
Refactor key handling
This commit is contained in:
commit
b421c8cdf0
1 changed files with 146 additions and 342 deletions
|
|
@ -596,244 +596,86 @@ where
|
|||
Event::Keyboard(KeyEvent::KeyPressed {
|
||||
key_code,
|
||||
modifiers,
|
||||
}) if state.is_focused => match (
|
||||
modifiers.logo(),
|
||||
modifiers.control(),
|
||||
modifiers.alt(),
|
||||
modifiers.shift(),
|
||||
) {
|
||||
(true, _, _, _) => {
|
||||
// Ignore super keys
|
||||
}) if state.is_focused => {
|
||||
let mod_no = calculate_modifier_number(state);
|
||||
let escape_code = match key_code {
|
||||
KeyCode::Insert => csi("2", mod_no),
|
||||
KeyCode::Delete => csi("3", mod_no),
|
||||
KeyCode::PageUp => csi("5", mod_no),
|
||||
KeyCode::PageDown => csi("6", mod_no),
|
||||
KeyCode::Up => {
|
||||
if is_app_cursor {
|
||||
ss3("A", mod_no)
|
||||
} else {
|
||||
csi("A", mod_no)
|
||||
}
|
||||
}
|
||||
KeyCode::Down => {
|
||||
if is_app_cursor {
|
||||
ss3("B", mod_no)
|
||||
} else {
|
||||
csi("B", mod_no)
|
||||
}
|
||||
}
|
||||
KeyCode::Right => {
|
||||
if is_app_cursor {
|
||||
ss3("C", mod_no)
|
||||
} else {
|
||||
csi("C", mod_no)
|
||||
}
|
||||
}
|
||||
KeyCode::Left => {
|
||||
if is_app_cursor {
|
||||
ss3("D", mod_no)
|
||||
} else {
|
||||
csi("D", mod_no)
|
||||
}
|
||||
}
|
||||
KeyCode::Home => {
|
||||
if is_app_cursor {
|
||||
ss3("H", mod_no)
|
||||
} else {
|
||||
csi("H", mod_no)
|
||||
}
|
||||
}
|
||||
KeyCode::End => {
|
||||
if is_app_cursor {
|
||||
ss3("F", mod_no)
|
||||
} else {
|
||||
csi("F", mod_no)
|
||||
}
|
||||
}
|
||||
KeyCode::F1 => ss3("P", mod_no),
|
||||
KeyCode::F2 => ss3("Q", mod_no),
|
||||
KeyCode::F3 => ss3("R", mod_no),
|
||||
KeyCode::F4 => ss3("S", mod_no),
|
||||
KeyCode::F5 => csi("15", mod_no),
|
||||
KeyCode::F6 => csi("17", mod_no),
|
||||
KeyCode::F7 => csi("18", mod_no),
|
||||
KeyCode::F8 => csi("19", mod_no),
|
||||
KeyCode::F9 => csi("20", mod_no),
|
||||
KeyCode::F10 => csi("21", mod_no),
|
||||
KeyCode::F11 => csi("23", mod_no),
|
||||
KeyCode::F12 => csi("24", mod_no),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(escape_code) = escape_code {
|
||||
terminal.input_scroll(escape_code);
|
||||
return Status::Captured;
|
||||
}
|
||||
(_, true, _, _) => match key_code {
|
||||
KeyCode::Up => {
|
||||
terminal.input_scroll(b"\x1B[1;5A".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Down => {
|
||||
terminal.input_scroll(b"\x1B[1;5B".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Right => {
|
||||
terminal.input_scroll(b"\x1B[1;5C".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Left => {
|
||||
terminal.input_scroll(b"\x1B[1;5D".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::End => {
|
||||
terminal.input_scroll(b"\x1B[1;5F".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Home => {
|
||||
terminal.input_scroll(b"\x1B[1;5H".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Insert => {
|
||||
terminal.input_scroll(b"\x1B[2;5~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Delete => {
|
||||
terminal.input_scroll(b"\x1B[3;5~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::PageUp => {
|
||||
terminal.input_scroll(b"\x1B[5;5~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::PageDown => {
|
||||
terminal.input_scroll(b"\x1B[6;5~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F1 => {
|
||||
terminal.input_scroll(b"\x1BO;5P".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F2 => {
|
||||
terminal.input_scroll(b"\x1BO;5Q".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F3 => {
|
||||
terminal.input_scroll(b"\x1BO;5R".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F4 => {
|
||||
terminal.input_scroll(b"\x1BO;5S".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F5 => {
|
||||
terminal.input_scroll(b"\x1B[15;5~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F6 => {
|
||||
terminal.input_scroll(b"\x1B[17;5~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F7 => {
|
||||
terminal.input_scroll(b"\x1B[18;5~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F8 => {
|
||||
terminal.input_scroll(b"\x1B[19;5~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F9 => {
|
||||
terminal.input_scroll(b"\x1B[20;5~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F10 => {
|
||||
terminal.input_scroll(b"\x1B[21;5~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F11 => {
|
||||
terminal.input_scroll(b"\x1B[23;5~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F12 => {
|
||||
terminal.input_scroll(b"\x1B[24;5~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
//This is normally Ctrl+Minus, but since that
|
||||
//is taken by zoom, we send that code for
|
||||
//Ctrl+Underline instead, like xterm and
|
||||
//gnome-terminal
|
||||
KeyCode::Underline => {
|
||||
terminal.input_scroll(b"\x1F".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
_ => (),
|
||||
},
|
||||
// Handle alt keys
|
||||
(_, _, true, _) => match key_code {
|
||||
KeyCode::Up => {
|
||||
terminal.input_scroll(b"\x1B[1;3A".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Down => {
|
||||
terminal.input_scroll(b"\x1B[1;3B".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Right => {
|
||||
terminal.input_scroll(b"\x1B[1;3C".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Left => {
|
||||
terminal.input_scroll(b"\x1B[1;3D".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::End => {
|
||||
terminal.input_scroll(b"\x1B[1;3F".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Home => {
|
||||
terminal.input_scroll(b"\x1B[1;3H".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Insert => {
|
||||
terminal.input_scroll(b"\x1B[2;3~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Delete => {
|
||||
terminal.input_scroll(b"\x1B[3;3~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::PageUp => {
|
||||
terminal.input_scroll(b"\x1B[5;3~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::PageDown => {
|
||||
terminal.input_scroll(b"\x1B[6;3~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F1 => {
|
||||
terminal.input_scroll(b"\x1B[1;3P".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F2 => {
|
||||
terminal.input_scroll(b"\x1B1;3Q".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F3 => {
|
||||
terminal.input_scroll(b"\x1B1;3R".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F4 => {
|
||||
terminal.input_scroll(b"\x1B1;3S".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F5 => {
|
||||
terminal.input_scroll(b"\x1B[15;3~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F6 => {
|
||||
terminal.input_scroll(b"\x1B[17;3~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F7 => {
|
||||
terminal.input_scroll(b"\x1B[18;3~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F8 => {
|
||||
terminal.input_scroll(b"\x1B[19;3~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F9 => {
|
||||
terminal.input_scroll(b"\x1B[20;3~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F10 => {
|
||||
terminal.input_scroll(b"\x1B[21;3~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F11 => {
|
||||
terminal.input_scroll(b"\x1B[23;3~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F12 => {
|
||||
terminal.input_scroll(b"\x1B[24;3~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Backspace => {
|
||||
terminal.input_scroll(b"\x1B\x7F".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
_ => (),
|
||||
},
|
||||
// Handle shift keys
|
||||
(_, _, _, true) => match key_code {
|
||||
KeyCode::End => {
|
||||
terminal.scroll(TerminalScroll::Bottom);
|
||||
}
|
||||
KeyCode::Home => {
|
||||
terminal.scroll(TerminalScroll::Top);
|
||||
}
|
||||
KeyCode::PageDown => {
|
||||
terminal.scroll(TerminalScroll::PageDown);
|
||||
}
|
||||
KeyCode::PageUp => {
|
||||
terminal.scroll(TerminalScroll::PageUp);
|
||||
}
|
||||
KeyCode::Tab => {
|
||||
terminal.input_scroll(b"\x1B[Z".as_slice());
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
// Handle keys with no modifiers
|
||||
(_, _, _, false) => match key_code {
|
||||
KeyCode::Backspace => {
|
||||
terminal.input_scroll(b"\x7F".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Tab => {
|
||||
terminal.input_scroll(b"\t".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
|
||||
//Special handle Enter, Escape, Backspace and Tab as described in
|
||||
//https://sw.kovidgoyal.net/kitty/keyboard-protocol/#legacy-key-event-encoding
|
||||
//Also special handle Ctrl-_ to behave like xterm
|
||||
let alt_prefix = if modifiers.alt() { "\x1B" } else { "" };
|
||||
match key_code {
|
||||
KeyCode::Enter => {
|
||||
terminal.input_scroll(b"\r".as_slice());
|
||||
terminal
|
||||
.input_scroll(format!("{}{}", alt_prefix, "\x0D").as_bytes().to_vec());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Escape => {
|
||||
//Escape with any modifier will cancel selection
|
||||
let had_selection = {
|
||||
let mut term = terminal.term.lock();
|
||||
term.selection.take().is_some()
|
||||
|
|
@ -841,113 +683,31 @@ where
|
|||
if had_selection {
|
||||
terminal.update();
|
||||
} else {
|
||||
terminal.input_scroll(b"\x1B".as_slice());
|
||||
terminal.input_scroll(
|
||||
format!("{}{}", alt_prefix, "\x1B").as_bytes().to_vec(),
|
||||
);
|
||||
}
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Up => {
|
||||
let code = if is_app_cursor { b"\x1BOA" } else { b"\x1B[A" };
|
||||
|
||||
terminal.input_scroll(code.as_slice());
|
||||
KeyCode::Backspace => {
|
||||
let code = if modifiers.control() { "\x08" } else { "\x7f" };
|
||||
terminal
|
||||
.input_scroll(format!("{}{}", alt_prefix, code).as_bytes().to_vec());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Down => {
|
||||
let code = if is_app_cursor { b"\x1BOB" } else { b"\x1B[B" };
|
||||
|
||||
terminal.input_scroll(code.as_slice());
|
||||
KeyCode::Tab => {
|
||||
let code = if modifiers.shift() { "\x1b[Z" } else { "\x09" };
|
||||
terminal
|
||||
.input_scroll(format!("{}{}", alt_prefix, code).as_bytes().to_vec());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Right => {
|
||||
let code = if is_app_cursor { b"\x1BOC" } else { b"\x1B[C" };
|
||||
|
||||
terminal.input_scroll(code.as_slice());
|
||||
KeyCode::Underline if modifiers.control() => {
|
||||
terminal.input_scroll(b"\x1F".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Left => {
|
||||
let code = if is_app_cursor { b"\x1BOD" } else { b"\x1B[D" };
|
||||
|
||||
terminal.input_scroll(code.as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::End => {
|
||||
let code = if is_app_cursor { b"\x1BOF" } else { b"\x1B[F" };
|
||||
|
||||
terminal.input_scroll(code.as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Home => {
|
||||
let code = if is_app_cursor { b"\x1BOH" } else { b"\x1B[H" };
|
||||
|
||||
terminal.input_scroll(code.as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Insert => {
|
||||
terminal.input_scroll(b"\x1B[2~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Delete => {
|
||||
terminal.input_scroll(b"\x1B[3~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::PageUp => {
|
||||
terminal.input_scroll(b"\x1B[5~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::PageDown => {
|
||||
terminal.input_scroll(b"\x1B[6~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F1 => {
|
||||
terminal.input_scroll(b"\x1BOP".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F2 => {
|
||||
terminal.input_scroll(b"\x1BOQ".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F3 => {
|
||||
terminal.input_scroll(b"\x1BOR".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F4 => {
|
||||
terminal.input_scroll(b"\x1BOS".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F5 => {
|
||||
terminal.input_scroll(b"\x1B[15~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F6 => {
|
||||
terminal.input_scroll(b"\x1B[17~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F7 => {
|
||||
terminal.input_scroll(b"\x1B[18~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F8 => {
|
||||
terminal.input_scroll(b"\x1B[19~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F9 => {
|
||||
terminal.input_scroll(b"\x1B[20~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F10 => {
|
||||
terminal.input_scroll(b"\x1B[21~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F11 => {
|
||||
terminal.input_scroll(b"\x1B[23~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F12 => {
|
||||
terminal.input_scroll(b"\x1B[24~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
_ => (),
|
||||
},
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Event::Keyboard(KeyEvent::ModifiersChanged(modifiers)) => {
|
||||
state.modifiers = modifiers;
|
||||
}
|
||||
|
|
@ -961,18 +721,17 @@ where
|
|||
(true, _, _, _) => {
|
||||
// Ignore super
|
||||
}
|
||||
(false, true, true, false) => {
|
||||
(false, true, true, _) => {
|
||||
// Handle ctrl-alt for non-control characters
|
||||
// Or should I try to minimize this to only
|
||||
// catch control sequences that conflicts with
|
||||
// keykodes for Split
|
||||
// if character != '\u{4}' && character != '\u{12}' {
|
||||
// is there any valid case for control characters with modifers
|
||||
// ctrl-alt?
|
||||
if !character.is_control() {
|
||||
let mut buf = [0, 0, 0, 0];
|
||||
let str = character.encode_utf8(&mut buf);
|
||||
terminal.input_scroll(str.as_bytes().to_vec());
|
||||
// and control characters 0-32
|
||||
if !character.is_control() || (character as u32) < 32 {
|
||||
// Handle alt for non-control characters
|
||||
let mut buf = [0x1B, 0, 0, 0, 0];
|
||||
let len = {
|
||||
let str = character.encode_utf8(&mut buf[1..]);
|
||||
str.len() + 1
|
||||
};
|
||||
terminal.input_scroll(buf[..len].to_vec());
|
||||
status = Status::Captured;
|
||||
}
|
||||
}
|
||||
|
|
@ -1316,3 +1075,48 @@ impl operation::Focusable for State {
|
|||
self.is_focused = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
shift 0b1 (1)
|
||||
alt 0b10 (2)
|
||||
ctrl 0b100 (4)
|
||||
super 0b1000 (8)
|
||||
hyper 0b10000 (16)
|
||||
meta 0b100000 (32)
|
||||
caps_lock 0b1000000 (64)
|
||||
num_lock 0b10000000 (128)
|
||||
*/
|
||||
fn calculate_modifier_number(state: &mut State) -> u8 {
|
||||
let mut mod_no = 0;
|
||||
if state.modifiers.shift() {
|
||||
mod_no |= 1;
|
||||
}
|
||||
if state.modifiers.alt() {
|
||||
mod_no |= 2;
|
||||
}
|
||||
if state.modifiers.control() {
|
||||
mod_no |= 4;
|
||||
}
|
||||
if state.modifiers.logo() {
|
||||
mod_no |= 8;
|
||||
}
|
||||
mod_no + 1
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn csi(code: &str, modifiers: u8) -> Option<Vec<u8>> {
|
||||
if modifiers == 1 {
|
||||
Some(format!("\x1B[{}~", code).as_bytes().to_vec())
|
||||
} else {
|
||||
Some(format!("\x1B[{};{}~", code, modifiers).as_bytes().to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn ss3(code: &str, modifiers: u8) -> Option<Vec<u8>> {
|
||||
if modifiers == 1 {
|
||||
Some(format!("\x1B\x4F{}", code).as_bytes().to_vec())
|
||||
} else {
|
||||
Some(format!("\x1B[1;{}{}", modifiers, code).as_bytes().to_vec())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue