mirror of
https://github.com/vim/vim
synced 2025-07-16 09:12:00 +00:00
patch 9.0.1084: code handling low level MS-Windows events cannot be tested
Problem: Code handling low level MS-Windows events cannot be tested. Solution: Add test_mswin_event() and tests using it. (Christopher Plewright, closes #11622)
This commit is contained in:
committed by
Bram Moolenaar
parent
418b547881
commit
20b795e0eb
@ -666,6 +666,8 @@ test_garbagecollect_soon() none free memory soon for testing
|
||||
test_getvalue({string}) any get value of an internal variable
|
||||
test_gui_event({event}, {args}) bool generate a GUI event for testing
|
||||
test_ignore_error({expr}) none ignore a specific error
|
||||
test_mswin_event({event}, {args})
|
||||
bool generate MS-Windows event for testing
|
||||
test_null_blob() Blob null value for testing
|
||||
test_null_channel() Channel null value for testing
|
||||
test_null_dict() Dict null value for testing
|
||||
|
@ -94,7 +94,7 @@ test_gui_event({event}, {args})
|
||||
"findrepl" search and replace text.
|
||||
"mouse" mouse button click event.
|
||||
"scrollbar" move or drag the scrollbar.
|
||||
"sendevent" send a low-level GUI event.
|
||||
"key" send a low-level keyboard event.
|
||||
"tabline" select a tab page by mouse click.
|
||||
"tabmenu" select a tabline menu entry.
|
||||
|
||||
@ -178,8 +178,8 @@ test_gui_event({event}, {args})
|
||||
dragging: 1 to drag the scrollbar and 0 to click in the
|
||||
scrollbar.
|
||||
|
||||
"sendevent":
|
||||
Send a low-level GUI event (e.g. key-up or down).
|
||||
"key":
|
||||
Send a low-level keyboard event (e.g. key-up or down).
|
||||
Currently only supported on MS-Windows.
|
||||
The supported items in {args} are:
|
||||
event: The supported string values are:
|
||||
@ -223,6 +223,72 @@ test_ignore_error({expr}) *test_ignore_error()*
|
||||
Can also be used as a |method|: >
|
||||
GetErrorText()->test_ignore_error()
|
||||
|
||||
|
||||
test_mswin_event({event}, {args}) *test_mswin_event()*
|
||||
Generate a low-level MS-Windows {event} with arguments {args}
|
||||
for testing Vim functionality. It works for MS-Windows GUI
|
||||
and for the console.
|
||||
|
||||
{event} is a String and the supported values are:
|
||||
"mouse" mouse event.
|
||||
"key" keyboard event.
|
||||
|
||||
"mouse":
|
||||
Inject either a mouse button click, or a mouse move, event.
|
||||
The supported items in {args} are:
|
||||
button: mouse button. The supported values are:
|
||||
0 right mouse button
|
||||
1 middle mouse button
|
||||
2 left mouse button
|
||||
3 mouse button release
|
||||
4 scroll wheel down
|
||||
5 scroll wheel up
|
||||
6 scroll wheel left
|
||||
7 scroll wheel right
|
||||
row: mouse click row number. The first row of the
|
||||
Vim window is 1 and the last row is 'lines'.
|
||||
col: mouse click column number. The maximum value
|
||||
of {col} is 'columns'.
|
||||
Note: row and col are always interpreted as
|
||||
screen cells for the console application.
|
||||
But, they may be interpreted as pixels
|
||||
for the GUI, depending on "cell".
|
||||
multiclick: set to 1 to inject a double-click mouse event.
|
||||
modifiers: key modifiers. The supported values are:
|
||||
4 shift is pressed
|
||||
8 alt is pressed
|
||||
16 ctrl is pressed
|
||||
move: Optional; if used and TRUE then a mouse move
|
||||
event can be generated.
|
||||
Only {args} row: and col: are used and
|
||||
required.
|
||||
Only results in an event when 'mousemoveevent'
|
||||
is set or a popup uses mouse move events.
|
||||
cell: Optional for the GUI: when present and TRUE
|
||||
then "move" uses screen cells instead of pixel
|
||||
positions. Not used by the console.
|
||||
|
||||
"key":
|
||||
Send a low-level keyboard event (e.g. keyup or keydown).
|
||||
The supported items in {args} are:
|
||||
event: The supported string values are:
|
||||
keyup generate a keyup event
|
||||
keydown generate a keydown event
|
||||
keycode: Keycode to use for a keyup or a keydown event.
|
||||
modifiers: Optional; key modifiers.
|
||||
The supported values are:
|
||||
2 shift is pressed
|
||||
4 ctrl is pressed
|
||||
8 alt is pressed
|
||||
Note: These values are different from the
|
||||
mouse modifiers.
|
||||
*E1291*
|
||||
Returns TRUE if the event is successfully added, FALSE if
|
||||
there is a failure.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
GetEvent()->test_mswin_event({args})
|
||||
<
|
||||
|
||||
test_null_blob() *test_null_blob()*
|
||||
Return a |Blob| that is null. Only useful for testing.
|
||||
|
@ -1186,6 +1186,7 @@ Testing: *test-functions*
|
||||
test_getvalue() get value of an internal variable
|
||||
test_gui_event() generate a GUI event for testing
|
||||
test_ignore_error() ignore a specific error message
|
||||
test_mswin_event() generate an MS-Windows event
|
||||
test_null_blob() return a null Blob
|
||||
test_null_channel() return a null Channel
|
||||
test_null_dict() return a null Dict
|
||||
|
@ -2694,6 +2694,8 @@ static funcentry_T global_functions[] =
|
||||
ret_bool, f_test_gui_event},
|
||||
{"test_ignore_error", 1, 1, FEARG_1, arg1_string,
|
||||
ret_void, f_test_ignore_error},
|
||||
{"test_mswin_event", 2, 2, FEARG_1, arg2_string_dict,
|
||||
ret_number, f_test_mswin_event},
|
||||
{"test_null_blob", 0, 0, 0, NULL,
|
||||
ret_blob, f_test_null_blob},
|
||||
{"test_null_channel", 0, 0, 0, NULL,
|
||||
@ -4387,7 +4389,12 @@ f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
|
||||
|
||||
if (*keys != NUL || execute)
|
||||
{
|
||||
if (lowlevel)
|
||||
if (lowlevel
|
||||
#ifdef FEAT_VTP
|
||||
&& (!is_term_win32()
|
||||
|| (keys[0] == 3 && ctrl_c_interrupts && typed))
|
||||
#endif
|
||||
)
|
||||
{
|
||||
#ifdef USE_INPUT_BUF
|
||||
ch_log(NULL, "feedkeys() lowlevel: %s", keys);
|
||||
|
165
src/gui_w32.c
165
src/gui_w32.c
@ -8643,41 +8643,176 @@ netbeans_draw_multisign_indicator(int row)
|
||||
#endif
|
||||
|
||||
#if defined(FEAT_EVAL) || defined(PROTO)
|
||||
int
|
||||
test_gui_w32_sendevent(dict_T *args)
|
||||
{
|
||||
char_u *event;
|
||||
INPUT inputs[1];
|
||||
|
||||
event = dict_get_string(args, "event", TRUE);
|
||||
if (event == NULL)
|
||||
// TODO: at the moment, this is just a copy of test_gui_mouse_event.
|
||||
// But, we could instead generate actual Win32 mouse event messages,
|
||||
// ie. to make it consistent wih test_gui_w32_sendevent_keyboard.
|
||||
static int
|
||||
test_gui_w32_sendevent_mouse(dict_T *args)
|
||||
{
|
||||
if (!dict_has_key(args, "row") || !dict_has_key(args, "col"))
|
||||
return FALSE;
|
||||
|
||||
ZeroMemory(inputs, sizeof(inputs));
|
||||
// Note: "move" is optional, requires fewer arguments
|
||||
int move = (int)dict_get_bool(args, "move", FALSE);
|
||||
|
||||
if (STRICMP(event, "keydown") == 0 || STRICMP(event, "keyup") == 0)
|
||||
if (!move && (!dict_has_key(args, "button")
|
||||
|| !dict_has_key(args, "multiclick")
|
||||
|| !dict_has_key(args, "modifiers")))
|
||||
return FALSE;
|
||||
|
||||
int row = (int)dict_get_number(args, "row");
|
||||
int col = (int)dict_get_number(args, "col");
|
||||
|
||||
if (move)
|
||||
{
|
||||
WORD vkCode;
|
||||
// the "move" argument expects row and col coordnates to be in pixels,
|
||||
// unless "cell" is specified and is TRUE.
|
||||
if (dict_get_bool(args, "cell", FALSE))
|
||||
{
|
||||
// calculate the middle of the character cell
|
||||
// Note: Cell coordinates are 1-based from vimscript
|
||||
int pY = (row - 1) * gui.char_height + gui.char_height / 2;
|
||||
int pX = (col - 1) * gui.char_width + gui.char_width / 2;
|
||||
gui_mouse_moved(pX, pY);
|
||||
}
|
||||
else
|
||||
gui_mouse_moved(col, row);
|
||||
}
|
||||
else
|
||||
{
|
||||
int button = (int)dict_get_number(args, "button");
|
||||
int repeated_click = (int)dict_get_number(args, "multiclick");
|
||||
int_u mods = (int)dict_get_number(args, "modifiers");
|
||||
|
||||
vkCode = dict_get_number_def(args, "keycode", 0);
|
||||
// Reset the scroll values to known values.
|
||||
// XXX: Remove this when/if the scroll step is made configurable.
|
||||
mouse_set_hor_scroll_step(6);
|
||||
mouse_set_vert_scroll_step(3);
|
||||
|
||||
gui_send_mouse_event(button, TEXT_X(col - 1), TEXT_Y(row - 1),
|
||||
repeated_click, mods);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
test_gui_w32_sendevent_keyboard(dict_T *args)
|
||||
{
|
||||
INPUT inputs[1];
|
||||
INPUT modkeys[3];
|
||||
SecureZeroMemory(inputs, sizeof(INPUT));
|
||||
SecureZeroMemory(modkeys, 3 * sizeof(INPUT));
|
||||
|
||||
char_u *event = dict_get_string(args, "event", TRUE);
|
||||
|
||||
if (event && (STRICMP(event, "keydown") == 0
|
||||
|| STRICMP(event, "keyup") == 0))
|
||||
{
|
||||
WORD vkCode = dict_get_number_def(args, "keycode", 0);
|
||||
if (vkCode <= 0 || vkCode >= 0xFF)
|
||||
{
|
||||
semsg(_(e_invalid_argument_nr), (long)vkCode);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL isModKey = (vkCode == VK_SHIFT || vkCode == VK_CONTROL
|
||||
|| vkCode == VK_MENU || vkCode == VK_LSHIFT || vkCode == VK_RSHIFT
|
||||
|| vkCode == VK_LCONTROL || vkCode == VK_RCONTROL
|
||||
|| vkCode == VK_LMENU || vkCode == VK_RMENU );
|
||||
|
||||
BOOL unwrapMods = FALSE;
|
||||
int mods = (int)dict_get_number(args, "modifiers");
|
||||
|
||||
// If there are modifiers in the args, and it is not a keyup event and
|
||||
// vkCode is not a modifier key, then we generate virtual modifier key
|
||||
// messages before sending the actual key message.
|
||||
if(mods && STRICMP(event, "keydown") == 0 && !isModKey)
|
||||
{
|
||||
int n = 0;
|
||||
if (mods & MOD_MASK_SHIFT)
|
||||
{
|
||||
modkeys[n].type = INPUT_KEYBOARD;
|
||||
modkeys[n].ki.wVk = VK_LSHIFT;
|
||||
n++;
|
||||
}
|
||||
if (mods & MOD_MASK_CTRL)
|
||||
{
|
||||
modkeys[n].type = INPUT_KEYBOARD;
|
||||
modkeys[n].ki.wVk = VK_LCONTROL;
|
||||
n++;
|
||||
}
|
||||
if (mods & MOD_MASK_ALT)
|
||||
{
|
||||
modkeys[n].type = INPUT_KEYBOARD;
|
||||
modkeys[n].ki.wVk = VK_LMENU;
|
||||
n++;
|
||||
}
|
||||
if (n)
|
||||
{
|
||||
(void)SetForegroundWindow(s_hwnd);
|
||||
SendInput(n, modkeys, sizeof(INPUT));
|
||||
}
|
||||
}
|
||||
|
||||
inputs[0].type = INPUT_KEYBOARD;
|
||||
inputs[0].ki.wVk = vkCode;
|
||||
if (STRICMP(event, "keyup") == 0)
|
||||
{
|
||||
inputs[0].ki.dwFlags = KEYEVENTF_KEYUP;
|
||||
if(!isModKey)
|
||||
unwrapMods = TRUE;
|
||||
}
|
||||
|
||||
(void)SetForegroundWindow(s_hwnd);
|
||||
SendInput(ARRAYSIZE(inputs), inputs, sizeof(INPUT));
|
||||
vim_free(event);
|
||||
|
||||
if (unwrapMods)
|
||||
{
|
||||
modkeys[0].type = INPUT_KEYBOARD;
|
||||
modkeys[0].ki.wVk = VK_LSHIFT;
|
||||
modkeys[0].ki.dwFlags = KEYEVENTF_KEYUP;
|
||||
|
||||
modkeys[1].type = INPUT_KEYBOARD;
|
||||
modkeys[1].ki.wVk = VK_LCONTROL;
|
||||
modkeys[1].ki.dwFlags = KEYEVENTF_KEYUP;
|
||||
|
||||
modkeys[2].type = INPUT_KEYBOARD;
|
||||
modkeys[2].ki.wVk = VK_LMENU;
|
||||
modkeys[2].ki.dwFlags = KEYEVENTF_KEYUP;
|
||||
|
||||
(void)SetForegroundWindow(s_hwnd);
|
||||
SendInput(3, modkeys, sizeof(INPUT));
|
||||
}
|
||||
}
|
||||
else
|
||||
semsg(_(e_invalid_argument_str), event);
|
||||
|
||||
vim_free(event);
|
||||
|
||||
{
|
||||
if (event == NULL)
|
||||
{
|
||||
semsg(_(e_missing_argument_str), "event");
|
||||
}
|
||||
else
|
||||
{
|
||||
semsg(_(e_invalid_value_for_argument_str_str), "event", event);
|
||||
vim_free(event);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int
|
||||
test_gui_w32_sendevent(char_u *event, dict_T *args)
|
||||
{
|
||||
if (STRICMP(event, "key") == 0)
|
||||
return test_gui_w32_sendevent_keyboard(args);
|
||||
else if (STRICMP(event, "mouse") == 0)
|
||||
return test_gui_w32_sendevent_mouse(args);
|
||||
else
|
||||
{
|
||||
semsg(_(e_invalid_value_for_argument_str_str), "event", event);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
378
src/os_win32.c
378
src/os_win32.c
@ -177,6 +177,25 @@ static void gotoxy(unsigned x, unsigned y);
|
||||
static void standout(void);
|
||||
static int s_cursor_visible = TRUE;
|
||||
static int did_create_conin = FALSE;
|
||||
// The 'input_record_buffer' is an internal dynamic fifo queue of MS-Windows
|
||||
// console INPUT_RECORD events that are normally read from the console input
|
||||
// buffer. This provides an injection point for testing the low-level handling
|
||||
// of INPUT_RECORDs.
|
||||
typedef struct input_record_buffer_node_S
|
||||
{
|
||||
INPUT_RECORD ir;
|
||||
struct input_record_buffer_node_S *next;
|
||||
} input_record_buffer_node_T;
|
||||
typedef struct input_record_buffer_S
|
||||
{
|
||||
input_record_buffer_node_T *head;
|
||||
input_record_buffer_node_T *tail;
|
||||
int length;
|
||||
} input_record_buffer_T;
|
||||
static input_record_buffer_T input_record_buffer;
|
||||
static int peek_input_record_buffer(INPUT_RECORD* irEvents, int nMaxLength);
|
||||
static int read_input_record_buffer(INPUT_RECORD* irEvents, int nMaxLength);
|
||||
static int write_input_record_buffer(INPUT_RECORD* irEvents, int nLength);
|
||||
#endif
|
||||
#ifdef FEAT_GUI_MSWIN
|
||||
static int s_dont_use_vimrun = TRUE;
|
||||
@ -224,7 +243,7 @@ static int default_console_color_fg = 0xc0c0c0; // white
|
||||
static void set_console_color_rgb(void);
|
||||
static void reset_console_color_rgb(void);
|
||||
static void restore_console_color_rgb(void);
|
||||
#endif
|
||||
#endif // !FEAT_GUI_MSWIN || VIMDLL
|
||||
|
||||
// This flag is newly created from Windows 10
|
||||
#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||
@ -319,6 +338,13 @@ read_console_input(
|
||||
int i;
|
||||
static INPUT_RECORD s_irPseudo;
|
||||
|
||||
if (s_dwMax == 0 && input_record_buffer.length > 0)
|
||||
{
|
||||
dwEvents = read_input_record_buffer(s_irCache, IRSIZE);
|
||||
s_dwIndex = 0;
|
||||
s_dwMax = dwEvents;
|
||||
}
|
||||
|
||||
if (nLength == -2)
|
||||
return (s_dwMax > 0) ? TRUE : FALSE;
|
||||
|
||||
@ -431,7 +457,7 @@ wait_for_single_object(
|
||||
return WaitForSingleObject(hHandle, dwMilliseconds);
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
#endif // !FEAT_GUI_MSWIN || VIMDLL
|
||||
|
||||
static void
|
||||
get_exe_name(void)
|
||||
@ -1014,7 +1040,7 @@ win32_kbd_patch_key(
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (pker->uChar.UnicodeChar != 0)
|
||||
if (pker->uChar.UnicodeChar > 0 && pker->uChar.UnicodeChar < 0xfffd)
|
||||
return 1;
|
||||
|
||||
CLEAR_FIELD(abKeystate);
|
||||
@ -1080,7 +1106,8 @@ decode_key_event(
|
||||
|
||||
// special cases
|
||||
if ((nModifs & CTRL) != 0 && (nModifs & ~CTRL) == 0
|
||||
&& pker->uChar.UnicodeChar == NUL)
|
||||
&& (pker->uChar.UnicodeChar == NUL
|
||||
|| pker->uChar.UnicodeChar == 0xfffd))
|
||||
{
|
||||
// Ctrl-6 is Ctrl-^
|
||||
if (pker->wVirtualKeyCode == '6')
|
||||
@ -1168,7 +1195,113 @@ decode_key_event(
|
||||
return (*pch != NUL);
|
||||
}
|
||||
|
||||
#endif // FEAT_GUI_MSWIN
|
||||
# if defined(FEAT_EVAL)
|
||||
static int
|
||||
encode_key_event(dict_T *args, INPUT_RECORD *ir)
|
||||
{
|
||||
static int s_dwMods = 0;
|
||||
|
||||
char_u *event = dict_get_string(args, "event", TRUE);
|
||||
if (event && (STRICMP(event, "keydown") == 0
|
||||
|| STRICMP(event, "keyup") == 0))
|
||||
{
|
||||
WORD vkCode = dict_get_number_def(args, "keycode", 0);
|
||||
if (vkCode <= 0 || vkCode >= 0xFF)
|
||||
{
|
||||
semsg(_(e_invalid_argument_nr), (long)vkCode);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ir->EventType = KEY_EVENT;
|
||||
KEY_EVENT_RECORD ker;
|
||||
ZeroMemory(&ker, sizeof(ker));
|
||||
ker.bKeyDown = STRICMP(event, "keydown") == 0;
|
||||
ker.wRepeatCount = 1;
|
||||
ker.wVirtualScanCode = 0;
|
||||
ker.dwControlKeyState = 0;
|
||||
int mods = (int)dict_get_number(args, "modifiers");
|
||||
// Encode the win32 console key modifiers from Vim keyboard modifiers.
|
||||
if (mods)
|
||||
{
|
||||
// If "modifiers" is explicitly set in the args, then we reset any
|
||||
// remembered modifer key state that may have been set from earlier
|
||||
// mod-key-down events, even if they are not yet unset by earlier
|
||||
// mod-key-up events.
|
||||
s_dwMods = 0;
|
||||
if (mods & MOD_MASK_SHIFT)
|
||||
ker.dwControlKeyState |= SHIFT_PRESSED;
|
||||
if (mods & MOD_MASK_CTRL)
|
||||
ker.dwControlKeyState |= LEFT_CTRL_PRESSED;
|
||||
if (mods & MOD_MASK_ALT)
|
||||
ker.dwControlKeyState |= LEFT_ALT_PRESSED;
|
||||
}
|
||||
|
||||
if (vkCode == VK_LSHIFT || vkCode == VK_RSHIFT || vkCode == VK_SHIFT)
|
||||
{
|
||||
if (STRICMP(event, "keydown") == 0)
|
||||
s_dwMods |= SHIFT_PRESSED;
|
||||
else
|
||||
s_dwMods &= ~SHIFT_PRESSED;
|
||||
}
|
||||
else if (vkCode == VK_LCONTROL || vkCode == VK_CONTROL)
|
||||
{
|
||||
if (STRICMP(event, "keydown") == 0)
|
||||
s_dwMods |= LEFT_CTRL_PRESSED;
|
||||
else
|
||||
s_dwMods &= ~LEFT_CTRL_PRESSED;
|
||||
}
|
||||
else if (vkCode == VK_RCONTROL)
|
||||
{
|
||||
if (STRICMP(event, "keydown") == 0)
|
||||
s_dwMods |= RIGHT_CTRL_PRESSED;
|
||||
else
|
||||
s_dwMods &= ~RIGHT_CTRL_PRESSED;
|
||||
}
|
||||
else if (vkCode == VK_LMENU || vkCode == VK_MENU)
|
||||
{
|
||||
if (STRICMP(event, "keydown") == 0)
|
||||
s_dwMods |= LEFT_ALT_PRESSED;
|
||||
else
|
||||
s_dwMods &= ~LEFT_ALT_PRESSED;
|
||||
}
|
||||
else if (vkCode == VK_RMENU)
|
||||
{
|
||||
if (STRICMP(event, "keydown") == 0)
|
||||
s_dwMods |= RIGHT_ALT_PRESSED;
|
||||
else
|
||||
s_dwMods &= ~RIGHT_ALT_PRESSED;
|
||||
}
|
||||
ker.dwControlKeyState |= s_dwMods;
|
||||
ker.wVirtualKeyCode = vkCode;
|
||||
win32_kbd_patch_key(&ker);
|
||||
|
||||
for (int i = ARRAY_LENGTH(VirtKeyMap);
|
||||
--i >= 0 && !ker.uChar.UnicodeChar; )
|
||||
{
|
||||
if (VirtKeyMap[i].wVirtKey == vkCode)
|
||||
ker.uChar.UnicodeChar = 0xfffd; // REPLACEMENT CHARACTER
|
||||
}
|
||||
|
||||
ir->Event.KeyEvent = ker;
|
||||
vim_free(event);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (event == NULL)
|
||||
{
|
||||
semsg(_(e_missing_argument_str), "event");
|
||||
}
|
||||
else
|
||||
{
|
||||
semsg(_(e_invalid_value_for_argument_str_str), "event", event);
|
||||
vim_free(event);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
# endif // FEAT_EVAL
|
||||
#endif // !FEAT_GUI_MSWIN || VIMDLL
|
||||
|
||||
|
||||
/*
|
||||
@ -1179,7 +1312,7 @@ decode_key_event(
|
||||
mch_setmouse(int on UNUSED)
|
||||
{
|
||||
}
|
||||
#else
|
||||
#else // !FEAT_GUI_MSWIN || VIMDLL
|
||||
static int g_fMouseAvail = FALSE; // mouse present
|
||||
static int g_fMouseActive = FALSE; // mouse enabled
|
||||
static int g_nMouseClick = -1; // mouse status
|
||||
@ -1234,21 +1367,21 @@ mch_bevalterm_changed(void)
|
||||
|
||||
/*
|
||||
* Win32 console mouse scroll event handler.
|
||||
* Loosely based on the _OnMouseWheel() function in gui_w32.c
|
||||
* Console version of the _OnMouseWheel() function in gui_w32.c
|
||||
*
|
||||
* This encodes the mouse scroll direction and keyboard modifiers into
|
||||
* g_nMouseClick, and the mouse position into g_xMouse and g_yMouse
|
||||
*
|
||||
* The direction of the scroll is decoded from two fields of the win32 console
|
||||
* mouse event record;
|
||||
* 1. The axis - vertical or horizontal flag - from dwEventFlags, and
|
||||
* 1. The orientation - vertical or horizontal flag - from dwEventFlags
|
||||
* 2. The sign - positive or negative (aka delta flag) - from dwButtonState
|
||||
*
|
||||
* When scroll axis is HORIZONTAL
|
||||
* When scroll orientation is HORIZONTAL
|
||||
* - If the high word of the dwButtonState member contains a positive
|
||||
* value, the wheel was rotated to the right.
|
||||
* - Otherwise, the wheel was rotated to the left.
|
||||
* When scroll axis is VERTICAL
|
||||
* When scroll orientation is VERTICAL
|
||||
* - If the high word of the dwButtonState member contains a positive value,
|
||||
* the wheel was rotated forward, away from the user.
|
||||
* - Otherwise, the wheel was rotated backward, toward the user.
|
||||
@ -1594,8 +1727,231 @@ decode_mouse_event(
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#endif // FEAT_GUI_MSWIN
|
||||
# ifdef FEAT_EVAL
|
||||
static int
|
||||
encode_mouse_event(dict_T *args, INPUT_RECORD *ir)
|
||||
{
|
||||
int button;
|
||||
int row;
|
||||
int col;
|
||||
int repeated_click;
|
||||
int_u mods;
|
||||
int move;
|
||||
|
||||
if (!dict_has_key(args, "row") || !dict_has_key(args, "col"))
|
||||
return FALSE;
|
||||
|
||||
// Note: "move" is optional, requires fewer arguments
|
||||
move = (int)dict_get_bool(args, "move", FALSE);
|
||||
if (!move && (!dict_has_key(args, "button")
|
||||
|| !dict_has_key(args, "multiclick")
|
||||
|| !dict_has_key(args, "modifiers")))
|
||||
return FALSE;
|
||||
|
||||
row = (int)dict_get_number(args, "row") - 1;
|
||||
col = (int)dict_get_number(args, "col") - 1;
|
||||
|
||||
ir->EventType = MOUSE_EVENT;
|
||||
MOUSE_EVENT_RECORD mer;
|
||||
ZeroMemory(&mer, sizeof(mer));
|
||||
mer.dwMousePosition.X = col;
|
||||
mer.dwMousePosition.Y = row;
|
||||
|
||||
if (move)
|
||||
{
|
||||
mer.dwButtonState = 0;
|
||||
mer.dwEventFlags = MOUSE_MOVED;
|
||||
}
|
||||
else
|
||||
{
|
||||
button = (int)dict_get_number(args, "button");
|
||||
repeated_click = (int)dict_get_number(args, "multiclick");
|
||||
mods = (int)dict_get_number(args, "modifiers");
|
||||
// Reset the scroll values to known values.
|
||||
// XXX: Remove this when/if the scroll step is made configurable.
|
||||
mouse_set_hor_scroll_step(6);
|
||||
mouse_set_vert_scroll_step(3);
|
||||
|
||||
switch (button)
|
||||
{
|
||||
case MOUSE_LEFT:
|
||||
mer.dwButtonState = FROM_LEFT_1ST_BUTTON_PRESSED;
|
||||
mer.dwEventFlags = repeated_click == 1 ? DOUBLE_CLICK : 0;
|
||||
break;
|
||||
case MOUSE_MIDDLE:
|
||||
mer.dwButtonState = FROM_LEFT_2ND_BUTTON_PRESSED;
|
||||
mer.dwEventFlags = repeated_click == 1 ? DOUBLE_CLICK : 0;
|
||||
break;
|
||||
case MOUSE_RIGHT:
|
||||
mer.dwButtonState = RIGHTMOST_BUTTON_PRESSED;
|
||||
mer.dwEventFlags = repeated_click == 1 ? DOUBLE_CLICK : 0;
|
||||
break;
|
||||
case MOUSE_RELEASE:
|
||||
// umm? Assume Left Release?
|
||||
mer.dwEventFlags = 0;
|
||||
|
||||
case MOUSE_MOVE:
|
||||
mer.dwButtonState = 0;
|
||||
mer.dwEventFlags = MOUSE_MOVED;
|
||||
break;
|
||||
case MOUSE_X1:
|
||||
mer.dwButtonState = FROM_LEFT_3RD_BUTTON_PRESSED;
|
||||
break;
|
||||
case MOUSE_X2:
|
||||
mer.dwButtonState = FROM_LEFT_4TH_BUTTON_PRESSED;
|
||||
break;
|
||||
case MOUSE_4: // KE_MOUSEDOWN;
|
||||
mer.dwButtonState = -1;
|
||||
mer.dwEventFlags = MOUSE_WHEELED;
|
||||
break;
|
||||
case MOUSE_5: // KE_MOUSEUP;
|
||||
mer.dwButtonState = +1;
|
||||
mer.dwEventFlags = MOUSE_WHEELED;
|
||||
break;
|
||||
case MOUSE_6: // KE_MOUSELEFT;
|
||||
mer.dwButtonState = -1;
|
||||
mer.dwEventFlags = MOUSE_HWHEELED;
|
||||
break;
|
||||
case MOUSE_7: // KE_MOUSERIGHT;
|
||||
mer.dwButtonState = +1;
|
||||
mer.dwEventFlags = MOUSE_HWHEELED;
|
||||
break;
|
||||
default:
|
||||
semsg(_(e_invalid_argument_str), "button");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
mer.dwControlKeyState = 0;
|
||||
if (mods != 0)
|
||||
{
|
||||
// Encode the win32 console key modifiers from Vim MOUSE modifiers.
|
||||
if (mods & MOUSE_SHIFT)
|
||||
mer.dwControlKeyState |= SHIFT_PRESSED;
|
||||
if (mods & MOUSE_CTRL)
|
||||
mer.dwControlKeyState |= LEFT_CTRL_PRESSED;
|
||||
if (mods & MOUSE_ALT)
|
||||
mer.dwControlKeyState |= LEFT_ALT_PRESSED;
|
||||
}
|
||||
ir->Event.MouseEvent = mer;
|
||||
return TRUE;
|
||||
}
|
||||
# endif // FEAT_EVAL
|
||||
|
||||
static int
|
||||
write_input_record_buffer(INPUT_RECORD* irEvents, int nLength)
|
||||
{
|
||||
int nCount = 0;
|
||||
while (nCount < nLength)
|
||||
{
|
||||
input_record_buffer.length++;
|
||||
input_record_buffer_node_T *event_node =
|
||||
malloc(sizeof(input_record_buffer_node_T));
|
||||
event_node->ir = irEvents[nCount++];
|
||||
event_node->next = NULL;
|
||||
if (input_record_buffer.tail == NULL)
|
||||
{
|
||||
input_record_buffer.head = event_node;
|
||||
input_record_buffer.tail = event_node;
|
||||
}
|
||||
else
|
||||
{
|
||||
input_record_buffer.tail->next = event_node;
|
||||
input_record_buffer.tail = input_record_buffer.tail->next;
|
||||
}
|
||||
}
|
||||
return nCount;
|
||||
}
|
||||
|
||||
static int
|
||||
read_input_record_buffer(INPUT_RECORD* irEvents, int nMaxLength)
|
||||
{
|
||||
int nCount = 0;
|
||||
while (nCount < nMaxLength && input_record_buffer.head != NULL)
|
||||
{
|
||||
input_record_buffer.length--;
|
||||
input_record_buffer_node_T *pop_head = input_record_buffer.head;
|
||||
irEvents[nCount++] = pop_head->ir;
|
||||
input_record_buffer.head = pop_head->next;
|
||||
vim_free(pop_head);
|
||||
if (input_record_buffer.length == 0)
|
||||
input_record_buffer.tail = NULL;
|
||||
}
|
||||
return nCount;
|
||||
}
|
||||
static int
|
||||
peek_input_record_buffer(INPUT_RECORD* irEvents, int nMaxLength)
|
||||
{
|
||||
int nCount = 0;
|
||||
input_record_buffer_node_T *temp = input_record_buffer.head;
|
||||
while (nCount < nMaxLength && temp != NULL)
|
||||
{
|
||||
irEvents[nCount++] = temp->ir;
|
||||
temp = temp->next;
|
||||
}
|
||||
return nCount;
|
||||
}
|
||||
#endif // !FEAT_GUI_MSWIN || VIMDLL
|
||||
|
||||
#ifdef FEAT_EVAL
|
||||
/*
|
||||
* The 'test_mswin_event' function is for testing Vim's low-level handling of
|
||||
* user input events. ie, this manages the encoding of INPUT_RECORD events
|
||||
* so that we have a way to test how Vim decodes INPUT_RECORD events in Windows
|
||||
* consoles.
|
||||
*
|
||||
* The 'test_mswin_event' function is based on 'test_gui_event'. In fact, when
|
||||
* the Windows GUI is running, the arguments; 'event' and 'args', are the same.
|
||||
* So, it acts as an alias for 'test_gui_event' for the Windows GUI.
|
||||
*
|
||||
* When the Windows console is running, the arguments; 'event' and 'args', are
|
||||
* a subset of what 'test_gui_event' handles, ie, only "key" and "mouse"
|
||||
* events are encoded as INPUT_RECORD events.
|
||||
*
|
||||
* Note: INPUT_RECORDs are only used by the Windows console, not the GUI. The
|
||||
* GUI sends MSG structs instead.
|
||||
*/
|
||||
int
|
||||
test_mswin_event(char_u *event, dict_T *args)
|
||||
{
|
||||
int lpEventsWritten = 0;
|
||||
|
||||
# if defined(VIMDLL) || defined(FEAT_GUI_MSWIN)
|
||||
if (gui.in_use)
|
||||
return test_gui_w32_sendevent(event, args);
|
||||
# endif
|
||||
|
||||
# if defined(VIMDLL) || !defined(FEAT_GUI_MSWIN)
|
||||
|
||||
// Currently implemented event record types are; KEY_EVENT and MOUSE_EVENT
|
||||
// Potentially could also implement: FOCUS_EVENT and WINDOW_BUFFER_SIZE_EVENT
|
||||
// Maybe also: MENU_EVENT
|
||||
|
||||
INPUT_RECORD ir;
|
||||
BOOL input_encoded = FALSE;
|
||||
if (STRCMP(event, "key") == 0)
|
||||
input_encoded = encode_key_event(args, &ir);
|
||||
else if (STRCMP(event, "mouse") == 0)
|
||||
input_encoded = encode_mouse_event(args, &ir);
|
||||
else
|
||||
{
|
||||
semsg(_(e_invalid_value_for_argument_str_str), "event", event);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Ideally, WriteConsoleInput would be used to inject these low-level
|
||||
// events. But, this doesnt work well in the CI test environment. So
|
||||
// implementing an input_record_buffer instead.
|
||||
if (input_encoded)
|
||||
lpEventsWritten = write_input_record_buffer(&ir, 1);
|
||||
|
||||
if (STRCMP(event, "mouse") == 0)
|
||||
exec_normal(TRUE, TRUE, TRUE);
|
||||
|
||||
# endif
|
||||
return lpEventsWritten;
|
||||
}
|
||||
#endif // FEAT_EVAL
|
||||
|
||||
#ifdef MCH_CURSOR_SHAPE
|
||||
/*
|
||||
|
@ -96,5 +96,5 @@ void gui_mch_post_balloon(BalloonEval *beval, char_u *mesg);
|
||||
BalloonEval *gui_mch_create_beval_area(void *target, char_u *mesg, void (*mesgCB)(BalloonEval *, int), void *clientData);
|
||||
void gui_mch_destroy_beval_area(BalloonEval *beval);
|
||||
void netbeans_draw_multisign_indicator(int row);
|
||||
int test_gui_w32_sendevent(dict_T *args);
|
||||
int test_gui_w32_sendevent(char_u *event, dict_T *args);
|
||||
/* vim: set ft=c : */
|
||||
|
@ -9,6 +9,7 @@ void dyn_libintl_end(void);
|
||||
void PlatformId(void);
|
||||
void mch_setmouse(int on);
|
||||
void mch_bevalterm_changed(void);
|
||||
int test_mswin_event(char_u *event, dict_T *args);
|
||||
void mch_update_cursor(void);
|
||||
int mch_char_avail(void);
|
||||
int mch_check_messages(void);
|
||||
|
@ -33,6 +33,7 @@ void f_test_null_string(typval_T *argvars, typval_T *rettv);
|
||||
void f_test_unknown(typval_T *argvars, typval_T *rettv);
|
||||
void f_test_void(typval_T *argvars, typval_T *rettv);
|
||||
void f_test_setmouse(typval_T *argvars, typval_T *rettv);
|
||||
void f_test_mswin_event(typval_T *argvars, typval_T *rettv);
|
||||
void f_test_gui_event(typval_T *argvars, typval_T *rettv);
|
||||
void f_test_settime(typval_T *argvars, typval_T *rettv);
|
||||
/* vim: set ft=c : */
|
||||
|
@ -827,7 +827,7 @@ static tcap_entry_T builtin_pcansi[] = {
|
||||
};
|
||||
|
||||
/*
|
||||
* These codes are valid for the Win32 Console . The entries that start with
|
||||
* These codes are valid for the Win32 Console. The entries that start with
|
||||
* ESC | are translated into console calls in os_win32.c. The function keys
|
||||
* are also translated in os_win32.c.
|
||||
*/
|
||||
|
@ -210,6 +210,7 @@ NEW_TESTS = \
|
||||
test_modeless \
|
||||
test_modeline \
|
||||
test_move \
|
||||
test_mswin_event \
|
||||
test_mzscheme \
|
||||
test_nested_function \
|
||||
test_netbeans \
|
||||
@ -454,6 +455,7 @@ NEW_TESTS_RES = \
|
||||
test_mksession.res \
|
||||
test_modeless.res \
|
||||
test_modeline.res \
|
||||
test_mswin_event.res \
|
||||
test_mzscheme.res \
|
||||
test_nested_function.res \
|
||||
test_netbeans.res \
|
||||
|
@ -20,6 +20,27 @@ else
|
||||
let g:Ttymouse_netterm = []
|
||||
endif
|
||||
|
||||
" Vim Mouse Codes.
|
||||
" Used by the GUI and by MS-Windows Consoles.
|
||||
" Keep these in sync with vim.h
|
||||
let s:MOUSE_CODE = {
|
||||
\ 'BTN_LEFT' : 0x00,
|
||||
\ 'BTN_MIDDLE' : 0x01,
|
||||
\ 'BTN_RIGHT' : 0x02,
|
||||
\ 'BTN_RELEASE' : 0x03,
|
||||
\ 'BTN_X1' : 0x300,
|
||||
\ 'BTN_X2' : 0x400,
|
||||
\ 'SCRL_DOWN' : 0x100,
|
||||
\ 'SCRL_UP' : 0x200,
|
||||
\ 'SCRL_LEFT' : 0x500,
|
||||
\ 'SCRL_RIGHT' : 0x600,
|
||||
\ 'MOVE' : 0x700,
|
||||
\ 'MOD_SHIFT' : 0x04,
|
||||
\ 'MOD_ALT' : 0x08,
|
||||
\ 'MOD_CTRL' : 0x10,
|
||||
\ }
|
||||
|
||||
|
||||
" Helper function to emit a terminal escape code.
|
||||
func TerminalEscapeCode(code, row, col, m)
|
||||
if &ttymouse ==# 'xterm2'
|
||||
@ -47,6 +68,31 @@ func NettermEscapeCode(row, col)
|
||||
return printf("\<Esc>}%d,%d\r", a:row, a:col)
|
||||
endfunc
|
||||
|
||||
" Send low level mouse event to MS-Windows consoles or GUI
|
||||
func MSWinMouseEvent(button, row, col, move, multiclick, modifiers)
|
||||
let args = { }
|
||||
let args.button = a:button
|
||||
" Scroll directions are inverted in the GUI, no idea why.
|
||||
if has('gui_running')
|
||||
if a:button == s:MOUSE_CODE.SCRL_UP
|
||||
let args.button = s:MOUSE_CODE.SCRL_DOWN
|
||||
elseif a:button == s:MOUSE_CODE.SCRL_DOWN
|
||||
let args.button = s:MOUSE_CODE.SCRL_UP
|
||||
elseif a:button == s:MOUSE_CODE.SCRL_LEFT
|
||||
let args.button = s:MOUSE_CODE.SCRL_RIGHT
|
||||
elseif a:button == s:MOUSE_CODE.SCRL_RIGHT
|
||||
let args.button = s:MOUSE_CODE.SCRL_LEFT
|
||||
endif
|
||||
endif
|
||||
let args.row = a:row
|
||||
let args.col = a:col
|
||||
let args.move = a:move
|
||||
let args.multiclick = a:multiclick
|
||||
let args.modifiers = a:modifiers
|
||||
call test_mswin_event("mouse", args)
|
||||
unlet args
|
||||
endfunc
|
||||
|
||||
func MouseLeftClickCode(row, col)
|
||||
if &ttymouse ==# 'dec'
|
||||
return DecEscapeCode(2, 4, a:row, a:col)
|
||||
@ -58,7 +104,11 @@ func MouseLeftClickCode(row, col)
|
||||
endfunc
|
||||
|
||||
func MouseLeftClick(row, col)
|
||||
call feedkeys(MouseLeftClickCode(a:row, a:col), 'Lx!')
|
||||
if has('win32')
|
||||
call MSWinMouseEvent(s:MOUSE_CODE.BTN_LEFT, a:row, a:col, 0, 0, 0)
|
||||
else
|
||||
call feedkeys(MouseLeftClickCode(a:row, a:col), 'Lx!')
|
||||
endif
|
||||
endfunc
|
||||
|
||||
func MouseMiddleClickCode(row, col)
|
||||
@ -70,7 +120,11 @@ func MouseMiddleClickCode(row, col)
|
||||
endfunc
|
||||
|
||||
func MouseMiddleClick(row, col)
|
||||
call feedkeys(MouseMiddleClickCode(a:row, a:col), 'Lx!')
|
||||
if has('win32')
|
||||
call MSWinMouseEvent(s:MOUSE_CODE.BTN_MIDDLE, a:row, a:col, 0, 0, 0)
|
||||
else
|
||||
call feedkeys(MouseMiddleClickCode(a:row, a:col), 'Lx!')
|
||||
endif
|
||||
endfunc
|
||||
|
||||
func MouseRightClickCode(row, col)
|
||||
@ -82,7 +136,11 @@ func MouseRightClickCode(row, col)
|
||||
endfunc
|
||||
|
||||
func MouseRightClick(row, col)
|
||||
call feedkeys(MouseRightClickCode(a:row, a:col), 'Lx!')
|
||||
if has('win32')
|
||||
call MSWinMouseEvent(s:MOUSE_CODE.BTN_RIGHT, a:row, a:col, 0, 0, 0)
|
||||
else
|
||||
call feedkeys(MouseRightClickCode(a:row, a:col), 'Lx!')
|
||||
endif
|
||||
endfunc
|
||||
|
||||
func MouseCtrlLeftClickCode(row, col)
|
||||
@ -91,7 +149,12 @@ func MouseCtrlLeftClickCode(row, col)
|
||||
endfunc
|
||||
|
||||
func MouseCtrlLeftClick(row, col)
|
||||
call feedkeys(MouseCtrlLeftClickCode(a:row, a:col), 'Lx!')
|
||||
if has('win32')
|
||||
call MSWinMouseEvent(s:MOUSE_CODE.BTN_LEFT, a:row, a:col, 0, 0,
|
||||
\ s:MOUSE_CODE.MOD_CTRL)
|
||||
else
|
||||
call feedkeys(MouseCtrlLeftClickCode(a:row, a:col), 'Lx!')
|
||||
endif
|
||||
endfunc
|
||||
|
||||
func MouseCtrlRightClickCode(row, col)
|
||||
@ -100,7 +163,12 @@ func MouseCtrlRightClickCode(row, col)
|
||||
endfunc
|
||||
|
||||
func MouseCtrlRightClick(row, col)
|
||||
call feedkeys(MouseCtrlRightClickCode(a:row, a:col), 'Lx!')
|
||||
if has('win32')
|
||||
call MSWinMouseEvent(s:MOUSE_CODE.BTN_RIGHT, a:row, a:col, 0, 0,
|
||||
\ s:MOUSE_CODE.MOD_CTRL)
|
||||
else
|
||||
call feedkeys(MouseCtrlRightClickCode(a:row, a:col), 'Lx!')
|
||||
endif
|
||||
endfunc
|
||||
|
||||
func MouseAltLeftClickCode(row, col)
|
||||
@ -109,7 +177,12 @@ func MouseAltLeftClickCode(row, col)
|
||||
endfunc
|
||||
|
||||
func MouseAltLeftClick(row, col)
|
||||
call feedkeys(MouseAltLeftClickCode(a:row, a:col), 'Lx!')
|
||||
if has('win32')
|
||||
call MSWinMouseEvent(s:MOUSE_CODE.BTN_LEFT, a:row, a:col, 0, 0,
|
||||
\ s:MOUSE_CODE.MOD_ALT)
|
||||
else
|
||||
call feedkeys(MouseAltLeftClickCode(a:row, a:col), 'Lx!')
|
||||
endif
|
||||
endfunc
|
||||
|
||||
func MouseAltRightClickCode(row, col)
|
||||
@ -118,7 +191,12 @@ func MouseAltRightClickCode(row, col)
|
||||
endfunc
|
||||
|
||||
func MouseAltRightClick(row, col)
|
||||
call feedkeys(MouseAltRightClickCode(a:row, a:col), 'Lx!')
|
||||
if has('win32')
|
||||
call MSWinMouseEvent(s:MOUSE_CODE.BTN_RIGHT, a:row, a:col, 0, 0,
|
||||
\ s:MOUSE_CODE.MOD_ALT)
|
||||
else
|
||||
call feedkeys(MouseAltRightClickCode(a:row, a:col), 'Lx!')
|
||||
endif
|
||||
endfunc
|
||||
|
||||
func MouseLeftReleaseCode(row, col)
|
||||
@ -132,7 +210,11 @@ func MouseLeftReleaseCode(row, col)
|
||||
endfunc
|
||||
|
||||
func MouseLeftRelease(row, col)
|
||||
call feedkeys(MouseLeftReleaseCode(a:row, a:col), 'Lx!')
|
||||
if has('win32')
|
||||
call MSWinMouseEvent(s:MOUSE_CODE.BTN_RELEASE, a:row, a:col, 0, 0, 0)
|
||||
else
|
||||
call feedkeys(MouseLeftReleaseCode(a:row, a:col), 'Lx!')
|
||||
endif
|
||||
endfunc
|
||||
|
||||
func MouseMiddleReleaseCode(row, col)
|
||||
@ -144,7 +226,11 @@ func MouseMiddleReleaseCode(row, col)
|
||||
endfunc
|
||||
|
||||
func MouseMiddleRelease(row, col)
|
||||
call feedkeys(MouseMiddleReleaseCode(a:row, a:col), 'Lx!')
|
||||
if has('win32')
|
||||
call MSWinMouseEvent(s:MOUSE_CODE.BTN_RELEASE, a:row, a:col, 0, 0, 0)
|
||||
else
|
||||
call feedkeys(MouseMiddleReleaseCode(a:row, a:col), 'Lx!')
|
||||
endif
|
||||
endfunc
|
||||
|
||||
func MouseRightReleaseCode(row, col)
|
||||
@ -156,7 +242,11 @@ func MouseRightReleaseCode(row, col)
|
||||
endfunc
|
||||
|
||||
func MouseRightRelease(row, col)
|
||||
call feedkeys(MouseRightReleaseCode(a:row, a:col), 'Lx!')
|
||||
if has('win32')
|
||||
call MSWinMouseEvent(s:MOUSE_CODE.BTN_RELEASE, a:row, a:col, 0, 0, 0)
|
||||
else
|
||||
call feedkeys(MouseRightReleaseCode(a:row, a:col), 'Lx!')
|
||||
endif
|
||||
endfunc
|
||||
|
||||
func MouseLeftDragCode(row, col)
|
||||
@ -168,7 +258,11 @@ func MouseLeftDragCode(row, col)
|
||||
endfunc
|
||||
|
||||
func MouseLeftDrag(row, col)
|
||||
call feedkeys(MouseLeftDragCode(a:row, a:col), 'Lx!')
|
||||
if has('win32')
|
||||
call MSWinMouseEvent(s:MOUSE_CODE.BTN_LEFT, a:row, a:col, 1, 0, 0)
|
||||
else
|
||||
call feedkeys(MouseLeftDragCode(a:row, a:col), 'Lx!')
|
||||
endif
|
||||
endfunc
|
||||
|
||||
func MouseWheelUpCode(row, col)
|
||||
@ -176,7 +270,11 @@ func MouseWheelUpCode(row, col)
|
||||
endfunc
|
||||
|
||||
func MouseWheelUp(row, col)
|
||||
call feedkeys(MouseWheelUpCode(a:row, a:col), 'Lx!')
|
||||
if has('win32')
|
||||
call MSWinMouseEvent(s:MOUSE_CODE.SCRL_UP, a:row, a:col, 0, 0, 0)
|
||||
else
|
||||
call feedkeys(MouseWheelUpCode(a:row, a:col), 'Lx!')
|
||||
endif
|
||||
endfunc
|
||||
|
||||
func MouseWheelDownCode(row, col)
|
||||
@ -184,7 +282,11 @@ func MouseWheelDownCode(row, col)
|
||||
endfunc
|
||||
|
||||
func MouseWheelDown(row, col)
|
||||
call feedkeys(MouseWheelDownCode(a:row, a:col), 'Lx!')
|
||||
if has('win32')
|
||||
call MSWinMouseEvent(s:MOUSE_CODE.SCRL_DOWN, a:row, a:col, 0, 0, 0)
|
||||
else
|
||||
call feedkeys(MouseWheelDownCode(a:row, a:col), 'Lx!')
|
||||
endif
|
||||
endfunc
|
||||
|
||||
func MouseWheelLeftCode(row, col)
|
||||
@ -192,7 +294,11 @@ func MouseWheelLeftCode(row, col)
|
||||
endfunc
|
||||
|
||||
func MouseWheelLeft(row, col)
|
||||
call feedkeys(MouseWheelLeftCode(a:row, a:col), 'Lx!')
|
||||
if has('win32')
|
||||
call MSWinMouseEvent(s:MOUSE_CODE.SCRL_LEFT, a:row, a:col, 0, 0, 0)
|
||||
else
|
||||
call feedkeys(MouseWheelLeftCode(a:row, a:col), 'Lx!')
|
||||
endif
|
||||
endfunc
|
||||
|
||||
func MouseWheelRightCode(row, col)
|
||||
@ -200,7 +306,67 @@ func MouseWheelRightCode(row, col)
|
||||
endfunc
|
||||
|
||||
func MouseWheelRight(row, col)
|
||||
call feedkeys(MouseWheelRightCode(a:row, a:col), 'Lx!')
|
||||
if has('win32')
|
||||
call MSWinMouseEvent(s:MOUSE_CODE.SCRL_RIGHT, a:row, a:col, 0, 0, 0)
|
||||
else
|
||||
call feedkeys(MouseWheelRightCode(a:row, a:col), 'Lx!')
|
||||
endif
|
||||
endfunc
|
||||
|
||||
func MouseShiftWheelUpCode(row, col)
|
||||
" todo feed shift mod.
|
||||
return TerminalEscapeCode(0x40, a:row, a:col, 'M')
|
||||
endfunc
|
||||
|
||||
func MouseShiftWheelUp(row, col)
|
||||
if has('win32')
|
||||
call MSWinMouseEvent(s:MOUSE_CODE.SCRL_UP, a:row, a:col, 0, 0,
|
||||
\ s:MOUSE_CODE.MOD_SHIFT)
|
||||
else
|
||||
call feedkeys(MouseShiftWheelUpCode(a:row, a:col), 'Lx!')
|
||||
endif
|
||||
endfunc
|
||||
|
||||
func MouseShiftWheelDownCode(row, col)
|
||||
" todo feed shift mod.
|
||||
return TerminalEscapeCode(0x41, a:row, a:col, 'M')
|
||||
endfunc
|
||||
|
||||
func MouseShiftWheelDown(row, col)
|
||||
if has('win32')
|
||||
call MSWinMouseEvent(s:MOUSE_CODE.SCRL_DOWN, a:row, a:col, 0, 0,
|
||||
\ s:MOUSE_CODE.MOD_SHIFT)
|
||||
else
|
||||
call feedkeys(MouseShiftWheelDownCode(a:row, a:col), 'Lx!')
|
||||
endif
|
||||
endfunc
|
||||
|
||||
func MouseShiftWheelLeftCode(row, col)
|
||||
" todo feed shift mod.
|
||||
return TerminalEscapeCode(0x42, a:row, a:col, 'M')
|
||||
endfunc
|
||||
|
||||
func MouseShiftWheelLeft(row, col)
|
||||
if has('win32')
|
||||
call MSWinMouseEvent(s:MOUSE_CODE.SCRL_LEFT, a:row, a:col, 0, 0,
|
||||
\ s:MOUSE_CODE.MOD_SHIFT)
|
||||
else
|
||||
call feedkeys(MouseShiftWheelLeftCode(a:row, a:col), 'Lx!')
|
||||
endif
|
||||
endfunc
|
||||
|
||||
func MouseShiftWheelRightCode(row, col)
|
||||
" todo feed shift mod.
|
||||
return TerminalEscapeCode(0x43, a:row, a:col, 'M')
|
||||
endfunc
|
||||
|
||||
func MouseShiftWheelRight(row, col)
|
||||
if has('win32')
|
||||
call MSWinMouseEvent(s:MOUSE_CODE.SCRL_RIGHT, a:row, a:col, 0, 0,
|
||||
\ s:MOUSE_CODE.MOD_SHIFT)
|
||||
else
|
||||
call feedkeys(MouseShiftWheelRightCode(a:row, a:col), 'Lx!')
|
||||
endif
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
@ -1281,7 +1281,7 @@ func Test_gui_mouse_move_event()
|
||||
let g:eventlist = g:eventlist[1 : ]
|
||||
endif
|
||||
|
||||
call assert_equal([#{row: 4, col: 31}, #{row: 11, col: 31}], g:eventlist)
|
||||
call assert_equal([#{row: 3, col: 30}, #{row: 10, col: 30}], g:eventlist)
|
||||
|
||||
" wiggle the mouse around within a screen cell, shouldn't trigger events
|
||||
call extend(args, #{cell: v:false})
|
||||
@ -1638,10 +1638,10 @@ endfunc
|
||||
" Test for sending low level key presses
|
||||
func SendKeys(keylist)
|
||||
for k in a:keylist
|
||||
call test_gui_event("sendevent", #{event: "keydown", keycode: k})
|
||||
call test_gui_event("key", #{event: "keydown", keycode: k})
|
||||
endfor
|
||||
for k in reverse(a:keylist)
|
||||
call test_gui_event("sendevent", #{event: "keyup", keycode: k})
|
||||
call test_gui_event("key", #{event: "keyup", keycode: k})
|
||||
endfor
|
||||
endfunc
|
||||
|
||||
|
651
src/testdir/test_mswin_event.vim
Normal file
651
src/testdir/test_mswin_event.vim
Normal file
@ -0,0 +1,651 @@
|
||||
" Test MS-Windows console event handling.
|
||||
|
||||
source check.vim
|
||||
CheckMSWindows
|
||||
" The mswin events should also work in gui
|
||||
|
||||
source mouse.vim
|
||||
|
||||
" Helper function for sending a sequence of low level key presses
|
||||
" The modifer key(s) can be included as normal key presses in the sequence
|
||||
func SendKeys(keylist)
|
||||
for k in a:keylist
|
||||
call test_mswin_event("key", #{event: "keydown", keycode: k})
|
||||
endfor
|
||||
for k in reverse(copy(a:keylist))
|
||||
call test_mswin_event("key", #{event: "keyup", keycode: k})
|
||||
endfor
|
||||
endfunc
|
||||
|
||||
" Send an individual key press
|
||||
" the modifers for the key press can be specified in the modifiers arg.
|
||||
func SendKey(key, modifiers)
|
||||
let args = { }
|
||||
let args.keycode = a:key
|
||||
let args.modifiers = a:modifiers
|
||||
let args.event = "keydown"
|
||||
call test_mswin_event("key", args)
|
||||
let args.event = "keyup"
|
||||
call test_mswin_event("key", args)
|
||||
unlet args
|
||||
endfunc
|
||||
|
||||
" Test MS-Windows console key events
|
||||
func Test_mswin_key_event()
|
||||
CheckMSWindows
|
||||
new
|
||||
|
||||
" flush out any garbage left in the buffer
|
||||
while getchar(0)
|
||||
endwhile
|
||||
|
||||
let VK = #{
|
||||
\ SPACE : 0x20,
|
||||
\ SHIFT : 0x10,
|
||||
\ LSHIFT : 0xA0,
|
||||
\ RSHIFT : 0xA1,
|
||||
\ CONTROL : 0x11,
|
||||
\ LCONTROL : 0xA2,
|
||||
\ RCONTROL : 0xA3,
|
||||
\ MENU : 0x12,
|
||||
\ ALT : 0x12,
|
||||
\ LMENU : 0xA4,
|
||||
\ LALT : 0xA4,
|
||||
\ RMENU : 0xA5,
|
||||
\ RALT : 0xA5,
|
||||
\ OEM_1 : 0xBA,
|
||||
\ OEM_2 : 0xBF,
|
||||
\ OEM_3 : 0xC0,
|
||||
\ OEM_4 : 0xDB,
|
||||
\ OEM_5 : 0xDC,
|
||||
\ OEM_6 : 0xDD,
|
||||
\ OEM_7 : 0xDE,
|
||||
\ OEM_PLUS : 0xBB,
|
||||
\ OEM_COMMA : 0xBC,
|
||||
\ OEM_MINUS : 0xBD,
|
||||
\ OEM_PERIOD : 0xBE,
|
||||
\ PRIOR : 0x21,
|
||||
\ NEXT : 0x22,
|
||||
\ END : 0x23,
|
||||
\ HOME : 0x24,
|
||||
\ LEFT : 0x25,
|
||||
\ UP : 0x26,
|
||||
\ RIGHT : 0x27,
|
||||
\ DOWN : 0x28,
|
||||
\ KEY_0 : 0x30,
|
||||
\ KEY_1 : 0x31,
|
||||
\ KEY_2 : 0x32,
|
||||
\ KEY_3 : 0x33,
|
||||
\ KEY_4 : 0x34,
|
||||
\ KEY_5 : 0x35,
|
||||
\ KEY_6 : 0x36,
|
||||
\ KEY_7 : 0x37,
|
||||
\ KEY_8 : 0x38,
|
||||
\ KEY_9 : 0x39,
|
||||
\ NUMPAD0 : 0x60,
|
||||
\ NUMPAD1 : 0x61,
|
||||
\ NUMPAD2 : 0x62,
|
||||
\ NUMPAD3 : 0x63,
|
||||
\ NUMPAD4 : 0x64,
|
||||
\ NUMPAD5 : 0x65,
|
||||
\ NUMPAD6 : 0x66,
|
||||
\ NUMPAD7 : 0x67,
|
||||
\ NUMPAD8 : 0x68,
|
||||
\ NUMPAD9 : 0x69,
|
||||
\ MULTIPLY : 0x6A,
|
||||
\ ADD : 0x6B,
|
||||
\ SUBTRACT : 0x6D,
|
||||
\ F1 : 0x70,
|
||||
\ F2 : 0x71,
|
||||
\ F3 : 0x72,
|
||||
\ F4 : 0x73,
|
||||
\ F5 : 0x74,
|
||||
\ F6 : 0x75,
|
||||
\ F7 : 0x76,
|
||||
\ F8 : 0x77,
|
||||
\ F9 : 0x78,
|
||||
\ F10 : 0x79,
|
||||
\ F11 : 0x7A,
|
||||
\ F12 : 0x7B,
|
||||
\ KEY_A : 0x41,
|
||||
\ KEY_B : 0x42,
|
||||
\ KEY_C : 0x43,
|
||||
\ KEY_D : 0x44,
|
||||
\ KEY_E : 0x45,
|
||||
\ KEY_F : 0x46,
|
||||
\ KEY_G : 0x47,
|
||||
\ KEY_H : 0x48,
|
||||
\ KEY_I : 0x49,
|
||||
\ KEY_J : 0x4A,
|
||||
\ KEY_K : 0x4B,
|
||||
\ KEY_L : 0x4C,
|
||||
\ KEY_M : 0x4D,
|
||||
\ KEY_N : 0x4E,
|
||||
\ KEY_O : 0x4F,
|
||||
\ KEY_P : 0x50,
|
||||
\ KEY_Q : 0x51,
|
||||
\ KEY_R : 0x52,
|
||||
\ KEY_S : 0x53,
|
||||
\ KEY_T : 0x54,
|
||||
\ KEY_U : 0x55,
|
||||
\ KEY_V : 0x56,
|
||||
\ KEY_W : 0x57,
|
||||
\ KEY_X : 0x58,
|
||||
\ KEY_Y : 0x59,
|
||||
\ KEY_Z : 0x5A
|
||||
\ }
|
||||
|
||||
let vim_MOD_MASK_SHIFT = 0x02
|
||||
let vim_MOD_MASK_CTRL = 0x04
|
||||
let vim_MOD_MASK_ALT = 0x08
|
||||
|
||||
let vim_key_modifiers = [
|
||||
\ ["", 0, []],
|
||||
\ ["S-", 2, [VK.SHIFT]],
|
||||
\ ["C-", 4, [VK.CONTROL]],
|
||||
\ ["C-S-", 6, [VK.CONTROL, VK.SHIFT]],
|
||||
\ ["A-", 8, [VK.MENU]],
|
||||
\ ["A-S-", 10, [VK.MENU, VK.SHIFT]],
|
||||
\ ["A-C-", 12, [VK.MENU, VK.CONTROL]],
|
||||
\ ["A-C-S-", 14, [VK.MENU, VK.CONTROL, VK.SHIFT]],
|
||||
\]
|
||||
|
||||
" Some punctuation characters
|
||||
" Assuming Standard US PC Keyboard layout
|
||||
let test_punctuation_keys = [
|
||||
\ [[VK.SPACE], ' '],
|
||||
\ [[VK.OEM_1], ';'],
|
||||
\ [[VK.OEM_2], '/'],
|
||||
\ [[VK.OEM_3], '`'],
|
||||
\ [[VK.OEM_4], '['],
|
||||
\ [[VK.OEM_5], '\'],
|
||||
\ [[VK.OEM_6], ']'],
|
||||
\ [[VK.OEM_7], ''''],
|
||||
\ [[VK.OEM_PLUS], '='],
|
||||
\ [[VK.OEM_COMMA], ','],
|
||||
\ [[VK.OEM_MINUS], '-'],
|
||||
\ [[VK.OEM_PERIOD], '.'],
|
||||
\ [[VK.SHIFT, VK.OEM_1], ':'],
|
||||
\ [[VK.SHIFT, VK.OEM_2], '?'],
|
||||
\ [[VK.SHIFT, VK.OEM_3], '~'],
|
||||
\ [[VK.SHIFT, VK.OEM_4], '{'],
|
||||
\ [[VK.SHIFT, VK.OEM_5], '|'],
|
||||
\ [[VK.SHIFT, VK.OEM_6], '}'],
|
||||
\ [[VK.SHIFT, VK.OEM_7], '"'],
|
||||
\ [[VK.SHIFT, VK.OEM_PLUS], '+'],
|
||||
\ [[VK.SHIFT, VK.OEM_COMMA], '<'],
|
||||
\ [[VK.SHIFT, VK.OEM_MINUS], '_'],
|
||||
\ [[VK.SHIFT, VK.OEM_PERIOD], '>'],
|
||||
\ [[VK.SHIFT, VK.KEY_1], '!'],
|
||||
\ [[VK.SHIFT, VK.KEY_2], '@'],
|
||||
\ [[VK.SHIFT, VK.KEY_3], '#'],
|
||||
\ [[VK.SHIFT, VK.KEY_4], '$'],
|
||||
\ [[VK.SHIFT, VK.KEY_5], '%'],
|
||||
\ [[VK.SHIFT, VK.KEY_6], '^'],
|
||||
\ [[VK.SHIFT, VK.KEY_7], '&'],
|
||||
\ [[VK.SHIFT, VK.KEY_8], '*'],
|
||||
\ [[VK.SHIFT, VK.KEY_9], '('],
|
||||
\ [[VK.SHIFT, VK.KEY_0], ')'],
|
||||
\ [[VK.LSHIFT, VK.KEY_9], '('],
|
||||
\ [[VK.RSHIFT, VK.KEY_0], ')']
|
||||
\ ]
|
||||
|
||||
for [kcodes, kstr] in test_punctuation_keys
|
||||
call SendKeys(kcodes)
|
||||
let ch = getcharstr(0)
|
||||
call assert_equal($"{kstr}", $"{ch}")
|
||||
let mod_mask = getcharmod()
|
||||
" the mod_mask is zero when no modifiers are used
|
||||
" and when the virtual termcap maps shift the character
|
||||
call assert_equal(0, mod_mask, $"key = {kstr}")
|
||||
endfor
|
||||
|
||||
" flush out any garbage left in the buffer
|
||||
while getchar(0)
|
||||
endwhile
|
||||
|
||||
for [kcodes, kstr] in test_punctuation_keys
|
||||
let modifiers = 0
|
||||
let key = kcodes[0]
|
||||
|
||||
for key in kcodes
|
||||
if index([VK.SHIFT, VK.LSHIFT, VK.RSHIFT], key) >= 0
|
||||
let modifiers = modifiers + vim_MOD_MASK_SHIFT
|
||||
endif
|
||||
if index([VK.CONTROL, VK.LCONTROL, VK.RCONTROL], key) >= 0
|
||||
let modifiers = modifiers + vim_MOD_MASK_CTRL
|
||||
endif
|
||||
if index([VK.ALT, VK.LALT, VK.RALT], key) >= 0
|
||||
let modifiers = modifiers + vim_MOD_MASK_ALT
|
||||
endif
|
||||
endfor
|
||||
|
||||
call SendKey(key, modifiers)
|
||||
let ch = getcharstr(0)
|
||||
call assert_equal($"{kstr}", $"{ch}")
|
||||
let mod_mask = getcharmod()
|
||||
" workaround for the virtual termcap maps changing the character instead
|
||||
" of sending Shift
|
||||
if index([VK.SHIFT, VK.LSHIFT, VK.RSHIFT], kcodes[0]) >= 0
|
||||
let modifiers = modifiers - vim_MOD_MASK_SHIFT
|
||||
endif
|
||||
call assert_equal(modifiers, mod_mask, $"key = {kstr}")
|
||||
endfor
|
||||
|
||||
" flush out any garbage left in the buffer
|
||||
while getchar(0)
|
||||
endwhile
|
||||
|
||||
" Test keyboard codes for digits
|
||||
" (0x30 - 0x39) : VK_0 - VK_9 are the same as ASCII '0' - '9'
|
||||
for kc in range(48, 57)
|
||||
call SendKeys([kc])
|
||||
let ch = getcharstr(0)
|
||||
call assert_equal(nr2char(kc), ch)
|
||||
call SendKey(kc, 0)
|
||||
let ch = getcharstr(0)
|
||||
call assert_equal(nr2char(kc), ch)
|
||||
endfor
|
||||
|
||||
" Test keyboard codes for Alt-0 to Alt-9
|
||||
" Expect +128 from the digit char codes
|
||||
for modkey in [VK.ALT, VK.LALT, VK.RALT]
|
||||
for kc in range(48, 57)
|
||||
call SendKeys([modkey, kc])
|
||||
let ch = getchar(0)
|
||||
call assert_equal(kc+128, ch)
|
||||
call SendKey(kc, vim_MOD_MASK_ALT)
|
||||
let ch = getchar(0)
|
||||
call assert_equal(kc+128, ch)
|
||||
endfor
|
||||
endfor
|
||||
|
||||
" Test for lowercase 'a' to 'z', VK codes 65(0x41) - 90(0x5A)
|
||||
" Note: VK_A-VK_Z virtual key codes coincide with uppercase ASCII codes A-Z.
|
||||
" eg VK_A is 65, and the ASCII character code for uppercase 'A' is also 65.
|
||||
" Caution: these are interpreted as lowercase when Shift is NOT pressed.
|
||||
" eg, sending VK_A (65) 'A' Key code without shift modifier, will produce ASCII
|
||||
" char 'a' (91) as the output. The ASCII codes for the lowercase letters are
|
||||
" numbered 32 higher than their uppercase versions.
|
||||
for kc in range(65, 90)
|
||||
call SendKeys([kc])
|
||||
let ch = getcharstr(0)
|
||||
call assert_equal(nr2char(kc + 32), ch)
|
||||
call SendKey(kc, 0)
|
||||
let ch = getcharstr(0)
|
||||
call assert_equal(nr2char(kc + 32), ch)
|
||||
endfor
|
||||
|
||||
" Test for Uppercase 'A' - 'Z' keys
|
||||
" ie. with VK_SHIFT, expect the keycode = character code.
|
||||
for kc in range(65, 90)
|
||||
call SendKeys([VK.SHIFT, kc])
|
||||
let ch = getcharstr(0)
|
||||
call assert_equal(nr2char(kc), ch)
|
||||
call SendKey(kc, vim_MOD_MASK_SHIFT)
|
||||
let ch = getcharstr(0)
|
||||
call assert_equal(nr2char(kc), ch)
|
||||
endfor
|
||||
|
||||
" Test for <Ctrl-A> to <Ctrl-Z> keys
|
||||
" Same as for lowercase, except with Ctrl Key
|
||||
" Expect the unicode characters 0x01 to 0x1A
|
||||
for modkey in [VK.CONTROL, VK.LCONTROL, VK.RCONTROL]
|
||||
for kc in range(65, 90)
|
||||
call SendKeys([modkey, kc])
|
||||
let ch = getcharstr(0)
|
||||
call assert_equal(nr2char(kc - 64), ch)
|
||||
call SendKey(kc, vim_MOD_MASK_CTRL)
|
||||
let ch = getcharstr(0)
|
||||
call assert_equal(nr2char(kc - 64), ch)
|
||||
endfor
|
||||
endfor
|
||||
|
||||
if !has("gui_running")
|
||||
" Test for <Alt-A> to <Alt-Z> keys
|
||||
" Expect the unicode characters 0xE1 to 0xFA
|
||||
" ie. 160 higher than the lowercase equivalent
|
||||
for kc in range(65, 90)
|
||||
call SendKeys([VK.LMENU, kc])
|
||||
let ch = getchar(0)
|
||||
call assert_equal(kc+160, ch)
|
||||
call SendKey(kc, vim_MOD_MASK_ALT)
|
||||
let ch = getchar(0)
|
||||
call assert_equal(kc+160, ch)
|
||||
endfor
|
||||
endif
|
||||
|
||||
if !has("gui_running")
|
||||
" Test for Function Keys 'F1' to 'F12'
|
||||
for n in range(1, 12)
|
||||
let kstr = $"F{n}"
|
||||
let keycode = eval('"\<' .. kstr .. '>"')
|
||||
call SendKeys([111+n])
|
||||
let ch = getcharstr(0)
|
||||
call assert_equal(keycode, $"{ch}", $"key = <{kstr}>")
|
||||
endfor
|
||||
endif
|
||||
|
||||
bw!
|
||||
endfunc
|
||||
|
||||
" Test MS-Windows console mouse events
|
||||
func Test_mswin_mouse_event()
|
||||
CheckMSWindows
|
||||
new
|
||||
|
||||
set mousemodel=extend
|
||||
call test_override('no_query_mouse', 1)
|
||||
call WaitForResponses()
|
||||
|
||||
let msg = ''
|
||||
|
||||
call setline(1, ['one two three', 'four five six'])
|
||||
|
||||
" Test mouse movement
|
||||
" by default, no mouse move events are generated
|
||||
" this setting enables it to generate move events
|
||||
set mousemev
|
||||
|
||||
if !has('gui_running')
|
||||
" console version needs a button pressed,
|
||||
" otherwise it ignores mouse movements.
|
||||
call MouseLeftClick(2, 3)
|
||||
endif
|
||||
call MSWinMouseEvent(0x700, 8, 13, 0, 0, 0)
|
||||
if has('gui_running')
|
||||
call feedkeys("\<Esc>", 'Lx!')
|
||||
endif
|
||||
let pos = getmousepos()
|
||||
call assert_equal(8, pos.screenrow)
|
||||
call assert_equal(13, pos.screencol)
|
||||
|
||||
if !has('gui_running')
|
||||
call MouseLeftClick(2, 3)
|
||||
call MSWinMouseEvent(0x700, 6, 4, 1, 0, 0)
|
||||
let pos = getmousepos()
|
||||
call assert_equal(6, pos.screenrow)
|
||||
call assert_equal(4, pos.screencol)
|
||||
endif
|
||||
|
||||
" test cells vs pixels
|
||||
if has('gui_running')
|
||||
let args = { }
|
||||
let args.row = 9
|
||||
let args.col = 7
|
||||
let args.move = 1
|
||||
let args.cell = 1
|
||||
call test_mswin_event("mouse", args)
|
||||
call feedkeys("\<Esc>", 'Lx!')
|
||||
let pos = getmousepos()
|
||||
call assert_equal(9, pos.screenrow)
|
||||
call assert_equal(7, pos.screencol)
|
||||
|
||||
let args.cell = 0
|
||||
call test_mswin_event("mouse", args)
|
||||
call feedkeys("\<Esc>", 'Lx!')
|
||||
let pos = getmousepos()
|
||||
call assert_equal(1, pos.screenrow)
|
||||
call assert_equal(1, pos.screencol)
|
||||
|
||||
unlet args
|
||||
endif
|
||||
|
||||
" finish testing mouse movement
|
||||
set mousemev&
|
||||
|
||||
" place the cursor using left click and release in normal mode
|
||||
call MouseLeftClick(2, 4)
|
||||
call MouseLeftRelease(2, 4)
|
||||
if has('gui_running')
|
||||
call feedkeys("\<Esc>", 'Lx!')
|
||||
endif
|
||||
call assert_equal([0, 2, 4, 0], getpos('.'))
|
||||
|
||||
" select and yank a word
|
||||
let @" = ''
|
||||
call MouseLeftClick(1, 9)
|
||||
let args = #{button: 0, row: 1, col: 9, multiclick: 1, modifiers: 0}
|
||||
call test_mswin_event('mouse', args)
|
||||
call MouseLeftRelease(1, 9)
|
||||
call feedkeys("y", 'Lx!')
|
||||
call assert_equal('three', @")
|
||||
|
||||
" create visual selection using right click
|
||||
let @" = ''
|
||||
|
||||
call MouseLeftClick(2 ,6)
|
||||
call MouseLeftRelease(2, 6)
|
||||
call MouseRightClick(2, 13)
|
||||
call MouseRightRelease(2, 13)
|
||||
call feedkeys("y", 'Lx!')
|
||||
call assert_equal('five six', @")
|
||||
|
||||
" paste using middle mouse button
|
||||
let @* = 'abc '
|
||||
call feedkeys('""', 'Lx!')
|
||||
call MouseMiddleClick(1, 9)
|
||||
call MouseMiddleRelease(1, 9)
|
||||
if has('gui_running')
|
||||
call feedkeys("\<Esc>", 'Lx!')
|
||||
endif
|
||||
call assert_equal(['one two abc three', 'four five six'], getline(1, '$'))
|
||||
|
||||
" test mouse scrolling (aka touchpad scrolling.)
|
||||
%d _
|
||||
set scrolloff=0
|
||||
call setline(1, range(1, 100))
|
||||
|
||||
" Scroll Down
|
||||
call MouseWheelDown(2, 1)
|
||||
call MouseWheelDown(2, 1)
|
||||
call MouseWheelDown(2, 1)
|
||||
call feedkeys("H", 'Lx!')
|
||||
call assert_equal(10, line('.'))
|
||||
|
||||
" Scroll Up
|
||||
call MouseWheelUp(2, 1)
|
||||
call MouseWheelUp(2, 1)
|
||||
call feedkeys("H", 'Lx!')
|
||||
call assert_equal(4, line('.'))
|
||||
|
||||
" Shift Scroll Down
|
||||
call MouseShiftWheelDown(2, 1)
|
||||
call feedkeys("H", 'Lx!')
|
||||
" should scroll from where it is (4) + visible buffer height - cmdheight
|
||||
let shift_scroll_height = line('w$') - line('w0') - &cmdheight
|
||||
call assert_equal(4 + shift_scroll_height, line('.'))
|
||||
|
||||
" Shift Scroll Up
|
||||
call MouseShiftWheelUp(2, 1)
|
||||
call feedkeys("H", 'Lx!')
|
||||
call assert_equal(4, line('.'))
|
||||
|
||||
if !has('gui_running')
|
||||
" Shift Scroll Down (using MOD)
|
||||
call MSWinMouseEvent(0x100, 2, 1, 0, 0, 0x04)
|
||||
call feedkeys("H", 'Lx!')
|
||||
" should scroll from where it is (4) + visible buffer height - cmdheight
|
||||
let shift_scroll_height = line('w$') - line('w0') - &cmdheight
|
||||
call assert_equal(4 + shift_scroll_height, line('.'))
|
||||
|
||||
" Shift Scroll Up (using MOD)
|
||||
call MSWinMouseEvent(0x200, 2, 1, 0, 0, 0x04)
|
||||
call feedkeys("H", 'Lx!')
|
||||
call assert_equal(4, line('.'))
|
||||
endif
|
||||
|
||||
set scrolloff&
|
||||
|
||||
%d _
|
||||
set nowrap
|
||||
" make the buffer 500 wide.
|
||||
call setline(1, range(10)->join('')->repeat(50))
|
||||
" Scroll Right
|
||||
call MouseWheelRight(1, 5)
|
||||
call MouseWheelRight(1, 10)
|
||||
call MouseWheelRight(1, 15)
|
||||
call feedkeys('g0', 'Lx!')
|
||||
call assert_equal(19, col('.'))
|
||||
|
||||
" Scroll Left
|
||||
call MouseWheelLeft(1, 15)
|
||||
call MouseWheelLeft(1, 10)
|
||||
call feedkeys('g0', 'Lx!')
|
||||
call assert_equal(7, col('.'))
|
||||
|
||||
" Shift Scroll Right
|
||||
call MouseShiftWheelRight(1, 10)
|
||||
call feedkeys('g0', 'Lx!')
|
||||
" should scroll from where it is (7) + window width
|
||||
call assert_equal(7 + winwidth(0), col('.'))
|
||||
|
||||
" Shift Scroll Left
|
||||
call MouseShiftWheelLeft(1, 50)
|
||||
call feedkeys('g0', 'Lx!')
|
||||
call assert_equal(7, col('.'))
|
||||
set wrap&
|
||||
|
||||
%d _
|
||||
call setline(1, repeat([repeat('a', 60)], 10))
|
||||
|
||||
" record various mouse events
|
||||
let mouseEventNames = [
|
||||
\ 'LeftMouse', 'LeftRelease', '2-LeftMouse', '3-LeftMouse',
|
||||
\ 'S-LeftMouse', 'A-LeftMouse', 'C-LeftMouse', 'MiddleMouse',
|
||||
\ 'MiddleRelease', '2-MiddleMouse', '3-MiddleMouse',
|
||||
\ 'S-MiddleMouse', 'A-MiddleMouse', 'C-MiddleMouse',
|
||||
\ 'RightMouse', 'RightRelease', '2-RightMouse',
|
||||
\ '3-RightMouse', 'S-RightMouse', 'A-RightMouse', 'C-RightMouse',
|
||||
\ ]
|
||||
let mouseEventCodes = map(copy(mouseEventNames), "'<' .. v:val .. '>'")
|
||||
let g:events = []
|
||||
for e in mouseEventCodes
|
||||
exe 'nnoremap ' .. e .. ' <Cmd>call add(g:events, "' ..
|
||||
\ substitute(e, '[<>]', '', 'g') .. '")<CR>'
|
||||
endfor
|
||||
|
||||
" Test various mouse buttons
|
||||
"(0 - Left, 1 - Middle, 2 - Right,
|
||||
" 0x300 - MOUSE_X1/FROM_LEFT_3RD_BUTTON,
|
||||
" 0x400 - MOUSE_X2/FROM_LEFT_4TH_BUTTON)
|
||||
for button in [0, 1, 2, 0x300, 0x400]
|
||||
" Single click
|
||||
let args = #{button: button, row: 2, col: 5, multiclick: 0, modifiers: 0}
|
||||
call test_mswin_event('mouse', args)
|
||||
let args.button = 3
|
||||
call test_mswin_event('mouse', args)
|
||||
|
||||
" Double Click
|
||||
let args.button = button
|
||||
call test_mswin_event('mouse', args)
|
||||
let args.multiclick = 1
|
||||
call test_mswin_event('mouse', args)
|
||||
let args.button = 3
|
||||
let args.multiclick = 0
|
||||
call test_mswin_event('mouse', args)
|
||||
|
||||
" Triple Click
|
||||
let args.button = button
|
||||
call test_mswin_event('mouse', args)
|
||||
let args.multiclick = 1
|
||||
call test_mswin_event('mouse', args)
|
||||
call test_mswin_event('mouse', args)
|
||||
let args.button = 3
|
||||
let args.multiclick = 0
|
||||
call test_mswin_event('mouse', args)
|
||||
|
||||
" Shift click
|
||||
let args = #{button: button, row: 3, col: 7, multiclick: 0, modifiers: 4}
|
||||
call test_mswin_event('mouse', args)
|
||||
let args.button = 3
|
||||
call test_mswin_event('mouse', args)
|
||||
|
||||
" Alt click
|
||||
let args.button = button
|
||||
let args.modifiers = 8
|
||||
call test_mswin_event('mouse', args)
|
||||
let args.button = 3
|
||||
call test_mswin_event('mouse', args)
|
||||
|
||||
" Ctrl click
|
||||
let args.button = button
|
||||
let args.modifiers = 16
|
||||
call test_mswin_event('mouse', args)
|
||||
let args.button = 3
|
||||
call test_mswin_event('mouse', args)
|
||||
|
||||
call feedkeys("\<Esc>", 'Lx!')
|
||||
endfor
|
||||
|
||||
if has('gui_running')
|
||||
call assert_equal(['LeftMouse', 'LeftRelease', 'LeftMouse',
|
||||
\ '2-LeftMouse', 'LeftMouse', '2-LeftMouse', '3-LeftMouse',
|
||||
\ 'S-LeftMouse', 'A-LeftMouse', 'C-LeftMouse', 'MiddleMouse',
|
||||
\ 'MiddleRelease', 'MiddleMouse', '2-MiddleMouse', 'MiddleMouse',
|
||||
\ '2-MiddleMouse', '3-MiddleMouse', 'S-MiddleMouse', 'A-MiddleMouse',
|
||||
\ 'C-MiddleMouse', 'RightMouse', 'RightRelease', 'RightMouse',
|
||||
\ '2-RightMouse', 'RightMouse', '2-RightMouse', '3-RightMouse',
|
||||
\ 'S-RightMouse', 'A-RightMouse', 'C-RightMouse'],
|
||||
\ g:events)
|
||||
else
|
||||
call assert_equal(['MiddleRelease', 'LeftMouse', '2-LeftMouse',
|
||||
\ '3-LeftMouse', 'S-LeftMouse', 'MiddleMouse', '2-MiddleMouse',
|
||||
\ '3-MiddleMouse', 'MiddleMouse', 'S-MiddleMouse', 'RightMouse',
|
||||
\ '2-RightMouse', '3-RightMouse'],
|
||||
\ g:events)
|
||||
endif
|
||||
|
||||
for e in mouseEventCodes
|
||||
exe 'nunmap ' .. e
|
||||
endfor
|
||||
|
||||
bw!
|
||||
call test_override('no_query_mouse', 0)
|
||||
set mousemodel&
|
||||
endfunc
|
||||
|
||||
|
||||
" Test MS-Windows test_mswin_event error handling
|
||||
func Test_mswin_event_error_handling()
|
||||
|
||||
let args = #{button: 0xfff, row: 2, col: 4, move: 0, multiclick: 0, modifiers: 0}
|
||||
if !has('gui_running')
|
||||
call assert_fails("call test_mswin_event('mouse', args)",'E475:')
|
||||
endif
|
||||
let args = #{button: 0, row: 2, col: 4, move: 0, multiclick: 0, modifiers: 0}
|
||||
call assert_fails("call test_mswin_event('a1b2c3', args)", 'E475:')
|
||||
call assert_fails("call test_mswin_event(test_null_string(), {})", 'E475:')
|
||||
|
||||
call assert_fails("call test_mswin_event([], args)", 'E1174:')
|
||||
call assert_fails("call test_mswin_event('abc', [])", 'E1206:')
|
||||
|
||||
call assert_false(test_mswin_event('mouse', test_null_dict()))
|
||||
let args = #{row: 2, col: 4, multiclick: 0, modifiers: 0}
|
||||
call assert_false(test_mswin_event('mouse', args))
|
||||
let args = #{button: 0, col: 4, multiclick: 0, modifiers: 0}
|
||||
call assert_false(test_mswin_event('mouse', args))
|
||||
let args = #{button: 0, row: 2, multiclick: 0, modifiers: 0}
|
||||
call assert_false(test_mswin_event('mouse', args))
|
||||
let args = #{button: 0, row: 2, col: 4, modifiers: 0}
|
||||
call assert_false(test_mswin_event('mouse', args))
|
||||
let args = #{button: 0, row: 2, col: 4, multiclick: 0}
|
||||
call assert_false(test_mswin_event('mouse', args))
|
||||
|
||||
call assert_false(test_mswin_event('key', test_null_dict()))
|
||||
call assert_fails("call test_mswin_event('key', [])", 'E1206:')
|
||||
call assert_fails("call test_mswin_event('key', {'event': 'keydown', 'keycode': 0x0})", 'E1291:')
|
||||
call assert_fails("call test_mswin_event('key', {'event': 'keydown', 'keycode': [15]})", 'E745:')
|
||||
call assert_fails("call test_mswin_event('key', {'event': 'keys', 'keycode': 0x41})", 'E475:')
|
||||
call assert_fails("call test_mswin_event('key', {'keycode': 0x41})", 'E417:')
|
||||
call assert_fails("call test_mswin_event('key', {'event': 'keydown'})", 'E1291:')
|
||||
|
||||
call assert_fails("sandbox call test_mswin_event('key', {'event': 'keydown', 'keycode': 61 })", 'E48:')
|
||||
|
||||
" flush out any garbage left in the buffer.
|
||||
while getchar(0)
|
||||
endwhile
|
||||
endfunc
|
||||
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
@ -437,25 +437,22 @@ func Test_1xterm_mouse_wheel()
|
||||
call assert_equal(1, line('w0'), msg)
|
||||
call assert_equal([0, 7, 1, 0], getpos('.'), msg)
|
||||
|
||||
if has('gui')
|
||||
" Horizontal wheel scrolling currently only works when vim is
|
||||
" compiled with gui enabled.
|
||||
call MouseWheelRight(1, 1)
|
||||
call assert_equal(7, 1 + virtcol(".") - wincol(), msg)
|
||||
call assert_equal([0, 7, 7, 0], getpos('.'), msg)
|
||||
call MouseWheelRight(1, 1)
|
||||
call assert_equal(7, 1 + virtcol(".") - wincol(), msg)
|
||||
call assert_equal([0, 7, 7, 0], getpos('.'), msg)
|
||||
|
||||
call MouseWheelRight(1, 1)
|
||||
call assert_equal(13, 1 + virtcol(".") - wincol(), msg)
|
||||
call assert_equal([0, 7, 13, 0], getpos('.'), msg)
|
||||
call MouseWheelRight(1, 1)
|
||||
call assert_equal(13, 1 + virtcol(".") - wincol(), msg)
|
||||
call assert_equal([0, 7, 13, 0], getpos('.'), msg)
|
||||
|
||||
call MouseWheelLeft(1, 1)
|
||||
call assert_equal(7, 1 + virtcol(".") - wincol(), msg)
|
||||
call assert_equal([0, 7, 13, 0], getpos('.'), msg)
|
||||
call MouseWheelLeft(1, 1)
|
||||
call assert_equal(7, 1 + virtcol(".") - wincol(), msg)
|
||||
call assert_equal([0, 7, 13, 0], getpos('.'), msg)
|
||||
|
||||
call MouseWheelLeft(1, 1)
|
||||
call assert_equal(1, 1 + virtcol(".") - wincol(), msg)
|
||||
call assert_equal([0, 7, 13, 0], getpos('.'), msg)
|
||||
|
||||
call MouseWheelLeft(1, 1)
|
||||
call assert_equal(1, 1 + virtcol(".") - wincol(), msg)
|
||||
call assert_equal([0, 7, 13, 0], getpos('.'), msg)
|
||||
endif
|
||||
endfor
|
||||
|
||||
let &mouse = save_mouse
|
||||
|
@ -1388,13 +1388,18 @@ test_gui_mouse_event(dict_T *args)
|
||||
|
||||
if (move)
|
||||
{
|
||||
int pY = row;
|
||||
int pX = col;
|
||||
// the "move" argument expects row and col coordnates to be in pixels,
|
||||
// unless "cell" is specified and is TRUE.
|
||||
if (dict_get_bool(args, "cell", FALSE))
|
||||
{
|
||||
// click in the middle of the character cell
|
||||
row = row * gui.char_height + gui.char_height / 2;
|
||||
col = col * gui.char_width + gui.char_width / 2;
|
||||
// calculate the middle of the character cell
|
||||
// Note: Cell coordinates are 1-based from vimscript
|
||||
pY = (row - 1) * gui.char_height + gui.char_height / 2;
|
||||
pX = (col - 1) * gui.char_width + gui.char_width / 2;
|
||||
}
|
||||
gui_mouse_moved(col, row);
|
||||
gui_mouse_moved(pX, pY);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1488,6 +1493,30 @@ test_gui_tabmenu_event(dict_T *args UNUSED)
|
||||
}
|
||||
# endif
|
||||
|
||||
void
|
||||
f_test_mswin_event(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
|
||||
{
|
||||
# ifdef MSWIN
|
||||
rettv->v_type = VAR_BOOL;
|
||||
rettv->vval.v_number = FALSE;
|
||||
|
||||
if (sandbox != 0)
|
||||
{
|
||||
emsg(_(e_not_allowed_in_sandbox));
|
||||
return;
|
||||
}
|
||||
|
||||
if (check_for_string_arg(argvars, 0) == FAIL
|
||||
|| check_for_dict_arg(argvars, 1) == FAIL
|
||||
|| argvars[1].vval.v_dict == NULL)
|
||||
return;
|
||||
|
||||
char_u *event = tv_get_string(&argvars[0]);
|
||||
rettv->vval.v_number = test_mswin_event(event, argvars[1].vval.v_dict);
|
||||
|
||||
# endif
|
||||
}
|
||||
|
||||
void
|
||||
f_test_gui_event(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
|
||||
{
|
||||
@ -1514,6 +1543,10 @@ f_test_gui_event(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
|
||||
# if defined(FIND_REPLACE_DIALOG)
|
||||
else if (STRCMP(event, "findrepl") == 0)
|
||||
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)
|
||||
rettv->vval.v_number = test_mswin_event(event, argvars[1].vval.v_dict);
|
||||
# endif
|
||||
else if (STRCMP(event, "mouse") == 0)
|
||||
rettv->vval.v_number = test_gui_mouse_event(argvars[1].vval.v_dict);
|
||||
@ -1523,10 +1556,6 @@ f_test_gui_event(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
|
||||
rettv->vval.v_number = test_gui_tabline_event(argvars[1].vval.v_dict);
|
||||
else if (STRCMP(event, "tabmenu") == 0)
|
||||
rettv->vval.v_number = test_gui_tabmenu_event(argvars[1].vval.v_dict);
|
||||
# ifdef FEAT_GUI_MSWIN
|
||||
else if (STRCMP(event, "sendevent") == 0)
|
||||
rettv->vval.v_number = test_gui_w32_sendevent(argvars[1].vval.v_dict);
|
||||
# endif
|
||||
else
|
||||
{
|
||||
semsg(_(e_invalid_argument_str), event);
|
||||
|
@ -695,6 +695,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1084,
|
||||
/**/
|
||||
1083,
|
||||
/**/
|
||||
|
Reference in New Issue
Block a user