mirror of
https://github.com/vim/vim
synced 2025-07-16 09:12:00 +00:00
patch 9.1.0050: Win32 Keyboard handling is sub-optimal
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>
This commit is contained in:
committed by
Christian Brabandt
parent
1fb4103206
commit
68d9472c65
@ -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
|
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
|
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:
|
vim:tw=78:sw=4:ts=8:noet:ft=help:norl:
|
||||||
|
@ -11189,6 +11189,7 @@ vt100-cursor-keys term.txt /*vt100-cursor-keys*
|
|||||||
vt100-function-keys term.txt /*vt100-function-keys*
|
vt100-function-keys term.txt /*vt100-function-keys*
|
||||||
w motion.txt /*w*
|
w motion.txt /*w*
|
||||||
w32-clientserver remote.txt /*w32-clientserver*
|
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*
|
w32-xpm-support gui_w32.txt /*w32-xpm-support*
|
||||||
w: eval.txt /*w:*
|
w: eval.txt /*w:*
|
||||||
w:current_syntax syntax.txt /*w:current_syntax*
|
w:current_syntax syntax.txt /*w:current_syntax*
|
||||||
|
@ -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
|
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:
|
{event} is a String and the supported values are:
|
||||||
"mouse" mouse event.
|
"mouse" mouse event.
|
||||||
"key" keyboard event.
|
"key" keyboard event.
|
||||||
|
"set_keycode_trans_strategy"
|
||||||
|
Change the key transation method
|
||||||
|
|
||||||
"mouse":
|
"mouse":
|
||||||
Inject either a mouse button click, or a mouse move, event.
|
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}
|
unprocessed key events. All other {args}
|
||||||
items are optional when this is set and true.
|
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,
|
Returns TRUE if the event is successfully added or executed,
|
||||||
FALSE if there is a failure.
|
FALSE if there is a failure.
|
||||||
|
|
||||||
|
513
src/gui_w32.c
513
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
|
# define gui_mswin_get_menu_height(fix_window) 0
|
||||||
#endif
|
#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)
|
#if defined(FEAT_RENDER_OPTIONS) || defined(PROTO)
|
||||||
int
|
int
|
||||||
gui_mch_set_rendering_options(char_u *s)
|
gui_mch_set_rendering_options(char_u *s)
|
||||||
@ -734,7 +814,7 @@ _OnDeadChar(
|
|||||||
UINT ch UNUSED,
|
UINT ch UNUSED,
|
||||||
int cRepeat 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;
|
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
|
static int
|
||||||
get_active_modifiers(void)
|
get_active_modifiers_experimental(void)
|
||||||
{
|
{
|
||||||
int modifiers = 0;
|
int modifiers = 0;
|
||||||
|
|
||||||
@ -858,6 +947,46 @@ get_active_modifiers(void)
|
|||||||
return modifiers;
|
return modifiers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "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.
|
* Key hit, add it to the input buffer.
|
||||||
*/
|
*/
|
||||||
@ -866,6 +995,20 @@ _OnChar(
|
|||||||
HWND hwnd UNUSED,
|
HWND hwnd UNUSED,
|
||||||
UINT cch,
|
UINT cch,
|
||||||
int cRepeat UNUSED)
|
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];
|
char_u string[40];
|
||||||
int len = 0;
|
int len = 0;
|
||||||
@ -880,7 +1023,7 @@ _OnChar(
|
|||||||
if (dead_key != DEAD_KEY_TRANSIENT_IN_ON_CHAR)
|
if (dead_key != DEAD_KEY_TRANSIENT_IN_ON_CHAR)
|
||||||
dead_key = DEAD_KEY_OFF;
|
dead_key = DEAD_KEY_OFF;
|
||||||
|
|
||||||
modifiers = get_active_modifiers();
|
modifiers = get_active_modifiers_experimental();
|
||||||
|
|
||||||
ch = simplify_key(ch, &modifiers);
|
ch = simplify_key(ch, &modifiers);
|
||||||
|
|
||||||
@ -916,6 +1059,30 @@ _OnChar(
|
|||||||
add_to_input_buf(string, len);
|
add_to_input_buf(string, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "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.
|
* Alt-Key hit, add it to the input buffer.
|
||||||
*/
|
*/
|
||||||
@ -924,6 +1091,20 @@ _OnSysChar(
|
|||||||
HWND hwnd UNUSED,
|
HWND hwnd UNUSED,
|
||||||
UINT cch,
|
UINT cch,
|
||||||
int cRepeat UNUSED)
|
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
|
char_u string[40]; // Enough for multibyte character
|
||||||
int len;
|
int len;
|
||||||
@ -936,7 +1117,69 @@ _OnSysChar(
|
|||||||
// ALT key pressed. Eg, if the user presses Alt-A, then ch == 'A'. Note
|
// 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
|
// that the system distinguishes Alt-a and Alt-A (Alt-Shift-a unless
|
||||||
// CAPSLOCK is pressed) at this point.
|
// 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);
|
ch = simplify_key(ch, &modifiers);
|
||||||
// remove the SHIFT modifier for keys where it's already included, e.g.,
|
// remove the SHIFT modifier for keys where it's already included, e.g.,
|
||||||
// '(' and '*'
|
// '(' and '*'
|
||||||
@ -1904,6 +2147,137 @@ outputDeadKey_rePost(MSG originalMsg)
|
|||||||
outputDeadKey_rePost_Ex(originalMsg, DEAD_KEY_OFF);
|
outputDeadKey_rePost_Ex(originalMsg, DEAD_KEY_OFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
* Process a single Windows message.
|
||||||
* If one is not available we hang until one is.
|
* If one is not available we hang until one is.
|
||||||
@ -1920,7 +2294,14 @@ process_message(void)
|
|||||||
#ifdef FEAT_MENU
|
#ifdef FEAT_MENU
|
||||||
static char_u k10[] = {K_SPECIAL, 'k', ';', 0};
|
static char_u k10[] = {K_SPECIAL, 'k', ';', 0};
|
||||||
#endif
|
#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);
|
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
|
* 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
|
* 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;
|
dead_key = DEAD_KEY_OFF;
|
||||||
|
}
|
||||||
|
|
||||||
if (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
|
* outputDeadKey_rePost() since we do not wish to reset dead_key
|
||||||
* value.
|
* 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,
|
outputDeadKey_rePost_Ex(msg,
|
||||||
/*dead_key2set=*/DEAD_KEY_SKIP_ON_CHAR);
|
/*dead_key2set=*/DEAD_KEY_SKIP_ON_CHAR);
|
||||||
@ -2090,7 +2475,7 @@ process_message(void)
|
|||||||
NULL, NULL) == NULL)
|
NULL, NULL) == NULL)
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
modifiers = get_active_modifiers();
|
modifiers = get_active_modifiers_via_ptr();
|
||||||
|
|
||||||
if (special_keys[i].vim_code1 == NUL)
|
if (special_keys[i].vim_code1 == NUL)
|
||||||
key = special_keys[i].vim_code0;
|
key = special_keys[i].vim_code0;
|
||||||
@ -2131,78 +2516,7 @@ process_message(void)
|
|||||||
// Not a special key.
|
// Not a special key.
|
||||||
if (special_keys[i].key_sym == 0)
|
if (special_keys[i].key_sym == 0)
|
||||||
{
|
{
|
||||||
WCHAR ch[8];
|
process_message_usual_key(vk, &msg);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef FEAT_MBYTE_IME
|
#ifdef FEAT_MBYTE_IME
|
||||||
@ -8875,6 +9189,43 @@ test_gui_w32_sendevent_keyboard(dict_T *args)
|
|||||||
return TRUE;
|
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
|
int
|
||||||
test_gui_w32_sendevent(char_u *event, dict_T *args)
|
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);
|
return test_gui_w32_sendevent_keyboard(args);
|
||||||
else if (STRICMP(event, "mouse") == 0)
|
else if (STRICMP(event, "mouse") == 0)
|
||||||
return test_gui_w32_sendevent_mouse(args);
|
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
|
else
|
||||||
{
|
{
|
||||||
semsg(_(e_invalid_value_for_argument_str_str), "event", event);
|
semsg(_(e_invalid_value_for_argument_str_str), "event", event);
|
||||||
|
@ -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);
|
rettv->vval.v_number = test_gui_find_repl(argvars[1].vval.v_dict);
|
||||||
# endif
|
# endif
|
||||||
# ifdef MSWIN
|
# 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);
|
rettv->vval.v_number = test_mswin_event(event, argvars[1].vval.v_dict);
|
||||||
# endif
|
# endif
|
||||||
else if (STRCMP(event, "mouse") == 0)
|
else if (STRCMP(event, "mouse") == 0)
|
||||||
|
@ -704,6 +704,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
50,
|
||||||
/**/
|
/**/
|
||||||
49,
|
49,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user