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 SS3 cursor key encoding to ConPty #5383

Merged
3 commits merged into from
Apr 17, 2020
Merged
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
56 changes: 16 additions & 40 deletions src/terminal/adapter/adaptDispatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
}
Expand All @@ -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;
}
Expand All @@ -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;
}
Expand All @@ -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;
}
Expand All @@ -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;
}
Expand Down
8 changes: 7 additions & 1 deletion src/terminal/parser/InputStateMachineEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
Expand Down
14 changes: 6 additions & 8 deletions src/terminal/parser/InputStateMachineEngine.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
45 changes: 45 additions & 0 deletions src/terminal/parser/ut_parser/InputEngineTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down