# HG changeset patch # User Christian Brabandt # Date 1453060805 -3600 # Node ID 4d97a97495bb7d1ba66f01a631abcaabb6fe5e31 # Parent bfc4a1d7725c53256d19e9ccd6d0188ebc7ab035 commit https://github.com/vim/vim/commit/25b2b94ea73eff2aeef624d2ba7f59a1a265a0c1 Author: Bram Moolenaar Date: Sun Jan 17 20:53:12 2016 +0100 patch 7.4.1124 Problem: MS-Windows: dead key behavior is not ideal. Solution: Handle dead keys differently when not in Insert or Select mode. (John Wellesz, closes https://github.com/vim/vim/issues/399) diff --git a/src/gui_w48.c b/src/gui_w48.c --- a/src/gui_w48.c +++ b/src/gui_w48.c @@ -301,18 +301,18 @@ static struct }; /* Local variables */ -static int s_button_pending = -1; +static int s_button_pending = -1; /* s_getting_focus is set when we got focus but didn't see mouse-up event yet, * so don't reset s_button_pending. */ -static int s_getting_focus = FALSE; - -static int s_x_pending; -static int s_y_pending; -static UINT s_kFlags_pending; -static UINT 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 s_getting_focus = FALSE; + +static int s_x_pending; +static int s_y_pending; +static UINT s_kFlags_pending; +static UINT 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 */ #ifdef WIN3264 static OSVERSIONINFO os_version; /* like it says. Init in gui_mch_init() */ @@ -641,6 +641,8 @@ char_to_string(int ch, char_u *string, i int modifiers; int ch = cch; /* special keys are negative */ + dead_key = 0; + /* TRACE("OnSysChar(%d, %c)\n", ch, ch); */ /* OK, we have a character key (given by ch) which was entered with the @@ -1710,6 +1712,34 @@ gui_mch_draw_part_cursor( DeleteBrush(hbr); } + +/* + * Generates a VK_SPACE when the internal dead_key flag is set to output the + * 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; + deadCharExpel.hwnd = originalMsg.hwnd; + deadCharExpel.wParam = VK_SPACE; + + MyTranslateMessage(&deadCharExpel); + + /* re-generate the current character free of the dead char influence */ + PostMessage(originalMsg.hwnd, originalMsg.message, originalMsg.wParam, + originalMsg.lParam); +} + + /* * Process a single Windows message. * If one is not available we hang until one is. @@ -1790,21 +1820,48 @@ process_message(void) if (msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN) { vk = (int) msg.wParam; + /* - * 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 handle it. + * Handle dead keys in special conditions in other cases we let Windows + * handle them and do not interfere. + * + * The dead_key flag must be reset on several occasions: + * - in _OnChar() (or _OnSysChar()) as any dead key was necessarily + * consumed at that point (This is when we let Windows combine the + * dead character on its own) * - * Note that VK_SPACE combines with the dead_key's character and only - * one WM_CHAR will be generated by TranslateMessage(), in the two - * other cases two WM_CHAR will be generated: the dead char and VK_BACK - * or VK_ESCAPE. That is most likely what the user expects. + * - Before doing something special such as regenerating keypresses to + * expel the dead character as this could trigger an infinite loop if + * for some reason MyTranslateMessage() do not trigger a call + * immediately to _OnChar() (or _OnSysChar()). */ - if (dead_key && (vk == VK_SPACE || vk == VK_BACK || vk == VK_ESCAPE)) + if (dead_key) { - dead_key = 0; - MyTranslateMessage(&msg); - 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 + * handle it. + * + * Note that VK_SPACE combines with the dead_key's character and + * only one WM_CHAR will be generated by TranslateMessage(), in + * the two other cases two WM_CHAR will be generated: the dead + * char and VK_BACK or VK_ESCAPE. That is most likely what the + * user expects. + */ + if ((vk == VK_SPACE || vk == VK_BACK || vk == VK_ESCAPE)) + { + dead_key = 0; + MyTranslateMessage(&msg); + return; + } + /* In modes where we are not typing, dead keys should behave + * normally */ + else if (!(get_real_state() & (INSERT | CMDLINE | SELECTMODE))) + { + outputDeadKey_rePost(msg); + return; + } } /* Check for CTRL-BREAK */ @@ -1822,6 +1879,19 @@ process_message(void) if (special_keys[i].key_sym == vk && (vk != VK_SPACE || !(GetKeyState(VK_MENU) & 0x8000))) { + /* + * Behave as exected if we have a dead key and the special key + * is a key that would normally trigger the dead key nominal + * 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); + return; + } + #ifdef FEAT_MENU /* Check for : Windows selects the menu. When is * mapped we want to use the mapping instead. */ diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -742,6 +742,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1124, +/**/ 1123, /**/ 1122,