From 32186f2422ba142fc85ae5bf10cf471e95b1f9ac Mon Sep 17 00:00:00 2001 From: James Holderness Date: Thu, 8 Feb 2024 16:09:05 +0000 Subject: [PATCH] Add support for NumLock mode. --- src/terminal/adapter/DispatchTypes.hpp | 1 + src/terminal/adapter/adaptDispatch.cpp | 6 +++++ src/terminal/input/terminalInput.cpp | 35 +++++++++++++++++--------- src/terminal/input/terminalInput.hpp | 3 ++- 4 files changed, 32 insertions(+), 13 deletions(-) diff --git a/src/terminal/adapter/DispatchTypes.hpp b/src/terminal/adapter/DispatchTypes.hpp index a0cabb0fde8..0c10aa209ee 100644 --- a/src/terminal/adapter/DispatchTypes.hpp +++ b/src/terminal/adapter/DispatchTypes.hpp @@ -542,6 +542,7 @@ namespace Microsoft::Console::VirtualTerminal::DispatchTypes UTF8_EXTENDED_MODE = DECPrivateMode(1005), SGR_EXTENDED_MODE = DECPrivateMode(1006), ALTERNATE_SCROLL = DECPrivateMode(1007), + XTERM_NumLockMode = DECPrivateMode(1035), ASB_AlternateScreenBuffer = DECPrivateMode(1049), XTERM_BracketedPasteMode = DECPrivateMode(2004), W32IM_Win32InputMode = DECPrivateMode(9001), diff --git a/src/terminal/adapter/adaptDispatch.cpp b/src/terminal/adapter/adaptDispatch.cpp index fb504c20200..0132d7845c1 100644 --- a/src/terminal/adapter/adaptDispatch.cpp +++ b/src/terminal/adapter/adaptDispatch.cpp @@ -1938,6 +1938,9 @@ bool AdaptDispatch::_ModeParamsHelper(const DispatchTypes::ModeParams param, con case DispatchTypes::ModeParams::ALTERNATE_SCROLL: _terminalInput.SetInputMode(TerminalInput::Mode::AlternateScroll, enable); return !_PassThroughInputModes(); + case DispatchTypes::ModeParams::XTERM_NumLockMode: + _terminalInput.SetInputMode(TerminalInput::Mode::NumLock, enable); + return true; case DispatchTypes::ModeParams::ASB_AlternateScreenBuffer: _SetAlternateScreenBufferMode(enable); return true; @@ -2076,6 +2079,9 @@ bool AdaptDispatch::RequestMode(const DispatchTypes::ModeParams param) case DispatchTypes::ModeParams::ALTERNATE_SCROLL: enabled = _terminalInput.GetInputMode(TerminalInput::Mode::AlternateScroll); break; + case DispatchTypes::ModeParams::XTERM_NumLockMode: + enabled = _terminalInput.GetInputMode(TerminalInput::Mode::NumLock); + break; case DispatchTypes::ModeParams::ASB_AlternateScreenBuffer: enabled = _usingAltBuffer; break; diff --git a/src/terminal/input/terminalInput.cpp b/src/terminal/input/terminalInput.cpp index 7c09ef46155..84a0b5a8e43 100644 --- a/src/terminal/input/terminalInput.cpp +++ b/src/terminal/input/terminalInput.cpp @@ -67,7 +67,7 @@ bool TerminalInput::GetInputMode(const Mode mode) const noexcept void TerminalInput::ResetInputModes() noexcept { - _inputMode = { Mode::Ansi, Mode::AutoRepeat, Mode::AlternateScroll }; + _inputMode = { Mode::Ansi, Mode::AutoRepeat, Mode::NumLock, Mode::AlternateScroll }; _mouseInputState.lastPos = { -1, -1 }; _mouseInputState.lastButton = 0; _initKeyboardMap(); @@ -211,23 +211,34 @@ TerminalInput::OutputType TerminalInput::HandleKey(const INPUT_RECORD& event) return _makeNoOutput(); } + // NumLock mode is an XTerm extension that changes the behavior of keys on + // the numeric keypad, suppressing the effects of KeyPad mode when NumLock + // is on. This is for compatibility with Linux apps that have a tendency to + // set Keypad mode while not actually wanting the keys to change. + const auto numLockMode = _inputMode.test(Mode::NumLock) && WI_IsFlagSet(controlKeyState, NUMLOCK_ON); + // The only enhanced key we care about is the Return key, because that // indicates that it's the key on the numeric keypad, which will transmit - // different escape sequences when the Keypad mode is enabled. - const auto enhancedReturnKey = WI_IsFlagSet(controlKeyState, ENHANCED_KEY) && virtualKeyCode == VK_RETURN; + // different escape sequences when the Keypad mode is enabled. But this + // doesn't apply when NumLock mode is active. + const auto enhancedReturnKey = WI_IsFlagSet(controlKeyState, ENHANCED_KEY) && virtualKeyCode == VK_RETURN && !numLockMode; // Using the control key state that we calculated above, combined with the // virtual key code, we've got a unique identifier for the key combination - // that we can lookup in our map of predefined key sequences. - auto keyCombo = virtualKeyCode; - WI_SetFlagIf(keyCombo, Ctrl, ctrlIsReallyPressed); - WI_SetFlagIf(keyCombo, Alt, altIsPressed); - WI_SetFlagIf(keyCombo, Shift, shiftIsPressed); - WI_SetFlagIf(keyCombo, Enhanced, enhancedReturnKey); - const auto keyMatch = _keyMap.find(keyCombo); - if (keyMatch != _keyMap.end()) + // that we can lookup in our map of predefined key sequences. But this is + // bypassed for numeric keypad keys when NumLock mode is active. + if (!(virtualKeyCode >= VK_NUMPAD0 && virtualKeyCode <= VK_DIVIDE && numLockMode)) { - return keyMatch->second; + auto keyCombo = virtualKeyCode; + WI_SetFlagIf(keyCombo, Ctrl, ctrlIsReallyPressed); + WI_SetFlagIf(keyCombo, Alt, altIsPressed); + WI_SetFlagIf(keyCombo, Shift, shiftIsPressed); + WI_SetFlagIf(keyCombo, Enhanced, enhancedReturnKey); + const auto keyMatch = _keyMap.find(keyCombo); + if (keyMatch != _keyMap.end()) + { + return keyMatch->second; + } } // If it's not in the key map, we'll use the UnicodeChar, if provided, diff --git a/src/terminal/input/terminalInput.hpp b/src/terminal/input/terminalInput.hpp index e8ae53267e2..915ba51ea2d 100644 --- a/src/terminal/input/terminalInput.hpp +++ b/src/terminal/input/terminalInput.hpp @@ -32,6 +32,7 @@ namespace Microsoft::Console::VirtualTerminal Keypad, CursorKey, BackarrowKey, + NumLock, Win32, Utf8MouseEncoding, @@ -77,7 +78,7 @@ namespace Microsoft::Console::VirtualTerminal std::wstring _focusInSequence; std::wstring _focusOutSequence; - til::enumset _inputMode{ Mode::Ansi, Mode::AutoRepeat, Mode::AlternateScroll }; + til::enumset _inputMode{ Mode::Ansi, Mode::AutoRepeat, Mode::NumLock, Mode::AlternateScroll }; bool _forceDisableWin32InputMode{ false }; // In the future, if we add support for "8-bit" input mode, these prefixes