W32 GUI: Ctrl+[ via Ctrl+dead^ (AZERTY, QWERTZ) #10687
Closed
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Provide Ctrl+[ via Ctrl+dead_circumflex on AZERTY, QWERTZ
This PR fixes second part (Win32 gvim) of #10454.
This is pretty "brute force" fix for UX regression introduced by
patch "8.2.4807: processing key events in Win32 GUI is not
ideal" (77fc0b0). Starting by
this revision it was not possible any more to generate ESC using
Ctrl+dead_circumflex on AZERTY keyboard layout in Win32 gvim.
Solution is found using trial-and-error approach. After AZERTY
solution was found, to check how generic it is QWERTZ (German)
Ctrl+dead_circumflex solution was found as well (made not big
sense as such but turned out to be good for generalization,
because windows handles Ctrl+dead_circumflex differently for
AZERTY and QWERTZ layouts, first solution for AZERTY was not
working for QWERTZ but QWERTZ was good enough for AZERTY. Hopes
are that other national layouts will be straight forward to add
if handling of CTRL+dead_key will ever be needed for them).
When we detect that Ctrl+dead_key is pressed, we check raw
vk+scan_code to be sure we are talking about specific key on the
keyboard. Condition that it is dead key is computed separately
already. So we restrict triggering of this fix to specific key on
the keyboard and to the fact that it is a dead key and that
now Ctrl is in hold state.
Firstly we inject WM_CHAR='[' into the message queue using
PostMessageW(). This will result in a call of
_WndProc()
after this call of process_message() will return (state of
Ctrl is separately dermined by _OnChar(), therefore '[' will be
Ctrl+[). This WM_CHAR will be processed as very next event.
After that gvim will go into waiting state to wait for some
subsequent key presses from the user.
In that moment gvim application is situated into "dead key" state -
next vk+scan_code of the key pressed will be translated by ToUnicode() call
differently from "normal state": preceding "dead key" will produce
"cicrumflex"-variant of the char (a->â,u->û etc), so we need to
"expel" this state. Don't want 'â' if user pressed 'a'.
There is already that boolean^H^H^H^H^H^H^Hint flag "dead_key" in
gui_w32.c to track the "dead key" state. Simple boolean usage of
that flag seems not enough for our needs any more, therefore
"dead_key" meaninig is extended from plain boolean to a
enumeration of several possible values, see below.
Remember there was this preceeding _WndProc()->_OnChar()
call where we feed Ctrl+[ into vim internal event queue
(add_to_input_buf()).
Normally _OnChar() would reset vim variable "dead_key" value to
0. We want however to maintain our special state even after that
_OnChar() call - to be in-sync with windows point of view. To
achieve that, we introduce new value of the global "dead_key"
variable: DEAD_KEY_TRANSIENT_IN_ON_CHAR.
So, back to waiting for further user input. Remember, that
application is marked by windows as "after dead key was press"
and when we obtain this future key press from user we still will
have this knowledge via DEAD_KEY_TRANSIENT_IN_ON_CHAR value of
"dead_key" variable, which was not removed by first _OnChar()
call.
Now we need to expel the dead key status in a special way, which
seems only(?) be possible to accomplish by handling of that
"poisoned" keypress in our _WndProc. We call TranslateMessage()
where we replace the key press of user with ' '(VK_SPACE) - it
will translate to just one WM_CHAR='^' event posted into our
queue. We self-post as well original char as WM_KEYDOWN to be
processed with PostMessage and return from this process_message()
call. (Even if we would skip call of TranslateMessage, Windows
still will force us to confront with that dead char by put in our
queue WM_CHAR = '^' event, seems to default to that even without
us calling TranslateMessage() with VK_SPACE).
That's where second special value of "dead_key" variable is
introduced: DEAD_KEY_SKIP_ON_CHAR. We set it and let "poisoned"
char to go through our _WndProc() ignoring it in _OnChar().
After that we are dealing with self-scheduled WM_KEYDOWN event in
subsequent call of process_message(), which reproduces the
original user key press.
PS/Sidenote: Detected by the way, perhaps already reported. It
seems that CTRL+6 handling is changed as well since 8.2.4807 for
AZERTY layout. Before that patch both CTRL+6 and CTRL+SHIFT+6 has
generated CTRL+^, since 8.2.4807 CTRL+6 generates CTRL+§ (and
CTRL+SHIFT+6 still generates CTRL+^). One can consider this
change to be kind of improvement, and if somebody really need old
behaviour it can easily be achieved by the user per configuration
with mapping CTRL+§.