Skip to content

Linux pwsh enables DECCKM, but Windows pwsh cannot handle it; arrow keys stop working after exiting linux powershell #12268

Closed

Description

Steps to reproduce

  1. Use Windows PowerShell 7 and PowerShell 7 in WSL.
  2. Launch Windows Powershell in Windows Terminal
  3. Launch wsl, pwsh
  4. Exit Linux powershell
  5. Observe the arrow keys

Linux powershell emits the escape sequence DECSET DECCKM[1] on startup before it emits the first prompt.

This reconfigures the cursor keys, which usually emit CSI A...D, to emit SS3 A...D instead.

Linux powershell can handle SS3 arrow key sequences. This is fine.

When Linux powershell exits, it does not restore DECCKM to its original state. All applications that manipulate global terminal state are expected to return the terminal to "normal" once they are done.

Because the state is not restored when you exit Linux powershell, Windows powershell (which doesn't know that the terminal state has been changed) will start to receive SS3 arrow key sequences.

Windows powershell cannot handle SS3 arrow key sequences, and it ignores them, so the arrow keys do not work.

This also reproduces when you SSH to a linux machine, but WSL is easier for a self-contained repro.

Expected behavior

DECCKM is disabled on exit.

Actual behavior

DECCKM remains enabled on exit, downstream applications get confused.

Environment data

(dhowett-sl) ~ % $PSVersionTable

Name                           Value
----                           -----
PSVersion                      7.0.0
PSEdition                      Core
GitCommitId                    7.0.0
OS                             Microsoft Windows 10.0.19041
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

(dhowett-sl) ~ % wsl pwsh -c '\$PSVersionTable'

Name                           Value
----                           -----
PSVersion                      7.0.0
PSEdition                      Core
GitCommitId                    7.0.0
OS                             Linux 4.19.84-microsoft-standard #1 SMP Wed Nov 13 11:44:37 UTC 2019
Platform                       Unix
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

[1] Notes about DECCKM

CSI ? Pm h
          DEC Private Mode Set (DECSET).
            Ps = 1  ⇒  Application Cursor Keys (DECCKM), VT100.

DECCKM reconfigures the arrow keys as follows

Key            Normal     Application
-------------+----------+-------------
Cursor Up    | CSI A    | SS3 A
Cursor Down  | CSI B    | SS3 B
Cursor Right | CSI C    | SS3 C
Cursor Left  | CSI D    | SS3 D
-------------+----------+-------------

[2] I've investigated PowerShell, PSReadline and dotnet/runtime, and I cannot determine where DECCKM is being enabled.

Activity

  1. DHowett-MSFT commented on Apr 6, 2020

    @DHowett-MSFT
    Author

    Originally filed: microsoft/terminal#5257

  2. LookoutHill commented on Apr 6, 2020

    @LookoutHill

    Dustin L. Howett (MSFT) (@DHowett-MSFT) As a workaround it seems like one could create a script that would emit the appropriate reset sequence. Would you post this sequence in PowerShell string format?

  3. DHowett-MSFT commented on Apr 6, 2020

    @DHowett-MSFT
    Author
    "`e[?1l"
    
  4. LookoutHill commented on Apr 6, 2020

    @LookoutHill

    Thanks for that. It gave me enough info to interpret this arcane knowledge. That sequence doesn't restore functionality, but the "Reset to Initial State" sequence ("`ec") does.

  5. DHowett-MSFT commented on Apr 6, 2020

    @DHowett-MSFT
    Author

    It legitimately looks like it's being stripped out of the output.

    When I type this:

    (dhowett-sl) ~ % "a`e[?1lb"
    

    I get this out of the pty:

    ab
    

    but when I run this:

    (dhowett-sl) ~ % wsl printf 'a\\e[?1lb'
    

    I get

    a␛[?1lb
    

    I wonder why it's being filtered from powershell's output stream. Similar sequences, like "`e[?2004l", are not.

  6. DHowett-MSFT commented on Apr 6, 2020

    @DHowett-MSFT
    Author

    As a workaround, you can do this:

    "`e[?;1l"
    

    Masking that you're requesting DECRST 1 by placing a ; before it confuses powershell, but Terminal can understand it.

  7. iSazonov commented on Apr 7, 2020

    @iSazonov
    Collaborator

    I've investigated PowerShell, PSReadline and dotnet/runtime, and I cannot determine where DECCKM is being enabled.

    Wow!
    /cc Dongbo Wang (@daxian-dbw) who have huge experience in the area.

  8. DHowett-MSFT commented on Apr 8, 2020

    @DHowett-MSFT
    Author

    Of note, this reproduces without PSReadline available 😄

    (I tracked down why I can't forcibly print "`e[?1l" -- PowerShell isn't using VT input on Windows, so that value is technically meaningless to it. Conhost is ignoring it.)

  9. lukaszroz commented on Sep 1, 2020

    @lukaszroz

    I have come across this bug when I SSH from Ubuntu to Windows machine. It works when I SSH from Bash without starting PowerShell. To reproduce in PowerShell on Ubuntu in Gnome Terminal:

    $ cat #try up/down/right/left arrow, Enter, Ctrl-D
    ^[[A^[[B^[[C^[[D
    
    $ pwsh
    PowerShell 7.0.3
    > ssh user@host
    PowerShell 7.0.3
    > exit #arrow keys don't work
    Connection to host  closed.
    > exit
    $ cat #try up/down/right/left arrow, Enter, Ctrl-D
    ^[OA^[OB^[OC^[OD
    ABCD
    

    After some digging I have found dotnet/corefx#6488. The Pull Request fixed a number of bugs related to terminal escape codes handling. It seems to me the DECCKM might be set in System.Console, see lines 937 - 947

  10. lukaszroz commented on Sep 1, 2020

    @lukaszroz

    Found the issue: dotnet/runtime#27626

  11. DHowett commented on Sep 1, 2020

    @DHowett

    Excellent investigation. Thanks!

  12. tig commented on Oct 21, 2020

    @tig

    Tagging TylerLeonhardt so he's aware of this relative to https://github.com/PowerShell/GraphicalTools

    Specifically, this is why out-consolegridview has issues on Linux where the cursor keys don't work after using it. Related to PowerShell/ConsoleGuiTools#99.

    GitHub
    A module that mixes PowerShell and GUIs! - built on Avalonia and gui.cs - PowerShell/GraphicalTools
  13. 16 remaining items

  14. wez commented on Mar 4, 2021

    @wez

    Please also disable that mode when running child processes!

  15. iSazonov commented on Mar 4, 2021

    @iSazonov
    Collaborator

    Wez Furlong (@wez) Welcome to review #14943. You can download artifacts there and check its locally.

  16. wez commented on Mar 4, 2021

    @wez

    I don't particularly want to dive into the code in powershell; I'm here because cli/cli#3071 was initially reported as a bug in my terminal emulator :-p

    The test scenario is:

    • on macos
    • launch powershell
    • inside powershell, run gh auth login
    • The unexpected cursor key encoding causes that program to crash
  17. iSazonov commented on Mar 4, 2021

    @iSazonov
    Collaborator

    Wez Furlong (@wez) You can just download the compiled artifacts, tests them in your environment and give a feedback before the PR will be merged.

  18. mklement0 commented on Mar 4, 2021

    @mklement0
    Contributor

    Wez Furlong (@wez), you can emulate what the PR will implement as follows:

    $Host.UI.Write("`e[?1l"); gh auth login; $Host.UI.Write("`e[?1h")

    For entire-session support - as a stopgap that should also work for older PS versions - you can place the following at the end of your $PROFILE file (assumes use of PSReadLine, which is true by default):

    # Turns application-key mode ON before displaying the PS prompt and back OFF right after.
    $function:PSConsoleHostReadLine = " `$Host.UI.Write(`"``e[?1h`"); $function:PSConsoleHostReadLine; `$Host.UI.Write(`"``e[?1l`") "
    # For non-interactive invocations of the PowerShell CLI: turn application-key mode off too, 
    # So that it is left OFF on exiting (obviously won't work for -NoProfile invocations).
    $Host.UI.Write("`e[?1l")
  19. wez commented on Mar 4, 2021

    @wez

    Thanks, but I don't use powershell; as I mentioned above, I'm just here because this issue was raised by one of the users of my terminal. Bernát Gábor (@gaborbernat): perhaps you could try those suggestions?

  20. gaborbernat commented on Mar 4, 2021

    @gaborbernat

    I can confirm that Michael Klement (@mklement0) solution works on:

    Name                           Value
    ----                           -----
    PSVersion                      7.1.2
    PSEdition                      Core
    GitCommitId                    7.1.2
    OS                             Darwin 19.6.0 Darwin Kernel Version 19.6.0: Tue Nov 10 00:10:30 PST 2020; root:xnu-6153.141.10~1/RELEASE_X86_64
    Platform                       Unix
    PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
    PSRemotingProtocolVersion      2.3
    SerializationVersion           1.1.0.1
    WSManStackVersion              3.0
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions