To: vim_dev@googlegroups.com Subject: Patch 9.0.0087 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 9.0.0087 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) Files: src/gui_w32.c *** ../vim-9.0.0086/src/gui_w32.c 2022-07-23 09:52:00.337814264 +0100 --- src/gui_w32.c 2022-07-26 21:25:43.632789990 +0100 *************** *** 29,34 **** --- 29,40 ---- # 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,539 **** 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 UINT surrogate_pending_ch = 0; // 0: no surrogate pending, // else a high surrogate --- 539,545 ---- 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 = DEAD_KEY_OFF; static UINT surrogate_pending_ch = 0; // 0: no surrogate pending, // else a high surrogate *************** *** 866,872 **** int modifiers; int ch = cch; // special keys are negative ! dead_key = 0; modifiers = get_active_modifiers(); --- 872,884 ---- int modifiers; int ch = cch; // special keys are negative ! 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,918 **** int modifiers; int ch = cch; // special keys are negative ! dead_key = 0; // 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 --- 924,930 ---- int modifiers; int ch = cch; // special keys are negative ! 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,1857 **** * dead key's nominal character and re-post the original message. */ static void ! outputDeadKey_rePost(MSG originalMsg) { static MSG deadCharExpel; ! if (!dead_key) return; ! dead_key = 0; // Make Windows generate the dead key's character deadCharExpel.message = originalMsg.message; --- 1856,1869 ---- * dead key's nominal character and re-post the original message. */ static void ! outputDeadKey_rePost_Ex(MSG originalMsg, int dead_key2set) { static MSG deadCharExpel; ! if (dead_key == DEAD_KEY_OFF) return; ! dead_key = dead_key2set; // Make Windows generate the dead key's character deadCharExpel.message = originalMsg.message; *************** *** 1866,1871 **** --- 1878,1892 ---- } /* + * 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,1944 **** * for some reason TranslateMessage() do not trigger a call * immediately to _OnChar() (or _OnSysChar()). */ ! if (dead_key) { /* * 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 * with the dead char now, so do nothing special and let Windows --- 1957,2004 ---- * for some reason TranslateMessage() do not trigger a call * immediately to _OnChar() (or _OnSysChar()). */ ! ! /* ! * 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 * with the dead char now, so do nothing special and let Windows *************** *** 1952,1958 **** */ if ((vk == VK_SPACE || vk == VK_BACK || vk == VK_ESCAPE)) { ! dead_key = 0; TranslateMessage(&msg); return; } --- 2012,2018 ---- */ if ((vk == VK_SPACE || vk == VK_BACK || vk == VK_ESCAPE)) { ! dead_key = DEAD_KEY_OFF; TranslateMessage(&msg); return; } *************** *** 1995,2001 **** * character output (such as a NUMPAD printable character or * the TAB key, etc...). */ ! if (dead_key && (special_keys[i].vim_code0 == 'K' || vk == VK_TAB || vk == CAR)) { outputDeadKey_rePost(msg); --- 2055,2061 ---- * character output (such as a NUMPAD printable character or * the TAB key, etc...). */ ! if (dead_key == DEAD_KEY_SET_DEFAULT && (special_keys[i].vim_code0 == 'K' || vk == VK_TAB || vk == CAR)) { outputDeadKey_rePost(msg); *************** *** 2081,2090 **** // 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) return; // Post the message as TranslateMessage would do. if (msg.message == WM_KEYDOWN) --- 2141,2168 ---- // If this is a dead key ToUnicode returns a negative value. len = ToUnicode(vk, scan_code, keyboard_state, ch, ARRAY_LENGTH(ch), 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) *** ../vim-9.0.0086/src/version.c 2022-07-26 20:42:21.822448308 +0100 --- src/version.c 2022-07-26 21:14:39.729664352 +0100 *************** *** 737,738 **** --- 737,740 ---- { /* Add new patch number below this line */ + /**/ + 87, /**/ -- hundred-and-one symptoms of being an internet addict: 143. You dream in pallettes of 216 websafe colors. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///