in src/terminal/adapter/ut_adapter/inputTest.cpp [313:535]
void InputTest::TerminalInputModifierKeyTests()
{
// Modifier key state values used in the method properties.
// #define RIGHT_ALT_PRESSED 0x0001
// #define LEFT_ALT_PRESSED 0x0002
// #define RIGHT_CTRL_PRESSED 0x0004
// #define LEFT_CTRL_PRESSED 0x0008
// #define SHIFT_PRESSED 0x0010
Log::Comment(L"Starting test...");
BEGIN_TEST_METHOD_PROPERTIES()
TEST_METHOD_PROPERTY(L"Data:uiModifierKeystate", L"{0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x000A, 0x000C, 0x000E, 0x0010, 0x0011, 0x0012, 0x0013}")
END_TEST_METHOD_PROPERTIES()
unsigned int uiKeystate;
VERIFY_SUCCEEDED_RETURN(TestData::TryGetValue(L"uiModifierKeystate", uiKeystate));
TerminalInput* const pInput = new TerminalInput(s_TerminalInputTestCallback);
const BYTE slashVkey = LOBYTE(VkKeyScanW(L'/'));
const BYTE nullVkey = LOBYTE(VkKeyScanW(0));
Log::Comment(L"Sending every possible VKEY at the input stream for interception during key DOWN.");
for (BYTE vkey = 0; vkey < BYTE_MAX; vkey++)
{
Log::Comment(NoThrowString().Format(L"Testing Key 0x%x", vkey));
bool fExpectedKeyHandled = true;
bool fModifySequence = false;
INPUT_RECORD irTest = { 0 };
irTest.EventType = KEY_EVENT;
irTest.Event.KeyEvent.dwControlKeyState = uiKeystate;
irTest.Event.KeyEvent.wRepeatCount = 1;
irTest.Event.KeyEvent.wVirtualKeyCode = vkey;
irTest.Event.KeyEvent.bKeyDown = TRUE;
irTest.Event.KeyEvent.uChar.UnicodeChar = LOWORD(MapVirtualKeyW(vkey, MAPVK_VK_TO_CHAR));
if (ControlPressed(uiKeystate))
{
// For Ctrl-/ see DifferentModifiersTest.
if (vkey == VK_DIVIDE || vkey == slashVkey)
{
continue;
}
// For Ctrl-@/Ctrl-Space see TerminalInputNullKeyTests.
if (vkey == nullVkey || vkey == ' ')
{
continue;
}
}
// Set up expected result
switch (vkey)
{
case VK_BACK:
// Backspace is kinda different from other keys - we'll handle in another test.
case VK_OEM_2:
// VK_OEM_2 is typically the '/?' key
continue;
// s_expectedInput = L"\x7f";
break;
case VK_PAUSE:
s_expectedInput = L"\x1a";
break;
case VK_UP:
fModifySequence = true;
s_expectedInput = L"\x1b[1;mA";
break;
case VK_DOWN:
fModifySequence = true;
s_expectedInput = L"\x1b[1;mB";
break;
case VK_RIGHT:
fModifySequence = true;
s_expectedInput = L"\x1b[1;mC";
break;
case VK_LEFT:
fModifySequence = true;
s_expectedInput = L"\x1b[1;mD";
break;
case VK_HOME:
fModifySequence = true;
s_expectedInput = L"\x1b[1;mH";
break;
case VK_INSERT:
fModifySequence = true;
s_expectedInput = L"\x1b[2;m~";
break;
case VK_DELETE:
fModifySequence = true;
s_expectedInput = L"\x1b[3;m~";
break;
case VK_END:
fModifySequence = true;
s_expectedInput = L"\x1b[1;mF";
break;
case VK_PRIOR:
fModifySequence = true;
s_expectedInput = L"\x1b[5;m~";
break;
case VK_NEXT:
fModifySequence = true;
s_expectedInput = L"\x1b[6;m~";
break;
case VK_F1:
fModifySequence = true;
s_expectedInput = L"\x1b[1;mP";
break;
case VK_F2:
fModifySequence = true;
s_expectedInput = L"\x1b[1;mQ";
break;
case VK_F3:
fModifySequence = true;
s_expectedInput = L"\x1b[1;mR";
break;
case VK_F4:
fModifySequence = true;
s_expectedInput = L"\x1b[1;mS";
break;
case VK_F5:
fModifySequence = true;
s_expectedInput = L"\x1b[15;m~";
break;
case VK_F6:
fModifySequence = true;
s_expectedInput = L"\x1b[17;m~";
break;
case VK_F7:
fModifySequence = true;
s_expectedInput = L"\x1b[18;m~";
break;
case VK_F8:
fModifySequence = true;
s_expectedInput = L"\x1b[19;m~";
break;
case VK_F9:
fModifySequence = true;
s_expectedInput = L"\x1b[20;m~";
break;
case VK_F10:
fModifySequence = true;
s_expectedInput = L"\x1b[21;m~";
break;
case VK_F11:
fModifySequence = true;
s_expectedInput = L"\x1b[23;m~";
break;
case VK_F12:
fModifySequence = true;
s_expectedInput = L"\x1b[24;m~";
break;
case VK_TAB:
if (AltPressed(uiKeystate))
{
// Alt+Tab isn't possible - thats reserved by the system.
continue;
}
else if (ShiftPressed(uiKeystate))
{
s_expectedInput = L"\x1b[Z";
}
else if (ControlPressed(uiKeystate))
{
s_expectedInput = L"\t";
}
break;
default:
wchar_t ch = irTest.Event.KeyEvent.uChar.UnicodeChar;
// Alt+Key generates [0x1b, Ctrl+key] into the stream
// Pressing the control key causes all bits but the 5 least
// significant ones to be zeroed out (when using ASCII).
if (AltPressed(uiKeystate) && ControlPressed(uiKeystate) && ch > 0x40 && ch <= 0x5A)
{
s_expectedInput.clear();
s_expectedInput.push_back(L'\x1b');
s_expectedInput.push_back(ch & 0b11111);
break;
}
// Alt+Key generates [0x1b, key] into the stream
if (AltPressed(uiKeystate) && !ControlPressed(uiKeystate) && ch != 0)
{
s_expectedInput.clear();
s_expectedInput.push_back(L'\x1b');
s_expectedInput.push_back(ch);
break;
}
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;
}
if (ch != 0)
{
s_expectedInput.clear();
s_expectedInput.push_back(irTest.Event.KeyEvent.uChar.UnicodeChar);
break;
}
fExpectedKeyHandled = false;
break;
}
if (fModifySequence && s_expectedInput.size() > 1)
{
bool fShift = !!(uiKeystate & SHIFT_PRESSED);
bool fAlt = (uiKeystate & LEFT_ALT_PRESSED) || (uiKeystate & RIGHT_ALT_PRESSED);
bool fCtrl = (uiKeystate & LEFT_CTRL_PRESSED) || (uiKeystate & RIGHT_CTRL_PRESSED);
s_expectedInput[s_expectedInput.size() - 2] = L'1' + (fShift ? 1 : 0) + (fAlt ? 2 : 0) + (fCtrl ? 4 : 0);
}
Log::Comment(NoThrowString().Format(L"Expected = \"%s\"", s_expectedInput.c_str()));
auto inputEvent = IInputEvent::Create(irTest);
// Send key into object (will trigger callback and verification)
VERIFY_ARE_EQUAL(fExpectedKeyHandled, pInput->HandleKey(inputEvent.get()), L"Verify key was handled if it should have been.");
}
}