changeset 28566:893251eed714 v8.2.4807

patch 8.2.4807: processing key eveints in Win32 GUI is not ideal Commit: https://github.com/vim/vim/commit/77fc0b02e53bdc49213900e0055cb6d678ce180d Author: LemonBoy <thatlemon@gmail.com> Date: Fri Apr 22 22:45:52 2022 +0100 patch 8.2.4807: processing key eveints in Win32 GUI is not ideal Problem: Processing key eveints in Win32 GUI is not ideal. Solution: Improve processing of key events. (closes https://github.com/vim/vim/issues/10155)
author Bram Moolenaar <Bram@vim.org>
date Sat, 23 Apr 2022 00:00:04 +0200
parents 7d76c24fbb4d
children 13523a6ff9e4
files src/gui_w32.c src/version.c
diffstat 2 files changed, 85 insertions(+), 60 deletions(-) [+]
line wrap: on
line diff
--- a/src/gui_w32.c
+++ b/src/gui_w32.c
@@ -824,14 +824,39 @@ char_to_string(int ch, char_u *string, i
     static void
 _OnChar(
     HWND hwnd UNUSED,
-    UINT ch,
+    UINT cch,
     int cRepeat UNUSED)
 {
     char_u	string[40];
     int		len = 0;
+    int		modifiers = 0;
+    int		ch = cch;   // special keys are negative
 
     dead_key = 0;
 
+    if (GetKeyState(VK_SHIFT) & 0x8000)
+	modifiers |= MOD_MASK_SHIFT;
+    if (GetKeyState(VK_CONTROL) & 0x8000)
+	modifiers |= MOD_MASK_CTRL;
+
+    ch = simplify_key(ch, &modifiers);
+    // remove the SHIFT modifier for keys where it's already included, e.g.,
+    // '(' and '*'
+    modifiers = may_remove_shift_modifier(modifiers, ch);
+
+    // Unify modifiers somewhat.  No longer use ALT to set the 8th bit.
+    ch = extract_modifiers(ch, &modifiers, FALSE, NULL);
+    if (ch == CSI)
+	ch = K_CSI;
+
+    if (modifiers)
+    {
+	string[0] = CSI;
+	string[1] = KS_MODIFIER;
+	string[2] = modifiers;
+	add_to_input_buf(string, 3);
+    }
+
     len = char_to_string(ch, string, 40, FALSE);
     if (len == 1 && string[0] == Ctrl_C && ctrl_c_interrupts)
     {
@@ -858,8 +883,6 @@ char_to_string(int ch, char_u *string, i
 
     dead_key = 0;
 
-    // TRACE("OnSysChar(%d, %c)\n", ch, ch);
-
     // 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
     // that the system distinguishes Alt-a and Alt-A (Alt-Shift-a unless
@@ -1816,7 +1839,6 @@ outputDeadKey_rePost(MSG originalMsg)
 							  originalMsg.lParam);
 }
 
-
 /*
  * Process a single Windows message.
  * If one is not available we hang until one is.
@@ -1833,6 +1855,7 @@ process_message(void)
 #ifdef FEAT_MENU
     static char_u k10[] = {K_SPECIAL, 'k', ';', 0};
 #endif
+    BYTE	keyboard_state[256];
 
     GetMessageW(&msg, NULL, 0, 0);
 
@@ -1894,18 +1917,10 @@ process_message(void)
 	     * 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;
-		TranslateMessage(&msg);
-		return;
 	    }
 	    // In modes where we are not typing, dead keys should behave
 	    // normally
@@ -1926,6 +1941,13 @@ process_message(void)
 	    add_to_input_buf(string, 1);
 	}
 
+	// This is an IME event or a synthetic keystroke, let Windows handle it.
+	if (vk == VK_PROCESSKEY || vk == VK_PACKET)
+	{
+	    TranslateMessage(&msg);
+	    return;
+	}
+
 	for (i = 0; special_keys[i].key_sym != 0; i++)
 	{
 	    // ignore VK_SPACE when ALT key pressed: system menu
@@ -2005,39 +2027,58 @@ process_message(void)
 		break;
 	    }
 	}
+
+	// Not a special key.
 	if (special_keys[i].key_sym == 0)
 	{
-	    // Some keys need C-S- where they should only need C-.
-	    // Ignore 0xff, Windows XP sends it when NUMLOCK has changed since
-	    // system startup (Helmut Stiegler, 2003 Oct 3).
-	    if (vk != 0xff
-		    && (GetKeyState(VK_CONTROL) & 0x8000)
-		    && !(GetKeyState(VK_SHIFT) & 0x8000)
-		    && !(GetKeyState(VK_MENU) & 0x8000))
+	    WCHAR	ch[8];
+	    int		len;
+	    int		i;
+	    UINT	scan_code;
+
+	    if (GetKeyState(VK_SHIFT) & 0x8000)
+		modifiers |= MOD_MASK_SHIFT;
+	    if (GetKeyState(VK_CONTROL) & 0x8000)
+		modifiers |= MOD_MASK_CTRL;
+	    if (GetKeyState(VK_LMENU) & 0x8000)
+		modifiers |= MOD_MASK_ALT;
+
+	    // Construct the state table with only a few modifiers, we don't
+	    // really care about the presence of Ctrl/Alt as those modifiers are
+	    // handled by Vim separately.
+	    memset(keyboard_state, 0, 256);
+	    if (GetKeyState(VK_SHIFT) & 0x8000)
+		keyboard_state[VK_SHIFT] = 0x80;
+	    if (GetKeyState(VK_RMENU) & 0x8000)
 	    {
-		// CTRL-6 is '^'; Japanese keyboard maps '^' to vk == 0xDE
-		if (vk == '6' || MapVirtualKey(vk, 2) == (UINT)'^')
-		{
-		    string[0] = Ctrl_HAT;
-		    add_to_input_buf(string, 1);
-		}
-		// vk == 0xBD AZERTY for CTRL-'-', but CTRL-[ for * QWERTY!
-		else if (vk == 0xBD)	// QWERTY for CTRL-'-'
-		{
-		    string[0] = Ctrl__;
-		    add_to_input_buf(string, 1);
-		}
-		// CTRL-2 is '@'; Japanese keyboard maps '@' to vk == 0xC0
-		else if (vk == '2' || MapVirtualKey(vk, 2) == (UINT)'@')
-		{
-		    string[0] = Ctrl_AT;
-		    add_to_input_buf(string, 1);
-		}
-		else
-		    TranslateMessage(&msg);
+		keyboard_state[VK_MENU] = 0x80;
+		keyboard_state[VK_CONTROL] = 0x80;
+	    }
+
+	    // Translate the virtual key according to the current keyboard
+	    // layout.
+	    scan_code = MapVirtualKey(vk, MAPVK_VK_TO_VSC);
+	    // Convert the scan-code into a sequence of zero or more unicode
+	    // codepoints.
+	    // 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)
+	    {
+		for (i = 0; i < len; i++)
+		    PostMessageW(msg.hwnd, WM_CHAR, ch[i], msg.lParam);
 	    }
 	    else
-		TranslateMessage(&msg);
+	    {
+		for (i = 0; i < len; i++)
+		    PostMessageW(msg.hwnd, WM_SYSCHAR, ch[i], msg.lParam);
+	    }
 	}
     }
 #ifdef FEAT_MBYTE_IME
@@ -3728,8 +3769,6 @@ gui_mch_browsedir(char_u *title, char_u 
     POINT   pt;
     int_u   modifiers = 0;
 
-    // TRACE("_OnDropFiles: %d files dropped\n", cFiles);
-
     // Obtain dropped position
     DragQueryPoint(hDrop, &pt);
     MapWindowPoints(s_hwnd, s_textArea, &pt, 1);
@@ -4580,10 +4619,8 @@ destroy_sizing_tip(void)
     WPARAM wParam,
     LPARAM lParam)
 {
-    /*
-    TRACE("WndProc: hwnd = %08x, msg = %x, wParam = %x, lParam = %x\n",
-	  hwnd, uMsg, wParam, lParam);
-    */
+    // TRACE("WndProc: hwnd = %08x, msg = %x, wParam = %x, lParam = %x\n",
+    //       hwnd, uMsg, wParam, lParam);
 
     HandleMouseHide(uMsg, lParam);
 
@@ -4635,20 +4672,6 @@ destroy_sizing_tip(void)
 	}
 	break;
 
-    case WM_KEYUP:
-	// handle CTRL-/
-	if ((GetKeyState(VK_CONTROL) & 0x8000) != 0 && wParam == 0xBF)
-	{
-	    char_u string[4];
-
-	    string[0] = CSI;
-	    string[1] = KS_MODIFIER;
-	    string[2] = MOD_MASK_CTRL;
-	    string[3] = 0x2F;
-	    add_to_input_buf(string, 4);
-	}
-	return 0L;
-
     case WM_CHAR:
 	// Don't use HANDLE_MSG() for WM_CHAR, it truncates wParam to a single
 	// byte while we want the UTF-16 character value.
--- a/src/version.c
+++ b/src/version.c
@@ -747,6 +747,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    4807,
+/**/
     4806,
 /**/
     4805,