terminal icon indicating copy to clipboard operation
terminal copied to clipboard

Launching in Russian layout causes Ctrl+C and other signal chars to not work

Open EntityinArray opened this issue 1 year ago • 7 comments

Windows Terminal version

1.19.11213.0

Windows build number

10.0.19045.0

Other Software

PSVersion 7.4.2 PSEdition Core GitCommitId 7.4.2 OS Microsoft Windows 10.0.19045 Platform Win32NT PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…} PSRemotingProtocolVersion 2.3 SerializationVersion 1.1.0.1 WSManStackVersion 3.0

Steps to reproduce

  • Change your keyboard layout to Russian
  • Open Windows Terminal
  • Try Ctrl+C

Expected Behavior

Sends interrupt

Actual Behavior

Types C

EntityinArray avatar May 06 '24 19:05 EntityinArray

Between which keyboard layouts are you switching? Does the issue persist even if you press Ctrl+C multiple times?

lhecker avatar May 06 '24 22:05 lhecker

Between which keyboard layouts are you switching? Does the issue persist even if you press Ctrl+C multiple times?

Sorry, i made a new discovery. The layout switching is not necessary. Bug occurs when you just start Windows Terminal in Russian layout.

I switch between English and Russian. If Windows Terminal is started with Russian layout, it doesn't accept signal chars at all until app restart, even if you switch layout back to English during runtime.

image

EntityinArray avatar May 07 '24 06:05 EntityinArray

I think this is just PowerShell. I can't reproduce it in a cmd shell or WSL bash. I think it's because the C key on the Russian keyboard is actually a Cyrillic с, and PowerShell can't translate that into a control character. You can see the same thing with a Hebrew keyboard layout.

I also found that it seems to be the first time you press a Ctrl key that "locks" the mapping for that tab. So if you open a pwsh tab with the Russian layout, then switch to English, press Ctrl+C, then switch back to Russian, it should work fine. But if you press Ctrl+C when the Russian layout is first active, it'll be broken for the rest of that session.

I also see the same behavior in conhost.

j4james avatar May 07 '24 10:05 j4james

This bug was tracked in the PSReadLine repository in https://github.com/PowerShell/PSReadLine/issues/1393, and it sounds like they've got a partial fix. The Ctrl keys still won't work when your keyboard layout is Russian, but they should work if you switch to English without needing to restart the shell. You'll need the latest beta version of PSReadLine to get that fix, though.

j4james avatar May 09 '24 13:05 j4james

Apropos @j4james I believe this code may not work in conhost: https://github.com/microsoft/terminal/blob/49e4eea60f737b46b8aeda505f4693df8a9d44a6/src/terminal/input/terminalInput.cpp#L267

If you try something like this:

#include <Windows.h>
#include <cstdio>

int main() {
    for (;;) {
        const auto hkl = GetKeyboardLayout(GetWindowThreadProcessId(GetForegroundWindow(), nullptr));
        printf("0x%p\n", hkl);
        Sleep(1000);
    }
}

you'll see that the layout never changes in conhost. I believe it's because of the window ownership lying that ntuser does where it makes it so that it appears as if cmd/pwsh/wsl owns the window. This seems to also affect GetWindowThreadProcessId which then returns the main thread ID of cmd/pwsh/wsl instead of the actual window handle. (BTW that seems like an OS bug?)

lhecker avatar May 09 '24 13:05 lhecker

It seems I may have spoken too soon. I'm currently looking how to solve this in pwsh actually, and I'm not actually testing it in conhost. So I probably shouldn't have written the above without confirming it.

Most importantly I found this comment in GetWindowThreadProcessId:

NB: This has implications on the scenario where the window's owner gets remapped via NtUserConsoleControl / ConsoleSetWindowOwner. If called by thread that owns a window, API will return true TID/PID and not remapped one. This is how it was done historically and we are keeping this behavior.

I guess this explains why the current code may work: The function gets called by conhost itself from threads that may own a window. That's slightly bodgy however of course. 😅

lhecker avatar May 09 '24 14:05 lhecker

@lhecker Note that the code you referenced is only applicable to shells using VT input sequences, like the WSL bash shell, and that doesn't have any problems with the Ctrl keys when using a Russian keyboard layout. But PSReadLine isn't using VT input sequences - they're doing the keyboard translation themselves. And regardless of whether they're picking up the correct layout at runtime, they simply don't handle Ctrl keys on a Russian keyboard.

j4james avatar May 09 '24 14:05 j4james