Skip to content

Commit

Permalink
Add support for Ctrl+# keys (#4938)
Browse files Browse the repository at this point in the history
## Summary of the Pull Request

Fixes the <kbd>Ctrl+Num</kbd> keys in both conhost and the Terminal. These keys are supposed to be mapped to specific characters according to [this doc](https://vt100.net/docs/vt220-rm/table3-5.html). Now we actually handle them correctly.

## PR Checklist
* [x] Closes #3507 
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated

## Validation Steps Performed

* Ran test
* tested in `gnome-terminal` with `showkeys -a`
* tested in conhost with `showkeys -a`
* tested in Windows Terminal with `showkeys -a`
  • Loading branch information
zadjii-msft authored Mar 18, 2020
1 parent d50409b commit f7d106d
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 1 deletion.
54 changes: 54 additions & 0 deletions src/terminal/adapter/ut_adapter/inputTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class Microsoft::Console::VirtualTerminal::InputTest
TEST_METHOD(TerminalInputModifierKeyTests);
TEST_METHOD(TerminalInputNullKeyTests);
TEST_METHOD(DifferentModifiersTest);
TEST_METHOD(CtrlNumTest);

wchar_t GetModifierChar(const bool fShift, const bool fAlt, const bool fCtrl)
{
Expand Down Expand Up @@ -511,6 +512,13 @@ void InputTest::TerminalInputModifierKeyTests()
s_pwsInputBuffer[1] = wchShifted;
fExpectedKeyHandled = true;
}
else if (ControlPressed(uiKeystate) && (vkey >= '1' && vkey <= '9'))
{
// The C-# keys get translated into very specific control
// characters that don't play nicely with this test. These keys
// are tested in the CtrlNumTest Test instead.
continue;
}
else
{
fExpectedKeyHandled = false;
Expand Down Expand Up @@ -714,3 +722,49 @@ void InputTest::DifferentModifiersTest()
// LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED is skipped because that's AltGr
TestKey(pInput, SHIFT_PRESSED | RIGHT_CTRL_PRESSED | RIGHT_ALT_PRESSED, vkey, L'?');
}

void InputTest::CtrlNumTest()
{
Log::Comment(L"Starting test...");

const TerminalInput* const pInput = new TerminalInput(s_TerminalInputTestCallback);

Log::Comment(L"Sending the various Ctrl+Num keys.");

unsigned int uiKeystate = LEFT_CTRL_PRESSED;
BYTE vkey = static_cast<WORD>('1');
s_pwszInputExpected = L"1";
TestKey(pInput, uiKeystate, vkey);

Log::Comment(NoThrowString().Format(
L"Skipping Ctrl+2, since that's supposed to send NUL, and doesn't play "
L"nicely with this test. Ctrl+2 is covered by other tests in this class."));

vkey = static_cast<WORD>('3');
s_pwszInputExpected = L"\x1b";
TestKey(pInput, uiKeystate, vkey);

vkey = static_cast<WORD>('4');
s_pwszInputExpected = L"\x1c";
TestKey(pInput, uiKeystate, vkey);

vkey = static_cast<WORD>('5');
s_pwszInputExpected = L"\x1d";
TestKey(pInput, uiKeystate, vkey);

vkey = static_cast<WORD>('6');
s_pwszInputExpected = L"\x1e";
TestKey(pInput, uiKeystate, vkey);

vkey = static_cast<WORD>('7');
s_pwszInputExpected = L"\x1f";
TestKey(pInput, uiKeystate, vkey);

vkey = static_cast<WORD>('8');
s_pwszInputExpected = L"\x7f";
TestKey(pInput, uiKeystate, vkey);

vkey = static_cast<WORD>('9');
s_pwszInputExpected = L"9";
TestKey(pInput, uiKeystate, vkey);
}
20 changes: 19 additions & 1 deletion src/terminal/input/terminalInput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,13 +185,31 @@ static constexpr std::array<TermKeyMap, 22> 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<TermKeyMap, 6> s_simpleModifiedKeyMapping{
static constexpr std::array<TermKeyMap, 14> 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" },
TermKeyMap{ VK_TAB, CTRL_PRESSED, L"\t" },
TermKeyMap{ VK_TAB, SHIFT_PRESSED, L"\x1b[Z" },
TermKeyMap{ VK_DIVIDE, CTRL_PRESSED, L"\x1F" },

// GH#3507 - We should also be encoding Ctrl+# according to the following table:
// https://vt100.net/docs/vt220-rm/table3-5.html
// * 1 and 9 do not send any special characters, but they _should_ send
// through the character unmodified.
// * 0 doesn't seem to send even an unmodified '0' through.
// * Ctrl+2 is already special-cased below in `HandleKey`, so it's not
// included here.
TermKeyMap{ static_cast<WORD>('1'), CTRL_PRESSED, L"1" },
// TermKeyMap{ static_cast<WORD>('2'), CTRL_PRESSED, L"\x00" },
TermKeyMap{ static_cast<WORD>('3'), CTRL_PRESSED, L"\x1B" },
TermKeyMap{ static_cast<WORD>('4'), CTRL_PRESSED, L"\x1C" },
TermKeyMap{ static_cast<WORD>('5'), CTRL_PRESSED, L"\x1D" },
TermKeyMap{ static_cast<WORD>('6'), CTRL_PRESSED, L"\x1E" },
TermKeyMap{ static_cast<WORD>('7'), CTRL_PRESSED, L"\x1F" },
TermKeyMap{ static_cast<WORD>('8'), CTRL_PRESSED, L"\x7F" },
TermKeyMap{ static_cast<WORD>('9'), CTRL_PRESSED, L"9" },

// These two are not implemented here, because they are system keys.
// TermKeyMap{ VK_TAB, ALT_PRESSED, L""}, This is the Windows system shortcut for switching windows.
// TermKeyMap{ VK_ESCAPE, ALT_PRESSED, L""}, This is another Windows system shortcut for switching windows.
Expand Down

0 comments on commit f7d106d

Please sign in to comment.