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

Created on 6 Apr 2020  ·  13Comments  ·  Source: PowerShell/PowerShell

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.

Issue-Question OS-Linux WG-Interactive-Console

All 13 comments

@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?

"`e[?1l"

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.

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.

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.

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

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

Of note, this reproduces without PSReadline available :smile:

(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.)

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

Excellent investigation. Thanks!

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 https://github.com/PowerShell/GraphicalTools/issues/99.

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

This also reproduces when you SSH to a linux machine

There is another case, namely an "intra-Unix" one:

The cursor keys in ksh only work if application-cursor mode is _off_ (keypad_local / rmkx)

Since PowerShell unconditionally turns that mode _on_ (keypad_transmit / smkx), even a simple call to the PowerShell CLI such as
pwsh -noprofile -c 'get-date'
breaks cursor-key handling in ksh.

(bash and zsh are _not_ affected, because they work in _either_ mode.)

Was this page helpful?
0 / 5 - 0 ratings