summaryrefslogtreecommitdiffstats
path: root/src/gui_w32.c
diff options
context:
space:
mode:
authorChristopher Plewright <chris@createng.com>2022-12-20 20:01:58 +0000
committerBram Moolenaar <Bram@vim.org>2022-12-20 20:01:58 +0000
commit20b795e0eba6c933868c8f7cf62fb85d4f007688 (patch)
treeac278d8ec958a58ba6c5a90fba8aef7270abc72f /src/gui_w32.c
parent418b54788106efd94bbc71a4b100afae1080cbfc (diff)
patch 9.0.1084: code handling low level MS-Windows events cannot be testedv9.0.1084
Problem: Code handling low level MS-Windows events cannot be tested. Solution: Add test_mswin_event() and tests using it. (Christopher Plewright, closes #11622)
Diffstat (limited to 'src/gui_w32.c')
-rw-r--r--src/gui_w32.c163
1 files changed, 149 insertions, 14 deletions
diff --git a/src/gui_w32.c b/src/gui_w32.c
index 6733ac0624..b4a33d9868 100644
--- a/src/gui_w32.c
+++ b/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)
+
+// 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)
{
- char_u *event;
- INPUT inputs[1];
+ if (!dict_has_key(args, "row") || !dict_has_key(args, "col"))
+ return FALSE;
- event = dict_get_string(args, "event", TRUE);
- if (event == NULL)
+ // Note: "move" is optional, requires fewer arguments
+ int 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;
- ZeroMemory(inputs, sizeof(inputs));
+ int row = (int)dict_get_number(args, "row");
+ int col = (int)dict_get_number(args, "col");
- if (STRICMP(event, "keydown") == 0 || STRICMP(event, "keyup") == 0)
+ if (move)
+ {
+ // 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
{
- WORD vkCode;
+ 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");
+
+ // 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;
+}
- vkCode = dict_get_number_def(args, "keycode", 0);
+ 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));
- }
- 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;
}
+
+ 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