Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for XTerm's NumLock mode #16686

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/terminal/adapter/DispatchTypes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
6 changes: 6 additions & 0 deletions src/terminal/adapter/adaptDispatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
35 changes: 23 additions & 12 deletions src/terminal/input/terminalInput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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,
Expand Down
3 changes: 2 additions & 1 deletion src/terminal/input/terminalInput.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ namespace Microsoft::Console::VirtualTerminal
Keypad,
CursorKey,
BackarrowKey,
NumLock,
Win32,

Utf8MouseEncoding,
Expand Down Expand Up @@ -77,7 +78,7 @@ namespace Microsoft::Console::VirtualTerminal
std::wstring _focusInSequence;
std::wstring _focusOutSequence;

til::enumset<Mode> _inputMode{ Mode::Ansi, Mode::AutoRepeat, Mode::AlternateScroll };
til::enumset<Mode> _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
Expand Down
Loading