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

Ctrl-[ no longer behaves as Esc on Czech keyboard on Windows (it worked in g/vim 8) #12595

Closed
risa2000 opened this issue Jun 25, 2023 · 25 comments

Comments

@risa2000
Copy link

Steps to reproduce

Using gVim on Windows (version 9.0.1664).
Pressing Ctrl-[ (or FWIW Ctrl-]) no longer works as expected (as Esc, or goto tag). It writes the Czech letters instead:
Ctrl-[ writes ú,
Ctrl-] writes ).
which are the actual letters on the Czech layout at the corresponding keys.
I did not check other Ctrl-<??> combinations.

Expected behaviour

I have found two similar issues already closed here: #11831, #10454
but since I am not familiar with Belgian layout, or behavior the Belgian users expect, I cannot really say if it concerns my case. But it definitely does not resolve it.

From what I read in those and some other threads about the Ctrl handling I assume there is a confusion among some people how Ctrl-[ works on non English layouts. I will try to explain on the Czech layout on Windows.

Note: For someone not familiar with Czech layouts, there are several "Czech" layouts with different degree of localization, but the one I will be talking about is the one named just Czech (the others are usually certain mix of English and Czech layout).

On the Czech layout the key right to P (which on the English layout is the one with [) has a Czech letter ú. The symbol [ is however written by AltGr+f on the Czech layout. For English key ] (which is right to [) the situation on the Czech keyboard is similar again - there is ) on Czech layout and ] is written by AltGr+g.

When Microsoft was localizing the keyboard they actually did a smart thing and did not map Ctrl-[ to Ctrl-AltGr-f (as happened on some linux distros), but realized that Ctrl-[ is indeed a control code (and not an actual letter) and that the usability should be more important than formal correctness. We may say they did not localize Ctrl-[ by the character, but by the key (i.e. kept the same key in the layout regardless its localized character).

I have been used to use Ctrl-[ for Esc and it worked in linux terminal, or Windows, regardless the keyboard layout for the past 30 years. The only dire cases were GUIs in some linux distros where they indeed expected users to write Ctrl-AltGr-f.

I am not sure what happened in g/Vim from ver 8 to ver 9, but it looks to me, like someone made an effort to actually break this behavior for some reason. I wonder what was the motivation and what is the proposed way forward?

Version of Vim

9.0.1664

Environment

Windows 10 Pro 64 bit,
gVim for Windows installed from https://github.com/vim/vim-win32-installer.

Logs and stack traces

No response

@tonymec
Copy link

tonymec commented Jun 26, 2023

  1. Have you tried the key combination Ctrl+AltGr+ú ? I have a hunch that it "might" give the desired result but since my keyboard layout is not the same as yours I cannot be sure.
  2. Any key can be simulated by a mapping. Even if solution 1 does not apply to you, the following (in your vimrc) ought to put Ctrl-[ on F8 and Ctrl-] on F9. Any other pair of keys not used by Vim can be used but I recommend selecting your {rhs} among the F and Shift-F keys.
map <F8> <C-[>
imap <F8> <C-[>
map <F9> <C-]>
imap <F9> <C-]>

Best regards,
Tony.

@tonymec
Copy link

tonymec commented Jun 26, 2023

...oops...
...selecting your {lhs}...

@risa2000
Copy link
Author

risa2000 commented Jun 26, 2023

@tonymec
I guess you missed my point and I probably did not make myself clear either.

My problem is not how to get Esc(code) into Vim. The Esc(key) on my keyboard does it, on any layout. The problem is, I have been typewriting (with 10 fingers) for more than 30 years and using Ctrl-[ as Esc as long as that (on vi in the early years). This is a pretty long history of muscle memory and one has to have pretty strong reason to break that.

The problem is that it has changed on Windows recently. I cannot say if it was with vim 9 or earlier (issues here suggest it might have been in vim 8) as I have been using my vim 8 (on Windows) for several years without an update.

What I can say however is that in very same Windows and using very same (Czech) layout, when I connect to linux terminal (using putty and XTERM emulation) and run vim (version 9) on that linux box (tested on gentoo and OpenWrt) it still works as expected. I.e. I am typing Ctrl+<key right to P> and it emits Esc(code) in the vim run on that linux box terminal.

So my keyboard did not change, the handling in the OS did not change, and my assumption is that Windows still emits the Esc(code) to the app (putty in this case) which passes it to the linux terminal, which passes it to vim running on that linux box.

Now some observations about the new vim and gVim on Windows:

  1. When I switch the keyboard layout to English, Ctrl+<key right to P> emits Esc(code) in gVim as expected.
  2. Doing the same with the Czech layout gets the Ctrl ignored and gVim emits ú. Which is the actual character on the Czech layout on this key.
  3. Doing the same with the Czech layout and vim (i.e. non graphical vim run in Windows console) emits Ctrl-_ (i.e. ^_ graphically).
  4. Typing Ctrl-AltGr-<key right to P> emits ÷ in both vim and gVim, which is the character the Czech layout emits when typing AltGr-<key right to P>. I.e. the Ctrl is ignored.
  5. Typing Ctrl-AltGr-F (which is literally "localizing" Ctrl-[ to the Czech layout) types [ in both vim and gVim, which is the expected character from the localized Czech layout for AltGr-F, i.e the Ctrl key is again ignored.

For me it looks like vim/gVim implementation is not only inconsistent with the behavior of its linux counterpart (run in linux terminal), but is even producing different (wrong) results when run in graphical form or console form (vim vs gVim on Windows).

@risa2000
Copy link
Author

FWIW: version 8.2.96 (which I have been using up to now, before updating to version 9), works as expected. I.e. with the Czech keyboard layout, it emits Esc(code), when pressing Ctrl-<key right to P> in both vim (in Windows console) and graphical gVim.

@k-takata
Copy link
Member

There was a big change in handling of key events in 8.2.4807, and after that there were several patches related to this.

8.2.4807: processing key eveints in Win32 GUI is not ideal
8.2.4811: Win32 GUI: caps lock doesn't work
8.2.4817: Win32 GUI: modifiers are not always used
8.2.4843: treating CTRL + ALT as AltGr is not backwards compatible
8.2.5157: MS-Windows GUI: CTRL-key combinations do not always work
9.0.0087: MS-Windows: CTRL-[ on Belgian keyboard does not work like Esc
9.0.0120: MS-Windows GUI: cannot use AltGr + Space
9.0.0686: the right ALT key does not work on some MS-Windows keyboards
9.0.0888: MS-Windows GUI: CTRL-] does not work on Swiss keyboard

There might be still some issues in some keyboard layouts.

@risa2000
Copy link
Author

@k-takata
Do you know, or could you point me to the forum, mailing list or any resource discussing the changes? I guess there must have been strong reasons for it and it would definitely help me to understand the motivation and the results. Why it was not rolled back after the issues started to pop up is another good question.

I have been a long time programmer (though I know nothing about vim implementation) and trying to find some fixes for each keyboard localization individually does not seem like a right way to do it - especially since before it worked for all layouts.

What do you suggest I can do about it?

@chrisbra
Copy link
Member

it starts at patch 8.2.4807 which is commit 77fc0b0 which links to #10155 and from there you should find links to related discussions

@k-takata
Copy link
Member

I think we need to modify this part:

vim/src/gui_w32.c

Lines 2164 to 2175 in e7d9ca2

if (dead_key == DEAD_KEY_SET_DEFAULT
&& (GetKeyState(VK_CONTROL) & 0x8000))
{
if ( // AZERTY CTRL+dead_circumflex
(vk == 221 && scan_code == 26)
// QWERTZ CTRL+dead_circumflex
|| (vk == 220 && scan_code == 41))
wm_char = '[';
if ( // QWERTZ CTRL+dead_two-overdots
(vk == 192 && scan_code == 27))
wm_char = ']';
}

I don't know the virtual key codes and the scan codes for the keys that cause the issue in Czech keyboards, though.

@risa2000
Copy link
Author

risa2000 commented Jun 29, 2023

@k-takata
I have read the author's comment at the original PR mentioned by @chrisbra and these sentences from the author introduction caught my attention:

  • We call ToUnicode with an intentionally reduced keyboard state to avoid
    a pitfall of TranslateMessage: not every combinations of Ctrl+
    produce a keycode (eg. Ctrl+] does not) and thus no WM_CHAR would be
    emitted for them.
  • Fixes the problem I noticed on my Windows machine and allows me to map <C-]>.

I do not know if the author uses a different (from English) keyboard layout and faced some issues when mapping <Ctrl-<key which emits ] character>> , or whether he is referring to <Ctrl-<key right to P> combo (which should emit an Esc(code)), but I have a feeling there is some fundamental misunderstanding about how Windows layouts and Ctrl codes work.

For people used to the English layout, defining a key press as <Ctrl-[>, for example in Vim doc, or elsewhere, simply means pressing together keys marked Ctrl and [. What it actually means however is "emitting an Esc(code)" by using Ctrl key combo. Since historically it started with English keyboards, we use English layout for that.

Now for the Czech layout (at least as defined by Windows, and I would expect the other layouts using the similar approach), the key press <Ctrl-[> is localized by a key position on a keyboard, not by a character which the key emits.
So, for example on Czech layout, the key "right to P" writes ú, yet when pressed with Ctrl emits the Esc(code) or ^[ graphically. Similarly pressing Ctrl together with the key "second right to P" emits ^], yet the key character is ) (and ( with the Shift).

This may get confusing because some Ctrl combos actually got localized by the key character. The Czech layout is QWERTZ (with Y and Z swapped), and emitting <Ctrl-Z> (e.g. to quit Python console) is indeed done by pressing Ctrl and the "key right to T".

What I am trying to say here is that there is some logic (at least in Windows) in how the layouts are localized, it is not just a mechanical translation of characters and key modifiers, and we cannot simply ignore that, or try to outsmart the system by "stripping that information and translating the keys differently".

@sme-prus001
Copy link

I believe it can seem even weirder for Cyrillic and other non-Latin keyboards, but it isn't strange at all when you get used to it. When in 'Cyrillic', e.g. Russian layout, pressing S correctly yields ы, Shift+S -- capital Ы, but of course you'd expect that Ctrl+S would send Ctrl+S to the program, not anything else. It was so in Vim up to 8.2 (I guess the latest good version was '2019 Dev 12, compiled Apr 21 2022, included patches: 1-4803'; or before #10155), it's also so in most of other editors like Notepad, but Vim 9 sends ы when you press Ctrl+S. The same behavior is of course for all the Ctrl-keys. Ctrl+X, Ctrl+C, Ctrl+V (that just prints чсм) etc.

In fact it's so inconvenient, that I had to return to Vim 8.2. Yes I known that Vim is another world and I do use its features, including :w, dd, yy, p, etc. but it's much better when the program obeys the usual Windows/GUI conventions too.

@risa2000
Copy link
Author

risa2000 commented Jun 29, 2023

@sme-prus001 I do not think it is strange at all. In fact, I believe that Microsoft actually did a pretty good job when localizing the keyboard layouts to "less than trivial clones of English one".

What I still do not understand what was the problem with the key handling the controversial PR was trying to fix. Right now it seems it has broken every non-standard layout (in Czech case it is even broken differently in Windows console and in GUI).

@k-takata I do not know who is the authority over Windows integration on this project, but I would suggest to roll back the change then discuss the problems the original PR was addressing and see how it should be solved correctly.

@ladayaroslav
Copy link

The same behavior is of course for all the Ctrl-keys

The same here. The problem seems to be that developers insist on "let's fix bugs one by one" approach, which in this case makes related bugs resurface in a vicious circle (despite being "closed").

In fact it's so inconvenient, that I had to return to Vim 8.2.

Well, I did:

imap <C-й> <C-q> 
imap <C-ц> <C-w>
...

instead, which kind of works.

@risa2000
Copy link
Author

risa2000 commented Jun 29, 2023

The same here. The problem seems to be that developers insist on "let's fix bugs one by one" approach, which in this case makes related bugs resurface in a vicious circle (despite being "closed").

I do not believe it is possible as "fixing" it would basically mean either reimplement the complete localization logic for every layout possible, or go back to trusting the system that it knows what it si doing (and rolling back the change).

@risa2000
Copy link
Author

Just a tip for anyone interested in seeing the issue clearly:

  • Install the pre-patch Vim (possibly one indicated by @sme-prus001 above), side by side with Vim 9. Install the Czech keyboard layout (the one called just Czech - this should not have any impact on your Windows and then you can remove it later, or if you are not scared of Cyrillic, Russian layout will be even more direct about the discrepancy, though I cannot comment on that one much myself).
  • Run both vims in recording mode and type all keys on both layouts (for the sake of demonstration), you would get comfort of vim recording mode telling you which keys are triggered by different combos). For the simplicity let's leave AltGr combos out, even though they might be affected as well.
  • If you would want to rule out other changes between the Vim versions (8 vs 9) and you have a possibility, run vim 9 on a linux box, through ssh & linux terminal. Do the same. putty seems to be pretty good in passing the key codes correctly to the linux terminal as well.
  • If you are even braver, you may try the same in Windows console and non-graphical vim.

@risa2000
Copy link
Author

risa2000 commented Jul 23, 2023

@brammool, @mattn, @LemonBoy, @ant0sha, @tonymec, @vim-ml, @vds2212, @ychin, @zewpo, @k-takata, @chrisbra, @sme-prus001, @ladayaroslav

When reading the comments on the PR #10155, the corresponding commit, and the follow-up fixes, I collected the list of people I am trying to reach by this shout-out out of desperation. I apologize to anyone who may feel being addressed wrongly, in that case please ignore the rest.

First I would like to get on the same page with Ctrl-<key> notation, codes and meanings. I already expressed myself above for those new I would try better version here (but feel free to read the full thread):

When seeing Ctrl-<char> (or Ctrl+<char>, or simply C-<char>) written anywhere (in vim doc, for example), my understanding is that it defines a combination of two keys (one of which is Ctrl key) pressed together, which emits a corresponding control code. Eg. Ctrl-[ is a control combo supposed to emit 0x1b or graphically ^[. In my previous comments here I used Esc(code), and from now on I will use ^[ for brevity.

It does not however mean that the key pressed together with Ctrl must be the key which emits a character <char> on a particular keyboard. We use a notation with characters assigned to the English layout as it was historically devised there, but technically, there is no direct dependency, nor requirement. In other words, I can use Ctrl and any key to send ^[, it just happens that on the English layout it would be a key which writes [.

For those who wonder, why I would not want to use the same key which writes the particular character, [ in the case of ^[, is that this key may not exist (directly) on the localized keyboard. In case of the Czech layout on Windows (and e.g. Lubuntu), [ is written as AltGr-F. (and ] is written as AltGr-G).

Now, what Windows does right is that it uses this important distinction extensively when defining localized keyboard layouts. So they define (on the Czech layout) Ctrl-<key right to P> to be the one which sends ^[ (and Ctrl-<2nd key right to P> as the one which sends ^]), despite the fact that characters [ and ] are written differently. The fact that <key right to P> corresponds to English layout [ key just proves that the guys who localized it understood what the control codes do.

If you finger type (with 10 fingers), typing Ctrl-<key right to P> is very easy to type - compared to trying literal triplet Ctrl-AltGr-F. Ctrl codes derived from characters which are directly available however get localized - e.g. Ctrl-Z is written with an actual key which writes Z even though the layout is QWERTZ.

But not only on Windows. I checked on friend’s Mac with MacOS and Vim 9 in terminal, and the Czech keyboard layout works there as expected - it honors localized Ctrl codes independently from the characters the key writes - i.e. ^[ is emitted by pressing Ctrl-<key right to P>, while this key writes ú without modifiers.

On Lubuntu (with the recent install and Vim 9) not sure whether Lubuntu (KDE?) Czech keyboard localization or Vim are wrong but I have to type Ctrl-AltGr-F in order to emit ^[. This is an example of how it should not be done. Forcing a user to type triplets in order to emit a control code does not make sense for what the control codes are used for.

When reading the comments on different threads these got my attention:

from @ant0sha (#11831 (comment))

This mystery reminds me of pre-8.2.4807 W32 gvim, which has
similar behavior, without us undertaken anything for that. My
best guess is, that Win API TranslateMessage() call has some
such interesting non-obvious "tunings" for key codes mapping,
coded for whatever reasons by some microsoft guys... And we lost
it after stopped to call TranslateMessage() in this famous
"improve processing of key events" commit 8.2.4807.

Which basically expresses my feeling about the whole affair, apart from the part about the “tuning”. This “tuning” is actually the layout localization implemented by the OS according to the principles I described above.

from @ant0sha (#11831 (comment))

"AZERTY <C-$> acts like QWERTY <C-]>"
behavior seems to be originally only restricted to (some? all?)
windows front-end versions and was not observed in any of unix
front ends so far. On the contrary, in the UNIX world,
workaround, pointed by @tonymec (C-AltGr-$) seems to
be the way of going until now.
Patch proposed is a step towards harmonization.

I am not sure if UNIX world means Linux world, but if it does, the way Linux (or some Linux GUIs?) are handling the localization is questionable at best (as per my example with the Czech layout and getting to Ctrl-AltGr-F combo for ^[). You do not want to harmonize with that world!

The question we should be asking however is, why cannot Vim just honor a localized layout on each platform as it did before the controversial patch?
What was so wrong with the key event processing (on Windows) that it must have been “improved” this way?

For the record: At the moment, the graphical Vim (gVim) and the console Vim are broken in two different ways on Czech layout, i.e. pressing Ctrl-<key right to P> emits two different (and wrong) characters.

The proposed way forward, if I understand well the comment and the list of patches posted here by @k-takata, is that a user of a non standard (i.e. non-English) layout should reverse engineer his keyboard layout implemented by the OS and recreate its implementation for Vim because we can no longer use the OS for that?

I am afraid that even if I wanted to do it for the Czech layout, I am not sure, I would not miss anything without actually writing some key translator and simulator and running all possible combinations through it, because I definitely do not use all possible control codes or other convoluted combinations. Plus there are several Czech layouts, so what to do with the others?

And if I do not submit a correct patch, I am out of luck? (see 6 months old comment from @sme-prus001 at 77fc0b0#commitcomment-97542548 stating that the patch basically broke completely the control codes on Cyrillic layout)

When it started to be clear that the patch had had no clue about how the localization works on Windows, why was it not rolled back?

@ant0sha
Copy link
Contributor

ant0sha commented Aug 6, 2023

The same behavior is of course for all the Ctrl-keys

The same here. The problem seems to be that developers insist on "let's fix bugs one by one" approach, which in this case makes related bugs resurface in a vicious circle (despite being "closed").

In fact it's so inconvenient, that I had to return to Vim 8.2.

Well, I did:

imap <C-й> <C-q> 
imap <C-ц> <C-w>
...

instead, which kind of works.

Good example. Exactly those mappings will not be possible any more if the handling of keyboard events in gvim will be reverted to the old state. And for those listed you perhaps would not care, but for other Russian letters it may be interesting.

@ladayaroslav
Copy link

Good example. Exactly those mappings will not be possible any more if the handling of keyboard events in gvim will be reverted to the old state. And for those listed you perhaps would not care, but for other Russian letters it may be interesting.

I'm pretty sure those (and the like) worked before the change.
The point is that these mappings are a) dirty hack and b) don't actually solve the problem completely.

I.e. we need working langmap (and so on, see the thread), not these... dumb hacks.

@ant0sha
Copy link
Contributor

ant0sha commented Aug 6, 2023

When it started to be clear that the patch had had no clue about how the localization works on Windows, why was it not rolled back?

I have to admit, such thoughts were also going in my head. But it was not my patch. And also, what stopped me that a lot of newly possible mappings will be get lost again, after existing for short time. So it is a (possible) trade off now between old broken shortcuts vs new broken shortcuts?

@ant0sha
Copy link
Contributor

ant0sha commented Aug 6, 2023

I.e. we need working langmap (and so on, see the thread), not these... dumb hacks.

@ladayaroslav:
Can you please point me to the issue with langmap?

@ladayaroslav
Copy link

@ladayaroslav: Can you please point me to the issue with langmap?

See here: #10615 (comment)

And (for "which in this case makes related bugs resurface in a vicious circle (despite being "closed")") — this one is alive and well, again: #10579

@risa2000
Copy link
Author

risa2000 commented Aug 6, 2023

I have to admit, such thoughts were also going in my head. But it was not my patch. And also, what stopped me that a lot of newly possible mappings will be get lost again, after existing for short time. So it is a (possible) trade off now between old broken shortcuts vs new broken shortcuts?

I guess I am kind of a Linux guy, in a sense the Linux project is maintained. Its maxim is/was "never break a user land". If you do (accidentally) you get booted either by maintainers, or by Linus himself :). I guess in my view, breaking a keyboard layout on a text editor is such a deed. In fact I cannot see how one can do much worse than that.

The idea that this could be considered an acceptable trade-off by anyone never crossed my mind. I guess that all the people involved in the patch (starting from the author and ending with the maintainer who checked it in) never used localized keyboard (a non-trivial one), or never used Ctrl codes on it, or never typewrite touch-type (and do not mind how the things are actually laid out). I have spent already more than enough time on explaining why Windows localized layout is superior to e.g. Linux one. (I cannot speak for MacOS much, but they seem to get at least the Ctrl codes right too.)

Anyway, I would consider the idea that we ditch the keyboard layout handling in the OS completely in order to get better control over it, to be a bold take on the subject, but only if the original keyboard layout is preserved. Not at the cost that any non-English layout is broken - and left to users to get fixed - which as I already also tried to explain - basically means reimplementing it for Vim. I do not see why anyone would want to do that, at least not in this ad-hoc way where people are guessing which keys should be used to emit the codes and even wanting to "harmonize" with flawed Linux scheme (sorry, if it sounds like I am picking at you, I am really not - it just happens your comment got my attention as an example of how "unguided" the whole affair was).

@risa2000
Copy link
Author

risa2000 commented Aug 7, 2023

When it started to be clear that the patch had had no clue about how the localization works on Windows, why was it not rolled back?

I have to admit, such thoughts were also going in my head. But it was not my patch. And also, what stopped me that a lot of newly possible mappings will be get lost again, after existing for short time. So it is a (possible) trade off now between old broken shortcuts vs new broken shortcuts?

One thing I realized I forgot and need to address directly (@ant0sha - again no hard feelings) reading this comment, in case this might be a common perception here:
The patch did not brake some old Vim shortcuts in favor of some new Vim shortcuts. It broke OS native keyboard layout in favor of some new Vim shortcuts. The OS native layout is something you expect to be a constant to the platform, something the apps should honor and therefore behave the same. Especially when the app is a text editor.

This is the reason why I believe there is no acceptable trade-off for this type of damage ("do not break the userland") and we should not be guessing which keys should emit which control codes as it is already well defined by the keyboard layout implemented by the OS.

@ant0sha
Copy link
Contributor

ant0sha commented Aug 9, 2023

To untangle from this circumstances I am working now on making two GUI w32 input "methods" to configurably coexist, classic one (based on TranslateMessage() win API) and experimental (based on ToUnicode() win API)

@k-takata
Copy link
Member

k-takata commented Aug 9, 2023

@ant0sha
I was thinking of creating an MR to revert all the changes listed in my previous comment, but make it configurable might be a good compromise.

@ant0sha
Copy link
Contributor

ant0sha commented Aug 9, 2023

@ant0sha I was thinking of creating an MR to revert all the changes listed in my previous comment, but make it configurable might be a good compromise.

done
#12752

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants