diff --git a/src/keymap.rs b/src/keymap.rs index a2eba2546..2c4a63e92 100644 --- a/src/keymap.rs +++ b/src/keymap.rs @@ -578,7 +578,7 @@ impl InputState { Movement::ForwardChar(n) }), E(K::BackTab, M::NONE) => Cmd::CompleteBackward, - E(K::Tab, M::NONE) => { + E(K::Char('I'), M::CTRL) | E(K::Tab, M::NONE) => { if positive { Cmd::Complete } else { @@ -907,7 +907,7 @@ impl InputState { } E(K::Char('H'), M::CTRL) | E::BACKSPACE => Cmd::Kill(Movement::BackwardChar(1)), E(K::BackTab, M::NONE) => Cmd::CompleteBackward, - E(K::Tab, M::NONE) => Cmd::Complete, + E(K::Char('I'), M::CTRL) | E(K::Tab, M::NONE) => Cmd::Complete, // Don't complete hints when the cursor is not at the end of a line E(K::Right, M::NONE) if wrt.has_hint() && wrt.is_cursor_at_end() => Cmd::CompleteHint, E(K::Char(k), M::ALT) => { @@ -1060,9 +1060,11 @@ impl InputState { } else { Movement::BackwardChar(n) }), - E(K::Char('J'), M::CTRL) | E::ENTER => Cmd::AcceptOrInsertLine { - accept_in_the_middle: true, - }, + E(K::Char('J'), M::CTRL) | E(K::Char('M'), M::CTRL) | E::ENTER => { + Cmd::AcceptOrInsertLine { + accept_in_the_middle: true, + } + } E(K::Down, M::NONE) => Cmd::LineDownOrNextHistory(1), E(K::Up, M::NONE) => Cmd::LineUpOrPreviousHistory(1), E(K::Char('R'), M::CTRL) => Cmd::ReverseSearchHistory, diff --git a/src/keys.rs b/src/keys.rs index c9dfa6662..eb21a5e73 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -33,7 +33,11 @@ impl KeyEvent { '\x05' => E(K::Char('E'), mods | M::CTRL), '\x06' => E(K::Char('F'), mods | M::CTRL), '\x07' => E(K::Char('G'), mods | M::CTRL), // '\a' - '\x08' => E(K::Backspace, mods), // '\b' + #[cfg(unix)] + '\x08' => E(K::Backspace, mods), // '\b' + #[cfg(windows)] + '\x08' => E(K::Char('H'), mods | M::CTRL), + #[cfg(unix)] '\x09' => { // '\t' if mods.contains(M::SHIFT) { @@ -43,10 +47,15 @@ impl KeyEvent { E(K::Tab, mods) } } + #[cfg(windows)] + '\x09' => E(K::Char('I'), mods | M::CTRL), '\x0a' => E(K::Char('J'), mods | M::CTRL), // '\n' (10) '\x0b' => E(K::Char('K'), mods | M::CTRL), '\x0c' => E(K::Char('L'), mods | M::CTRL), + #[cfg(unix)] '\x0d' => E(K::Enter, mods), // '\r' (13) + #[cfg(windows)] + '\x0d' => E(K::Char('M'), mods | M::CTRL), '\x0e' => E(K::Char('N'), mods | M::CTRL), '\x0f' => E(K::Char('O'), mods | M::CTRL), '\x10' => E(K::Char('P'), mods | M::CTRL), @@ -188,10 +197,17 @@ mod tests { } #[test] + #[cfg(unix)] fn from() { assert_eq!(E(K::Tab, M::NONE), E::from('\t')); } + #[test] + #[cfg(windows)] + fn from() { + assert_eq!(E(K::Char('I'), M::CTRL), E::from('\t')); + } + #[test] fn normalize() { assert_eq!(E::ctrl('A'), E::normalize(E(K::Char('\x01'), M::NONE))); diff --git a/src/tty/unix.rs b/src/tty/unix.rs index d02aee302..fb751267a 100644 --- a/src/tty/unix.rs +++ b/src/tty/unix.rs @@ -677,7 +677,7 @@ impl RawReader for PosixRawReader { Err(e) => return Err(e.into()), } } - debug!(target: "rustyline", "key: {:?}", key); + debug!(target: "rustyline", "c: {:?} => key: {:?}", c, key); Ok(key) } diff --git a/src/tty/windows.rs b/src/tty/windows.rs index 16d78b5da..498a591b2 100644 --- a/src/tty/windows.rs +++ b/src/tty/windows.rs @@ -137,14 +137,14 @@ impl RawReader for ConsoleRawReader { let alt_gr = key_event.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED) == (LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED); - let alt = key_event.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED) != 0; let mut mods = M::NONE; if !alt_gr && key_event.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) != 0 { mods |= M::CTRL; } - if alt && !alt_gr { + if !alt_gr && key_event.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED) != 0 + { mods |= M::ALT; } if key_event.dwControlKeyState & SHIFT_PRESSED != 0 { @@ -152,39 +152,52 @@ impl RawReader for ConsoleRawReader { } let utf16 = unsafe { *key_event.uChar.UnicodeChar() }; - let key = if utf16 == 0 { - KeyEvent( - match i32::from(key_event.wVirtualKeyCode) { - winuser::VK_LEFT => K::Left, - winuser::VK_RIGHT => K::Right, - winuser::VK_UP => K::Up, - winuser::VK_DOWN => K::Down, - winuser::VK_DELETE => K::Delete, - winuser::VK_HOME => K::Home, - winuser::VK_END => K::End, - winuser::VK_PRIOR => K::PageUp, - winuser::VK_NEXT => K::PageDown, - winuser::VK_INSERT => K::Insert, - winuser::VK_F1 => K::F(1), - winuser::VK_F2 => K::F(2), - winuser::VK_F3 => K::F(3), - winuser::VK_F4 => K::F(4), - winuser::VK_F5 => K::F(5), - winuser::VK_F6 => K::F(6), - winuser::VK_F7 => K::F(7), - winuser::VK_F8 => K::F(8), - winuser::VK_F9 => K::F(9), - winuser::VK_F10 => K::F(10), - winuser::VK_F11 => K::F(11), - winuser::VK_F12 => K::F(12), - // winuser::VK_BACK is correctly handled because the key_event.UnicodeChar - // is also set. - _ => continue, - }, - mods, - ) + let key_code = match i32::from(key_event.wVirtualKeyCode) { + winuser::VK_LEFT => K::Left, + winuser::VK_RIGHT => K::Right, + winuser::VK_UP => K::Up, + winuser::VK_DOWN => K::Down, + winuser::VK_DELETE => K::Delete, + winuser::VK_HOME => K::Home, + winuser::VK_END => K::End, + winuser::VK_PRIOR => K::PageUp, + winuser::VK_NEXT => K::PageDown, + winuser::VK_INSERT => K::Insert, + winuser::VK_F1 => K::F(1), + winuser::VK_F2 => K::F(2), + winuser::VK_F3 => K::F(3), + winuser::VK_F4 => K::F(4), + winuser::VK_F5 => K::F(5), + winuser::VK_F6 => K::F(6), + winuser::VK_F7 => K::F(7), + winuser::VK_F8 => K::F(8), + winuser::VK_F9 => K::F(9), + winuser::VK_F10 => K::F(10), + winuser::VK_F11 => K::F(11), + winuser::VK_F12 => K::F(12), + winuser::VK_BACK => K::Backspace, // vs Ctrl-h + winuser::VK_RETURN => K::Enter, // vs Ctrl-m + winuser::VK_ESCAPE => K::Esc, + winuser::VK_TAB => { + if mods.contains(M::SHIFT) { + mods.remove(M::SHIFT); + K::BackTab + } else { + K::Tab // vs Ctrl-i + } + } + _ => { + if utf16 == 0 { + continue; + } else { + K::UnknownEscSeq + } + } + }; + let key = if key_code != K::UnknownEscSeq { + KeyEvent(key_code, mods) } else if utf16 == 27 { - KeyEvent(K::Esc, mods) + KeyEvent(K::Esc, mods) // FIXME dead code ? } else { if (0xD800..0xDC00).contains(&utf16) { surrogate = utf16; @@ -203,7 +216,7 @@ impl RawReader for ConsoleRawReader { let c = rc?; KeyEvent::new(c, mods) }; - debug!(target: "rustyline", "key: {:?}", key); + debug!(target: "rustyline", "wVirtualKeyCode: {:#x}, utf16: {:#x}, dwControlKeyState: {:#x} => key: {:?}", key_event.wVirtualKeyCode, utf16, key_event.dwControlKeyState, key); return Ok(key); } }