# HG changeset patch # User Bram Moolenaar # Date 1658867402 -7200 # Node ID aeaeb92c2764463fc15ce864f06f8114717fc568 # Parent 91a6d31b921c5868c7e916c47931f4cf060130f4 patch 9.0.0087: MS-Windows: CTRL-[ on Belgian keyboard does not work like Esc Commit: https://github.com/vim/vim/commit/3f0266739db7d27cb7f03f9d131114fb0af3df71 Author: Anton Sharonov Date: Tue Jul 26 21:26:18 2022 +0100 patch 9.0.0087: MS-Windows: CTRL-[ on Belgian keyboard does not work like Esc Problem: MS-Windows: CTRL-[ on Belgian keyboard does not work like Esc. Solution: Figure out what the key code means. (Anton Sharonov, closes #10687, closes #10454) diff --git a/src/gui_w32.c b/src/gui_w32.c --- a/src/gui_w32.c +++ b/src/gui_w32.c @@ -29,6 +29,12 @@ # include "gui_dwrite.h" #endif +// values for "dead_key" +#define DEAD_KEY_OFF 0 // no dead key +#define DEAD_KEY_SET_DEFAULT 1 // dead key pressed +#define DEAD_KEY_TRANSIENT_IN_ON_CHAR 2 // wait for next key press +#define DEAD_KEY_SKIP_ON_CHAR 3 // skip next _OnChar() + #if defined(FEAT_DIRECTX) static DWriteContext *s_dwc = NULL; static int s_directx_enabled = 0; @@ -533,7 +539,7 @@ static int s_y_pending; static UINT s_kFlags_pending; static UINT_PTR s_wait_timer = 0; // Timer for get char from user static int s_timed_out = FALSE; -static int dead_key = 0; // 0: no dead key, 1: dead key pressed +static int dead_key = DEAD_KEY_OFF; static UINT surrogate_pending_ch = 0; // 0: no surrogate pending, // else a high surrogate @@ -866,7 +872,13 @@ get_active_modifiers(void) int modifiers; int ch = cch; // special keys are negative - dead_key = 0; + if (dead_key == DEAD_KEY_SKIP_ON_CHAR) + return; + + // keep DEAD_KEY_TRANSIENT_IN_ON_CHAR value for later handling in + // process_message() + if (dead_key != DEAD_KEY_TRANSIENT_IN_ON_CHAR) + dead_key = DEAD_KEY_OFF; modifiers = get_active_modifiers(); @@ -912,7 +924,7 @@ get_active_modifiers(void) int modifiers; int ch = cch; // special keys are negative - dead_key = 0; + dead_key = DEAD_KEY_OFF; // OK, we have a character key (given by ch) which was entered with the // ALT key pressed. Eg, if the user presses Alt-A, then ch == 'A'. Note @@ -1844,14 +1856,14 @@ gui_mch_draw_part_cursor( * dead key's nominal character and re-post the original message. */ static void -outputDeadKey_rePost(MSG originalMsg) +outputDeadKey_rePost_Ex(MSG originalMsg, int dead_key2set) { static MSG deadCharExpel; - if (!dead_key) + if (dead_key == DEAD_KEY_OFF) return; - dead_key = 0; + dead_key = dead_key2set; // Make Windows generate the dead key's character deadCharExpel.message = originalMsg.message; @@ -1866,6 +1878,15 @@ outputDeadKey_rePost(MSG originalMsg) } /* + * Wrapper for outputDeadKey_rePost_Ex which always reset dead_key value. + */ + static void +outputDeadKey_rePost(MSG originalMsg) +{ + outputDeadKey_rePost_Ex(originalMsg, DEAD_KEY_OFF); +} + +/* * Process a single Windows message. * If one is not available we hang until one is. */ @@ -1936,8 +1957,47 @@ process_message(void) * for some reason TranslateMessage() do not trigger a call * immediately to _OnChar() (or _OnSysChar()). */ - if (dead_key) - { + + /* + * We are at the moment after WM_CHAR with DEAD_KEY_SKIP_ON_CHAR event + * was handled by _WndProc, this keypress we want to process normally + */ + if (dead_key == DEAD_KEY_SKIP_ON_CHAR) + dead_key = DEAD_KEY_OFF; + + if (dead_key != DEAD_KEY_OFF) + { + /* + * Expell the dead key pressed with Ctrl in a special way. + * + * After dead key was pressed with Ctrl in some cases, ESC was + * artificially injected and handled by _OnChar(), now we are + * dealing with completely new key press from the user. If we don't + * do anything, ToUnicode() call will interpret this vk+scan_code + * under influence of "dead-modifier". To prevent this we translate + * this message replacing current char from user with VK_SPACE, + * which will cause WM_CHAR with dead_key's character itself. Using + * DEAD_KEY_SKIP_ON_CHAR value of dead_char we force _OnChar() to + * ignore this one WM_CHAR event completely. Afterwards (due to + * usage of PostMessage), this procedure is scheduled to be called + * again with user char and on next entry we will clean + * DEAD_KEY_SKIP_ON_CHAR. We cannot use original + * outputDeadKey_rePost() since we do not wish to reset dead_key + * value. + */ + if (dead_key == DEAD_KEY_TRANSIENT_IN_ON_CHAR) + { + outputDeadKey_rePost_Ex(msg, + /*dead_key2set=*/DEAD_KEY_SKIP_ON_CHAR); + return; + } + + if (dead_key != DEAD_KEY_SET_DEFAULT) + { + // should never happen - is there a way to make ASSERT here? + return; + } + /* * If a dead key was pressed and the user presses VK_SPACE, * VK_BACK, or VK_ESCAPE it means that he actually wants to deal @@ -1952,7 +2012,7 @@ process_message(void) */ if ((vk == VK_SPACE || vk == VK_BACK || vk == VK_ESCAPE)) { - dead_key = 0; + dead_key = DEAD_KEY_OFF; TranslateMessage(&msg); return; } @@ -1995,7 +2055,7 @@ process_message(void) * character output (such as a NUMPAD printable character or * the TAB key, etc...). */ - if (dead_key && (special_keys[i].vim_code0 == 'K' + if (dead_key == DEAD_KEY_SET_DEFAULT && (special_keys[i].vim_code0 == 'K' || vk == VK_TAB || vk == CAR)) { outputDeadKey_rePost(msg); @@ -2081,10 +2141,28 @@ process_message(void) // If this is a dead key ToUnicode returns a negative value. len = ToUnicode(vk, scan_code, keyboard_state, ch, ARRAY_LENGTH(ch), 0); - dead_key = len < 0; + if (len < 0) + dead_key = DEAD_KEY_SET_DEFAULT; if (len <= 0) + { + if ( dead_key == DEAD_KEY_SET_DEFAULT + && (GetKeyState(VK_CONTROL) & 0x8000) + && ( (vk == 221 && scan_code == 26) // AZERTY CTRL+dead_circumflex + || (vk == 220 && scan_code == 41) // QWERTZ CTRL+dead_circumflex + ) + ) + { + // post WM_CHAR='[' - which will be interpreted with CTRL + // stil hold as ESC + PostMessageW(msg.hwnd, WM_CHAR, '[', msg.lParam); + // ask _OnChar() to not touch this state, wait for next key + // press and maintain knowledge that we are "poisoned" with + // "dead state" + dead_key = DEAD_KEY_TRANSIENT_IN_ON_CHAR; + } return; + } // Post the message as TranslateMessage would do. if (msg.message == WM_KEYDOWN) diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -736,6 +736,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 87, +/**/ 86, /**/ 85,