diff options
author | Christopher Plewright <chris@createng.com> | 2022-12-20 20:01:58 +0000 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2022-12-20 20:01:58 +0000 |
commit | 20b795e0eba6c933868c8f7cf62fb85d4f007688 (patch) | |
tree | ac278d8ec958a58ba6c5a90fba8aef7270abc72f /src/gui_w32.c | |
parent | 418b54788106efd94bbc71a4b100afae1080cbfc (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.c | 163 |
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 |