void InputTest::TerminalInputModifierKeyTests()

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.");
    }
}