Skip to content

Support CSI {key} u keys without modifiers#11364

Closed
trygveaa wants to merge 1 commit into
vim:masterfrom
trygveaa:support-csi-key-without-modifier
Closed

Support CSI {key} u keys without modifiers#11364
trygveaa wants to merge 1 commit into
vim:masterfrom
trygveaa:support-csi-key-without-modifier

Conversation

@trygveaa

Copy link
Copy Markdown
Contributor

The kitty terminal emulator, as well as some others, suppors sending keys as CSI {key} u, like the keys with modifiers that's already supported, but for keys without any modifiers. The most notable example is escape being sent as CSI 27 u, to be able to distinguish the key press from the start of an escape sequence. It's also used to support some "special" keys, like media keys and print screen.

The main reason for adding support for this is a problem with kitty and the existing key handling in vim. By default kitty has support for keys that are not traditionally supported in terminals, like super+, and sends those as keys with modifiers. E.g. super+q is CSI 113 ; 9 u. If I press such a key, vim sets seenModifyOtherKeys to true and stops processing normal control keys, so the bindings i have for those stops working because kitty sends them as normal control keys by default.

I can set kitty to send control keys as keys with modifiers by enabling disambiguate escape codes by sending CSI > 1 u. This makes the control keys work again. However, this also changes the escape key to be sent as CSI 27 u, so that stops working. By adding support for this, all keys work as far as I know.

The problem exists by default when I'm not enabling disambiguate escape codes though, so it would be nice if vim could enable this automatically. I think it should be safe to send it to any terminal emulator, but alternatively vim could query for support of the protocol by sending CSI ? u and check if it gets a reply like CSI ? flags u.

Note that none of the escape sequences I wrote actually contains spaces, they were just added for readability.

You can read more about the keyboard handling in kitty here: https://sw.kovidgoyal.net/kitty/keyboard-protocol/

There's also an issue in kitty's repo with some discussion here: kovidgoyal/kitty#4075

The kitty terminal emulator, as well as some others, suppors sending
keys as `CSI {key} u`, like the keys with modifiers that's already
supported, but for keys without any modifiers. The most notable example
is escape being sent as `CSI 27 u`, to be able to distinguish the key
press from the start of an escape sequence. It's also used to support
some "special" keys, like media keys and print screen.

The main reason for adding support for this is a problem with kitty and
the existing key handling in vim. By default kitty has support for keys
that are not traditionally supported in terminals, like super+<key>, and
sends those as keys with modifiers. E.g. super+q is `CSI 113 ; 9 u`. If
I press such a key, vim sets `seenModifyOtherKeys` to true and stops
processing normal control keys, so the bindings i have for those stops
working because kitty sends them as normal control keys by default.

I can set kitty to send control keys as keys with modifiers by enabling
disambiguate escape codes by sending `CSI > 1 u`. This makes the control
keys work again. However, this also changes the escape key to be sent as
`CSI 27 u`, so that stops working. By adding support for this, all keys
work as far as I know.

The problem exists by default when I'm not enabling disambiguate escape
codes though, so it would be nice if vim could enable this
automatically. I think it should be safe to send it to any terminal
emulator, but alternatively vim could query for support of the protocol
by sending `CSI ? u` and check if it gets a reply like `CSI ? flags u`.

Note that none of the escape sequences I wrote actually contains spaces,
they were just added for readability.

You can read more about the keyboard handling in kitty here:
https://sw.kovidgoyal.net/kitty/keyboard-protocol/

There's also an issue in kitty's repo with some discussion here:
kovidgoyal/kitty#4075
@codecov

codecov Bot commented Oct 14, 2022

Copy link
Copy Markdown

Codecov Report

Merging #11364 (0cd49e6) into master (ba43e76) will decrease coverage by 0.01%.
The diff coverage is 81.81%.

@@            Coverage Diff             @@
##           master   #11364      +/-   ##
==========================================
- Coverage   81.87%   81.86%   -0.02%     
==========================================
  Files         162      162              
  Lines      189326   189337      +11     
  Branches    43064    43065       +1     
==========================================
- Hits       155014   155003      -11     
- Misses      21769    21783      +14     
- Partials    12543    12551       +8     
Flag Coverage Δ
huge-clang-none 82.75% <81.81%> (-0.01%) ⬇️
huge-gcc-none 54.71% <0.00%> (-0.01%) ⬇️
huge-gcc-testgui 53.14% <0.00%> (-0.01%) ⬇️
huge-gcc-unittests 0.29% <0.00%> (-0.01%) ⬇️
linux 82.53% <81.81%> (-0.02%) ⬇️
mingw-x64-HUGE 76.47% <ø> (-0.01%) ⬇️
mingw-x86-HUGE 77.33% <ø> (+<0.01%) ⬆️
windows 78.13% <ø> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
src/term.c 73.65% <81.81%> (-0.11%) ⬇️
src/sound.c 66.66% <0.00%> (-1.76%) ⬇️
src/profiler.c 83.40% <0.00%> (-0.68%) ⬇️
src/message.c 78.67% <0.00%> (-0.23%) ⬇️
src/channel.c 83.91% <0.00%> (-0.18%) ⬇️
src/regexp_nfa.c 89.77% <0.00%> (-0.10%) ⬇️
src/search.c 85.10% <0.00%> (-0.09%) ⬇️
src/gui.c 72.82% <0.00%> (-0.05%) ⬇️
src/terminal.c 77.77% <0.00%> (-0.03%) ⬇️
... and 3 more

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

@trygveaa

Copy link
Copy Markdown
Contributor Author

The problem exists by default when I'm not enabling disambiguate escape codes though, so it would be nice if vim could enable this automatically. I think it should be safe to send it to any terminal emulator, but alternatively vim could query for support of the protocol by sending CSI ? u and check if it gets a reply like CSI ? flags u.

Do you have any tips on how to do this? I guess the easiest would be to add CSI > 1 u to t_TI and CSI < u to t_TE, but I'm not sure if that's okay/the right thing to do?

@brammool

brammool commented Oct 14, 2022 via email

Copy link
Copy Markdown
Contributor

@brammool

brammool commented Oct 14, 2022 via email

Copy link
Copy Markdown
Contributor

@brammool brammool closed this in b9c09c1 Oct 14, 2022
@trygveaa

Copy link
Copy Markdown
Contributor Author

First of all, your patch most likely works fine and it looks like it won't cause trouble for other terminals.

I will use the code from handle_key_with_modifier() to put the key in the buffer, it requires special handling in some cases and it's good to handle multi-byte codes (not sure if anyone sends these, but then sending Esc this way wasn't expected either).

Thanks for merging and fixing that!

There appears to be no reason for this, it's just a bad kitty.

Isn't the reason to distinguish between the escape key and escape sequences, and to support more keys? Anyways, I'm not one to say what is correct or not to do.

Be very careful with sending that code, because if you send it to other terminals you will completely break key handling with modifiers. For some unknown reason Kitty decided to go their own way and use "1" instead of "2".

It is NOT safe to send "CSI > 1 u", because it puts some terminals in a bad state, where Vim cannot recognize keys with modifiers.

What 2 are you talking about? Do you mean the sequence vim has for t_TI, CSI > 4 ; 2 m? This is not the same, it's a different sequence (ends in m instead of u). CSI > flags u is a sequence to enable kittys keyboard protocol, where flags is a bit-flag number indicating what to enable from the list on https://sw.kovidgoyal.net/kitty/keyboard-protocol/#progressive-enhancement. 1 is to enable disambiguate escape codes, which is what's relevant here.

For the terminal emulators that don't support this keyboard protocol, won't CSI > 1 u just be an unknown CSI sequence? And as far as I know, unknown CSI sequences are ignored and doesn't do anything?

This was noticed by terminal emulators a bit later, which is when "CSI > 2 u" was added, which does work.

Are you mixing CSI > 2 u and CSI > 4 ; 2 m, or are there any terminal emulators that has CSI > 2 u doing something other than kitty?

Does Kitty send a specific termresponse? We do not appear to check for that. It might not be enough, because it appears there are multiple verisons of Kitty that behave in different ways.

Yes, if you send CSI ? u, kitty responds with CSI ? flags u, where flags is a number indicating what enhancements are enabled, corresponding to the flags parameter you send when enabling it. Here is a list of the enhancements: https://sw.kovidgoyal.net/kitty/keyboard-protocol/#progressive-enhancement

@trygveaa
trygveaa deleted the support-csi-key-without-modifier branch October 14, 2022 13:12
@trygveaa

Copy link
Copy Markdown
Contributor Author

Here's how neovim is querying this btw, if that's at all helpful: neovim/neovim#18181

Btw, the terminal emulators foot and wezterm also implement this protocol, though they don't send CSI u sequences until you enable it with CSI > 1 u, so they didn't trigger this issue unless you enabled that yourself. And I see that wezterm actually sends CSI 27 ; 1 u for escape, so it was still working with it enabled.

@brammool

brammool commented Oct 14, 2022 via email

Copy link
Copy Markdown
Contributor

@brammool

brammool commented Oct 14, 2022 via email

Copy link
Copy Markdown
Contributor

@brammool

brammool commented Oct 14, 2022 via email

Copy link
Copy Markdown
Contributor

@chdiza

chdiza commented Oct 14, 2022

Copy link
Copy Markdown

Great, let's have a dozen more terminal emulators that all work in slightly different ways...

This is what Kitty is trying to solve with its keyboard protocol. It's 2022 and the modifier situation still sucks hard. The kitty protocol was invented to fix the suck once and for all, in hopes that it will gradually be adopted by various console programs and terminal emulators.

I don't know what "kitty keyboard protocol" is

It's in one of the links in an earlier comment, IIUC.

@brammool

Copy link
Copy Markdown
Contributor

https://xkcd.com/927/

@trygveaa

Copy link
Copy Markdown
Contributor Author

It doesn't help, any program will still accept Esc as the escape key. Unless it has a special "kitty mode" perhaps, which defeats the idea to be able to work with any terminal without hard coding it.

So as I understand it, a program can send CSI > 1 u to enable the protocol and then CSI ? u to check if it's enabled. If it receives CSI ? 1 u, it knows that the keyboard protocol is enabled and escape will be sent as CSI 27 u (or CSI 27 ; 1 u) and never as \e, so it knows that any \e that appears is the start of an escape sequence and not the escape key. This is a protocol meant to be supported in multiple terminal emulators (three support it as of now), so you don't need to hard code each terminal.

I don't know what "kitty keyboard protocol" is

It's in one of the links in an earlier comment, IIUC.

Correct, this one: https://sw.kovidgoyal.net/kitty/keyboard-protocol/

Great, let's have a dozen more terminal emulators that all work in slightly different ways...

This is what Kitty is trying to solve with its keyboard protocol. It's 2022 and the modifier situation still sucks hard. The kitty protocol was invented to fix the suck once and for all, in hopes that it will gradually be adopted by various console programs and terminal emulators.

https://xkcd.com/927/

Well, yes, having many standards is impractical, but it's also sort of the only way to fix the issues with the existing ones I think.

That is not what I mean, t_RV is normally set to "Esc [ > c". On nearly all "advanced" terminals it returns a version string, where the version can be used to guess the type of terminal. This is done in handle_version_response(). It's mainly a cludge to handle users setting $TERM to something containing "xterm" even though it is really not an xterm. You can tell them a thousand times that they shouldn't do that, but it happens anyway.

I tried it myself. Kitty seems to default $TERM to "xterm-kitty". Since this contains "xterm" Vim will sent the t_RV sequence. What comes back is "Esc [ > 1;4000;21c". I don't know what other versions of Kitty send, thus can't be sure how to recognize a kitty from that.

I don't think you should check if the terminal is kitty and do specific things based on that. That wouldn't allow other terminal emulators to implement the keyboard protocol. It would be better to check specifically for the keyboard protocol. This can be done by sending CSI ? u and check if you get CSI ? <flags> u back. I see that neovim queries with CSI ? u CSI c. I think this is because other terminals implement CSI c, so you know that when you get the response for that you should also have gotten the response for CSI ? u if it's implemented, so you know it's not implemented if you haven't gotten a response (instead of waiting for a response with a timeout).

If you get a response that it's supported, you send CSI > 1 u to enable it, and CSI < u when vim exits to disable it.

@brammool

brammool commented Oct 15, 2022 via email

Copy link
Copy Markdown
Contributor

@trygveaa

Copy link
Copy Markdown
Contributor Author

First we would need to know when to send that code to enable this protocol. Letting the user tweak their setup is not a good plan.

Wouldn't it make sense to send it when the application starts?

I don't think we need to change anything for Esc handling. The current code has some tricks to handle a single Esc. When the Esc arrives as an escape sequence then everything works as before. Not using the single-Esc handling doesn't have any advantage, it just won't be used.

Yes, I agree that the Esc handling in vim doesn't need to be changed. It was just an example of how the protocol can be used for proper separation of the key and control sequences, which can be an issue in some programs. For instance tmux waits 500ms by default after an escape character to determine if it's the key or a control sequence.

Why not implement modifyOtherKeys? That's what xterm supports and it's working fine already. I have not yet seen a reason why yet another protocol is going to save the world. The Kitty docs mention some reasons that are irrelevant for Vim.

I suppose that's a good question. The reason I went here to vim is that the problem I have is that mappings I have with keys using ctrl in vim stops working after some keys are pressed (because seenModifyOtherKeys is set to true), so it seemed most natural to change vim. And the most straightforward way to fix this seemed to be to get vim to accept CSI u keys without modifiers and enable the kitty keyboard protocol.

First of all there is the risc that this code shows up on terminals. We have had the same problem with the cursor position report. I actually noticed Kitty gave an error message for one of the requests we send. Also, this seems like a terminal property that should be in terminfo/termcap, not something that requires an async check.

Hm, not sure about this. @kovidgoyal: Maybe you have some input here?

For modifyOtherKeys we can detect whether it is working. We could do it for this one, but I wonder if it makes any difference in what we do with the keys. It is important that everything goes back to normal when exiting or when executing a shell command.

If you send CSI < u when vim exits, everything goes back to normal. This seems analogous to sending CSI > 4 ; m to me, which you have to send on exit for things to go back to normal after you've sent CSI > 4 ; 2 m.

I suppose if a user does change t_TI and t_TE it would just work.

Yes, so now with this patch in, I can set it and get it working properly for me at least. It would be nicer if kitty and vim worked well together out of the box though.

@kovidgoyal

kovidgoyal commented Oct 16, 2022 via email

Copy link
Copy Markdown

@brammool

brammool commented Oct 16, 2022 via email

Copy link
Copy Markdown
Contributor

@brammool

brammool commented Oct 16, 2022 via email

Copy link
Copy Markdown
Contributor

@kovidgoyal

kovidgoyal commented Oct 16, 2022 via email

Copy link
Copy Markdown

@brammool

brammool commented Oct 16, 2022 via email

Copy link
Copy Markdown
Contributor

@kovidgoyal

kovidgoyal commented Oct 16, 2022 via email

Copy link
Copy Markdown

@chdiza

chdiza commented Oct 16, 2022

Copy link
Copy Markdown

I'm saying that modifyOtherKeys solves most of the problems with modifiers, and Vim users have not mentioned things that are missing.

But vim users have mentioned things that are missing, even if they have not used the word "modifyOtherKeys".

E.g., I know I've seen people wonder why they can't make the Cmd key on an Apple keyboard be part of the LHS of a console vim mapping---even after using a terminal emulator that doesn't automatically capture the "Cmd" before it gets to whatever program runs in the terminal. I wonder that myself! (I might've even been one of the people who asked about that.) It's flippin' 2022 and I can't make e.g., Control-Opt-Cmd-h be a vim LHS.

modifyOtherKeys doesn't handle the Cmd key, which is an extremely convenient and obvious modifier for anyone on an Apple keyboard. It's not some obscure thing. Plus, modifyOtherKeys has undesirable side effects.

@brammool

brammool commented Oct 17, 2022 via email

Copy link
Copy Markdown
Contributor

trygveaa added a commit to trygveaa/vim that referenced this pull request Oct 18, 2022
As mentioned in issue vim#7562 and patch 8.2.2246, cursor keys are not
recognized at the hit-Enter prompt after executing an external command.
While arrow keys were fixed by that, the Home and End keys are also
considered cursor keys by xterm and also change control sequences
between normal and application mode, so they were still not working.

To be honest, the reason I discovered this is that after enabling the
kitty keyboard protocol as discussed in PR vim#11364 the Home and End keys
stopped working. While debugging this, I noticed this inconsistency
between the handling of the arrow keys and Home/End keys since the arrow
keys still worked. The reason for this is that in this mode, kitty sends
the arrow and Home/End keys the same way as in normal terminal mode, and
vim supports that for arrow keys, but not for Home/End keys.

I would hesitate to change the builtin termcap for xterm to just fix
behavior in kitty, but since this is an inconsistency between the
handling of the arrow keys and the Home/End keys that I don't think
should be there, and since it actually fixes the vim#7562 issue for
Home/End keys in xterm I think it makes sense to do this change. And it
happens to also fix the problem I have with Home/End keys in the kitty
keyboard protocol (at least as long as TERM is some xterm name).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants