diff --git a/src/consts.rs b/src/consts.rs index e0ee405c7b..f30014436d 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -1,68 +1,101 @@ - #[derive(Debug, Clone, PartialEq, Copy)] -pub enum KeyPress { - UnknownEscSeq, +pub enum Key { Backspace, Char(char), - Ctrl(char), Delete, Down, End, Enter, // Ctrl('M') Esc, Home, + Insert, Left, - Meta(char), Null, PageDown, PageUp, Right, Tab, // Ctrl('I') + Unknown, Up, } +#[derive(Debug, Clone, PartialEq, Copy)] +pub struct KeyPress { + pub key: Key, + pub alt: bool, + pub ctrl: bool, + pub shift: bool, + pub sup: bool, +} + +macro_rules! key { + ($key:tt) => (key!(Key::Char($key))); + ($($key:tt)*) => (KeyPress { key: $($key)*, alt: false, ctrl: false, shift: false, sup: false }); +} + +macro_rules! alt { + ($key:tt) => (alt!(Key::Char($key))); + ($($key:tt)*) => (KeyPress { key: $($key)*, alt: true, ctrl: false, shift: false, sup: false }); +} + +macro_rules! ctrl { + ($key:tt) => (ctrl!(Key::Char($key))); + ($($key:tt)*) => (KeyPress { key: $($key)*, alt: false, ctrl: true, shift: false, sup: false }); +} + +macro_rules! shift { + ($key:tt) => (shift!(Key::Char($key))); + ($($key:tt)*) => (KeyPress { key: $($key)*, alt: false, ctrl: false, shift: true, sup: false }); +} + +macro_rules! sup { + ($key:tt) => (sup!(Key::Char($key))); + ($($key:tt)*) => (KeyPress { key: $($key)*, alt: false, ctrl: false, shift: false, sup: true }); +} + #[allow(match_same_arms)] pub fn char_to_key_press(c: char) -> KeyPress { if !c.is_control() { - return KeyPress::Char(c); + return key!(c); } + match c { - '\x00' => KeyPress::Null, - '\x01' => KeyPress::Ctrl('A'), - '\x02' => KeyPress::Ctrl('B'), - '\x03' => KeyPress::Ctrl('C'), - '\x04' => KeyPress::Ctrl('D'), - '\x05' => KeyPress::Ctrl('E'), - '\x06' => KeyPress::Ctrl('F'), - '\x07' => KeyPress::Ctrl('G'), - '\x08' => KeyPress::Backspace, // '\b' - '\x09' => KeyPress::Tab, - '\x0a' => KeyPress::Ctrl('J'), // '\n' (10) - '\x0b' => KeyPress::Ctrl('K'), - '\x0c' => KeyPress::Ctrl('L'), - '\x0d' => KeyPress::Enter, // '\r' (13) - '\x0e' => KeyPress::Ctrl('N'), - '\x10' => KeyPress::Ctrl('P'), - '\x12' => KeyPress::Ctrl('R'), - '\x13' => KeyPress::Ctrl('S'), - '\x14' => KeyPress::Ctrl('T'), - '\x15' => KeyPress::Ctrl('U'), - '\x16' => KeyPress::Ctrl('V'), - '\x17' => KeyPress::Ctrl('W'), - '\x19' => KeyPress::Ctrl('Y'), - '\x1a' => KeyPress::Ctrl('Z'), - '\x1b' => KeyPress::Esc, - '\x7f' => KeyPress::Backspace, // TODO Validate - _ => KeyPress::Null, + '\x00' => key!(Key::Null), + '\x01' => ctrl!('A'), + '\x02' => ctrl!('B'), + '\x03' => ctrl!('C'), + '\x04' => ctrl!('D'), + '\x05' => ctrl!('E'), + '\x06' => ctrl!('F'), + '\x07' => ctrl!('G'), + '\x08' => key!(Key::Backspace), // '\b' + '\x09' => key!(Key::Tab), + '\x0a' => ctrl!('J'), // '\n' (10) + '\x0b' => ctrl!('K'), + '\x0c' => ctrl!('L'), + '\x0d' => key!(Key::Enter), // '\r' (13) + '\x0e' => ctrl!('N'), + '\x10' => ctrl!('P'), + '\x12' => ctrl!('R'), + '\x13' => ctrl!('S'), + '\x14' => ctrl!('T'), + '\x15' => ctrl!('U'), + '\x16' => ctrl!('V'), + '\x17' => ctrl!('W'), + '\x19' => ctrl!('Y'), + '\x1a' => ctrl!('Z'), + '\x1b' => key!(Key::Esc), + '\x7f' => key!(Key::Backspace), // TODO Validate + _ => key!(Key::Null), } } #[cfg(test)] mod tests { - use super::{char_to_key_press, KeyPress}; + use super::{char_to_key_press, Key, KeyPress}; #[test] fn char_to_key() { - assert_eq!(KeyPress::Esc, char_to_key_press('\x1b')); + assert_eq!(key!(Key::Esc), char_to_key_press('\x1b')); } } diff --git a/src/lib.rs b/src/lib.rs index 8143fc21bd..56e3023cdf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,6 +27,7 @@ extern crate winapi; extern crate kernel32; pub mod completion; +#[macro_use] mod consts; pub mod error; pub mod history; @@ -47,7 +48,7 @@ use tty::{RawMode, RawReader, Terminal, Term}; use encode_unicode::CharExt; use completion::{Completer, longest_common_prefix}; -use consts::KeyPress; +use consts::{Key, KeyPress}; use history::{Direction, History}; use line_buffer::{LineBuffer, MAX_LINE, WordAction}; use kill_ring::{Mode, KillRing}; @@ -552,13 +553,13 @@ fn complete_line(rdr: &mut R, key = try!(rdr.next_key(config.keyseq_timeout())); match key { - KeyPress::Tab => { + key!(Key::Tab) => { i = (i + 1) % (candidates.len() + 1); // Circular if i == candidates.len() { try!(beep()); } } - KeyPress::Esc => { + key!(Key::Esc) => { // Re-show original buffer s.snapshot(); if i < candidates.len() { @@ -591,7 +592,7 @@ fn complete_line(rdr: &mut R, // we can't complete any further, wait for second tab let mut key = try!(rdr.next_key(config.keyseq_timeout())); // if any character other than tab, pass it to the main loop - if key != KeyPress::Tab { + if key != key!(Key::Tab) { return Ok(Some(key)); } // move cursor to EOL to avoid overwriting the command line @@ -604,14 +605,14 @@ fn complete_line(rdr: &mut R, let msg = format!("\nDisplay all {} possibilities? (y or n)", candidates.len()); try!(write_and_flush(s.out, msg.as_bytes())); s.old_rows += 1; - while key != KeyPress::Char('y') && key != KeyPress::Char('Y') && - key != KeyPress::Char('n') && key != KeyPress::Char('N') && - key != KeyPress::Backspace { + while key != key!('y') && key != key!('Y') && + key != key!('n') && key != key!('N') && + key != key!(Key::Backspace) { key = try!(rdr.next_key(config.keyseq_timeout())); } show_completions = match key { - KeyPress::Char('y') | - KeyPress::Char('Y') => true, + key!('y') | + key!('Y') => true, _ => false, }; } @@ -648,22 +649,22 @@ fn page_completions(rdr: &mut R, for row in 0..num_rows { if row == pause_row { try!(write_and_flush(s.out, b"\n--More--")); - let mut key = KeyPress::Null; - while key != KeyPress::Char('y') && key != KeyPress::Char('Y') && - key != KeyPress::Char('n') && key != KeyPress::Char('N') && - key != KeyPress::Char('q') && - key != KeyPress::Char('Q') && - key != KeyPress::Char(' ') && - key != KeyPress::Backspace && key != KeyPress::Enter { + let mut key = key!(Key::Null); + while key != key!('y') && key != key!('Y') && + key != key!('n') && key != key!('N') && + key != key!('q') && + key != key!('Q') && + key != key!(' ') && + key != key!(Key::Backspace) && key != key!(Key::Enter) { key = try!(rdr.next_key(config.keyseq_timeout())); } match key { - KeyPress::Char('y') | - KeyPress::Char('Y') | - KeyPress::Char(' ') => { + key!('y') | + key!('Y') | + key!(' ') => { pause_row += s.term.get_rows() - 1; } - KeyPress::Enter => { + key!(Key::Enter) => { pause_row += 1; } _ => break, @@ -721,16 +722,16 @@ fn reverse_incremental_search(rdr: &mut R, try!(s.refresh_prompt_and_line(&prompt)); key = try!(rdr.next_key(config.keyseq_timeout())); - if let KeyPress::Char(c) = key { + if let key!(c) = key { search_buf.push(c); } else { match key { - KeyPress::Ctrl('H') | - KeyPress::Backspace => { + ctrl!('H') | + key!(Key::Backspace) => { search_buf.pop(); continue; } - KeyPress::Ctrl('R') => { + ctrl!('R') => { direction = Direction::Reverse; if history_idx > 0 { history_idx -= 1; @@ -739,7 +740,7 @@ fn reverse_incremental_search(rdr: &mut R, continue; } } - KeyPress::Ctrl('S') => { + ctrl!('S') => { direction = Direction::Forward; if history_idx < history.len() - 1 { history_idx += 1; @@ -748,7 +749,7 @@ fn reverse_incremental_search(rdr: &mut R, continue; } } - KeyPress::Ctrl('G') => { + ctrl!('G') => { // Restore current edited line (before search) s.snapshot(); try!(s.refresh_line()); @@ -800,26 +801,26 @@ fn readline_edit(prompt: &str, continue; } let mut key = try!(rk); - if let KeyPress::Char(c) = key { + if let key!(c) = key { editor.kill_ring.reset(); try!(edit_insert(&mut s, c)); continue; } // autocomplete - if key == KeyPress::Tab && completer.is_some() { + if key == key!(Key::Tab) && completer.is_some() { let next = try!(complete_line(&mut rdr, &mut s, completer.unwrap(), &editor.config)); if next.is_some() { editor.kill_ring.reset(); key = next.unwrap(); - if let KeyPress::Char(c) = key { + if let key!(c) = key { try!(edit_insert(&mut s, c)); continue; } } else { continue; } - } else if key == KeyPress::Ctrl('R') { + } else if key == ctrl!('R') { // Search history backward let next = try!(reverse_incremental_search(&mut rdr, &mut s, &editor.history, &editor.config)); @@ -828,28 +829,28 @@ fn readline_edit(prompt: &str, } else { continue; } - } else if key == KeyPress::UnknownEscSeq { + } else if key == key!(Key::Unknown) { continue; } match key { - KeyPress::Ctrl('A') | - KeyPress::Home => { + ctrl!('A') | + key!(Key::Home) => { editor.kill_ring.reset(); // Move to the beginning of line. try!(edit_move_home(&mut s)) } - KeyPress::Ctrl('B') | - KeyPress::Left => { + ctrl!('B') | + key!(Key::Left) => { editor.kill_ring.reset(); // Move back a character. try!(edit_move_left(&mut s)) } - KeyPress::Ctrl('C') => { + ctrl!('C') => { editor.kill_ring.reset(); return Err(error::ReadlineError::Interrupted); } - KeyPress::Ctrl('D') => { + ctrl!('D') => { editor.kill_ring.reset(); if s.line.is_empty() { return Err(error::ReadlineError::Eof); @@ -858,94 +859,94 @@ fn readline_edit(prompt: &str, try!(edit_delete(&mut s)) } } - KeyPress::Ctrl('E') | - KeyPress::End => { + ctrl!('E') | + key!(Key::End) => { editor.kill_ring.reset(); // Move to the end of line. try!(edit_move_end(&mut s)) } - KeyPress::Ctrl('F') | - KeyPress::Right => { + ctrl!('F') | + key!(Key::Right) => { editor.kill_ring.reset(); // Move forward a character. try!(edit_move_right(&mut s)) } - KeyPress::Ctrl('H') | - KeyPress::Backspace => { + ctrl!('H') | + key!(Key::Backspace) => { editor.kill_ring.reset(); // Delete one character backward. try!(edit_backspace(&mut s)) } - KeyPress::Ctrl('K') => { + ctrl!('K') => { // Kill the text from point to the end of the line. if let Some(text) = try!(edit_kill_line(&mut s)) { editor.kill_ring.kill(&text, Mode::Append) } } - KeyPress::Ctrl('L') => { + ctrl!('L') => { // Clear the screen leaving the current line at the top of the screen. try!(s.term.clear_screen(&mut s.out)); try!(s.refresh_line()) } - KeyPress::Ctrl('N') | - KeyPress::Down => { + ctrl!('N') | + key!(Key::Down) => { editor.kill_ring.reset(); // Fetch the next command from the history list. try!(edit_history_next(&mut s, &editor.history, false)) } - KeyPress::Ctrl('P') | - KeyPress::Up => { + ctrl!('P') | + key!(Key::Up) => { editor.kill_ring.reset(); // Fetch the previous command from the history list. try!(edit_history_next(&mut s, &editor.history, true)) } - KeyPress::Ctrl('T') => { + ctrl!('T') => { editor.kill_ring.reset(); // Exchange the char before cursor with the character at cursor. try!(edit_transpose_chars(&mut s)) } - KeyPress::Ctrl('U') => { + ctrl!('U') => { // Kill backward from point to the beginning of the line. if let Some(text) = try!(edit_discard_line(&mut s)) { editor.kill_ring.kill(&text, Mode::Prepend) } } #[cfg(unix)] - KeyPress::Ctrl('V') => { + ctrl!('V') => { // Quoted insert editor.kill_ring.reset(); let c = try!(rdr.next_char()); try!(edit_insert(&mut s, c)) // FIXME } - KeyPress::Ctrl('W') => { + ctrl!('W') => { // Kill the word behind point, using white space as a word boundary if let Some(text) = try!(edit_delete_prev_word(&mut s, char::is_whitespace)) { editor.kill_ring.kill(&text, Mode::Prepend) } } - KeyPress::Ctrl('Y') => { + ctrl!('Y') => { // retrieve (yank) last item killed if let Some(text) = editor.kill_ring.yank() { try!(edit_yank(&mut s, text)) } } #[cfg(unix)] - KeyPress::Ctrl('Z') => { + ctrl!('Z') => { try!(original_mode.disable_raw_mode()); try!(tty::suspend()); try!(s.term.enable_raw_mode()); // TODO original_mode may have changed try!(s.refresh_line()) } // TODO CTRL-_ // undo - KeyPress::Enter | - KeyPress::Ctrl('J') => { + key!(Key::Enter) | + ctrl!('J') => { // Accept the line regardless of where the cursor is. editor.kill_ring.reset(); try!(edit_move_end(&mut s)); break; } - KeyPress::Meta('\x08') | - KeyPress::Meta('\x7f') => { + alt!('\x08') | + alt!('\x7f') => { // kill one word backward // Kill from the cursor to the start of the current word, or, if between words, to the start of the previous word. if let Some(text) = try!(edit_delete_prev_word(&mut s, @@ -953,59 +954,59 @@ fn readline_edit(prompt: &str, editor.kill_ring.kill(&text, Mode::Prepend) } } - KeyPress::Meta('<') => { + alt!('<') => { // move to first entry in history editor.kill_ring.reset(); try!(edit_history(&mut s, &editor.history, true)) } - KeyPress::Meta('>') => { + alt!('>') => { // move to last entry in history editor.kill_ring.reset(); try!(edit_history(&mut s, &editor.history, false)) } - KeyPress::Meta('B') => { + alt!('B') => { // move backwards one word editor.kill_ring.reset(); try!(edit_move_to_prev_word(&mut s)) } - KeyPress::Meta('C') => { + alt!('C') => { // capitalize word after point editor.kill_ring.reset(); try!(edit_word(&mut s, WordAction::CAPITALIZE)) } - KeyPress::Meta('D') => { + alt!('D') => { // kill one word forward if let Some(text) = try!(edit_delete_word(&mut s)) { editor.kill_ring.kill(&text, Mode::Append) } } - KeyPress::Meta('F') => { + alt!('F') => { // move forwards one word editor.kill_ring.reset(); try!(edit_move_to_next_word(&mut s)) } - KeyPress::Meta('L') => { + alt!('L') => { // lowercase word after point editor.kill_ring.reset(); try!(edit_word(&mut s, WordAction::LOWERCASE)) } - KeyPress::Meta('T') => { + alt!('T') => { // transpose words editor.kill_ring.reset(); try!(edit_transpose_words(&mut s)) } - KeyPress::Meta('U') => { + alt!('U') => { // uppercase word after point editor.kill_ring.reset(); try!(edit_word(&mut s, WordAction::UPPERCASE)) } - KeyPress::Meta('Y') => { + alt!('Y') => { // yank-pop if let Some((yank_size, text)) = editor.kill_ring.yank_pop() { try!(edit_yank_pop(&mut s, yank_size, text)) } } - KeyPress::Delete => { + key!(Key::Delete) => { editor.kill_ring.reset(); try!(edit_delete(&mut s)) } @@ -1176,7 +1177,7 @@ mod test { use history::History; use completion::Completer; use config::Config; - use consts::KeyPress; + use consts::{Key, KeyPress}; use {Position, State}; use super::{Editor, Result}; use tty::{Terminal, Term}; @@ -1256,11 +1257,11 @@ mod test { fn complete_line() { let mut out = ::std::io::sink(); let mut s = init_state(&mut out, "rus", 3, 80); - let keys = &[KeyPress::Enter]; + let keys = &[key!(Key::Enter)]; let mut rdr = keys.iter(); let completer = SimpleCompleter; let key = super::complete_line(&mut rdr, &mut s, &completer, &Config::default()).unwrap(); - assert_eq!(Some(KeyPress::Enter), key); + assert_eq!(Some(key!(Key::Enter)), key); assert_eq!("rust", s.line.as_str()); assert_eq!(4, s.line.pos()); } @@ -1280,54 +1281,54 @@ mod test { #[test] fn delete_key() { - assert_line(&[KeyPress::Char('a'), KeyPress::Delete, KeyPress::Enter], + assert_line(&[key!('a'), key!(Key::Delete), key!(Key::Enter)], "a"); - assert_line(&[KeyPress::Char('a'), KeyPress::Left, KeyPress::Delete, KeyPress::Enter], + assert_line(&[key!('a'), key!(Key::Left), key!(Key::Delete), key!(Key::Enter)], ""); } #[test] fn down_key() { - assert_line(&[KeyPress::Down, KeyPress::Enter], ""); + assert_line(&[key!(Key::Down), key!(Key::Enter)], ""); } #[test] fn end_key() { - assert_line(&[KeyPress::End, KeyPress::Enter], ""); + assert_line(&[key!(Key::End), key!(Key::Enter)], ""); } #[test] fn home_key() { - assert_line(&[KeyPress::Home, KeyPress::Enter], ""); + assert_line(&[key!(Key::Home), key!(Key::Enter)], ""); } #[test] fn left_key() { - assert_line(&[KeyPress::Left, KeyPress::Enter], ""); + assert_line(&[key!(Key::Left), key!(Key::Enter)], ""); } #[test] fn meta_backspace_key() { - assert_line(&[KeyPress::Meta('\x08'), KeyPress::Enter], ""); + assert_line(&[alt!('\x08'), key!(Key::Enter)], ""); } #[test] fn page_down_key() { - assert_line(&[KeyPress::PageDown, KeyPress::Enter], ""); + assert_line(&[key!(Key::PageDown), key!(Key::Enter)], ""); } #[test] fn page_up_key() { - assert_line(&[KeyPress::PageUp, KeyPress::Enter], ""); + assert_line(&[key!(Key::PageUp), key!(Key::Enter)], ""); } #[test] fn right_key() { - assert_line(&[KeyPress::Right, KeyPress::Enter], ""); + assert_line(&[key!(Key::Right), key!(Key::Enter)], ""); } #[test] fn up_key() { - assert_line(&[KeyPress::Up, KeyPress::Enter], ""); + assert_line(&[key!(Key::Up), key!(Key::Enter)], ""); } } diff --git a/src/tty/unix.rs b/src/tty/unix.rs index 90085c4e81..e6ab67249e 100644 --- a/src/tty/unix.rs +++ b/src/tty/unix.rs @@ -10,7 +10,7 @@ use nix::sys::signal; use nix::sys::termios; use char_iter; -use consts::{self, KeyPress}; +use consts::{self, Key, KeyPress}; use ::Result; use ::error; use super::{RawMode, RawReader, Term}; @@ -102,72 +102,90 @@ impl PosixRawReader { } fn escape_sequence(&mut self) -> Result { - // Read the next two bytes representing the escape sequence. - let seq1 = try!(self.next_char()); - if seq1 == '[' { - // ESC [ sequences. - let seq2 = try!(self.next_char()); - if seq2.is_digit(10) { - // Extended escape, read additional byte. - let seq3 = try!(self.next_char()); - if seq3 == '~' { - match seq2 { - '1' => Ok(KeyPress::Home), // xterm - '3' => Ok(KeyPress::Delete), - '4' => Ok(KeyPress::End), // xterm - '5' => Ok(KeyPress::PageUp), - '6' => Ok(KeyPress::PageDown), - '7' => Ok(KeyPress::Home), - '8' => Ok(KeyPress::End), - _ => Ok(KeyPress::UnknownEscSeq), - } - } else { - Ok(KeyPress::UnknownEscSeq) - } - } else { - match seq2 { - 'A' => Ok(KeyPress::Up), // ANSI - 'B' => Ok(KeyPress::Down), - 'C' => Ok(KeyPress::Right), - 'D' => Ok(KeyPress::Left), - 'F' => Ok(KeyPress::End), - 'H' => Ok(KeyPress::Home), - _ => Ok(KeyPress::UnknownEscSeq), - } - } - } else if seq1 == 'O' { - // ESC O sequences. - let seq2 = try!(self.next_char()); - match seq2 { - 'A' => Ok(KeyPress::Up), - 'B' => Ok(KeyPress::Down), - 'C' => Ok(KeyPress::Right), - 'D' => Ok(KeyPress::Left), - 'F' => Ok(KeyPress::End), - 'H' => Ok(KeyPress::Home), - _ => Ok(KeyPress::UnknownEscSeq), - } - } else { - // TODO ESC-N (n): search history forward not interactively - // TODO ESC-P (p): search history backward not interactively - // TODO ESC-R (r): Undo all changes made to this line. - match seq1 { - '\x08' => Ok(KeyPress::Meta('\x08')), // Backspace - '<' => Ok(KeyPress::Meta('<')), - '>' => Ok(KeyPress::Meta('>')), - 'b' | 'B' => Ok(KeyPress::Meta('B')), - 'c' | 'C' => Ok(KeyPress::Meta('C')), - 'd' | 'D' => Ok(KeyPress::Meta('D')), - 'f' | 'F' => Ok(KeyPress::Meta('F')), - 'l' | 'L' => Ok(KeyPress::Meta('L')), - 't' | 'T' => Ok(KeyPress::Meta('T')), - 'u' | 'U' => Ok(KeyPress::Meta('U')), - 'y' | 'Y' => Ok(KeyPress::Meta('Y')), - '\x7f' => Ok(KeyPress::Meta('\x7f')), // Delete - _ => { - // writeln!(io::stderr(), "key: {:?}, seq1: {:?}", KeyPress::Esc, seq1).unwrap(); - Ok(KeyPress::UnknownEscSeq) - } + // try to match the next several characters against known escape sequences + match try!(self.next_char()) { + '[' => match try!(self.next_char()) { + '1' => match try!(self.next_char()) { + ';' => match try!(self.next_char()) { + '3' => match try!(self.next_char()) { + 'A' => Ok(alt!(Key::Up)), + 'B' => Ok(alt!(Key::Down)), + 'C' => Ok(alt!(Key::Right)), + 'D' => Ok(alt!(Key::Left)), + 'F' => Ok(alt!(Key::End)), + 'H' => Ok(alt!(Key::Home)), + _ => Ok(key!(Key::Unknown)), + }, + '5' => match try!(self.next_char()) { + 'A' => Ok(ctrl!(Key::Up)), + 'B' => Ok(ctrl!(Key::Down)), + 'C' => Ok(ctrl!(Key::Right)), + 'D' => Ok(ctrl!(Key::Left)), + 'F' => Ok(ctrl!(Key::End)), + 'H' => Ok(ctrl!(Key::Home)), + _ => Ok(key!(Key::Unknown)), + }, + _ => Ok(key!(Key::Unknown)), + }, + '~' => Ok(key!(Key::Home)), + _ => Ok(key!(Key::Unknown)), + }, + '3' => match try!(self.next_char()) { + '~' => Ok(key!(Key::Delete)), + _ => Ok(key!(Key::Unknown)), + }, + '4' => match try!(self.next_char()) { + '~' => Ok(key!(Key::End)), // xterm + _ => Ok(key!(Key::Unknown)), + }, + '5' => match try!(self.next_char()) { + '~' => Ok(key!(Key::PageUp)), + _ => Ok(key!(Key::Unknown)), + }, + '6' => match try!(self.next_char()) { + '~' => Ok(key!(Key::PageDown)), + _ => Ok(key!(Key::Unknown)), + }, + '7' => match try!(self.next_char()) { + '~' => Ok(key!(Key::Home)), + _ => Ok(key!(Key::Unknown)), + }, + '8' => match try!(self.next_char()) { + '~' => Ok(key!(Key::End)), + _ => Ok(key!(Key::Unknown)), + }, + 'A' => Ok(key!(Key::Up)), + 'B' => Ok(key!(Key::Down)), + 'C' => Ok(key!(Key::Right)), + 'D' => Ok(key!(Key::Left)), + 'F' => Ok(key!(Key::End)), + 'H' => Ok(key!(Key::Home)), + _ => Ok(key!(Key::Unknown)), + }, + 'O' => match try!(self.next_char()) { + 'A' => Ok(key!(Key::Up)), + 'B' => Ok(key!(Key::Down)), + 'C' => Ok(key!(Key::Right)), + 'D' => Ok(key!(Key::Left)), + 'F' => Ok(key!(Key::End)), + 'H' => Ok(key!(Key::Home)), + _ => Ok(key!(Key::Unknown)), + }, + '\x08' => Ok(alt!('\x08') ), // Backspace + '<' => Ok(alt!('<') ), + '>' => Ok(alt!('>') ), + 'b' | 'B' => Ok(alt!('B') ), + 'c' | 'C' => Ok(alt!('C') ), + 'd' | 'D' => Ok(alt!('D') ), + 'f' | 'F' => Ok(alt!('F') ), + 'l' | 'L' => Ok(alt!('L') ), + 't' | 'T' => Ok(alt!('T') ), + 'u' | 'U' => Ok(alt!('U') ), + 'y' | 'Y' => Ok(alt!('Y') ), + '\x7f' => Ok(alt!('\x7f') ), // Delete + _ => { + // writeln!(io::stderr(), "key: {:?}, seq1: {:?}", key!(Key::Esc,) seq1).unwrap(); + Ok(key!(Key::Unknown)) } } } @@ -178,7 +196,7 @@ impl RawReader for PosixRawReader { let c = try!(self.next_char()); let mut key = consts::char_to_key_press(c); - if key == KeyPress::Esc { + if key == key!(Key::Esc) { let mut fds = [poll::PollFd::new(STDIN_FILENO, poll::POLLIN, poll::EventFlags::empty())]; match poll::poll(&mut fds, timeout_ms) { diff --git a/src/tty/windows.rs b/src/tty/windows.rs index 4b2133835d..285cf56414 100644 --- a/src/tty/windows.rs +++ b/src/tty/windows.rs @@ -7,7 +7,7 @@ use std::sync::atomic; use kernel32; use winapi; -use consts::{self, KeyPress}; +use consts::{self, Key, KeyPress}; use ::error; use ::Result; use super::{RawMode, RawReader, Term}; @@ -125,15 +125,15 @@ impl RawReader for ConsoleRawReader { let utf16 = key_event.UnicodeChar; if utf16 == 0 { match key_event.wVirtualKeyCode as i32 { - winapi::VK_LEFT => return Ok(KeyPress::Left), - winapi::VK_RIGHT => return Ok(KeyPress::Right), - winapi::VK_UP => return Ok(KeyPress::Up), - winapi::VK_DOWN => return Ok(KeyPress::Down), - winapi::VK_DELETE => return Ok(KeyPress::Delete), - winapi::VK_HOME => return Ok(KeyPress::Home), - winapi::VK_END => return Ok(KeyPress::End), - winapi::VK_PRIOR => return Ok(KeyPress::PageUp), - winapi::VK_NEXT => return Ok(KeyPress::PageDown), + winapi::VK_LEFT => return Ok(key!(Key::Left)), + winapi::VK_RIGHT => return Ok(key!(Key::Right)), + winapi::VK_UP => return Ok(key!(Key::Up)), + winapi::VK_DOWN => return Ok(key!(Key::Down)), + winapi::VK_DELETE => return Ok(key!(Key::Delete)), + winapi::VK_HOME => return Ok(key!(Key::Home)), + winapi::VK_END => return Ok(key!(Key::End)), + winapi::VK_PRIOR => return Ok(key!(Key::PageUp)), + winapi::VK_NEXT => return Ok(key!(Key::PageDown)), _ => continue, }; } else if utf16 == 27 { @@ -149,15 +149,15 @@ impl RawReader for ConsoleRawReader { let c = try!(orc.unwrap()); if meta { match c { - 'b' | 'B' => return Ok(KeyPress::Meta('B')), - 'c' | 'C' => return Ok(KeyPress::Meta('C')), - 'd' | 'D' => return Ok(KeyPress::Meta('D')), - 'f' | 'F' => return Ok(KeyPress::Meta('F')), - 'l' | 'L' => return Ok(KeyPress::Meta('L')), - 't' | 'T' => return Ok(KeyPress::Meta('T')), - 'u' | 'U' => return Ok(KeyPress::Meta('U')), - 'y' | 'Y' => return Ok(KeyPress::Meta('Y')), - _ => return Ok(KeyPress::UnknownEscSeq), + 'b' | 'B' => return Ok(alt!(Key::Char('B')) ), + 'c' | 'C' => return Ok(alt!(Key::Char('C')) ), + 'd' | 'D' => return Ok(alt!(Key::Char('D')) ), + 'f' | 'F' => return Ok(alt!(Key::Char('F')) ), + 'l' | 'L' => return Ok(alt!(Key::Char('L')) ), + 't' | 'T' => return Ok(alt!(Key::Char('T')) ), + 'u' | 'U' => return Ok(alt!(Key::Char('U')) ), + 'y' | 'Y' => return Ok(alt!(Key::Char('Y')) ), + _ => return Ok(key!(Key::Unknown)), } } else { return Ok(consts::char_to_key_press(c));