summaryrefslogtreecommitdiffstats
path: root/src/os_win32.c
diff options
context:
space:
mode:
authorChristopher Plewright <chris@createng.com>2022-10-16 19:47:45 +0100
committerBram Moolenaar <Bram@vim.org>2022-10-16 19:47:45 +0100
commit2a46f81ec7739967265759838afe7972e5f81e5e (patch)
tree0815a1dd6382fde04a67d6db374b1de60bc686e9 /src/os_win32.c
parent6a12d26f3404e45ce25cf9152857e355b28f392a (diff)
patch 9.0.0775: MS-Windows: mouse scrolling not supported in the consolev9.0.0775
Problem: MS-Windows: mouse scrolling not supported in the console. Solution: Add event handling for mouse scroll events. (Christopher Plewright, closes #11374)
Diffstat (limited to 'src/os_win32.c')
-rw-r--r--src/os_win32.c137
1 files changed, 130 insertions, 7 deletions
diff --git a/src/os_win32.c b/src/os_win32.c
index 2a9d1cf57f..003fdea1b9 100644
--- a/src/os_win32.c
+++ b/src/os_win32.c
@@ -1231,6 +1231,100 @@ mch_bevalterm_changed(void)
}
# endif
+
+/*
+ * Win32 console mouse scroll event handler.
+ * Loosely based on 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
+ * 2. The sign - positive or negative (aka delta flag) - from dwButtonState
+ *
+ * When scroll axis 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
+ * - 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.
+ */
+ static void
+decode_mouse_wheel(MOUSE_EVENT_RECORD *pmer)
+{
+ win_T *wp;
+ int horizontal = (pmer->dwEventFlags == MOUSE_HWHEELED);
+ int zDelta = pmer->dwButtonState;
+
+ g_xMouse = pmer->dwMousePosition.X;
+ g_yMouse = pmer->dwMousePosition.Y;
+
+#ifdef FEAT_PROP_POPUP
+ int lcol;
+ int lrow;
+ lcol = g_xMouse;
+ lrow = g_yMouse;
+ wp = mouse_find_win(&lrow, &lcol, FAIL_POPUP);
+ if (wp != NULL && popup_is_popup(wp))
+ {
+ g_nMouseClick = -1;
+ cmdarg_T cap;
+ oparg_T oa;
+ CLEAR_FIELD(cap);
+ clear_oparg(&oa);
+ cap.oap = &oa;
+ if (horizontal)
+ {
+ cap.arg = zDelta < 0 ? MSCR_LEFT : MSCR_RIGHT;
+ cap.cmdchar = zDelta < 0 ? K_MOUSELEFT : K_MOUSERIGHT;
+ }
+ else
+ {
+ cap.cmdchar = zDelta < 0 ? K_MOUSEUP : K_MOUSEDOWN;
+ cap.arg = zDelta < 0 ? MSCR_UP : MSCR_DOWN;
+ }
+
+ // Mouse hovers over popup window, scroll it if possible.
+ mouse_row = wp->w_winrow;
+ mouse_col = wp->w_wincol;
+ nv_mousescroll(&cap);
+ update_screen(0);
+ setcursor();
+ out_flush();
+ return;
+ }
+#endif
+ mouse_col = g_xMouse;
+ mouse_row = g_yMouse;
+
+ char_u modifiers = 0;
+ char_u direction = 0;
+
+ // Decode the direction into an event that Vim can process
+ if (horizontal)
+ direction = zDelta >= 0 ? KE_MOUSELEFT : KE_MOUSERIGHT;
+ else
+ direction = zDelta >= 0 ? KE_MOUSEDOWN : KE_MOUSEUP;
+
+ // Decode the win32 console key modifers into Vim mouse modifers.
+ if (pmer->dwControlKeyState & SHIFT_PRESSED)
+ modifiers |= MOD_MASK_SHIFT; //MOUSE_SHIFT;
+ if (pmer->dwControlKeyState & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
+ modifiers |= MOD_MASK_CTRL; //MOUSE_CTRL;
+ if (pmer->dwControlKeyState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED))
+ modifiers |= MOD_MASK_ALT; // MOUSE_ALT;
+
+ // add (bitwise or) the scroll direction and the key modifier chars
+ // together.
+ g_nMouseClick = ((direction << 8) | modifiers);
+
+ return;
+}
+
/*
* Decode a MOUSE_EVENT. If it's a valid event, return MOUSE_LEFT,
* MOUSE_MIDDLE, or MOUSE_RIGHT for a click; MOUSE_DRAG for a mouse
@@ -1304,6 +1398,13 @@ decode_mouse_event(
if (g_nMouseClick != -1)
return TRUE;
+ if (pmer->dwEventFlags == MOUSE_WHEELED
+ || pmer->dwEventFlags == MOUSE_HWHEELED)
+ {
+ decode_mouse_wheel(pmer);
+ return TRUE; // we now should have a mouse scroll in g_nMouseClick
+ }
+
nButton = -1;
g_xMouse = pmer->dwMousePosition.X;
g_yMouse = pmer->dwMousePosition.Y;
@@ -1939,12 +2040,34 @@ mch_inchar(
fprintf(fdDump, "{%02x @ %d, %d}",
g_nMouseClick, g_xMouse, g_yMouse);
# endif
- typeahead[typeaheadlen++] = ESC + 128;
- typeahead[typeaheadlen++] = 'M';
- typeahead[typeaheadlen++] = g_nMouseClick;
- typeahead[typeaheadlen++] = g_xMouse + '!';
- typeahead[typeaheadlen++] = g_yMouse + '!';
- g_nMouseClick = -1;
+ char_u modifiers = ((char_u *)(&g_nMouseClick))[0];
+ char_u scroll_dir = ((char_u *)(&g_nMouseClick))[1];
+
+ if (scroll_dir == KE_MOUSEDOWN
+ || scroll_dir == KE_MOUSEUP
+ || scroll_dir == KE_MOUSELEFT
+ || scroll_dir == KE_MOUSERIGHT)
+ {
+ if (modifiers > 0)
+ {
+ typeahead[typeaheadlen++] = CSI;
+ typeahead[typeaheadlen++] = KS_MODIFIER;
+ typeahead[typeaheadlen++] = modifiers;
+ }
+ typeahead[typeaheadlen++] = CSI;
+ typeahead[typeaheadlen++] = KS_EXTRA;
+ typeahead[typeaheadlen++] = scroll_dir;
+ g_nMouseClick = -1;
+ }
+ else
+ {
+ typeahead[typeaheadlen++] = ESC + 128;
+ typeahead[typeaheadlen++] = 'M';
+ typeahead[typeaheadlen++] = g_nMouseClick;
+ typeahead[typeaheadlen++] = g_xMouse + '!';
+ typeahead[typeaheadlen++] = g_yMouse + '!';
+ g_nMouseClick = -1;
+ }
}
else
{
@@ -8361,7 +8484,7 @@ stop_timeout(void)
{
if (timer_active)
{
- BOOL ret = DeleteTimerQueueTimer(NULL, timer_handle, NULL);
+ BOOL ret = DeleteTimerQueueTimer(NULL, timer_handle, NULL);
timer_active = FALSE;
if (!ret && GetLastError() != ERROR_IO_PENDING)
{