comparison src/gui_w32.c @ 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 16bd027b039e
children 7c96d7924ea5
comparison
equal deleted inserted replaced
28565:7d76c24fbb4d 28566:893251eed714
822 * Key hit, add it to the input buffer. 822 * Key hit, add it to the input buffer.
823 */ 823 */
824 static void 824 static void
825 _OnChar( 825 _OnChar(
826 HWND hwnd UNUSED, 826 HWND hwnd UNUSED,
827 UINT ch, 827 UINT cch,
828 int cRepeat UNUSED) 828 int cRepeat UNUSED)
829 { 829 {
830 char_u string[40]; 830 char_u string[40];
831 int len = 0; 831 int len = 0;
832 int modifiers = 0;
833 int ch = cch; // special keys are negative
832 834
833 dead_key = 0; 835 dead_key = 0;
836
837 if (GetKeyState(VK_SHIFT) & 0x8000)
838 modifiers |= MOD_MASK_SHIFT;
839 if (GetKeyState(VK_CONTROL) & 0x8000)
840 modifiers |= MOD_MASK_CTRL;
841
842 ch = simplify_key(ch, &modifiers);
843 // remove the SHIFT modifier for keys where it's already included, e.g.,
844 // '(' and '*'
845 modifiers = may_remove_shift_modifier(modifiers, ch);
846
847 // Unify modifiers somewhat. No longer use ALT to set the 8th bit.
848 ch = extract_modifiers(ch, &modifiers, FALSE, NULL);
849 if (ch == CSI)
850 ch = K_CSI;
851
852 if (modifiers)
853 {
854 string[0] = CSI;
855 string[1] = KS_MODIFIER;
856 string[2] = modifiers;
857 add_to_input_buf(string, 3);
858 }
834 859
835 len = char_to_string(ch, string, 40, FALSE); 860 len = char_to_string(ch, string, 40, FALSE);
836 if (len == 1 && string[0] == Ctrl_C && ctrl_c_interrupts) 861 if (len == 1 && string[0] == Ctrl_C && ctrl_c_interrupts)
837 { 862 {
838 trash_input_buf(); 863 trash_input_buf();
855 int len; 880 int len;
856 int modifiers; 881 int modifiers;
857 int ch = cch; // special keys are negative 882 int ch = cch; // special keys are negative
858 883
859 dead_key = 0; 884 dead_key = 0;
860
861 // TRACE("OnSysChar(%d, %c)\n", ch, ch);
862 885
863 // OK, we have a character key (given by ch) which was entered with the 886 // OK, we have a character key (given by ch) which was entered with the
864 // ALT key pressed. Eg, if the user presses Alt-A, then ch == 'A'. Note 887 // ALT key pressed. Eg, if the user presses Alt-A, then ch == 'A'. Note
865 // that the system distinguishes Alt-a and Alt-A (Alt-Shift-a unless 888 // that the system distinguishes Alt-a and Alt-A (Alt-Shift-a unless
866 // CAPSLOCK is pressed) at this point. 889 // CAPSLOCK is pressed) at this point.
1814 // re-generate the current character free of the dead char influence 1837 // re-generate the current character free of the dead char influence
1815 PostMessage(originalMsg.hwnd, originalMsg.message, originalMsg.wParam, 1838 PostMessage(originalMsg.hwnd, originalMsg.message, originalMsg.wParam,
1816 originalMsg.lParam); 1839 originalMsg.lParam);
1817 } 1840 }
1818 1841
1819
1820 /* 1842 /*
1821 * Process a single Windows message. 1843 * Process a single Windows message.
1822 * If one is not available we hang until one is. 1844 * If one is not available we hang until one is.
1823 */ 1845 */
1824 static void 1846 static void
1831 int modifiers = 0; 1853 int modifiers = 0;
1832 int key; 1854 int key;
1833 #ifdef FEAT_MENU 1855 #ifdef FEAT_MENU
1834 static char_u k10[] = {K_SPECIAL, 'k', ';', 0}; 1856 static char_u k10[] = {K_SPECIAL, 'k', ';', 0};
1835 #endif 1857 #endif
1858 BYTE keyboard_state[256];
1836 1859
1837 GetMessageW(&msg, NULL, 0, 0); 1860 GetMessageW(&msg, NULL, 0, 0);
1838 1861
1839 #ifdef FEAT_OLE 1862 #ifdef FEAT_OLE
1840 // Look after OLE Automation commands 1863 // Look after OLE Automation commands
1892 /* 1915 /*
1893 * If a dead key was pressed and the user presses VK_SPACE, 1916 * If a dead key was pressed and the user presses VK_SPACE,
1894 * VK_BACK, or VK_ESCAPE it means that he actually wants to deal 1917 * VK_BACK, or VK_ESCAPE it means that he actually wants to deal
1895 * with the dead char now, so do nothing special and let Windows 1918 * with the dead char now, so do nothing special and let Windows
1896 * handle it. 1919 * handle it.
1897 *
1898 * Note that VK_SPACE combines with the dead_key's character and
1899 * only one WM_CHAR will be generated by TranslateMessage(), in
1900 * the two other cases two WM_CHAR will be generated: the dead
1901 * char and VK_BACK or VK_ESCAPE. That is most likely what the
1902 * user expects.
1903 */ 1920 */
1904 if ((vk == VK_SPACE || vk == VK_BACK || vk == VK_ESCAPE)) 1921 if ((vk == VK_SPACE || vk == VK_BACK || vk == VK_ESCAPE))
1905 { 1922 {
1906 dead_key = 0; 1923 dead_key = 0;
1907 TranslateMessage(&msg);
1908 return;
1909 } 1924 }
1910 // In modes where we are not typing, dead keys should behave 1925 // In modes where we are not typing, dead keys should behave
1911 // normally 1926 // normally
1912 else if (!(get_real_state() & (INSERT | CMDLINE | SELECTMODE))) 1927 else if (!(get_real_state() & (INSERT | CMDLINE | SELECTMODE)))
1913 { 1928 {
1922 trash_input_buf(); 1937 trash_input_buf();
1923 got_int = TRUE; 1938 got_int = TRUE;
1924 ctrl_break_was_pressed = TRUE; 1939 ctrl_break_was_pressed = TRUE;
1925 string[0] = Ctrl_C; 1940 string[0] = Ctrl_C;
1926 add_to_input_buf(string, 1); 1941 add_to_input_buf(string, 1);
1942 }
1943
1944 // This is an IME event or a synthetic keystroke, let Windows handle it.
1945 if (vk == VK_PROCESSKEY || vk == VK_PACKET)
1946 {
1947 TranslateMessage(&msg);
1948 return;
1927 } 1949 }
1928 1950
1929 for (i = 0; special_keys[i].key_sym != 0; i++) 1951 for (i = 0; special_keys[i].key_sym != 0; i++)
1930 { 1952 {
1931 // ignore VK_SPACE when ALT key pressed: system menu 1953 // ignore VK_SPACE when ALT key pressed: system menu
2003 add_to_input_buf(string, len); 2025 add_to_input_buf(string, len);
2004 } 2026 }
2005 break; 2027 break;
2006 } 2028 }
2007 } 2029 }
2030
2031 // Not a special key.
2008 if (special_keys[i].key_sym == 0) 2032 if (special_keys[i].key_sym == 0)
2009 { 2033 {
2010 // Some keys need C-S- where they should only need C-. 2034 WCHAR ch[8];
2011 // Ignore 0xff, Windows XP sends it when NUMLOCK has changed since 2035 int len;
2012 // system startup (Helmut Stiegler, 2003 Oct 3). 2036 int i;
2013 if (vk != 0xff 2037 UINT scan_code;
2014 && (GetKeyState(VK_CONTROL) & 0x8000) 2038
2015 && !(GetKeyState(VK_SHIFT) & 0x8000) 2039 if (GetKeyState(VK_SHIFT) & 0x8000)
2016 && !(GetKeyState(VK_MENU) & 0x8000)) 2040 modifiers |= MOD_MASK_SHIFT;
2041 if (GetKeyState(VK_CONTROL) & 0x8000)
2042 modifiers |= MOD_MASK_CTRL;
2043 if (GetKeyState(VK_LMENU) & 0x8000)
2044 modifiers |= MOD_MASK_ALT;
2045
2046 // Construct the state table with only a few modifiers, we don't
2047 // really care about the presence of Ctrl/Alt as those modifiers are
2048 // handled by Vim separately.
2049 memset(keyboard_state, 0, 256);
2050 if (GetKeyState(VK_SHIFT) & 0x8000)
2051 keyboard_state[VK_SHIFT] = 0x80;
2052 if (GetKeyState(VK_RMENU) & 0x8000)
2017 { 2053 {
2018 // CTRL-6 is '^'; Japanese keyboard maps '^' to vk == 0xDE 2054 keyboard_state[VK_MENU] = 0x80;
2019 if (vk == '6' || MapVirtualKey(vk, 2) == (UINT)'^') 2055 keyboard_state[VK_CONTROL] = 0x80;
2020 { 2056 }
2021 string[0] = Ctrl_HAT; 2057
2022 add_to_input_buf(string, 1); 2058 // Translate the virtual key according to the current keyboard
2023 } 2059 // layout.
2024 // vk == 0xBD AZERTY for CTRL-'-', but CTRL-[ for * QWERTY! 2060 scan_code = MapVirtualKey(vk, MAPVK_VK_TO_VSC);
2025 else if (vk == 0xBD) // QWERTY for CTRL-'-' 2061 // Convert the scan-code into a sequence of zero or more unicode
2026 { 2062 // codepoints.
2027 string[0] = Ctrl__; 2063 // If this is a dead key ToUnicode returns a negative value.
2028 add_to_input_buf(string, 1); 2064 len = ToUnicode(vk, scan_code, keyboard_state, ch, ARRAY_LENGTH(ch),
2029 } 2065 0);
2030 // CTRL-2 is '@'; Japanese keyboard maps '@' to vk == 0xC0 2066 dead_key = len < 0;
2031 else if (vk == '2' || MapVirtualKey(vk, 2) == (UINT)'@') 2067
2032 { 2068 if (len <= 0)
2033 string[0] = Ctrl_AT; 2069 return;
2034 add_to_input_buf(string, 1); 2070
2035 } 2071 // Post the message as TranslateMessage would do.
2036 else 2072 if (msg.message == WM_KEYDOWN)
2037 TranslateMessage(&msg); 2073 {
2074 for (i = 0; i < len; i++)
2075 PostMessageW(msg.hwnd, WM_CHAR, ch[i], msg.lParam);
2038 } 2076 }
2039 else 2077 else
2040 TranslateMessage(&msg); 2078 {
2079 for (i = 0; i < len; i++)
2080 PostMessageW(msg.hwnd, WM_SYSCHAR, ch[i], msg.lParam);
2081 }
2041 } 2082 }
2042 } 2083 }
2043 #ifdef FEAT_MBYTE_IME 2084 #ifdef FEAT_MBYTE_IME
2044 else if (msg.message == WM_IME_NOTIFY) 2085 else if (msg.message == WM_IME_NOTIFY)
2045 _OnImeNotify(msg.hwnd, (DWORD)msg.wParam, (DWORD)msg.lParam); 2086 _OnImeNotify(msg.hwnd, (DWORD)msg.wParam, (DWORD)msg.lParam);
3725 UINT cFiles = DragQueryFile(hDrop, DRAGQVAL, NULL, 0); 3766 UINT cFiles = DragQueryFile(hDrop, DRAGQVAL, NULL, 0);
3726 UINT i; 3767 UINT i;
3727 char_u **fnames; 3768 char_u **fnames;
3728 POINT pt; 3769 POINT pt;
3729 int_u modifiers = 0; 3770 int_u modifiers = 0;
3730
3731 // TRACE("_OnDropFiles: %d files dropped\n", cFiles);
3732 3771
3733 // Obtain dropped position 3772 // Obtain dropped position
3734 DragQueryPoint(hDrop, &pt); 3773 DragQueryPoint(hDrop, &pt);
3735 MapWindowPoints(s_hwnd, s_textArea, &pt, 1); 3774 MapWindowPoints(s_hwnd, s_textArea, &pt, 1);
3736 3775
4578 HWND hwnd, 4617 HWND hwnd,
4579 UINT uMsg, 4618 UINT uMsg,
4580 WPARAM wParam, 4619 WPARAM wParam,
4581 LPARAM lParam) 4620 LPARAM lParam)
4582 { 4621 {
4583 /* 4622 // TRACE("WndProc: hwnd = %08x, msg = %x, wParam = %x, lParam = %x\n",
4584 TRACE("WndProc: hwnd = %08x, msg = %x, wParam = %x, lParam = %x\n", 4623 // hwnd, uMsg, wParam, lParam);
4585 hwnd, uMsg, wParam, lParam);
4586 */
4587 4624
4588 HandleMouseHide(uMsg, lParam); 4625 HandleMouseHide(uMsg, lParam);
4589 4626
4590 s_uMsg = uMsg; 4627 s_uMsg = uMsg;
4591 s_wParam = wParam; 4628 s_wParam = wParam;
4632 { 4669 {
4633 _OnEndSession(); 4670 _OnEndSession();
4634 return 0L; 4671 return 0L;
4635 } 4672 }
4636 break; 4673 break;
4637
4638 case WM_KEYUP:
4639 // handle CTRL-/
4640 if ((GetKeyState(VK_CONTROL) & 0x8000) != 0 && wParam == 0xBF)
4641 {
4642 char_u string[4];
4643
4644 string[0] = CSI;
4645 string[1] = KS_MODIFIER;
4646 string[2] = MOD_MASK_CTRL;
4647 string[3] = 0x2F;
4648 add_to_input_buf(string, 4);
4649 }
4650 return 0L;
4651 4674
4652 case WM_CHAR: 4675 case WM_CHAR:
4653 // Don't use HANDLE_MSG() for WM_CHAR, it truncates wParam to a single 4676 // Don't use HANDLE_MSG() for WM_CHAR, it truncates wParam to a single
4654 // byte while we want the UTF-16 character value. 4677 // byte while we want the UTF-16 character value.
4655 _OnChar(hwnd, (UINT)wParam, (int)(short)LOWORD(lParam)); 4678 _OnChar(hwnd, (UINT)wParam, (int)(short)LOWORD(lParam));