ConPTY: transmit DECSET/DECRST state when client application enters/exits ENABLE_VIRTUAL_TERMINAL_INPUT mode #9537

Open
opened 2026-01-31 01:57:00 +00:00 by claunia · 9 comments
Owner

Originally created by @DHowett on GitHub (Jul 10, 2020).

Certain applications (mainly those using the Cygwin/MSYS runtime) will attempt to change VT input parameters while VT input is technically off. Because we do nothing to communicate the expected VT input parameters to a connected terminal before we turn on VT input passthrough, it's possible for the connected terminal to disagree with the conhost acting as its pty host.

When the application enters ENABLE_VIRTUAL_TERMINAL_INPUT mode, ConPTY should send a string of DECSET/DECRST sequences to bring the connected terminal in line with it to keep up the illusion of passthrough.

Notes from #6737:

From the Terminal's perspective, ENABLE_VIRTUAL_TERMINAL_INPUT is always on. It can't be lost/forgotten, because the terminal only generates VT. In general, it always has conhost sitting between it and the application to do translation from VT input. There are cases when the conhost sitting in the middle enters passthrough mode and dumps input straight out of terminal into the application.
Therefore, Terminal needs to be aware of DECCKM. Whether it receives DECCKM and therefore whether it generates the right cursor keys, however, is based on whether the application has requested ENABLE_VIRTUAL_TERMINAL_INPUT.
(There are applications that ask for DECCKM or other VT input format changes but are not in VT input mode, and sending them that data will freak them out.)

For WT 1.0, here's the matrix of behaviors.

ActionVT Output ModeVT Input ModeNotes
Application prints \e[?1h VT output is off, request ignored
conhost (PTY) (only) enables DECCKM
conhost (PTY) _and Terminal_ enable DECCKM
ActionVT Output ModeVT Input ModePTY in DECCKM modeTerminal in DECCKM modeNotes
User presses arrow key Terminal emits \e[A or \eOA
conhost (PTY) translates it into KEY_EVENT_RECORD
Terminal emits \e[A
conhost (PTY) translates it into KEY_EVENT_RECORD
Terminal emits \eOA
conhost (PTY) translates it into KEY_EVENT_RECORD
passthrough mode Terminal emits \e[A
conhost (PTY) passes it through unmodified
Terminal emits \eOA
conhost (PTY) passes it through unmodified
BEHAVIORS BEFORE TERMINAL 1.0
ActionVT Output ModeVT Input ModeNotes
Application prints \e[?1h VT output is off, request ignored
conhost (PTY) (only) enables DECCKM
ActionVT Output ModeVT Input ModePTY in DECCKM modeNotes
User presses arrow key ignored Terminal emits \e[A
conhost (PTY) translates it into KEY_EVENT_RECORD
Terminal emits \e[A
conhost (PTY) translates it into \e[A
Terminal emits \e[A
conhost (PTY) translates it into \e[OA

@DHowett

Okay, I'm literally seeing this behavior at the PTY:

  • Input Mode = 0x9
  • Input Mode = 0x209
  • Input Mode = 0x9
  • Print out DECCKM
  • Input Mode = 0x209
  • Input Mode = 0x9

This happens with printf, this happens with less's startup (though it prints more than just DECCKM)`, this happens pretty much every time I launch a process.

It's quite literally disabling VT input mode only while it is changing the input configuration. If we'd ever made the console more strict ("VT input mode changes only apply when VT input mode is on"), this would break horribly. I wonder why they'd do this?
@DHowett

Whether it receives DECCKM and therefore whether it generates the right cursor keys, however, is based on whether the application has requested ENABLE_VIRTUAL_TERMINAL_INPUT.

I totally did not expect that. If ENABLE_VIRTUAL_TERMINAL_INPUT is designed to affect which control sequences a pseudoconsole forwards from WriteConsole to the terminal, it is worth documenting.

This regressed with #6485

Why doesn't Windows Terminal Preview 1.1.1812.0 have the same problem, then? 6ff8ba7 was cherry-picked from 5e2c4c6, which is included in that version.
@KalleOlaviNiemitalo

Originally created by @DHowett on GitHub (Jul 10, 2020). Certain applications (mainly those using the Cygwin/MSYS runtime) will attempt to change VT input parameters while VT input is technically off. Because we do nothing to communicate the expected VT input parameters to a connected terminal before we _turn on VT input passthrough_, it's possible for the connected terminal to disagree with the conhost acting as its pty host. When the application enters `ENABLE_VIRTUAL_TERMINAL_INPUT` mode, ConPTY should send a string of `DECSET`/`DECRST` sequences to bring the connected terminal in line with it to keep up the illusion of passthrough. Notes from #6737: > From the Terminal's perspective, `ENABLE_VIRTUAL_TERMINAL_INPUT` is always on. It can't be lost/forgotten, because the terminal only generates VT. In general, it always has conhost sitting between it and the application to do translation from VT input. There are cases when the conhost sitting in the middle enters passthrough mode and dumps input straight out of terminal into the application. > Therefore, Terminal needs to be aware of DECCKM. Whether it receives `DECCKM` and therefore whether it _generates the right cursor keys_, however, is based on whether the application has requested `ENABLE_VIRTUAL_TERMINAL_INPUT`. > (There are applications that ask for DECCKM or other VT input format changes but are _not in VT input mode_, and sending them that data will freak them out.) > > For WT 1.0, here's the matrix of behaviors. > > <table><tbody> > <tr><th>Action</th><th>VT Output Mode</th><th>VT Input Mode</th><th>Notes</th></tr> > <tr> > <td rowspan="4">Application prints <code>\e[?1h</code></td> > <td>❌</td> > <td>❌</td> > <td rowspan="2">VT output is off, request ignored</td> > </tr> > <tr> > <td>❌</td> > <td>✅</td> > <!-- rowspanned --> > </tr> > <tr> > <!--<td rowspan="1">Application prints `\e[?1h`</td>--> > <td>✅</td> > <td>❌</td> > <td>conhost (PTY) (only) enables DECCKM</td> > </tr> > <tr> > <!--<td rowspan="1">Application prints `\e[?1h`</td>--> > <td>✅</td> > <td>✅</td> > <td>conhost (PTY) _and Terminal_ enable DECCKM</td> > </tr> > </tbody></table> > <table><tbody> > <tr><th>Action</th><th>VT Output Mode</th><th>VT Input Mode</th><th>PTY in DECCKM mode</th><th>Terminal in DECCKM mode</th><th>Notes</th></tr> > <tr> > <td rowspan="8">User presses arrow key</td> > <td>❌</td> > <td>❌</td> > <td>❌</td> > <td>❌</td> > <td>Terminal emits <code>\e[A</code> or <code>\eOA</code><br>conhost (PTY) translates it into KEY_EVENT_RECORD</td> > </tr> > <tr> > <!--<td rowspan="1">Application prints `\e[?1h`</td>--> > <td>✅</td> > <td>❌</td> > <td>✅</td> > <td>❌</td> > <td>Terminal emits <code>\e[A</code><br>conhost (PTY) translates it into KEY_EVENT_RECORD</td> > </tr> > <tr> > <!--<td rowspan="1">Application prints `\e[?1h`</td>--> > <td>✅</td> > <td>❌</td> > <td>✅</td> > <td>✅</td> > <td>Terminal emits <code>\eOA</code><br>conhost (PTY) translates it into KEY_EVENT_RECORD</td> > </tr> > <tr> > <!--<td rowspan="1">Application prints `\e[?1h`</td>--> > <td>✅</td> > <td>✅</td> > <td rowspan="4"><em>passthrough mode</em></td> > <td>❌</td> > <td rowspan="2">Terminal emits <code>\e[A</code><br>conhost (PTY) <b>passes it through unmodified</b></td> > </tr> > <tr> > <!--<td rowspan="1">Application prints `\e[?1h`</td>--> > <td>❌</td> > <td>✅</td> > <!-- rowspanned --> > <td>❌</td> > <!-- rowspanned --> > </tr> > <tr> > <!--<td rowspan="1">Application prints `\e[?1h`</td>--> > <td>✅</td> > <td>✅</td> > <!-- rowspanned --> > <td>✅</td> > <td rowspan="2">Terminal emits <code>\eOA</code><br>conhost (PTY) <b>passes it through unmodified</b></td> > </tr> > <tr> > <!--<td rowspan="1">Application prints `\e[?1h`</td>--> > <td>❌</td> > <td>✅</td> > <!-- rowspanned --> > <td>✅</td> > <!-- rowspanned --> > </tr> > </tbody></table> > > <details> > <summary>BEHAVIORS BEFORE TERMINAL 1.0</summary> > > <table><tbody> > <tr><th>Action</th><th>VT Output Mode</th><th>VT Input Mode</th><th>Notes</th></tr> > <tr> > <td rowspan="4">Application prints <code>\e[?1h</code></td> > <td>❌</td> > <td>❌</td> > <td rowspan="2">VT output is off, request ignored</td> > </tr> > <tr> > <td>❌</td> > <td>✅</td> > <!-- rowspanned --> > </tr> > <tr> > <!--<td rowspan="1">Application prints `\e[?1h`</td>--> > <td>✅</td> > <td>❌</td> > <td rowspan="2">conhost (PTY) (only) enables DECCKM</td> > </tr> > <tr> > <!--<td rowspan="1">Application prints `\e[?1h`</td>--> > <td>✅</td> > <td>✅</td> > <!-- rowspanned --> > </tr> > </tbody></table> > <table><tbody> > <tr><th>Action</th><th>VT Output Mode</th><th>VT Input Mode</th><th>PTY in DECCKM mode</th><th>Notes</th></tr> > <tr> > <td rowspan="8">User presses arrow key</td> > <td>❌</td> > <td>❌</td> > <td rowspan="2"><em>ignored</em></td> > <td rowspan="2">Terminal emits <code>\e[A</code><br>conhost (PTY) translates it into KEY_EVENT_RECORD</td> > </tr> > <tr> > <!--<td rowspan="1">Application prints `\e[?1h`</td>--> > <td>✅</td> > <td>❌</td> > <!-- rowspanned --> > <!-- rowspanned --> > </tr> > <tr> > <!--<td rowspan="1">Application prints `\e[?1h`</td>--> > <td>❌</td> > <td>✅</td> > <td>❌</td> > <td rowspan="2">Terminal emits <code>\e[A</code><br>conhost (PTY) translates it into <code>\e[A</code></td> > </tr> > <tr> > <!--<td rowspan="1">Application prints `\e[?1h`</td>--> > <td>✅</td> > <td>✅</td> > <td>❌</td> > <!-- rowspanned --> > </tr> > <tr> > <!--<td rowspan="1">Application prints `\e[?1h`</td>--> > <td>❌</td> > <td>✅</td> > <td>✅</td> > <td rowspan="2">Terminal emits <code>\e[A</code><br>conhost (PTY) translates it into <code>\e[OA</code></td> > </tr> > <tr> > <!--<td rowspan="1">Application prints `\e[?1h`</td>--> > <td>✅</td> > <td>✅</td> > <td>✅</td> > <!-- rowspanned --> > </tr> > </tbody></table> > > </details> > _@DHowett_ > Okay, I'm literally seeing this behavior at the PTY: > > * Input Mode = 0x9 > * Input Mode = 0x209 > * Input Mode = 0x9 > * Print out `DECCKM` > * Input Mode = 0x209 > * Input Mode = 0x9 > > This happens with `printf`, this happens with less's startup (though it prints more than just DECCKM)`, this happens pretty much every time I launch a process. > > It's quite literally disabling VT input mode _only while it is changing the input configuration_. If we'd ever made the console more strict ("VT input mode changes only apply when VT input mode is on"), this would break horribly. I wonder why they'd do this? > _@DHowett_ > > Whether it receives `DECCKM` and therefore whether it _generates the right cursor keys_, however, is based on whether the application has requested `ENABLE_VIRTUAL_TERMINAL_INPUT`. > > I totally did not expect that. If `ENABLE_VIRTUAL_TERMINAL_INPUT` is designed to affect which control sequences a pseudoconsole forwards from `WriteConsole` to the terminal, it is worth documenting. > > > This regressed with #6485 > > Why doesn't Windows Terminal Preview 1.1.1812.0 have the same problem, then? [6ff8ba7](https://github.com/microsoft/terminal/commit/6ff8ba772890bf8abb8431295fe97c8e9e280dcb) was cherry-picked from [5e2c4c6](https://github.com/microsoft/terminal/commit/5e2c4c66e3dcb66c9d60769a2a028e39711168fd), which is included in that version. > _@KalleOlaviNiemitalo_
claunia added the Issue-BugArea-InputProduct-ConptyPriority-2 labels 2026-01-31 01:57:00 +00:00
Author
Owner

@RokyBanana commented on GitHub (Jul 16, 2020):

Is there an ETA on this or do I have to downgrade?

I have no problem using the terminal in VS Code, but that's not a solution.

@RokyBanana commented on GitHub (Jul 16, 2020): Is there an ETA on this or do I have to downgrade? I have no problem using the terminal in VS Code, but that's not a solution.
Author
Owner

@DHowett commented on GitHub (Jul 16, 2020):

Use the preview version where this isn’t a problem?

@DHowett commented on GitHub (Jul 16, 2020): Use the preview version where this isn’t a problem?
Author
Owner

@RokyBanana commented on GitHub (Jul 16, 2020):

Use the preview version where this isn’t a problem?

Have I missed a download? In that case I'm sorry. I'm currenty running "Git for Windows 2.27.0.windows.1 (64bit)".

@RokyBanana commented on GitHub (Jul 16, 2020): > Use the preview version where this isn’t a problem? Have I missed a download? In that case I'm sorry. I'm currenty running "Git for Windows 2.27.0.windows.1 (64bit)".
Author
Owner

@DHowett commented on GitHub (Jul 16, 2020):

Oh, sorry! Windows Terminal Preview 1.1+, which should be released to the stable channel soon, doesn’t exhibit this issue. Note if you switch today that it won’t migrate your settings from the Release branch. It’s still pretty stable; we all use it every day to make sure we’re the most exposed to any weird issues it might have. 😄

@DHowett commented on GitHub (Jul 16, 2020): Oh, sorry! [Windows Terminal Preview](https://aka.ms/terminal-preview) 1.1+, which should be released to the stable channel soon, doesn’t exhibit this issue. Note if you switch today that it won’t migrate your settings from the Release branch. It’s still pretty stable; we all use it every day to make sure we’re the most exposed to any weird issues it might have. :smile:
Author
Owner

@DHowett commented on GitHub (Jul 19, 2020):

This is wild!

cygwin/msys2 sets and resets ENABLE_VIRTUAL_TERMINAL_INPUT not on every process launch, but for literally every character that's typed.

When we emit DECSET/DECRST for every state transition (to make sure the connected terminal does the right thing even outside of win32 input mode), each byte input into a msys2 application results in about 200 bytes of control sequences just to maintain terminal state.

(@kalleolaviniemitalo might find this interesting, even if just because they've been helping out with some VT_INPUT issues 😄)

@DHowett commented on GitHub (Jul 19, 2020): This is wild! _cygwin/msys2 sets and resets `ENABLE_VIRTUAL_TERMINAL_INPUT` not on every process launch, but for literally every character that's typed._ When we emit DECSET/DECRST for every state transition (to make sure the connected terminal does the right thing even outside of win32 input mode), each byte input into a msys2 application results in about 200 bytes of control sequences just to maintain terminal state. (@kalleolaviniemitalo might find this interesting, even if just because they've been helping out with some VT_INPUT issues :smile:)
Author
Owner

@lazka commented on GitHub (Aug 2, 2020):

(@tyan0 is working in this area in cygwin, mentioning here in case he wants to chime in)

@lazka commented on GitHub (Aug 2, 2020): (@tyan0 is working in this area in cygwin, mentioning here in case he wants to chime in)
Author
Owner

@dsm1212 commented on GitHub (Sep 28, 2020):

I'm don't quite follow this here, but this keeps happening to my terminal. I launch a new one and it is fine for a while, but eventually arrow keys stop working. 4.4.23(1) Release. Same issue as reported here?

@dsm1212 commented on GitHub (Sep 28, 2020): I'm don't quite follow this here, but this keeps happening to my terminal. I launch a new one and it is fine for a while, but eventually arrow keys stop working. 4.4.23(1) Release. Same issue as reported here?
Author
Owner

@hlovdal commented on GitHub (Feb 16, 2021):

Any progress on this?

@hlovdal commented on GitHub (Feb 16, 2021): Any progress on this?
Author
Owner

@zadjii-msft commented on GitHub (Feb 16, 2021):

@hlovdal Nope. We'll make sure to update this thread when there is. In the meantime, might I recommend the Subscribe button?
image
That way you'll be notified of any updates to this thread, without needlessly pinging everyone on this thread ☺️

@zadjii-msft commented on GitHub (Feb 16, 2021): @hlovdal Nope. We'll make sure to update this thread when there is. In the meantime, might I recommend the Subscribe button? ![image](https://user-images.githubusercontent.com/18356694/91237459-5cbb0c80-e700-11ea-9347-b9b1ec2813b1.png) That way you'll be notified of any updates to this thread, without needlessly pinging everyone on this thread ☺️
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#9537