From 6e38ddfb9c1f3b9cf04d7f1c43793ef038724ae3 Mon Sep 17 00:00:00 2001 From: James Holderness Date: Tue, 30 Aug 2022 13:51:36 +0100 Subject: [PATCH 1/5] Add support for backarrow key mode. --- src/terminal/adapter/DispatchTypes.hpp | 1 + src/terminal/adapter/adaptDispatch.cpp | 3 +++ src/terminal/input/terminalInput.cpp | 33 ++++++++++++++++++-------- src/terminal/input/terminalInput.hpp | 1 + 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/terminal/adapter/DispatchTypes.hpp b/src/terminal/adapter/DispatchTypes.hpp index afa1de0f797..5a0bf610eb6 100644 --- a/src/terminal/adapter/DispatchTypes.hpp +++ b/src/terminal/adapter/DispatchTypes.hpp @@ -384,6 +384,7 @@ namespace Microsoft::Console::VirtualTerminal::DispatchTypes ATT610_StartCursorBlink = DECPrivateMode(12), DECTCEM_TextCursorEnableMode = DECPrivateMode(25), XTERM_EnableDECCOLMSupport = DECPrivateMode(40), + DECBKM_BackarrowKeyMode = DECPrivateMode(67), VT200_MOUSE_MODE = DECPrivateMode(1000), BUTTON_EVENT_MOUSE_MODE = DECPrivateMode(1002), ANY_EVENT_MOUSE_MODE = DECPrivateMode(1003), diff --git a/src/terminal/adapter/adaptDispatch.cpp b/src/terminal/adapter/adaptDispatch.cpp index 549d4b3f366..14f7ca52136 100644 --- a/src/terminal/adapter/adaptDispatch.cpp +++ b/src/terminal/adapter/adaptDispatch.cpp @@ -1038,6 +1038,9 @@ bool AdaptDispatch::_ModeParamsHelper(const DispatchTypes::ModeParams param, con case DispatchTypes::ModeParams::XTERM_EnableDECCOLMSupport: success = EnableDECCOLMSupport(enable); break; + case DispatchTypes::ModeParams::DECBKM_BackarrowKeyMode: + success = _SetInputMode(TerminalInput::Mode::BackarrowKey, enable); + break; case DispatchTypes::ModeParams::VT200_MOUSE_MODE: success = EnableVT200MouseMode(enable); break; diff --git a/src/terminal/input/terminalInput.cpp b/src/terminal/input/terminalInput.cpp index 79b5ef74f5f..19f9104eb44 100644 --- a/src/terminal/input/terminalInput.cpp +++ b/src/terminal/input/terminalInput.cpp @@ -71,9 +71,8 @@ static constexpr std::array s_cursorKeysVt52Mapping{ TermKeyMap{ VK_END, L"\033F" }, }; -static constexpr std::array s_keypadNumericMapping{ +static constexpr std::array s_keypadNumericMapping{ TermKeyMap{ VK_TAB, L"\x09" }, - TermKeyMap{ VK_BACK, L"\x7f" }, TermKeyMap{ VK_PAUSE, L"\x1a" }, TermKeyMap{ VK_ESCAPE, L"\x1b" }, TermKeyMap{ VK_INSERT, L"\x1b[2~" }, @@ -103,9 +102,8 @@ static constexpr std::array s_keypadNumericMapping{ //It seems to me as though this was used for early numpad implementations, where presently numlock would enable // "numeric" mode, outputting the numbers on the keys, while "application" mode does things like pgup/down, arrow keys, etc. //These keys aren't translated at all in numeric mode, so I figured I'd leave them out of the numeric table. -static constexpr std::array s_keypadApplicationMapping{ +static constexpr std::array s_keypadApplicationMapping{ TermKeyMap{ VK_TAB, L"\x09" }, - TermKeyMap{ VK_BACK, L"\x7f" }, TermKeyMap{ VK_PAUSE, L"\x1a" }, TermKeyMap{ VK_ESCAPE, L"\x1b" }, TermKeyMap{ VK_INSERT, L"\x1b[2~" }, @@ -153,9 +151,8 @@ static constexpr std::array s_keypadApplicationMapping{ // TermKeyMap{ VK_TAB, L"\x1bOI" }, // So I left them here as a reference just in case. }; -static constexpr std::array s_keypadVt52Mapping{ +static constexpr std::array s_keypadVt52Mapping{ TermKeyMap{ VK_TAB, L"\x09" }, - TermKeyMap{ VK_BACK, L"\x7f" }, TermKeyMap{ VK_PAUSE, L"\x1a" }, TermKeyMap{ VK_ESCAPE, L"\x1b" }, TermKeyMap{ VK_INSERT, L"\x1b[2~" }, @@ -211,10 +208,7 @@ static constexpr std::array s_modifierKeyMapping{ // These sequences are not later updated to encode the modifier state in the // sequence itself, they are just weird exceptional cases to the general // rules above. -static constexpr std::array s_simpleModifiedKeyMapping{ - TermKeyMap{ VK_BACK, CTRL_PRESSED, L"\x8" }, - TermKeyMap{ VK_BACK, ALT_PRESSED, L"\x1b\x7f" }, - TermKeyMap{ VK_BACK, CTRL_PRESSED | ALT_PRESSED, L"\x1b\x8" }, +static constexpr std::array s_simpleModifiedKeyMapping{ TermKeyMap{ VK_TAB, CTRL_PRESSED, L"\t" }, TermKeyMap{ VK_TAB, SHIFT_PRESSED, L"\x1b[Z" }, TermKeyMap{ VK_DIVIDE, CTRL_PRESSED, L"\x1F" }, @@ -562,6 +556,25 @@ bool TerminalInput::HandleKey(const IInputEvent* const pInEvent) return false; } + // The VK_BACK key depends on the state of Backarrow Key mode (DECBKM). + // If the mode is set, we should send BS. If reset, we should send DEL. + if (keyEvent.GetVirtualKeyCode() == VK_BACK) + { + // The Ctrl modifier reverses the interpretation of DECBKM. + const auto backarrowMode = _inputMode.test(Mode::BackarrowKey) != keyEvent.IsCtrlPressed(); + const auto seq = backarrowMode ? L'\x08' : L'\x7f'; + // The Alt modifier adds an escape prefix. + if (keyEvent.IsAltPressed()) + { + _SendEscapedInputSequence(seq); + } + else + { + _SendInputSequence({ &seq, 1 }); + } + return true; + } + // Many keyboard layouts have an AltGr key, which makes widely used characters accessible. // For instance on a German keyboard layout "[" is written by pressing AltGr+8. // Furthermore Ctrl+Alt is traditionally treated as an alternative way to AltGr by Windows. diff --git a/src/terminal/input/terminalInput.hpp b/src/terminal/input/terminalInput.hpp index 8f0ac5dcbee..80ff4e8c06f 100644 --- a/src/terminal/input/terminalInput.hpp +++ b/src/terminal/input/terminalInput.hpp @@ -41,6 +41,7 @@ namespace Microsoft::Console::VirtualTerminal Ansi, Keypad, CursorKey, + BackarrowKey, Win32, Utf8MouseEncoding, From add635230cf684c70be20d50885a9bffce4a9994 Mon Sep 17 00:00:00 2001 From: James Holderness Date: Tue, 30 Aug 2022 14:15:54 +0100 Subject: [PATCH 2/5] Handle specifics of focus mode in its own method. --- src/terminal/adapter/adaptDispatch.cpp | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/src/terminal/adapter/adaptDispatch.cpp b/src/terminal/adapter/adaptDispatch.cpp index 14f7ca52136..eee5a827fa8 100644 --- a/src/terminal/adapter/adaptDispatch.cpp +++ b/src/terminal/adapter/adaptDispatch.cpp @@ -978,23 +978,7 @@ bool AdaptDispatch::_SetInputMode(const TerminalInput::Mode mode, const bool ena // impact on the actual connected terminal. We can't remove this check, // because SSH <=7.7 is out in the wild on all versions of Windows <=2004. - // GH#12799 - If the app requested that we disable focus events, DON'T pass - // that through. ConPTY would _always_ like to know about focus events. - - return !_api.IsConsolePty() || - !_api.IsVtInputEnabled() || - (!enable && mode == TerminalInput::Mode::FocusEvent); - - // Another way of writing the above statement is: - // - // const bool inConpty = _api.IsConsolePty(); - // const bool shouldPassthrough = inConpty && _api.IsVtInputEnabled(); - // const bool disabledFocusEvents = inConpty && (!enable && mode == TerminalInput::Mode::FocusEvent); - // return !shouldPassthrough || disabledFocusEvents; - // - // It's like a "filter" left to right. Due to the early return via - // !IsConsolePty, once you're at the !enable part, IsConsolePty can only be - // true anymore. + return !_api.IsConsolePty() || !_api.IsVtInputEnabled(); } // Routine Description: @@ -2091,7 +2075,9 @@ bool AdaptDispatch::EnableAnyEventMouseMode(const bool enabled) // - True if handled successfully. False otherwise. bool AdaptDispatch::EnableFocusEventMode(const bool enabled) { - return _SetInputMode(TerminalInput::Mode::FocusEvent, enabled); + // GH#12799 - If the app requested that we disable focus events, DON'T pass + // that through. ConPTY would _always_ like to know about focus events. + return _SetInputMode(TerminalInput::Mode::FocusEvent, enabled) || !enabled; } //Routine Description: From 887ea6d33476564f6256215f065260d47d53432c Mon Sep 17 00:00:00 2001 From: James Holderness Date: Tue, 30 Aug 2022 19:52:08 +0100 Subject: [PATCH 3/5] Reset DECBKM in RIS. --- src/terminal/adapter/adaptDispatch.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/terminal/adapter/adaptDispatch.cpp b/src/terminal/adapter/adaptDispatch.cpp index eee5a827fa8..400096db064 100644 --- a/src/terminal/adapter/adaptDispatch.cpp +++ b/src/terminal/adapter/adaptDispatch.cpp @@ -1861,6 +1861,9 @@ bool AdaptDispatch::HardReset() EnableSGRExtendedMouseMode(false); EnableAnyEventMouseMode(false); + // Reset the Backarrow Key mode + _SetInputMode(TerminalInput::Mode::BackarrowKey, false); + // Delete all current tab stops and reapply _ResetTabStops(); From 97e7ea628f1d6fe904f78cc9d4dc6655860b4fd0 Mon Sep 17 00:00:00 2001 From: James Holderness Date: Tue, 30 Aug 2022 20:25:09 +0100 Subject: [PATCH 4/5] Add unit test for backarrow key mode. --- src/terminal/adapter/ut_adapter/inputTest.cpp | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/src/terminal/adapter/ut_adapter/inputTest.cpp b/src/terminal/adapter/ut_adapter/inputTest.cpp index ace7de68019..f1c9bf2698b 100644 --- a/src/terminal/adapter/ut_adapter/inputTest.cpp +++ b/src/terminal/adapter/ut_adapter/inputTest.cpp @@ -43,6 +43,7 @@ class Microsoft::Console::VirtualTerminal::InputTest TEST_METHOD(TerminalInputNullKeyTests); TEST_METHOD(DifferentModifiersTest); TEST_METHOD(CtrlNumTest); + TEST_METHOD(BackarrowKeyModeTest); wchar_t GetModifierChar(const bool fShift, const bool fAlt, const bool fCtrl) { @@ -788,3 +789,65 @@ void InputTest::CtrlNumTest() s_expectedInput = L"9"; TestKey(pInput, uiKeystate, vkey); } + +void InputTest::BackarrowKeyModeTest() +{ + Log::Comment(L"Starting test..."); + + const auto pInput = new TerminalInput(s_TerminalInputTestCallback); + const BYTE vkey = VK_BACK; + + Log::Comment(L"Sending backspace key combos with DECBKM enabled."); + pInput->SetInputMode(TerminalInput::Mode::BackarrowKey, true); + + s_expectedInput = L"\x8"; + TestKey(pInput, 0, vkey); + + s_expectedInput = L"\x8"; + TestKey(pInput, SHIFT_PRESSED, vkey); + + s_expectedInput = L"\x7f"; + TestKey(pInput, LEFT_CTRL_PRESSED, vkey); + + s_expectedInput = L"\x7f"; + TestKey(pInput, LEFT_CTRL_PRESSED | SHIFT_PRESSED, vkey); + + s_expectedInput = L"\x1b\x8"; + TestKey(pInput, LEFT_ALT_PRESSED, vkey); + + s_expectedInput = L"\x1b\x8"; + TestKey(pInput, LEFT_ALT_PRESSED | SHIFT_PRESSED, vkey); + + s_expectedInput = L"\x1b\x7f"; + TestKey(pInput, LEFT_ALT_PRESSED | LEFT_CTRL_PRESSED, vkey); + + s_expectedInput = L"\x1b\x7f"; + TestKey(pInput, LEFT_ALT_PRESSED | LEFT_CTRL_PRESSED | SHIFT_PRESSED, vkey); + + Log::Comment(L"Sending backspace key combos with DECBKM disabled."); + pInput->SetInputMode(TerminalInput::Mode::BackarrowKey, false); + + s_expectedInput = L"\x7f"; + TestKey(pInput, 0, vkey); + + s_expectedInput = L"\x7f"; + TestKey(pInput, SHIFT_PRESSED, vkey); + + s_expectedInput = L"\x8"; + TestKey(pInput, LEFT_CTRL_PRESSED, vkey); + + s_expectedInput = L"\x8"; + TestKey(pInput, LEFT_CTRL_PRESSED | SHIFT_PRESSED, vkey); + + s_expectedInput = L"\x1b\x7f"; + TestKey(pInput, LEFT_ALT_PRESSED, vkey); + + s_expectedInput = L"\x1b\x7f"; + TestKey(pInput, LEFT_ALT_PRESSED | SHIFT_PRESSED, vkey); + + s_expectedInput = L"\x1b\x8"; + TestKey(pInput, LEFT_ALT_PRESSED | LEFT_CTRL_PRESSED, vkey); + + s_expectedInput = L"\x1b\x8"; + TestKey(pInput, LEFT_ALT_PRESSED | LEFT_CTRL_PRESSED | SHIFT_PRESSED, vkey); +} From 5522352b769904c1c9718c2232466586ba5ff1ab Mon Sep 17 00:00:00 2001 From: James Holderness Date: Wed, 31 Aug 2022 01:17:22 +0100 Subject: [PATCH 5/5] Add DECBKM to dictionary. --- .github/actions/spelling/expect/expect.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/actions/spelling/expect/expect.txt b/.github/actions/spelling/expect/expect.txt index b5f048bc3c2..0c94916712e 100644 --- a/.github/actions/spelling/expect/expect.txt +++ b/.github/actions/spelling/expect/expect.txt @@ -496,6 +496,7 @@ DECALN DECANM DECAUPSS DECAWM +DECBKM DECCKM DECCOLM DECCRA