Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issues with Vim and comprehensive keyboard handling #4075

Closed
comex opened this issue Sep 28, 2021 · 5 comments
Closed

Issues with Vim and comprehensive keyboard handling #4075

comex opened this issue Sep 28, 2021 · 5 comments
Labels

Comments

@comex
Copy link

comex commented Sep 28, 2021

In short: When running Vim on Kitty on macOS, if you input Cmd-<anything> (well, anything that isn't a Kitty shortcut), then for the rest of the Vim session, Ctrl-<anything> keystrokes will have their Vim-default behavior, ignoring any mappings the user has set up for them in Vim.

Sounds weird, right?

This results from the combination of two different issues related to comprehensive keyboard handling. Vim supports, and enables by default, xterm's variant of it, aka "modifyOtherKeys" (relevant vim documentation).

The first issue is that Vim's default sequence for enabling modifyOtherKeys is "CSI > 4 ; 2 m". Kitty tries to be compatible with this xterm feature, but it only recognizes "CSI > 4 ; 1 m". According to xterm documentation (this part plus this part), both of those sequences enable reporting of modifier keys, but they differ in which modifier keys are reported.

Since Kitty doesn't recognize "CSI > 4 ; 2 m", it ignores it and leaves comprehensive keyboard handling disabled. This leads to the second issue, which could arguably be considered either a Vim bug or a Kitty bug:

Kitty documents that "Key events that could not be represented in legacy mode are encoded using a CSI u escape code, that most terminal programs should just ignore." However, Vim doesn't ignore them. Whenever it sees any such escape code, it sets a global boolean seenModifyOtherKeys (regardless of whether it tried to enable modifyOtherKeys in the first place). The effect of this variable is to make the mapping lookup code ignore legacy representations for Ctrl (e.g. 0x01 => Ctrl-A) and Alt (e.g. 0xc0 => Alt-A), permanently until the user quits Vim. (This functionality was added in 2019 in this commit.)

To Reproduce
I reproduced this with the latest master of Vim (be01090ef) and Kitty (b1375e5).

  1. Run kitty -c /dev/null
  2. In the terminal, run vim --noplugin -u /tmp/my-vimrc, where /tmp/my-vimrc should contain:
set nocompatible
map <C-a> aGot C-a<ESC>
  1. Type Ctrl-A; the text "Got C-a" is added to the buffer.
  2. Type Cmd-F (or any other keystroke that Kitty will represent using a CSI u code).
  3. Type Ctrl-A again; no text is added to the buffer.
@comex comex added the bug label Sep 28, 2021
@kovidgoyal
Copy link
Owner

Just add CSI > 4 ; 1 m to t_ti in your vimrc and you should be fine. This really needs to be fixed in vim, however since the chances of vim doing the sensible thing arent very high, I suppose I can have 4;2m also work the same as 4;1m in kitty.

@page-down
Copy link
Contributor

I recently discovered an anomaly with vim. On vim 8.2 without any configuration, pressing ESC to exit Insert mode undoes all input.

# press ESC
1 change; before #1  0 seconds ago
# ESC
Already at oldest change

Then I found this recent changes.

After troubleshooting and rolling back this change, ESC worked fine in vim again.

Before this, at least the ESC worked, after the change, the user has to configure t_ti for each environment before the ESC key can be used properly in vim, which seems a bit difficult.

@kovidgoyal
Copy link
Owner

Hmm that sucks, I didnt notice because I dont use ESC in vim. This is
why we cant have nice things. I guess all that's left to do is disable
the xterm compatibility escapes totally. If software wants to use
extended keys in kitty they will need to ask for them using kitty's
escape codes. I believe kakoune currently uses the xterm escape codes to
turn on this mode in kitty as well. So heads up for @mawww you should
update kakoune if that is indeed the case.

@comex
Copy link
Author

comex commented Oct 9, 2021

Hello,

d6a43a7 brought back the original issue, where Vim does not successfully enable comprehensive keyboard handling, but after receiving a 'CSI u' sequence thinks it has, causing Ctrl to stop working properly.

I also found the cause of the ESC issue (maybe @kovidgoyal already realized this). The only 'CSI u' sequences that Vim recognizes are, to quote the source code:

    // Key with modifier:
    //  {lead}27;{modifier};{key}~
    //  {lead}{key};{modifier}u

If it's just (to use Vim's terminology) {lead}{key}u without any modifier, Vim won't recognize it and will pass the whole CSI sequence through unchanged. In the case of pressing the escape key, the CSI sequence is " [ 2 7 u" (without spaces). Vim interprets this as pressing the escape key (exit insert mode), then the command [2 (cursor to 2nd previous unmatched #if, #else, or #ifdef), then the command 7u (undo 7 times)!

This could easily be fixed on Vim's end and probably should be. On the other hand, Vim's current behavior is not completely bogus. xterm itself never sends 'CSI u' sequences without modifiers, and even the name of the option that Vim enables ("modifyOtherKeys") suggests that it's about modifiers. So it's reasonable to be unprepared for sequences without modifiers.

If it's worth supporting existing versions of Vim, I think there are two options:

  1. Support the xterm sequence, but instead of just making it a synonym for comprehensive keyboard handling, make it enable a different mode where only keystrokes with modifiers are sent using CSI sequences.
  2. Don't support the xterm sequence, and don't send 'CSI u' sequences if comprehensive keyboard handling isn't enabled, even for keystrokes like Cmd-<key> which have no other representation.

@kovidgoyal
Copy link
Owner

kovidgoyal commented Oct 10, 2021

Yeah but that issue is a lot better than ESC not working. And IMO this needs to be fixed in vim. I dont particularly care to implement a whole new, and completely inferior, keyboard mode just for vim, that I will then have to carry around in kitty's code forever. There is absolutely no reason it should be enabling modifyOtherKeys on seeing CSI u. Nowhere is xterm's (admittedly completely inadequate) docs does it suggest applications do that. I am guessing the original motivation for it was that xterm stupidly makes their modifyOtherKeyboard mode user controllable rather than application controllable. So sending the XTMODKEYS escape code to turn it on is completely meaningless with no defined effect.

As for not sending CSI u for keys that have no representation, that just means those keys become unusable everywhere without adding support for the full mode. Which punishes the entire ecosystem because of one badly behaving program.

trygveaa added a commit to trygveaa/vim that referenced this issue Oct 14, 2022
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants