To: vim_dev@googlegroups.com Subject: Patch 8.2.4807 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.4807 Problem: Processing key eveints in Win32 GUI is not ideal. Solution: Improve processing of key events. (closes #10155) Files: src/gui_w32.c *** ../vim-8.2.4806/src/gui_w32.c 2022-04-13 11:47:21.711886557 +0100 --- src/gui_w32.c 2022-04-22 22:45:08.369018686 +0100 *************** *** 824,837 **** static void _OnChar( HWND hwnd UNUSED, ! UINT ch, int cRepeat UNUSED) { char_u string[40]; int len = 0; dead_key = 0; len = char_to_string(ch, string, 40, FALSE); if (len == 1 && string[0] == Ctrl_C && ctrl_c_interrupts) { --- 824,862 ---- static void _OnChar( HWND hwnd UNUSED, ! 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,865 **** 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 --- 883,888 ---- *************** *** 1816,1822 **** originalMsg.lParam); } - /* * Process a single Windows message. * If one is not available we hang until one is. --- 1839,1844 ---- *************** *** 1833,1838 **** --- 1855,1861 ---- #ifdef FEAT_MENU static char_u k10[] = {K_SPECIAL, 'k', ';', 0}; #endif + BYTE keyboard_state[256]; GetMessageW(&msg, NULL, 0, 0); *************** *** 1894,1911 **** * 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 --- 1917,1926 ---- *************** *** 1926,1931 **** --- 1941,1953 ---- 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,2043 **** break; } } 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)) { ! // 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); } else ! TranslateMessage(&msg); } } #ifdef FEAT_MBYTE_IME --- 2027,2084 ---- break; } } + + // Not a special key. if (special_keys[i].key_sym == 0) { ! 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) { ! 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 ! { ! for (i = 0; i < len; i++) ! PostMessageW(msg.hwnd, WM_SYSCHAR, ch[i], msg.lParam); ! } } } #ifdef FEAT_MBYTE_IME *************** *** 3728,3735 **** 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); --- 3769,3774 ---- *************** *** 4580,4589 **** WPARAM wParam, LPARAM lParam) { ! /* ! TRACE("WndProc: hwnd = %08x, msg = %x, wParam = %x, lParam = %x\n", ! hwnd, uMsg, wParam, lParam); ! */ HandleMouseHide(uMsg, lParam); --- 4619,4626 ---- WPARAM wParam, LPARAM lParam) { ! // TRACE("WndProc: hwnd = %08x, msg = %x, wParam = %x, lParam = %x\n", ! // hwnd, uMsg, wParam, lParam); HandleMouseHide(uMsg, lParam); *************** *** 4635,4654 **** } 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. --- 4672,4677 ---- *** ../vim-8.2.4806/src/version.c 2022-04-22 21:20:22.829092772 +0100 --- src/version.c 2022-04-22 22:45:20.280996863 +0100 *************** *** 748,749 **** --- 748,751 ---- { /* Add new patch number below this line */ + /**/ + 4807, /**/ -- A day without sunshine is like, well, night. /// 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 ///