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

Open
opened 2026-01-31 07:50:22 +00:00 by claunia · 26 comments
Owner

Originally created by @EntityinArray on GitHub (May 6, 2024).

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

Originally created by @EntityinArray on GitHub (May 6, 2024). ### 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
claunia added the Issue-BugArea-InputProduct-Terminal labels 2026-01-31 07:50:22 +00:00
Author
Owner

@lhecker commented on GitHub (May 6, 2024):

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

@lhecker commented on GitHub (May 6, 2024): Between which keyboard layouts are you switching? Does the issue persist even if you press Ctrl+C multiple times?
Author
Owner

@EntityinArray commented on GitHub (May 7, 2024):

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 commented on GitHub (May 7, 2024): > 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](https://github.com/microsoft/terminal/assets/18554021/af8d4fd4-67bd-42cf-9895-d00a25529a9c)
Author
Owner

@j4james commented on GitHub (May 7, 2024):

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 commented on GitHub (May 7, 2024): 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 <kbd>Ctrl</kbd> key that "locks" the mapping for that tab. So if you open a pwsh tab with the Russian layout, then switch to English, press <kbd>Ctrl</kbd>+<kbd>C</kbd>, then switch back to Russian, it should work fine. But if you press <kbd>Ctrl</kbd>+<kbd>C</kbd> 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.
Author
Owner

@j4james commented on GitHub (May 9, 2024):

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 commented on GitHub (May 9, 2024): 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.
Author
Owner

@lhecker commented on GitHub (May 9, 2024):

Apropos @j4james I believe this code may not work in conhost:
49e4eea60f/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 commented on GitHub (May 9, 2024): 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: ```cpp #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?)
Author
Owner

@lhecker commented on GitHub (May 9, 2024):

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 commented on GitHub (May 9, 2024): 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. 😅
Author
Owner

@j4james commented on GitHub (May 9, 2024):

@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 commented on GitHub (May 9, 2024): @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.
Author
Owner

@github-account1111 commented on GitHub (Oct 28, 2024):

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.

No this also happens with Ctrl+a, Ctrl+x and I imagine other Ctrl shortcuts. Given that Microsoft still refuse to ship an up-to-date Powershell with Windows 10 and 11, this needs to be fixed.

@github-account1111 commented on GitHub (Oct 28, 2024): > 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. No this also happens with Ctrl+a, Ctrl+x and I imagine other Ctrl shortcuts. Given that Microsoft still refuse to ship an up-to-date Powershell with Windows 10 and 11, this needs to be fixed.
Author
Owner

@zadjii-msft commented on GitHub (Oct 28, 2024):

Putting this back in the triage queue because it's not clear to my (extremely sleep deprived) brain from the discussion here which one of the following is actually the responsible area path for this bug:

  • OS
  • conhost
  • terminal
  • powershell
  • pwsh
  • PsReadline
@zadjii-msft commented on GitHub (Oct 28, 2024): Putting this back in the triage queue because it's not clear to my (extremely sleep deprived) brain from the discussion here which one of the following is actually the responsible area path for this bug: * OS * conhost * terminal * `powershell` * `pwsh` * PsReadline
Author
Owner

@ftoh commented on GitHub (Nov 3, 2024):

I have two PCs. Only one affected the bug.

Affected
Windows 11 Pro 23H2 (build 22631.4317)
Windows Terminal 1.21.2911.0
PowerShell 7.4.6

Not affected
Windows 11 Pro 22H2 (build 22621.4317)
Windows Terminal 1.21.2911.0
PowerShell 7.4.6

UPD
Affected: PSReadLine 2.4.0 beta-0 (I don't know version was before I update it to latest)
Not Affected: PSReadLine 2.3.5

@ftoh commented on GitHub (Nov 3, 2024): I have two PCs. Only one affected the bug. Affected Windows 11 Pro **_23H2_** (build **_22631.4317_**) Windows Terminal 1.21.2911.0 PowerShell 7.4.6 Not affected Windows 11 Pro **_22H2_** (build **_22621.4317_**) Windows Terminal 1.21.2911.0 PowerShell 7.4.6 **_UPD_** Affected: PSReadLine 2.4.0 beta-0 (I don't know version was before I update it to latest) Not Affected: PSReadLine 2.3.5
Author
Owner

@EntityinArray commented on GitHub (Nov 15, 2024):

New interesting discovery:

  1. Launch Terminal in Russian layout (i believe any other non-english layout will work)
  2. Switch to English
  3. Typing with control depressed causes English chars to appear. Typing with control pressed causes Russian chars to appear

I hope this info gives clues to any devs at least somewhat familiar with this Rube Goldbergian mess and what might be happening under the hood

@EntityinArray commented on GitHub (Nov 15, 2024): New interesting discovery: 1. Launch Terminal in Russian layout (i believe any other non-english layout will work) 2. Switch to English 3. Typing with control depressed causes English chars to appear. Typing with control pressed causes Russian chars to appear I hope this info gives clues to any devs at least somewhat familiar with this Rube Goldbergian mess and what might be happening under the hood
Author
Owner

@o-sdn-o commented on GitHub (Nov 15, 2024):

New interesting discovery:

This behavior is typical only for PSReadline (PSReadLine 2.4.0-beta0 xlink: https://github.com/PowerShell/PSReadLine/issues/2865). And it does not matter in which terminal emulator it was launched in Windows Terminal or not. There is no such behavior outside PSReadline.

P.S.: To reproduce this behavior, the use a different input method for each app system option must be disabled.

Image

@o-sdn-o commented on GitHub (Nov 15, 2024): > New interesting discovery: This behavior is typical only for PSReadline (PSReadLine 2.4.0-beta0 xlink: https://github.com/PowerShell/PSReadLine/issues/2865). And it does not matter in which terminal emulator it was launched in Windows Terminal or not. There is no such behavior outside PSReadline. P.S.: To reproduce this behavior, the `use a different input method for each app` system option must be disabled. ![Image](https://github.com/user-attachments/assets/75b3cb96-03d9-4643-895e-2e0b9a0bd1c0)
Author
Owner

@dkandrov commented on GitHub (Nov 20, 2024):

I have same issue:
Image

@dkandrov commented on GitHub (Nov 20, 2024): I have same issue: ![Image](https://github.com/user-attachments/assets/80f2356e-2d74-446e-9234-e51b82fb32e7)
Author
Owner

@o-sdn-o commented on GitHub (Nov 21, 2024):

I have same issue...

This behavior is not a Windows Terminal issue. It is exactly the same in other terminals. It is a PSReadLine issue.

https://github.com/user-attachments/assets/7087d68d-e6e6-406d-b0da-e2a768c6a264

@o-sdn-o commented on GitHub (Nov 21, 2024): > I have same issue... This behavior is not a Windows Terminal issue. It is exactly the same in other terminals. It is a PSReadLine issue. https://github.com/user-attachments/assets/7087d68d-e6e6-406d-b0da-e2a768c6a264
Author
Owner

@dkandrov commented on GitHub (Nov 21, 2024):

This behavior is not a Windows Terminal issue. It is exactly the same in other terminals. It is a PSReadLine issue.

I understand this, but no one has added a “screenshot” or screencast, so I've spent some time trying to figure out if I'm having the exact same problem or not. After that I decided to add screen cast.

@dkandrov commented on GitHub (Nov 21, 2024): > This behavior is not a Windows Terminal issue. It is exactly the same in other terminals. It is a PSReadLine issue. I understand this, but no one has added a “screenshot” or screencast, so I've spent some time trying to figure out if I'm having the exact same problem or not. After that I decided to add screen cast.
Author
Owner

@ForNeVeR commented on GitHub (Mar 6, 2025):

JFYI, this has been worked around (by yours truly) in PSReadline: https://github.com/PowerShell/PSReadLine/issues/1393

install-Module PSReadLine -Repository PSGallery -Scope CurrentUser -AllowPrerelease -force should fix this (for some definition of "fix" at least: now PSReadline can watch for runtime keyboard layout changes in most cases, and Ctrl+C will finally work after you switch to English).

I had to implement a complex heuristic to work around inability to determine the keyboard layout of the console window. If there was an API exposing this, everything would be much easier.

Also I tried implementing this in a layout-agnostic way, but eventually decided against since it broke some tests in PSReadline: apparently, not any keyboard layout is expected to provide key bindings from the US layout. I'd be interested in seeing how exactly is this implemented in cmd or conhost (sorry, I am not sure where to look for this particular binding, and my first assumption would be — in a closed-source part of cmd), to replicate the behavior in PSReadline — we mostly can do that, or at least I believe so.

@ForNeVeR commented on GitHub (Mar 6, 2025): JFYI, this has been worked around (by yours truly) in PSReadline: https://github.com/PowerShell/PSReadLine/issues/1393 `install-Module PSReadLine -Repository PSGallery -Scope CurrentUser -AllowPrerelease -force` should fix this (for some definition of "fix" at least: now PSReadline can watch for runtime keyboard layout changes in most cases, and `Ctrl+C` will finally work after you switch to English). I had to implement a complex heuristic to work around inability to determine the keyboard layout of the console window. If there was an API exposing this, everything would be much easier. Also I tried implementing this in a layout-agnostic way, but eventually decided against since it broke some tests in PSReadline: apparently, not any keyboard layout is expected to provide key bindings from the US layout. I'd be interested in seeing how exactly is this implemented in `cmd` or `conhost` (sorry, I am not sure where to look for this particular binding, and my first assumption would be — in a closed-source part of `cmd`), to replicate the behavior in PSReadline — we _mostly_ can do that, or at least I believe so.
Author
Owner

@o-sdn-o commented on GitHub (Mar 6, 2025):

install-Module PSReadLine -Repository PSGallery -Scope CurrentUser -AllowPrerelease -force should fix this

This may not work, the behavior remains the same:

https://github.com/user-attachments/assets/24e455a7-6895-4da5-8663-141a88c2b0fd

@o-sdn-o commented on GitHub (Mar 6, 2025): > `install-Module PSReadLine -Repository PSGallery -Scope CurrentUser -AllowPrerelease -force` should fix this This may not work, the behavior remains the same: https://github.com/user-attachments/assets/24e455a7-6895-4da5-8663-141a88c2b0fd
Author
Owner

@ForNeVeR commented on GitHub (Mar 6, 2025):

It is not clear what you mean by "may not work". Definitely works for me. Are you following the instructions correctly?

@ForNeVeR commented on GitHub (Mar 6, 2025): It is not clear what you mean by "may not work". Definitely works for me. Are you following the instructions correctly?
Author
Owner

@o-sdn-o commented on GitHub (Mar 6, 2025):

Are you following the instructions correctly?

I just updated PSReadline module to version 2.4.1beta and tried to reproduce the problem.

  1. Set the same layout for all windows (system-wide setting).
  2. Switch kb layout to RU.
  3. Launch pwsh.
  4. Press Ctrl+C.
  5. Got a character instead of ^C.
@o-sdn-o commented on GitHub (Mar 6, 2025): > Are you following the instructions correctly? I just updated PSReadline module to version 2.4.1beta and tried to reproduce the problem. 1. Set the same layout for all windows (system-wide setting). 2. Switch kb layout to RU. 3. Launch pwsh. 4. Press Ctrl+C. 5. Got a character instead of ^C.
Author
Owner

@ForNeVeR commented on GitHub (Mar 6, 2025):

But this is the expected behavior (unfortunately; believe me I understand it's not convenient, but it's still better than before).

You should switch back to English before 4.

@ForNeVeR commented on GitHub (Mar 6, 2025): But this is the expected behavior (unfortunately; believe me I understand it's not convenient, but it's still better than before). You should switch back to English before 4.
Author
Owner

@o-sdn-o commented on GitHub (Mar 6, 2025):

You should switch back to English before 4.

Oops, sorry, everything is correct and definitely works. I wrote that it doesn't work because for some unknown reason I was convinced that Ctrl+C (and any other keys with the Ctrl modifier) ​​should work regardless of the layout.

@o-sdn-o commented on GitHub (Mar 6, 2025): > You should switch back to English before 4. Oops, sorry, everything is correct and definitely works. I wrote that it doesn't work because for some unknown reason I was convinced that Ctrl+C (and any other keys with the Ctrl modifier) ​​should work regardless of the layout.
Author
Owner

@ForNeVeR commented on GitHub (Mar 6, 2025):

I am convinced that it should work as well.

The problem is that it doesn't work like this, and there are complicated reasons behind that.

(My understanding is that it is expected to be different between keyboard layouts: some keyboard layouts traditionally follow the convention of using US keys for everything, some aren't, and we do not have any comprehensive lists of these categories yet.)

The fix is that PSReadline now follows the keyboard layout change.

Previously, it was remembering the active layout when Ctrl+C (I think?) was pressed for the first time during PowerShell session, and using that layout for all the future key presses. So, you start pwsh with Russian layout (or some others), you press Ctrl+C, it doesn't work and you are screwed for the whole shell session duration — it will never work in same session again, even if you switch the layout to English. The only exit is to restart the shell.

After my fix, you are no longer terminally screwed after hitting Ctrl+C once and getting the wrong result — you can switch the layout to English, and Ctrl+C will work for you again. In the same shell session!

It is not ideal because you are correct: it should work regardless of the chosen layout, at least for pair RU/EN.

But we are not there, yet.

And this is already better than nothing (arguably? Feel free to tell your honest feedback on the change).

@ForNeVeR commented on GitHub (Mar 6, 2025): I am convinced that it _should_ work as well. The problem is that it doesn't work like this, and there are complicated reasons behind that. (My understanding is that it is expected to be different between keyboard layouts: some keyboard layouts traditionally follow the convention of using US keys for everything, some aren't, and we do not have any comprehensive lists of these categories yet.) The fix is that PSReadline now follows the keyboard layout change. Previously, it was remembering the active layout when `Ctrl+C` (I think?) was pressed for the first time during PowerShell session, and using that layout for all the future key presses. So, you start `pwsh` with Russian layout (or some others), you press `Ctrl+C`, it doesn't work _and you are screwed_ for the whole shell session duration — it will never work in same session again, even if you switch the layout to English. The only exit is to restart the shell. After my fix, you are _no longer_ terminally screwed after hitting `Ctrl+C` once and getting the wrong result — you can switch the layout to English, and `Ctrl+C` will work for you again. In the same shell session! It is not ideal because you are correct: _it should work regardless of the chosen layout_, at least for pair RU/EN. But we are not there, yet. And this is already better than nothing (arguably? Feel free to tell your honest feedback on the change).
Author
Owner

@o-sdn-o commented on GitHub (Mar 6, 2025):

I completely agree with you. Thank you for what you do.

@o-sdn-o commented on GitHub (Mar 6, 2025): I completely agree with you. Thank you for what you do.
Author
Owner

@j4james commented on GitHub (Mar 6, 2025):

FYI, you can see how we handle this in Windows Terminal (when converting keyboard events to VT input sequences) in the code here:
3760caed97/src/terminal/input/terminalInput.cpp (L301-L309)

We first attempt to generate a control code from the base character reported by the keyboard layout for the key (the charSequence in the code above), and if that doesn't work, we try again with the virtual key code.

So with a Russian keyboard layout, when you press Ctrl+C, it's first going to attempt to convert the Cyrillic с into a control code. And when that fails, it tries again with the virtual key code, which in this case should be 0x43 (i.e. ASCII C), so that succeeds.

@j4james commented on GitHub (Mar 6, 2025): FYI, you can see how we handle this in Windows Terminal (when converting keyboard events to VT input sequences) in the code here: https://github.com/microsoft/terminal/blob/3760caed97fa9140a40777a8fbc1c95785e6d2ab/src/terminal/input/terminalInput.cpp#L301-L309 We first attempt to generate a control code from the base character reported by the keyboard layout for the key (the `charSequence` in the code above), and if that doesn't work, we try again with the virtual key code. So with a Russian keyboard layout, when you press <kbd>Ctrl</kbd>+<kbd>C</kbd>, it's first going to attempt to convert the Cyrillic `с` into a control code. And when that fails, it tries again with the virtual key code, which in this case should be 0x43 (i.e. ASCII `C`), so that succeeds.
Author
Owner

@ForNeVeR commented on GitHub (Mar 7, 2025):

Thank you, that is very useful and interesting insight! I'll investigate if it's possible to take a similar approach in PSReadline.

@ForNeVeR commented on GitHub (Mar 7, 2025): Thank you, that is very useful and interesting insight! I'll investigate if it's possible to take a similar approach in PSReadline.
Author
Owner

@a-kachurin commented on GitHub (Oct 16, 2025):

Same there(
Win11 25h2 PSReadLine 2.4.1

@a-kachurin commented on GitHub (Oct 16, 2025): Same there( Win11 25h2 PSReadLine 2.4.1
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#21635