Repository: microsoft/terminal (language: cpp)

Issue:
Windows Terminal does not set CAPSLOCK_ON in KEY_EVENT_RECORD.dwControlKeyState
### Windows Terminal version

1.11.3471.0

### Windows build number

10.0.19044.1586

### Other Software

_No response_

### Steps to reproduce

Run the following code in Windows Terminal and Conhost respectively. Compile with `/std:c++latest` for `std::format`.
Strike some keys with capslock off and on.

```
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <format>

void write_key_event(HANDLE console_out, KEY_EVENT_RECORD& key_event) {
    auto unicode = key_event.uChar.UnicodeChar;
    auto unicode_str = unicode < 32 ? std::wstring(L" ") : std::wstring(1, unicode);
    auto key_state = (key_event.bKeyDown ? L"Down" : L"Up");
    auto msg = std::format(
        L"KeyState: {:>4}, KeyCode: {:#04x}, ScanCode: {:#04x}, Unicode: {} ({:#06x}), Modifiers: {:#06x}\n",
        key_state, key_event.wVirtualKeyCode, key_event.wVirtualScanCode,
        unicode_str, unicode, key_event.dwControlKeyState);
    WriteConsoleW(console_out, msg.data(), msg.length(), nullptr, nullptr);
}

int main() {
    HANDLE console_in = GetStdHandle(STD_INPUT_HANDLE);
    HANDLE console_out = GetStdHandle(STD_OUTPUT_HANDLE);

    // Enable raw mode.
    SetConsoleMode(console_in, 0);

    while (true) {
        INPUT_RECORD input_record;
        DWORD num_records_read = 0;
        auto result = ReadConsoleInputW(console_in, &input_record, 1, &num_records_read);
        if (input_record.EventType != KEY_EVENT) {
            continue;
        }

        KEY_EVENT_RECORD& key_event = input_record.Event.KeyEvent;
        write_key_event(console_out, key_event);

        if (key_event.uChar.UnicodeChar == 'q') {
            break;
        }
    }

    return EXIT_SUCCESS;
}
```

### Expected Behavior

When capslock is off, the "Modifiers: ..." does not include 0x80. With capslock on, it does include 0x80.

For example, I get this output in Conhost.exe:
```
C:\Users\Kaas\source\Playground\x64\Debug>Playground.exe
KeyState: Down, KeyCode: 0x41, ScanCode: 0x1e, Unicode: a (0x0061), Modifiers: 0x0000
KeyState:   Up, KeyCode: 0x41, ScanCode: 0x1e, Unicode: a (0x0061), Modifiers: 0x0000
KeyState: Down, KeyCode: 0x53, ScanCode: 0x1f, Unicode: s (0x0073), Modifiers: 0x0000
KeyState:   Up, KeyCode: 0x53, ScanCode: 0x1f, Unicode: s (0x0073), Modifiers: 0x0000
KeyState: Down, KeyCode: 0x44, ScanCode: 0x20, Unicode: d (0x0064), Modifiers: 0x0000
KeyState:   Up, KeyCode: 0x44, ScanCode: 0x20, Unicode: d (0x0064), Modifiers: 0x0000
KeyState: Down, KeyCode: 0x14, ScanCode: 0x3a, Unicode:   (0x0000), Modifiers: 0x0080
KeyState:   Up, KeyCode: 0x14, ScanCode: 0x3a, Unicode:   (0x0000), Modifiers: 0x0080
KeyState: Down, KeyCode: 0x41, ScanCode: 0x1e, Unicode: A (0x0041), Modifiers: 0x0080
KeyState:   Up, KeyCode: 0x41, ScanCode: 0x1e, Unicode: A (0x0041), Modifiers: 0x0080
KeyState: Down, KeyCode: 0x53, ScanCode: 0x1f, Unicode: S (0x0053), Modifiers: 0x0080
KeyState:   Up, KeyCode: 0x53, ScanCode: 0x1f, Unicode: S (0x0053), Modifiers: 0x0080
KeyState: Down, KeyCode: 0x44, ScanCode: 0x20, Unicode: D (0x0044), Modifiers: 0x0080
KeyState:   Up, KeyCode: 0x44, ScanCode: 0x20, Unicode: D (0x0044), Modifiers: 0x0080
KeyState: Down, KeyCode: 0x14, ScanCode: 0x3a, Unicode:   (0x0000), Modifiers: 0x0000
KeyState:   Up, KeyCode: 0x14, ScanCode: 0x3a, Unicode:   (0x0000), Modifiers: 0x0000
KeyState: Down, KeyCode: 0x51, ScanCode: 0x10, Unicode: q (0x0071), Modifiers: 0x0000
```

### Actual Behavior

Works as expected in Conhost.

In Windows Terminal, the "Modifiers: ..." doesn't include 0x80 regardless of the state of capslock.

For example, I get this output in wt.exe:
```
C:\Users\Kaas\source\Playground\x64\Debug>Playground.exe
KeyState:   Up, KeyCode: 0x0d, ScanCode: 0x1c, Unicode:   (0x000d), Modifiers: 0x0000
KeyState: Down, KeyCode: 0x41, ScanCode: 0x1e, Unicode: a (0x0061), Modifiers: 0x0000
KeyState:   Up, KeyCode: 0x41, ScanCode: 0x1e, Unicode: a (0x0061), Modifiers: 0x0000
KeyState: Down, KeyCode: 0x53, ScanCode: 0x1f, Unicode: s (0x0073), Modifiers: 0x0000
KeyState:   Up, KeyCode: 0x53, ScanCode: 0x1f, Unicode: s (0x0073), Modifiers: 0x0000
KeyState: Down, KeyCode: 0x44, ScanCode: 0x20, Unicode: d (0x0064), Modifiers: 0x0000
KeyState:   Up, KeyCode: 0x44, ScanCode: 0x20, Unicode: d (0x0064), Modifiers: 0x0000
KeyState: Down, KeyCode: 0x14, ScanCode: 0x3a, Unicode:   (0x0000), Modifiers: 0x0000
KeyState:   Up, KeyCode: 0x14, ScanCode: 0x3a, Unicode:   (0x0000), Modifiers: 0x0000
KeyState: Down, KeyCode: 0x41, ScanCode: 0x1e, Unicode: A (0x0041), Modifiers: 0x0000
KeyState:   Up, KeyCode: 0x41, ScanCode: 0x1e, Unicode: A (0x0041), Modifiers: 0x0000
KeyState: Down, KeyCode: 0x53, ScanCode: 0x1f, Unicode: S (0x0053), Modifiers: 0x0000
KeyState:   Up, KeyCode: 0x53, ScanCode: 0x1f, Unicode: S (0x0053), Modifiers: 0x0000
KeyState: Down, KeyCode: 0x44, ScanCode: 0x20, Unicode: D (0x0044), Modifiers: 0x0000
KeyState:   Up, KeyCode: 0x44, ScanCode: 0x20, Unicode: D (0x0044), Modifiers: 0x0000
KeyState: Down, KeyCode: 0x14, ScanCode: 0x3a, Unicode:   (0x0000), Modifiers: 0x0000
KeyState:   Up, KeyCode: 0x14, ScanCode: 0x3a, Unicode:   (0x0000), Modifiers: 0x0000
KeyState: Down, KeyCode: 0x51, ScanCode: 0x10, Unicode: q (0x0071), Modifiers: 0x0000
```

I haven't tested other keyboard modalities, since I don't have keys for those on my keyboard, but perhaps they're also affected?


Discussion / hints:
You know, I bet it doesn't. 

I would reckon the problem is around https://github.com/microsoft/terminal/blob/e428272752968c00ad9d4a32d3bad5ea010e991b/src/cascadia/TerminalControl/TermControl.cpp#L993-L997

or lower in the stack than that. We're not checking in TermControl if capslock is pressed, so we're never pluming that flag through to `ControlCore`/`Terminal` & eventually the underlying conpty. 

Fix patch:
diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp
index d09c1c06884..818a10c9b4b 100644
--- a/src/cascadia/TerminalControl/TermControl.cpp
+++ b/src/cascadia/TerminalControl/TermControl.cpp
@@ -2163,6 +2163,23 @@ namespace winrt::Microsoft::Terminal::Control::implementation
             }
         }
 
+        constexpr std::array<KeyModifier, 3> modalities{ {
+            { VirtualKey::CapitalLock, ControlKeyStates::CapslockOn },
+            { VirtualKey::NumberKeyLock, ControlKeyStates::NumlockOn },
+            { VirtualKey::Scroll, ControlKeyStates::ScrolllockOn },
+        } };
+
+        for (const auto& mod : modalities)
+        {
+            const auto state = window.GetKeyState(mod.vkey);
+            const auto isLocked = WI_IsFlagSet(state, CoreVirtualKeyStates::Locked);
+
+            if (isLocked)
+            {
+                flags |= mod.flags;
+            }
+        }
+
         return flags;
     }
 


Test patch: