]> granicus.if.org Git - vim/commitdiff
patch 7.4.1124 v7.4.1124
authorBram Moolenaar <Bram@vim.org>
Sun, 17 Jan 2016 19:53:12 +0000 (20:53 +0100)
committerBram Moolenaar <Bram@vim.org>
Sun, 17 Jan 2016 19:53:12 +0000 (20:53 +0100)
Problem:    MS-Windows: dead key behavior is not ideal.
Solution:   Handle dead keys differently when not in Insert or Select mode.
            (John Wellesz, closes #399)

src/gui_w48.c
src/version.c

index ef288e1e64963580c1380d97976c30cf52170cc1..1f3822be93ca6d55e1c19dee17b659a2a667aebd 100644 (file)
@@ -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_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_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 @@ _OnSysChar(
     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 <F10>: Windows selects the menu.  When <F10> is
                 * mapped we want to use the mapping instead. */
index 09176eb547988d6de162d87f910163bb928951f0..a1eb08399c2e5666bb03e2cadfd84de8ee4990ee 100644 (file)
@@ -741,6 +741,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1124,
 /**/
     1123,
 /**/