Add SS3 cursor key encoding to ConPty (#5383)
## Summary of the Pull Request Adds SS3 cursor encoding for cursor keys and home/end button. Reverts a portion of #4913 that checks for VT Input Mode. ## PR Checklist * [X] Closes #4873 ## Validation Steps Performed 1. Open pwsh 2. run `wsl` 3. execute `printf "\e[?1h"` 4. verify keys work 5. exit back to pwsh 6. verify keys work still (didn't previously) Also verified that those keys work in vim when connected to my Raspberry Pi over SSH.
This commit is contained in:
parent
f04b7aae87
commit
f1fe4c6ccd
|
@ -1056,11 +1056,8 @@ bool AdaptDispatch::SetKeypadMode(const bool fApplicationMode)
|
|||
bool success = true;
|
||||
success = _pConApi->PrivateSetKeypadMode(fApplicationMode);
|
||||
|
||||
// If we're a conpty, AND WE'RE IN VT INPUT MODE, always return false
|
||||
// The VT Input mode check is to work around ssh.exe v7.7, which uses VT
|
||||
// output, but not Input. Once the conpty supports these types of input,
|
||||
// this check can be removed. See GH#4911
|
||||
if (_pConApi->IsConsolePty() && _pConApi->PrivateIsVtInputEnabled())
|
||||
// If we're a conpty, always return false
|
||||
if (_pConApi->IsConsolePty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -1078,11 +1075,8 @@ bool AdaptDispatch::SetCursorKeysMode(const bool applicationMode)
|
|||
bool success = true;
|
||||
success = _pConApi->PrivateSetCursorKeysMode(applicationMode);
|
||||
|
||||
// If we're a conpty, AND WE'RE IN VT INPUT MODE, always return false
|
||||
// The VT Input mode check is to work around ssh.exe v7.7, which uses VT
|
||||
// output, but not Input. Once the conpty supports these types of input,
|
||||
// this check can be removed. See GH#4911
|
||||
if (_pConApi->IsConsolePty() && _pConApi->PrivateIsVtInputEnabled())
|
||||
// If we're a conpty, always return false
|
||||
if (_pConApi->IsConsolePty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -1878,11 +1872,8 @@ bool AdaptDispatch::EnableVT200MouseMode(const bool enabled)
|
|||
bool success = true;
|
||||
success = _pConApi->PrivateEnableVT200MouseMode(enabled);
|
||||
|
||||
// If we're a conpty, AND WE'RE IN VT INPUT MODE, always return false
|
||||
// The VT Input mode check is to work around ssh.exe v7.7, which uses VT
|
||||
// output, but not Input. Once the conpty supports these types of input,
|
||||
// this check can be removed. See GH#4911
|
||||
if (_pConApi->IsConsolePty() && _pConApi->PrivateIsVtInputEnabled())
|
||||
// If we're a conpty, always return false
|
||||
if (_pConApi->IsConsolePty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -1902,11 +1893,8 @@ bool AdaptDispatch::EnableUTF8ExtendedMouseMode(const bool enabled)
|
|||
bool success = true;
|
||||
success = _pConApi->PrivateEnableUTF8ExtendedMouseMode(enabled);
|
||||
|
||||
// If we're a conpty, AND WE'RE IN VT INPUT MODE, always return false
|
||||
// The VT Input mode check is to work around ssh.exe v7.7, which uses VT
|
||||
// output, but not Input. Once the conpty supports these types of input,
|
||||
// this check can be removed. See GH#4911
|
||||
if (_pConApi->IsConsolePty() && _pConApi->PrivateIsVtInputEnabled())
|
||||
// If we're a conpty, always return false
|
||||
if (_pConApi->IsConsolePty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -1926,11 +1914,8 @@ bool AdaptDispatch::EnableSGRExtendedMouseMode(const bool enabled)
|
|||
bool success = true;
|
||||
success = _pConApi->PrivateEnableSGRExtendedMouseMode(enabled);
|
||||
|
||||
// If we're a conpty, AND WE'RE IN VT INPUT MODE, always return false
|
||||
// The VT Input mode check is to work around ssh.exe v7.7, which uses VT
|
||||
// output, but not Input. Once the conpty supports these types of input,
|
||||
// this check can be removed. See GH#4911
|
||||
if (_pConApi->IsConsolePty() && _pConApi->PrivateIsVtInputEnabled())
|
||||
// If we're a conpty, always return false
|
||||
if (_pConApi->IsConsolePty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -1949,11 +1934,8 @@ bool AdaptDispatch::EnableButtonEventMouseMode(const bool enabled)
|
|||
bool success = true;
|
||||
success = _pConApi->PrivateEnableButtonEventMouseMode(enabled);
|
||||
|
||||
// If we're a conpty, AND WE'RE IN VT INPUT MODE, always return false
|
||||
// The VT Input mode check is to work around ssh.exe v7.7, which uses VT
|
||||
// output, but not Input. Once the conpty supports these types of input,
|
||||
// this check can be removed. See GH#4911
|
||||
if (_pConApi->IsConsolePty() && _pConApi->PrivateIsVtInputEnabled())
|
||||
// If we're a conpty, always return false
|
||||
if (_pConApi->IsConsolePty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -1973,11 +1955,8 @@ bool AdaptDispatch::EnableAnyEventMouseMode(const bool enabled)
|
|||
bool success = true;
|
||||
success = _pConApi->PrivateEnableAnyEventMouseMode(enabled);
|
||||
|
||||
// If we're a conpty, AND WE'RE IN VT INPUT MODE, always return false
|
||||
// The VT Input mode check is to work around ssh.exe v7.7, which uses VT
|
||||
// output, but not Input. Once the conpty supports these types of input,
|
||||
// this check can be removed. See GH#4911
|
||||
if (_pConApi->IsConsolePty() && _pConApi->PrivateIsVtInputEnabled())
|
||||
// If we're a conpty, always return false
|
||||
if (_pConApi->IsConsolePty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -1997,11 +1976,8 @@ bool AdaptDispatch::EnableAlternateScroll(const bool enabled)
|
|||
bool success = true;
|
||||
success = _pConApi->PrivateEnableAlternateScroll(enabled);
|
||||
|
||||
// If we're a conpty, AND WE'RE IN VT INPUT MODE, always return false
|
||||
// The VT Input mode check is to work around ssh.exe v7.7, which uses VT
|
||||
// output, but not Input. Once the conpty supports these types of input,
|
||||
// this check can be removed. See GH#4911
|
||||
if (_pConApi->IsConsolePty() && _pConApi->PrivateIsVtInputEnabled())
|
||||
// If we're a conpty, always return false
|
||||
if (_pConApi->IsConsolePty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -73,7 +73,13 @@ struct Ss3ToVkey
|
|||
short vkey;
|
||||
};
|
||||
|
||||
static constexpr std::array<Ss3ToVkey, 4> s_ss3Map = {
|
||||
static constexpr std::array<Ss3ToVkey, 10> s_ss3Map = {
|
||||
Ss3ToVkey{ Ss3ActionCodes::ArrowUp, VK_UP },
|
||||
Ss3ToVkey{ Ss3ActionCodes::ArrowDown, VK_DOWN },
|
||||
Ss3ToVkey{ Ss3ActionCodes::ArrowRight, VK_RIGHT },
|
||||
Ss3ToVkey{ Ss3ActionCodes::ArrowLeft, VK_LEFT },
|
||||
Ss3ToVkey{ Ss3ActionCodes::End, VK_END },
|
||||
Ss3ToVkey{ Ss3ActionCodes::Home, VK_HOME },
|
||||
Ss3ToVkey{ Ss3ActionCodes::SS3_F1, VK_F1 },
|
||||
Ss3ToVkey{ Ss3ActionCodes::SS3_F2, VK_F2 },
|
||||
Ss3ToVkey{ Ss3ActionCodes::SS3_F3, VK_F3 },
|
||||
|
|
|
@ -116,14 +116,12 @@ namespace Microsoft::Console::VirtualTerminal
|
|||
|
||||
enum class Ss3ActionCodes : wchar_t
|
||||
{
|
||||
// The "Cursor Keys" are sometimes sent as a SS3 in "application mode"
|
||||
// But for now we'll only accept them as Normal Mode sequences, as CSI's.
|
||||
// ArrowUp = L'A',
|
||||
// ArrowDown = L'B',
|
||||
// ArrowRight = L'C',
|
||||
// ArrowLeft = L'D',
|
||||
// Home = L'H',
|
||||
// End = L'F',
|
||||
ArrowUp = L'A',
|
||||
ArrowDown = L'B',
|
||||
ArrowRight = L'C',
|
||||
ArrowLeft = L'D',
|
||||
Home = L'H',
|
||||
End = L'F',
|
||||
SS3_F1 = L'P',
|
||||
SS3_F2 = L'Q',
|
||||
SS3_F3 = L'R',
|
||||
|
|
|
@ -253,6 +253,7 @@ class Microsoft::Console::VirtualTerminal::InputEngineTest
|
|||
TEST_METHOD(CursorPositioningTest);
|
||||
TEST_METHOD(CSICursorBackTabTest);
|
||||
TEST_METHOD(EnhancedKeysTest);
|
||||
TEST_METHOD(SS3CursorKeyTest);
|
||||
TEST_METHOD(AltBackspaceTest);
|
||||
TEST_METHOD(AltCtrlDTest);
|
||||
TEST_METHOD(AltIntermediateTest);
|
||||
|
@ -844,6 +845,50 @@ void InputEngineTest::EnhancedKeysTest()
|
|||
VerifyExpectedInputDrained();
|
||||
}
|
||||
|
||||
void InputEngineTest::SS3CursorKeyTest()
|
||||
{
|
||||
auto pfn = std::bind(&TestState::TestInputCallback, &testState, std::placeholders::_1);
|
||||
auto dispatch = std::make_unique<TestInteractDispatch>(pfn, &testState);
|
||||
auto inputEngine = std::make_unique<InputStateMachineEngine>(std::move(dispatch));
|
||||
auto _stateMachine = std::make_unique<StateMachine>(std::move(inputEngine));
|
||||
VERIFY_IS_NOT_NULL(_stateMachine);
|
||||
testState._stateMachine = _stateMachine.get();
|
||||
|
||||
// clang-format off
|
||||
const std::map<int, std::wstring> cursorKeys{
|
||||
{ VK_UP, L"\x1bOA" },
|
||||
{ VK_DOWN, L"\x1bOB" },
|
||||
{ VK_RIGHT, L"\x1bOC" },
|
||||
{ VK_LEFT, L"\x1bOD" },
|
||||
{ VK_HOME, L"\x1bOH" },
|
||||
{ VK_END, L"\x1bOF" },
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
for (const auto& [vkey, seq] : cursorKeys)
|
||||
{
|
||||
INPUT_RECORD inputRec;
|
||||
|
||||
const wchar_t wch = (wchar_t)MapVirtualKeyW(vkey, MAPVK_VK_TO_CHAR);
|
||||
const WORD scanCode = (WORD)MapVirtualKeyW(vkey, MAPVK_VK_TO_VSC);
|
||||
|
||||
inputRec.EventType = KEY_EVENT;
|
||||
inputRec.Event.KeyEvent.bKeyDown = TRUE;
|
||||
inputRec.Event.KeyEvent.dwControlKeyState = 0;
|
||||
inputRec.Event.KeyEvent.wRepeatCount = 1;
|
||||
inputRec.Event.KeyEvent.wVirtualKeyCode = static_cast<WORD>(vkey);
|
||||
inputRec.Event.KeyEvent.wVirtualScanCode = scanCode;
|
||||
inputRec.Event.KeyEvent.uChar.UnicodeChar = wch;
|
||||
|
||||
testState.vExpectedInput.push_back(inputRec);
|
||||
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"Processing \"%s\"", seq.c_str()));
|
||||
_stateMachine->ProcessString(seq);
|
||||
}
|
||||
VerifyExpectedInputDrained();
|
||||
}
|
||||
|
||||
void InputEngineTest::AltBackspaceTest()
|
||||
{
|
||||
auto pfn = std::bind(&TestState::TestInputCallback, &testState, std::placeholders::_1);
|
||||
|
|
Loading…
Reference in a new issue