1
0
forked from aniani/vim

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:
Christopher Plewright
2022-12-20 20:01:58 +00:00
committed by Bram Moolenaar
parent 418b547881
commit 20b795e0eb
17 changed files with 1490 additions and 74 deletions

View File

@@ -666,6 +666,8 @@ test_garbagecollect_soon() none free memory soon for testing
test_getvalue({string}) any get value of an internal variable test_getvalue({string}) any get value of an internal variable
test_gui_event({event}, {args}) bool generate a GUI event for testing test_gui_event({event}, {args}) bool generate a GUI event for testing
test_ignore_error({expr}) none ignore a specific error 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_blob() Blob null value for testing
test_null_channel() Channel null value for testing test_null_channel() Channel null value for testing
test_null_dict() Dict null value for testing test_null_dict() Dict null value for testing

View File

@@ -94,7 +94,7 @@ test_gui_event({event}, {args})
"findrepl" search and replace text. "findrepl" search and replace text.
"mouse" mouse button click event. "mouse" mouse button click event.
"scrollbar" move or drag the scrollbar. "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. "tabline" select a tab page by mouse click.
"tabmenu" select a tabline menu entry. "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 dragging: 1 to drag the scrollbar and 0 to click in the
scrollbar. scrollbar.
"sendevent": "key":
Send a low-level GUI event (e.g. key-up or down). Send a low-level keyboard event (e.g. key-up or down).
Currently only supported on MS-Windows. Currently only supported on MS-Windows.
The supported items in {args} are: The supported items in {args} are:
event: The supported string values are: event: The supported string values are:
@@ -224,6 +224,72 @@ test_ignore_error({expr}) *test_ignore_error()*
GetErrorText()->test_ignore_error() 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()* test_null_blob() *test_null_blob()*
Return a |Blob| that is null. Only useful for testing. Return a |Blob| that is null. Only useful for testing.

View File

@@ -1186,6 +1186,7 @@ Testing: *test-functions*
test_getvalue() get value of an internal variable test_getvalue() get value of an internal variable
test_gui_event() generate a GUI event for testing test_gui_event() generate a GUI event for testing
test_ignore_error() ignore a specific error message 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_blob() return a null Blob
test_null_channel() return a null Channel test_null_channel() return a null Channel
test_null_dict() return a null Dict test_null_dict() return a null Dict

View File

@@ -2694,6 +2694,8 @@ static funcentry_T global_functions[] =
ret_bool, f_test_gui_event}, ret_bool, f_test_gui_event},
{"test_ignore_error", 1, 1, FEARG_1, arg1_string, {"test_ignore_error", 1, 1, FEARG_1, arg1_string,
ret_void, f_test_ignore_error}, 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, {"test_null_blob", 0, 0, 0, NULL,
ret_blob, f_test_null_blob}, ret_blob, f_test_null_blob},
{"test_null_channel", 0, 0, 0, NULL, {"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 (*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 #ifdef USE_INPUT_BUF
ch_log(NULL, "feedkeys() lowlevel: %s", keys); ch_log(NULL, "feedkeys() lowlevel: %s", keys);

View File

@@ -8643,41 +8643,176 @@ netbeans_draw_multisign_indicator(int row)
#endif #endif
#if defined(FEAT_EVAL) || defined(PROTO) #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); // TODO: at the moment, this is just a copy of test_gui_mouse_event.
if (event == NULL) // 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; 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) if (vkCode <= 0 || vkCode >= 0xFF)
{ {
semsg(_(e_invalid_argument_nr), (long)vkCode); semsg(_(e_invalid_argument_nr), (long)vkCode);
return FALSE; 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].type = INPUT_KEYBOARD;
inputs[0].ki.wVk = vkCode; inputs[0].ki.wVk = vkCode;
if (STRICMP(event, "keyup") == 0) if (STRICMP(event, "keyup") == 0)
{
inputs[0].ki.dwFlags = KEYEVENTF_KEYUP; inputs[0].ki.dwFlags = KEYEVENTF_KEYUP;
if(!isModKey)
unwrapMods = TRUE;
}
(void)SetForegroundWindow(s_hwnd); (void)SetForegroundWindow(s_hwnd);
SendInput(ARRAYSIZE(inputs), inputs, sizeof(INPUT)); SendInput(ARRAYSIZE(inputs), inputs, sizeof(INPUT));
}
else
semsg(_(e_invalid_argument_str), event);
vim_free(event); 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
{
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; 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 #endif

View File

@@ -177,6 +177,25 @@ static void gotoxy(unsigned x, unsigned y);
static void standout(void); static void standout(void);
static int s_cursor_visible = TRUE; static int s_cursor_visible = TRUE;
static int did_create_conin = FALSE; 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 #endif
#ifdef FEAT_GUI_MSWIN #ifdef FEAT_GUI_MSWIN
static int s_dont_use_vimrun = TRUE; 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 set_console_color_rgb(void);
static void reset_console_color_rgb(void); static void reset_console_color_rgb(void);
static void restore_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 // This flag is newly created from Windows 10
#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
@@ -319,6 +338,13 @@ read_console_input(
int i; int i;
static INPUT_RECORD s_irPseudo; 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) if (nLength == -2)
return (s_dwMax > 0) ? TRUE : FALSE; return (s_dwMax > 0) ? TRUE : FALSE;
@@ -431,7 +457,7 @@ wait_for_single_object(
return WaitForSingleObject(hHandle, dwMilliseconds); return WaitForSingleObject(hHandle, dwMilliseconds);
} }
# endif # endif
#endif #endif // !FEAT_GUI_MSWIN || VIMDLL
static void static void
get_exe_name(void) get_exe_name(void)
@@ -1014,7 +1040,7 @@ win32_kbd_patch_key(
return 1; return 1;
} }
if (pker->uChar.UnicodeChar != 0) if (pker->uChar.UnicodeChar > 0 && pker->uChar.UnicodeChar < 0xfffd)
return 1; return 1;
CLEAR_FIELD(abKeystate); CLEAR_FIELD(abKeystate);
@@ -1080,7 +1106,8 @@ decode_key_event(
// special cases // special cases
if ((nModifs & CTRL) != 0 && (nModifs & ~CTRL) == 0 if ((nModifs & CTRL) != 0 && (nModifs & ~CTRL) == 0
&& pker->uChar.UnicodeChar == NUL) && (pker->uChar.UnicodeChar == NUL
|| pker->uChar.UnicodeChar == 0xfffd))
{ {
// Ctrl-6 is Ctrl-^ // Ctrl-6 is Ctrl-^
if (pker->wVirtualKeyCode == '6') if (pker->wVirtualKeyCode == '6')
@@ -1168,7 +1195,113 @@ decode_key_event(
return (*pch != NUL); 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) mch_setmouse(int on UNUSED)
{ {
} }
#else #else // !FEAT_GUI_MSWIN || VIMDLL
static int g_fMouseAvail = FALSE; // mouse present static int g_fMouseAvail = FALSE; // mouse present
static int g_fMouseActive = FALSE; // mouse enabled static int g_fMouseActive = FALSE; // mouse enabled
static int g_nMouseClick = -1; // mouse status static int g_nMouseClick = -1; // mouse status
@@ -1234,21 +1367,21 @@ mch_bevalterm_changed(void)
/* /*
* Win32 console mouse scroll event handler. * 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 * This encodes the mouse scroll direction and keyboard modifiers into
* g_nMouseClick, and the mouse position into g_xMouse and g_yMouse * 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 * The direction of the scroll is decoded from two fields of the win32 console
* mouse event record; * 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 * 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 * - If the high word of the dwButtonState member contains a positive
* value, the wheel was rotated to the right. * value, the wheel was rotated to the right.
* - Otherwise, the wheel was rotated to the left. * - 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, * - If the high word of the dwButtonState member contains a positive value,
* the wheel was rotated forward, away from the user. * the wheel was rotated forward, away from the user.
* - Otherwise, the wheel was rotated backward, toward the user. * - Otherwise, the wheel was rotated backward, toward the user.
@@ -1594,8 +1727,231 @@ decode_mouse_event(
return TRUE; 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 #ifdef MCH_CURSOR_SHAPE
/* /*

View File

@@ -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); 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 gui_mch_destroy_beval_area(BalloonEval *beval);
void netbeans_draw_multisign_indicator(int row); 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 : */ /* vim: set ft=c : */

View File

@@ -9,6 +9,7 @@ void dyn_libintl_end(void);
void PlatformId(void); void PlatformId(void);
void mch_setmouse(int on); void mch_setmouse(int on);
void mch_bevalterm_changed(void); void mch_bevalterm_changed(void);
int test_mswin_event(char_u *event, dict_T *args);
void mch_update_cursor(void); void mch_update_cursor(void);
int mch_char_avail(void); int mch_char_avail(void);
int mch_check_messages(void); int mch_check_messages(void);

View File

@@ -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_unknown(typval_T *argvars, typval_T *rettv);
void f_test_void(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_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_gui_event(typval_T *argvars, typval_T *rettv);
void f_test_settime(typval_T *argvars, typval_T *rettv); void f_test_settime(typval_T *argvars, typval_T *rettv);
/* vim: set ft=c : */ /* vim: set ft=c : */

View File

@@ -210,6 +210,7 @@ NEW_TESTS = \
test_modeless \ test_modeless \
test_modeline \ test_modeline \
test_move \ test_move \
test_mswin_event \
test_mzscheme \ test_mzscheme \
test_nested_function \ test_nested_function \
test_netbeans \ test_netbeans \
@@ -454,6 +455,7 @@ NEW_TESTS_RES = \
test_mksession.res \ test_mksession.res \
test_modeless.res \ test_modeless.res \
test_modeline.res \ test_modeline.res \
test_mswin_event.res \
test_mzscheme.res \ test_mzscheme.res \
test_nested_function.res \ test_nested_function.res \
test_netbeans.res \ test_netbeans.res \

View File

@@ -20,6 +20,27 @@ else
let g:Ttymouse_netterm = [] let g:Ttymouse_netterm = []
endif 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. " Helper function to emit a terminal escape code.
func TerminalEscapeCode(code, row, col, m) func TerminalEscapeCode(code, row, col, m)
if &ttymouse ==# 'xterm2' if &ttymouse ==# 'xterm2'
@@ -47,6 +68,31 @@ func NettermEscapeCode(row, col)
return printf("\<Esc>}%d,%d\r", a:row, a:col) return printf("\<Esc>}%d,%d\r", a:row, a:col)
endfunc 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) func MouseLeftClickCode(row, col)
if &ttymouse ==# 'dec' if &ttymouse ==# 'dec'
return DecEscapeCode(2, 4, a:row, a:col) return DecEscapeCode(2, 4, a:row, a:col)
@@ -58,7 +104,11 @@ func MouseLeftClickCode(row, col)
endfunc endfunc
func MouseLeftClick(row, col) func MouseLeftClick(row, col)
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!') call feedkeys(MouseLeftClickCode(a:row, a:col), 'Lx!')
endif
endfunc endfunc
func MouseMiddleClickCode(row, col) func MouseMiddleClickCode(row, col)
@@ -70,7 +120,11 @@ func MouseMiddleClickCode(row, col)
endfunc endfunc
func MouseMiddleClick(row, col) func MouseMiddleClick(row, col)
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!') call feedkeys(MouseMiddleClickCode(a:row, a:col), 'Lx!')
endif
endfunc endfunc
func MouseRightClickCode(row, col) func MouseRightClickCode(row, col)
@@ -82,7 +136,11 @@ func MouseRightClickCode(row, col)
endfunc endfunc
func MouseRightClick(row, col) func MouseRightClick(row, col)
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!') call feedkeys(MouseRightClickCode(a:row, a:col), 'Lx!')
endif
endfunc endfunc
func MouseCtrlLeftClickCode(row, col) func MouseCtrlLeftClickCode(row, col)
@@ -91,7 +149,12 @@ func MouseCtrlLeftClickCode(row, col)
endfunc endfunc
func MouseCtrlLeftClick(row, col) func MouseCtrlLeftClick(row, col)
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!') call feedkeys(MouseCtrlLeftClickCode(a:row, a:col), 'Lx!')
endif
endfunc endfunc
func MouseCtrlRightClickCode(row, col) func MouseCtrlRightClickCode(row, col)
@@ -100,7 +163,12 @@ func MouseCtrlRightClickCode(row, col)
endfunc endfunc
func MouseCtrlRightClick(row, col) func MouseCtrlRightClick(row, col)
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!') call feedkeys(MouseCtrlRightClickCode(a:row, a:col), 'Lx!')
endif
endfunc endfunc
func MouseAltLeftClickCode(row, col) func MouseAltLeftClickCode(row, col)
@@ -109,7 +177,12 @@ func MouseAltLeftClickCode(row, col)
endfunc endfunc
func MouseAltLeftClick(row, col) func MouseAltLeftClick(row, col)
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!') call feedkeys(MouseAltLeftClickCode(a:row, a:col), 'Lx!')
endif
endfunc endfunc
func MouseAltRightClickCode(row, col) func MouseAltRightClickCode(row, col)
@@ -118,7 +191,12 @@ func MouseAltRightClickCode(row, col)
endfunc endfunc
func MouseAltRightClick(row, col) func MouseAltRightClick(row, col)
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!') call feedkeys(MouseAltRightClickCode(a:row, a:col), 'Lx!')
endif
endfunc endfunc
func MouseLeftReleaseCode(row, col) func MouseLeftReleaseCode(row, col)
@@ -132,7 +210,11 @@ func MouseLeftReleaseCode(row, col)
endfunc endfunc
func MouseLeftRelease(row, col) func MouseLeftRelease(row, col)
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!') call feedkeys(MouseLeftReleaseCode(a:row, a:col), 'Lx!')
endif
endfunc endfunc
func MouseMiddleReleaseCode(row, col) func MouseMiddleReleaseCode(row, col)
@@ -144,7 +226,11 @@ func MouseMiddleReleaseCode(row, col)
endfunc endfunc
func MouseMiddleRelease(row, col) func MouseMiddleRelease(row, col)
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!') call feedkeys(MouseMiddleReleaseCode(a:row, a:col), 'Lx!')
endif
endfunc endfunc
func MouseRightReleaseCode(row, col) func MouseRightReleaseCode(row, col)
@@ -156,7 +242,11 @@ func MouseRightReleaseCode(row, col)
endfunc endfunc
func MouseRightRelease(row, col) func MouseRightRelease(row, col)
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!') call feedkeys(MouseRightReleaseCode(a:row, a:col), 'Lx!')
endif
endfunc endfunc
func MouseLeftDragCode(row, col) func MouseLeftDragCode(row, col)
@@ -168,7 +258,11 @@ func MouseLeftDragCode(row, col)
endfunc endfunc
func MouseLeftDrag(row, col) func MouseLeftDrag(row, col)
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!') call feedkeys(MouseLeftDragCode(a:row, a:col), 'Lx!')
endif
endfunc endfunc
func MouseWheelUpCode(row, col) func MouseWheelUpCode(row, col)
@@ -176,7 +270,11 @@ func MouseWheelUpCode(row, col)
endfunc endfunc
func MouseWheelUp(row, col) func MouseWheelUp(row, col)
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!') call feedkeys(MouseWheelUpCode(a:row, a:col), 'Lx!')
endif
endfunc endfunc
func MouseWheelDownCode(row, col) func MouseWheelDownCode(row, col)
@@ -184,7 +282,11 @@ func MouseWheelDownCode(row, col)
endfunc endfunc
func MouseWheelDown(row, col) func MouseWheelDown(row, col)
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!') call feedkeys(MouseWheelDownCode(a:row, a:col), 'Lx!')
endif
endfunc endfunc
func MouseWheelLeftCode(row, col) func MouseWheelLeftCode(row, col)
@@ -192,7 +294,11 @@ func MouseWheelLeftCode(row, col)
endfunc endfunc
func MouseWheelLeft(row, col) func MouseWheelLeft(row, col)
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!') call feedkeys(MouseWheelLeftCode(a:row, a:col), 'Lx!')
endif
endfunc endfunc
func MouseWheelRightCode(row, col) func MouseWheelRightCode(row, col)
@@ -200,7 +306,67 @@ func MouseWheelRightCode(row, col)
endfunc endfunc
func MouseWheelRight(row, col) func MouseWheelRight(row, col)
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!') 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 endfunc
" vim: shiftwidth=2 sts=2 expandtab " vim: shiftwidth=2 sts=2 expandtab

View File

@@ -1281,7 +1281,7 @@ func Test_gui_mouse_move_event()
let g:eventlist = g:eventlist[1 : ] let g:eventlist = g:eventlist[1 : ]
endif 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 " wiggle the mouse around within a screen cell, shouldn't trigger events
call extend(args, #{cell: v:false}) call extend(args, #{cell: v:false})
@@ -1638,10 +1638,10 @@ endfunc
" Test for sending low level key presses " Test for sending low level key presses
func SendKeys(keylist) func SendKeys(keylist)
for k in a: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 endfor
for k in reverse(a:keylist) 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 endfor
endfunc endfunc

View 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

View File

@@ -437,9 +437,6 @@ func Test_1xterm_mouse_wheel()
call assert_equal(1, line('w0'), msg) call assert_equal(1, line('w0'), msg)
call assert_equal([0, 7, 1, 0], getpos('.'), 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 MouseWheelRight(1, 1)
call assert_equal(7, 1 + virtcol(".") - wincol(), msg) call assert_equal(7, 1 + virtcol(".") - wincol(), msg)
call assert_equal([0, 7, 7, 0], getpos('.'), msg) call assert_equal([0, 7, 7, 0], getpos('.'), msg)
@@ -455,7 +452,7 @@ func Test_1xterm_mouse_wheel()
call MouseWheelLeft(1, 1) call MouseWheelLeft(1, 1)
call assert_equal(1, 1 + virtcol(".") - wincol(), msg) call assert_equal(1, 1 + virtcol(".") - wincol(), msg)
call assert_equal([0, 7, 13, 0], getpos('.'), msg) call assert_equal([0, 7, 13, 0], getpos('.'), msg)
endif
endfor endfor
let &mouse = save_mouse let &mouse = save_mouse

View File

@@ -1388,13 +1388,18 @@ test_gui_mouse_event(dict_T *args)
if (move) 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)) if (dict_get_bool(args, "cell", FALSE))
{ {
// click in the middle of the character cell // calculate the middle of the character cell
row = row * gui.char_height + gui.char_height / 2; // Note: Cell coordinates are 1-based from vimscript
col = col * gui.char_width + gui.char_width / 2; 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 else
{ {
@@ -1488,6 +1493,30 @@ test_gui_tabmenu_event(dict_T *args UNUSED)
} }
# endif # 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 void
f_test_gui_event(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 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) # if defined(FIND_REPLACE_DIALOG)
else if (STRCMP(event, "findrepl") == 0) else if (STRCMP(event, "findrepl") == 0)
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
# 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 # endif
else if (STRCMP(event, "mouse") == 0) else if (STRCMP(event, "mouse") == 0)
rettv->vval.v_number = test_gui_mouse_event(argvars[1].vval.v_dict); 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); rettv->vval.v_number = test_gui_tabline_event(argvars[1].vval.v_dict);
else if (STRCMP(event, "tabmenu") == 0) else if (STRCMP(event, "tabmenu") == 0)
rettv->vval.v_number = test_gui_tabmenu_event(argvars[1].vval.v_dict); 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 else
{ {
semsg(_(e_invalid_argument_str), event); semsg(_(e_invalid_argument_str), event);

View File

@@ -695,6 +695,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 */
/**/
1084,
/**/ /**/
1083, 1083,
/**/ /**/