summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnton Sharonov <anton.sharonov@gmail.com>2024-01-23 23:19:02 +0100
committerChristian Brabandt <cb@256bit.org>2024-01-23 23:19:02 +0100
commit68d9472c65ec75725a0b431048bebe036921331c (patch)
tree3fccc1018b80c681e556138b81d4c7fe4a4362e7
parent1fb41032060df09ca2640dc49541f11062f6dfaa (diff)
patch 9.1.0050: Win32 Keyboard handling is sub-optimalv9.1.0050
Problem: Win32 Keyboard handling is sub-optimal and has many issues with international keyboards (risa2000) (after v8.2.4807) Solution: soft-rollback the change, allow the user to select a suitable key-translation strategy (Anton Sharonov) Read about the details in the help: :h w32-experimental-keycode-trans-strategy fixes: #10615 fixes: #12595 closes: #12752 Signed-off-by: Anton Sharonov <anton.sharonov@gmail.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
-rw-r--r--runtime/doc/gui_w32.txt36
-rw-r--r--runtime/doc/tags1
-rw-r--r--runtime/doc/testing.txt12
-rw-r--r--src/gui_w32.c513
-rw-r--r--src/testing.c2
-rw-r--r--src/version.c2
6 files changed, 483 insertions, 83 deletions
diff --git a/runtime/doc/gui_w32.txt b/runtime/doc/gui_w32.txt
index 780c0a00fa..c6f5725d82 100644
--- a/runtime/doc/gui_w32.txt
+++ b/runtime/doc/gui_w32.txt
@@ -1,4 +1,4 @@
-*gui_w32.txt* For Vim version 9.1. Last change: 2022 Mar 09
+*gui_w32.txt* For Vim version 9.1. Last change: 2024 Jan 23
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -454,4 +454,38 @@ You may need to get the vim16x16.xpm file from github:
https://github.com/vim/vim/blob/master/runtime/vim16x16.xpm
+Keycode translation strategy *w32-experimental-keycode-trans-strategy*
+
+In Patch v8.2.4807 W32 GVIM was changed over to experimental keycode
+translation method with the aim to be able to use more keyboard shortcuts and
+especially supporting non-standard keyboard layouts. In order to implement
+this support Win API TranslateMessage() call was dropped, and instead the
+recognition of keycode was changed over to ToUnicode() Win API call. This
+approach uncovered numerous corner cases, which are apparently covered by
+TranslateMessage() implementation, each of it is necessary to be dealt with on
+an individual basis. Therefore the decision was taken to declare this
+functionality experimental for the time being and to recover "classic" keycode
+translation method as default again.
+
+Discussion about use of "experimental" keycode translation method will
+probably last some time yet. In the meantime, if you are impacted by this
+change over back to "classic" keycode translation method in W32 GVIM, you can
+enable "experimental" translation method again in your vimrc using following
+snippet:
+>
+ :call test_mswin_event('set_keycode_trans_strategy', {'strategy': 'experimental'})
+<
+Similarly, in case you need to turn back "classic" keycode translation method
+(for example for testing purposes), please use:
+>
+ :call test_mswin_event('set_keycode_trans_strategy', {'strategy': 'classic'})
+<
+Alternatively (this method is especially useful for the TINY GVIM build, where
+test_mswin_event() cannot be called), an environment variable
+VIM_KEYCODE_TRANS_STRATEGY can be set to the desired value ("experimental" or
+"classic"), to override the default, e.g., type in dos prompt:
+>
+ set VIM_KEYCODE_TRANS_STRATEGY=experimental
+ gvim.exe
+<
vim:tw=78:sw=4:ts=8:noet:ft=help:norl:
diff --git a/runtime/doc/tags b/runtime/doc/tags
index 46a396e9fc..809c6fd33f 100644
--- a/runtime/doc/tags
+++ b/runtime/doc/tags
@@ -11189,6 +11189,7 @@ vt100-cursor-keys term.txt /*vt100-cursor-keys*
vt100-function-keys term.txt /*vt100-function-keys*
w motion.txt /*w*
w32-clientserver remote.txt /*w32-clientserver*
+w32-experimental-keycode-trans-strategy gui_w32.txt /*w32-experimental-keycode-trans-strategy*
w32-xpm-support gui_w32.txt /*w32-xpm-support*
w: eval.txt /*w:*
w:current_syntax syntax.txt /*w:current_syntax*
diff --git a/runtime/doc/testing.txt b/runtime/doc/testing.txt
index dabdd32b02..442285dc86 100644
--- a/runtime/doc/testing.txt
+++ b/runtime/doc/testing.txt
@@ -1,4 +1,4 @@
-*testing.txt* For Vim version 9.1. Last change: 2023 May 18
+*testing.txt* For Vim version 9.1. Last change: 2024 Jan 23
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -234,6 +234,8 @@ test_mswin_event({event}, {args}) *test_mswin_event()*
{event} is a String and the supported values are:
"mouse" mouse event.
"key" keyboard event.
+ "set_keycode_trans_strategy"
+ Change the key transation method
"mouse":
Inject either a mouse button click, or a mouse move, event.
@@ -290,6 +292,14 @@ test_mswin_event({event}, {args}) *test_mswin_event()*
unprocessed key events. All other {args}
items are optional when this is set and true.
+ "set_keycode_trans_strategy":
+ |w32-experimental-keycode-trans-strategy|
+ Switch the keycode translation method. The supported methods are:
+ experimental: The method used after Patch v8.2.4807
+ using ToUnicode() Win API call.
+ classic: The method used pre Patch v8.2.4807
+ using the TranslateMessage() Win API call.
+
Returns TRUE if the event is successfully added or executed,
FALSE if there is a failure.
diff --git a/src/gui_w32.c b/src/gui_w32.c
index 0935ecfd12..f628dd663b 100644
--- a/src/gui_w32.c
+++ b/src/gui_w32.c
@@ -50,6 +50,86 @@ static int gui_mswin_get_menu_height(int fix_window);
# define gui_mswin_get_menu_height(fix_window) 0
#endif
+typedef struct keycode_trans_strategy {
+ void (*ptr_on_char) (HWND /*hwnd UNUSED*/, UINT /*cch*/, int /*cRepeat UNUSED*/);
+ void (*ptr_on_sys_char) (HWND /*hwnd UNUSED*/, UINT /*cch*/, int /*cRepeat UNUSED*/);
+ void (*ptr_process_message_usual_key) (UINT /*vk*/, const MSG* /*pmsg*/);
+ int (*ptr_get_active_modifiers)(void);
+ int (*is_experimental)(void);
+} keycode_trans_strategy;
+
+// forward declarations for input instance initializer
+static void _OnChar_experimental(HWND /*hwnd UNUSED*/, UINT /*cch*/, int /*cRepeat UNUSED*/);
+static void _OnSysChar_experimental(HWND /*hwnd UNUSED*/, UINT /*cch*/, int /*cRepeat UNUSED*/);
+static void process_message_usual_key_experimental(UINT /*vk*/, const MSG* /*pmsg*/);
+static int get_active_modifiers_experimental(void);
+static int is_experimental_true(void);
+
+keycode_trans_strategy keycode_trans_strategy_experimental = {
+ _OnChar_experimental // ptr_on_char
+ , _OnSysChar_experimental // ptr_on_sys_char
+ , process_message_usual_key_experimental // ptr_process_message_usual_key
+ , get_active_modifiers_experimental
+ , is_experimental_true
+};
+
+// forward declarations for input instance initializer
+static void _OnChar_classic(HWND /*hwnd UNUSED*/, UINT /*cch*/, int /*cRepeat UNUSED*/);
+static void _OnSysChar_classic(HWND /*hwnd UNUSED*/, UINT /*cch*/, int /*cRepeat UNUSED*/);
+static void process_message_usual_key_classic(UINT /*vk*/, const MSG* /*pmsg*/);
+static int get_active_modifiers_classic(void);
+static int is_experimental_false(void);
+
+keycode_trans_strategy keycode_trans_strategy_classic = {
+ _OnChar_classic // ptr_on_char
+ , _OnSysChar_classic // ptr_on_sys_char
+ , process_message_usual_key_classic // ptr_process_message_usual_key
+ , get_active_modifiers_classic
+ , is_experimental_false
+};
+
+keycode_trans_strategy *keycode_trans_strategy_used = NULL;
+
+static int is_experimental_true(void)
+{
+ return 1;
+}
+
+static int is_experimental_false(void)
+{
+ return 0;
+}
+
+/*
+ * Initialize the keycode translation strategy.
+ */
+static void keycode_trans_strategy_init(void)
+{
+ const char *strategy = NULL;
+
+ // set default value as fallback
+ keycode_trans_strategy_used = &keycode_trans_strategy_classic;
+
+ strategy = getenv("VIM_KEYCODE_TRANS_STRATEGY");
+ if (strategy == NULL)
+ {
+ return;
+ }
+
+ if (STRICMP(strategy, "classic") == 0)
+ {
+ keycode_trans_strategy_used = &keycode_trans_strategy_classic;
+ return;
+ }
+
+ if (STRICMP(strategy, "experimental") == 0)
+ {
+ keycode_trans_strategy_used = &keycode_trans_strategy_experimental;
+ return;
+ }
+
+}
+
#if defined(FEAT_RENDER_OPTIONS) || defined(PROTO)
int
gui_mch_set_rendering_options(char_u *s)
@@ -734,7 +814,7 @@ _OnDeadChar(
UINT ch UNUSED,
int cRepeat UNUSED)
{
- dead_key = 1;
+ dead_key = DEAD_KEY_SET_DEFAULT;
}
/*
@@ -831,8 +911,17 @@ char_to_string(int ch, char_u *string, int slen, int had_alt)
return len;
}
+/*
+ * Experimental implementation, introduced in v8.2.4807
+ * "processing key event in Win32 GUI is not ideal"
+ *
+ * TODO: since introduction, this experimental function started
+ * to be used as well outside of original key press/processing
+ * area, and usages not via "get_active_modifiers_via_ptr" should
+ * be watched.
+ */
static int
-get_active_modifiers(void)
+get_active_modifiers_experimental(void)
{
int modifiers = 0;
@@ -859,6 +948,46 @@ get_active_modifiers(void)
}
/*
+ * "Classic" implementation, existing prior to v8.2.4807
+ */
+ static int
+get_active_modifiers_classic(void)
+{
+ int modifiers = 0;
+
+ if (GetKeyState(VK_SHIFT) & 0x8000)
+ modifiers |= MOD_MASK_SHIFT;
+ /*
+ * Don't use caps-lock as shift, because these are special keys
+ * being considered here, and we only want letters to get
+ * shifted -- webb
+ */
+ /*
+ if (GetKeyState(VK_CAPITAL) & 0x0001)
+ modifiers ^= MOD_MASK_SHIFT;
+ */
+ if (GetKeyState(VK_CONTROL) & 0x8000)
+ modifiers |= MOD_MASK_CTRL;
+ if (GetKeyState(VK_MENU) & 0x8000)
+ modifiers |= MOD_MASK_ALT;
+
+ return modifiers;
+}
+
+ static int
+get_active_modifiers(void)
+{
+ return get_active_modifiers_experimental();
+}
+
+ static int
+get_active_modifiers_via_ptr(void)
+{
+ // marshal to corresponding implementation
+ return keycode_trans_strategy_used->ptr_get_active_modifiers();
+}
+
+/*
* Key hit, add it to the input buffer.
*/
static void
@@ -867,6 +996,20 @@ _OnChar(
UINT cch,
int cRepeat UNUSED)
{
+ // marshal to corresponding implementation
+ keycode_trans_strategy_used->ptr_on_char(hwnd, cch, cRepeat);
+}
+
+/*
+ * Experimental implementation, introduced in v8.2.4807
+ * "processing key event in Win32 GUI is not ideal"
+ */
+ static void
+_OnChar_experimental(
+ HWND hwnd UNUSED,
+ UINT cch,
+ int cRepeat UNUSED)
+{
char_u string[40];
int len = 0;
int modifiers;
@@ -880,7 +1023,7 @@ _OnChar(
if (dead_key != DEAD_KEY_TRANSIENT_IN_ON_CHAR)
dead_key = DEAD_KEY_OFF;
- modifiers = get_active_modifiers();
+ modifiers = get_active_modifiers_experimental();
ch = simplify_key(ch, &modifiers);
@@ -917,6 +1060,30 @@ _OnChar(
}
/*
+ * "Classic" implementation, existing prior to v8.2.4807
+ */
+ static void
+_OnChar_classic(
+ 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)
+ {
+ trash_input_buf();
+ got_int = TRUE;
+ }
+
+ add_to_input_buf(string, len);
+}
+
+/*
* Alt-Key hit, add it to the input buffer.
*/
static void
@@ -925,6 +1092,20 @@ _OnSysChar(
UINT cch,
int cRepeat UNUSED)
{
+ // marshal to corresponding implementation
+ keycode_trans_strategy_used->ptr_on_sys_char(hwnd, cch, cRepeat);
+}
+
+/*
+ * Experimental implementation, introduced in v8.2.4807
+ * "processing key event in Win32 GUI is not ideal"
+ */
+ static void
+_OnSysChar_experimental(
+ HWND hwnd UNUSED,
+ UINT cch,
+ int cRepeat UNUSED)
+{
char_u string[40]; // Enough for multibyte character
int len;
int modifiers;
@@ -936,7 +1117,69 @@ _OnSysChar(
// 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
// CAPSLOCK is pressed) at this point.
- modifiers = get_active_modifiers();
+ modifiers = get_active_modifiers_experimental();
+ 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;
+
+ len = 0;
+ if (modifiers)
+ {
+ string[len++] = CSI;
+ string[len++] = KS_MODIFIER;
+ string[len++] = modifiers;
+ }
+
+ if (IS_SPECIAL((int)ch))
+ {
+ string[len++] = CSI;
+ string[len++] = K_SECOND((int)ch);
+ string[len++] = K_THIRD((int)ch);
+ }
+ else
+ {
+ // Although the documentation isn't clear about it, we assume "ch" is
+ // a Unicode character.
+ len += char_to_string(ch, string + len, 40 - len, TRUE);
+ }
+
+ add_to_input_buf(string, len);
+}
+
+/*
+ * "Classic" implementation, existing prior to v8.2.4807
+ */
+ static void
+_OnSysChar_classic(
+ HWND hwnd UNUSED,
+ UINT cch,
+ int cRepeat UNUSED)
+{
+ char_u string[40]; // Enough for multibyte character
+ int len;
+ 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
+ // 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
+ // CAPSLOCK is pressed) at this point.
+ modifiers = MOD_MASK_ALT;
+ 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 '*'
@@ -1905,6 +2148,137 @@ outputDeadKey_rePost(MSG originalMsg)
}
/*
+ * Refactored out part of process_message(), responsible for
+ * handling the case of "not a special key"
+ */
+static void process_message_usual_key(UINT vk, const MSG *pmsg)
+{
+ // marshal to corresponding implementation
+ keycode_trans_strategy_used->ptr_process_message_usual_key(vk, pmsg);
+}
+
+/*
+ * Experimental implementation, introduced in v8.2.4807
+ * "processing key event in Win32 GUI is not ideal"
+ */
+static void process_message_usual_key_experimental(UINT vk, const MSG *pmsg)
+{
+ WCHAR ch[8];
+ int len;
+ int i;
+ UINT scan_code;
+ BYTE keyboard_state[256];
+
+ // 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_CAPITAL) & 0x0001)
+ keyboard_state[VK_CAPITAL] = 0x01;
+ // Alt-Gr is synthesized as Alt + Ctrl.
+ if ((GetKeyState(VK_RMENU) & 0x8000)
+ && (GetKeyState(VK_CONTROL) & 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);
+ if (len < 0)
+ dead_key = DEAD_KEY_SET_DEFAULT;
+
+ if (len <= 0)
+ {
+ int wm_char = NUL;
+
+ if (dead_key == DEAD_KEY_SET_DEFAULT
+ && (GetKeyState(VK_CONTROL) & 0x8000))
+ {
+ if ( // AZERTY CTRL+dead_circumflex
+ (vk == 221 && scan_code == 26)
+ // QWERTZ CTRL+dead_circumflex
+ || (vk == 220 && scan_code == 41))
+ wm_char = '[';
+ if ( // QWERTZ CTRL+dead_two-overdots
+ (vk == 192 && scan_code == 27))
+ wm_char = ']';
+ }
+ if (wm_char != NUL)
+ {
+ // post WM_CHAR='[' - which will be interpreted with CTRL
+ // still hold as ESC
+ PostMessageW(pmsg->hwnd, WM_CHAR, wm_char, pmsg->lParam);
+ // ask _OnChar() to not touch this state, wait for next key
+ // press and maintain knowledge that we are "poisoned" with
+ // "dead state"
+ dead_key = DEAD_KEY_TRANSIENT_IN_ON_CHAR;
+ }
+ return;
+ }
+
+ // Post the message as TranslateMessage would do.
+ if (pmsg->message == WM_KEYDOWN)
+ {
+ for (i = 0; i < len; i++)
+ PostMessageW(pmsg->hwnd, WM_CHAR, ch[i], pmsg->lParam);
+ }
+ else
+ {
+ for (i = 0; i < len; i++)
+ PostMessageW(pmsg->hwnd, WM_SYSCHAR, ch[i], pmsg->lParam);
+ }
+}
+
+/*
+ * "Classic" implementation, existing prior to v8.2.4807
+ */
+static void process_message_usual_key_classic(UINT vk, const MSG *pmsg)
+{
+ char_u string[40];
+
+ // 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(pmsg);
+ }
+ else
+ TranslateMessage(pmsg);
+}
+
+/*
* Process a single Windows message.
* If one is not available we hang until one is.
*/
@@ -1920,7 +2294,14 @@ process_message(void)
#ifdef FEAT_MENU
static char_u k10[] = {K_SPECIAL, 'k', ';', 0};
#endif
- BYTE keyboard_state[256];
+ static int keycode_trans_strategy_initialized = 0;
+
+ // lazy initialize - first time only
+ if (!keycode_trans_strategy_initialized)
+ {
+ keycode_trans_strategy_initialized = 1;
+ keycode_trans_strategy_init();
+ }
GetMessageW(&msg, NULL, 0, 0);
@@ -1980,8 +2361,11 @@ process_message(void)
* We are at the moment after WM_CHAR with DEAD_KEY_SKIP_ON_CHAR event
* was handled by _WndProc, this keypress we want to process normally
*/
- if (dead_key == DEAD_KEY_SKIP_ON_CHAR)
+ if (keycode_trans_strategy_used->is_experimental()
+ && dead_key == DEAD_KEY_SKIP_ON_CHAR)
+ {
dead_key = DEAD_KEY_OFF;
+ }
if (dead_key != DEAD_KEY_OFF)
{
@@ -2003,7 +2387,8 @@ process_message(void)
* outputDeadKey_rePost() since we do not wish to reset dead_key
* value.
*/
- if (dead_key == DEAD_KEY_TRANSIENT_IN_ON_CHAR)
+ if (keycode_trans_strategy_used->is_experimental() &&
+ dead_key == DEAD_KEY_TRANSIENT_IN_ON_CHAR)
{
outputDeadKey_rePost_Ex(msg,
/*dead_key2set=*/DEAD_KEY_SKIP_ON_CHAR);
@@ -2090,7 +2475,7 @@ process_message(void)
NULL, NULL) == NULL)
break;
#endif
- modifiers = get_active_modifiers();
+ modifiers = get_active_modifiers_via_ptr();
if (special_keys[i].vim_code1 == NUL)
key = special_keys[i].vim_code0;
@@ -2131,78 +2516,7 @@ process_message(void)
// Not a special key.
if (special_keys[i].key_sym == 0)
{
- WCHAR ch[8];
- int len;
- int i;
- UINT scan_code;
-
- // 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_CAPITAL) & 0x0001)
- keyboard_state[VK_CAPITAL] = 0x01;
- // Alt-Gr is synthesized as Alt + Ctrl.
- if ((GetKeyState(VK_RMENU) & 0x8000)
- && (GetKeyState(VK_CONTROL) & 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);
- if (len < 0)
- dead_key = DEAD_KEY_SET_DEFAULT;
-
- if (len <= 0)
- {
- int wm_char = NUL;
-
- if (dead_key == DEAD_KEY_SET_DEFAULT
- && (GetKeyState(VK_CONTROL) & 0x8000))
- {
- if ( // AZERTY CTRL+dead_circumflex
- (vk == 221 && scan_code == 26)
- // QWERTZ CTRL+dead_circumflex
- || (vk == 220 && scan_code == 41))
- wm_char = '[';
- if ( // QWERTZ CTRL+dead_two-overdots
- (vk == 192 && scan_code == 27))
- wm_char = ']';
- }
- if (wm_char != NUL)
- {
- // post WM_CHAR='[' - which will be interpreted with CTRL
- // still hold as ESC
- PostMessageW(msg.hwnd, WM_CHAR, wm_char, msg.lParam);
- // ask _OnChar() to not touch this state, wait for next key
- // press and maintain knowledge that we are "poisoned" with
- // "dead state"
- dead_key = DEAD_KEY_TRANSIENT_IN_ON_CHAR;
- }
- 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);
- }
+ process_message_usual_key(vk, &msg);
}
}
#ifdef FEAT_MBYTE_IME
@@ -8875,6 +9189,43 @@ test_gui_w32_sendevent_keyboard(dict_T *args)
return TRUE;
}
+ static int
+test_gui_w32_sendevent_set_keycode_trans_strategy(dict_T *args)
+{
+ int handled = 0;
+ char_u *strategy = dict_get_string(args, "strategy", TRUE);
+
+ if (strategy)
+ {
+ if (STRICMP(strategy, "classic") == 0)
+ {
+ handled = 1;
+ keycode_trans_strategy_used = &keycode_trans_strategy_classic;
+ }
+ else if (STRICMP(strategy, "experimental") == 0)
+ {
+ handled = 1;
+ keycode_trans_strategy_used = &keycode_trans_strategy_experimental;
+ }
+ }
+
+ if (!handled)
+ {
+ if (strategy == NULL)
+ {
+ semsg(_(e_missing_argument_str), "strategy");
+ }
+ else
+ {
+ semsg(_(e_invalid_value_for_argument_str_str), "strategy", strategy);
+ vim_free(strategy);
+ }
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
int
test_gui_w32_sendevent(char_u *event, dict_T *args)
{
@@ -8882,6 +9233,8 @@ test_gui_w32_sendevent(char_u *event, dict_T *args)
return test_gui_w32_sendevent_keyboard(args);
else if (STRICMP(event, "mouse") == 0)
return test_gui_w32_sendevent_mouse(args);
+ else if (STRICMP(event, "set_keycode_trans_strategy") == 0)
+ return test_gui_w32_sendevent_set_keycode_trans_strategy(args);
else
{
semsg(_(e_invalid_value_for_argument_str_str), "event", event);
diff --git a/src/testing.c b/src/testing.c
index 1835643689..0d731daa76 100644
--- a/src/testing.c
+++ b/src/testing.c
@@ -1539,7 +1539,7 @@ f_test_gui_event(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
rettv->vval.v_number = test_gui_find_repl(argvars[1].vval.v_dict);
# endif
# ifdef MSWIN
- else if (STRCMP(event, "key") == 0 || STRCMP(event, "mouse") == 0)
+ else if (STRCMP(event, "key") == 0 || STRCMP(event, "mouse") == 0 || STRCMP(event, "set_keycode_trans_strategy") == 0)
rettv->vval.v_number = test_mswin_event(event, argvars[1].vval.v_dict);
# endif
else if (STRCMP(event, "mouse") == 0)
diff --git a/src/version.c b/src/version.c
index 2a54c47940..3b56f2f611 100644
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 50,
+/**/
49,
/**/
48,