microsoft / terminal

The new Windows Terminal and the original Windows console host, all in the same place!
MIT License
95.02k stars 8.23k forks source link

Some keybindings used by PSReadLine aren't getting through #879

Closed DJackman123 closed 4 years ago

DJackman123 commented 5 years ago

Environment

Windows build number: 10.0.18362.86
Windows Terminal version (if applicable): 0.1.1361.0

Any other software?

Steps to reproduce

Open a PowerShell tab in Windows Terminal. Attempt to use these PSReadLine key bindings (use the Get-PSReadLineKeyHandler command to see a list of all key bindings):

Expected behavior

Key executes the specified PSReadLine function.

Actual behavior

Nothing happens (or the current tab changes in the case of Alt+digit)

DHowett-MSFT commented 5 years ago

This is likely a duplicate of #530 but with more information

DHowett-MSFT commented 5 years ago

TL;DR: There are actually some things that just cannot be represented via VT sequences, (Shift-Ctrl-Enter, Shift-[anything that isn't a letter/number]), and for which we'll need to devise or extend a standard.

oising commented 5 years ago

@dhowett-msft -- I was thinking about this before and there is a VT200+ command, DECUDK for user-defined keys. Normally this is limited to fifteen of the terminal's top-row function keys: F6 through F14, Do, Help, and F17 through F20. They are only triggered by using shift: e.g. shift+F6 will emit the user defined sequence, but F6 alone remains F6. What if we extended this scheme to cover Enter, Backspace, Del etc? The devil is in the details but it's somewhat consistent and keeps shift as an independently inert key in VT land. I'm not sure how this might work with respect to shift+ctrl+enter, since we'd be redefining ctrl+enter, not just enter. Unless we choose to read that as shift+enter is an entirely new key, and that ctrl is a modifier for that. Hmmm.

zadjii-msft commented 5 years ago

In my opinion, the right way to fix this is to add support for full INPUT_RECORDs via VT, at least between the Terminal and Conpty. This'll let the terminal act just like conhost in terms of keypresses, but requires a decent amount of work.

The other potential trick here is how do we get full INPUT_RECORDs in UWP? Doesn't seem to me like all the state we'd want is actually exposed, so we might have to live with "good enough" INPUT_RECORD synthesis, and only fill in the info we can gather.

oising commented 5 years ago

@zadjii-msft As long as it doesn't become a nest of windows-specific magic. One of the goals of ConPTY is to allow anyone to write a drop-in replacement terminal that speaks VT. If it has to speak WinAPI then I think we've failed somewhere along the way.

zadjii-msft commented 5 years ago

Oh I'm very aware of that. I think this is primarily a case of making sure that Windows-specific programs running attached to a conpty terminal can still behave the way they used to, if the terminal is capable of acting as a Windows-specific terminal.

The alternative is driving with PSReadline to stop using those keychords, because they won't work on *nix. Kinda curious that this is still a problem at all, with all the cross-platform stuff powershell is working on. I woulda thought they changed those keybindings. I guess them changing the defaults won't prevent people from setting them back to what they like, even if they don't work cross-platform.

DJackman123 commented 5 years ago

The problem with pushing it back to PSReadLine to change its default keybindings is that the whole reason these particular bindings were used was to make the text editing experience in PowerShell consistent with other text editors (like Visual Studio). That's the case for keybindings like Ctrl+Backspace, Ctrl+Space, PageUp, and PageDown especially.

lzybkr commented 5 years ago

Alacritty has an interesting solution to this problem. They support remapping keys (from the OS point of view) to arbitrary character (VT) sequences. See their default config file.

This would still require custom key bindings in PSReadLine or similar applications. For example, in my alacritty.yml, I might add:

  # Replace Ctrl+Space with F12,a
  - { key: Space,    mods: Control,   chars: "\x1b[24~a"                     }

Then in my PowerShell profile I might add:

Set-PSReadLineKeyHandler -Chord 'F12,a' -Function MenuComplete
oising commented 5 years ago

It turns out that the xterm guys may have a more generalized approach for dealing with modifiers:

CSI > Ps ; Ps m
          Set or reset resource-values used by xterm to decide whether
          to construct escape sequences holding information about the
          modifiers pressed with a given key.

          The first parameter identifies the resource to set/reset.  The
          second parameter is the value to assign to the resource.

          If the second parameter is omitted, the resource is reset to
          its initial value.

            Ps = 0  -> modifyKeyboard.
            Ps = 1  -> modifyCursorKeys.
            Ps = 2  -> modifyFunctionKeys.
            Ps = 4  -> modifyOtherKeys.

          If no parameters are given, all resources are reset to their
          initial values.

I know we're trying not to step too far outside DEC VT stuff, but xterm is the de-facto standard. I don't think we should aim to emulate xterm, but we definitely need to take on enough to solve our open problems. Anyway, this seems to imply that xterm has a scheme for passing modifiers for all keys, not just shifted f5-f20 on vanilla DEC hardware.

Thoughts?

zadjii-msft commented 5 years ago

Oh, that's a really good idea. We'd need to add support to conpty for parsing them, but that shouldn't be impossible.

oising commented 5 years ago

Just to add more to the mix, here's Kitty's approach: https://sw.kovidgoyal.net/kitty/protocol-extensions.html#keyboard-handling

The escape sequence encodes the following properties: Type of event: press,repeat,release Modifiers pressed at the time of the event The actual key being pressed

As you can see, they've got a pretty good analog of how we already encode things with INPUT_RECORD. I'm curious if xterm does the same.

miniksa commented 5 years ago

I generally prefer the xterm way. xterm is the de facto standard for terminal communication. Generally any valid VT parser should discard those particular CSIs if they don't understand them. And if we can get away with solving the problem without going fully toward the INPUT_RECORD model, then I think we should.

However, Kitty's approach does seem pretty decent if we do indeed end up having to do something like INPUT_RECORD. There looks to be a provision to reset out of the special mode... but I would say that not a ton of applications/terminals/users are expecting or ready to do a reset when things go wrong. And if a reset doesn't occur... we could be causing strange things to happen.

I think this won't become clear until we choose a path and start down it by trying it out. At which point, I'd encourage the xterm-style way first until proven otherwise.

If anything, I think we should probably accept both methods as input to our system but only actively try to emit the xterm way out of the pty interface until proven otherwise.

oising commented 5 years ago

Agree @miniksa -- the Kitty guy's protocol using Application Program Commands (APC) is pretty neat, but it's de-facto making anything that parses them a "KittyApp"(tm) and not a VT app. I guess Xterm are doing the same thing, but they are the Gold Standard. APC is meant for VT apps to signal each other, and should be ignored (never echoed) by terminals (although DEC does use some APCs itself, namely DECEKBD -- extended keyboard report.) That said, it's a open, well-known way to do internal signalling, if needed.

ocalvo commented 5 years ago

Just want to point out that legacy tools like ZtreeWin are very hard to impossible to use under Windows Terminal without some kind of support for direct raw input.

DHowett-MSFT commented 5 years ago

Here's a thought: could this instead just be a profile setting? "I want to run a legacy thing like ZTW" => "do the raw input dance"

Tyriar commented 5 years ago

Just throwing my vote in for the xterm way. xterm.js doesn't implement CSI > Ps ; Ps m yet, but if it helps solve this issue we definitely would.

j4james commented 4 years ago

Another option to consider would be the VT510 PCTerm mode (enabled with DECPCTERM), where the keyboard generates a unique scancode (typically one byte) for both the press and release of every key. With that you should be able to handle any key combination imaginable.

You can see a list of the scan codes here: https://vt100.net/docs/vt510-rm/chapter8.html#S8.13

oising commented 4 years ago

Another option to consider would be the VT510 PCTerm mode (enabled with DECPCTERM), where the keyboard generates a unique scancode (typically one byte) for both the press and release of every key. With that you should be able to handle any key combination imaginable.

You can see a list of the scan codes here: https://vt100.net/docs/vt510-rm/chapter8.html#S8.13

Man, DEC really were the masters of having twenty different ways to do something. I hadn't seen this before. Very interesting.

factormystic commented 4 years ago

Just curious, how come this works okay in conhost? Is it because that is working with raw input, whereas terminal is only processing characters?

zadjii-msft commented 4 years ago

@factormystic basically, yes. The full story's much more complicated, but that's definitely the tl;dr version.


For my future sanity, the text on invisible-island changed:

CSI > Pp ; Pv m
CSI > Pp m
          Set/reset key modifier options, xterm.  Set or reset resource-
          values used by xterm to decide whether to construct escape
          sequences holding information about the modifiers pressed with
          a given key.

          The first parameter Pp identifies the resource to set/reset.
          The second parameter Pv is the value to assign to the
          resource.

          If the second parameter is omitted, the resource is reset to
          its initial value.  Values 3  and 5  are reserved for keypad-
          keys and string-keys.

            Pp = 0  ⇒  modifyKeyboard.
            Pp = 1  ⇒  modifyCursorKeys.
            Pp = 2  ⇒  modifyFunctionKeys.
            Pp = 4  ⇒  modifyOtherKeys.

          If no parameters are given, all resources are reset to their
          initial values.

Also:

It seems to work in xterm, but maybe not gnome-terminal image

\x1[<something maybe>;<modifiers>;<char value>~

for <char value>: space == 32, A=65, a=97, etc

natebarkei commented 4 years ago

This seriously breaks the usability of terminal for powershell. I realize what I'm saying here doesn't really add to the solution. But even though this is a difficult problem, I feel that by not assigning this a higher priority for fixing, it shows a lack of concern for a basic mandatory feature of this program.

Please bump this higher in your stack of things to fix/solve!!

koron commented 4 years ago

3935 modified (fixed?) for Ctrl+Backspace only.

But it breaks Ctrl+h behavior for many applications.

TunerBuilder commented 4 years ago

Do we have any updates about this? I was really thrilled at the beginning about the project, but if basic functionalities such as CTRL + SPACE do not work, I don't see the point of using it.

zadjii-msft commented 4 years ago

When there are updates, we'll be sure to post here. We agree that this is a highly important feature, but it's one that unfortunately is going to take a lot of work to get quite right. It's a harder problem than just "add this keychord to the terminal" - it involves implementing an entire other input encoding to the conpty backend, and then also implementing a similar synthesis of input from the Terminal.

I've got this crazy thought that some of the work in #4856 might enable this keybinding for WSL applications, but it still won't work for Win32 console apps, like powershell.exe and pwsh.exe.

lzybkr commented 4 years ago

@zadjii-msft - PSReadLine supports VT input mode if you set $env:PSREADLINE_VTINPUT = 1. As it isn't the default, it's not widely tested. It could in fact be completely broken, but the person who implemented it was happy with using that mode under tmux.

zadjii-msft commented 4 years ago

@lzybkr Oh I didn't know that existed! That's certainly an interesting idea. Looks like with #4856 merged, we do pipe a NUL all the way through conpty to the client app for Ctrl+Space, but PSReadline doesn't accept it as the key for Ctrl+Space. It looks like it's being treated by PsReadline as Ctrl+@. That's perfectly understandable - they both have the same encoding in VT. Weirdly enough though, binding Ctrl-@ to MenuComplete still doesn't trigger it, event with #4856 merged and PSREADLINE_VTINPUT = 1 set.

lzybkr commented 4 years ago

It's probably an easy fix here.

yanoryuichi commented 4 years ago

Not sure it's already fixed in development, but CTRL-H doesn't work in Vim in my environment. It works in Command prompt, but not work in Windows Terminal when I use Vim.

awson commented 4 years ago

When I use Far Manager under the Terminal, RightCtrl+N (N is numeric key) keys don't work.

Is it a manifestation of this issue? (if yes, it's very sad, since makes Terminal unusable to host Far Manager)

DHowett-MSFT commented 4 years ago

Unfortunately, yes. Anything that requires modifiers alone or specific modifiers (right versus left) is covered by this issue.

ghost commented 4 years ago

:tada:This issue was addressed in #6309, which has now been successfully released as Windows Terminal Preview v1.1.1671.0.:tada:

Handy links: