Mercurial > vim
diff src/os_win32.c @ 30882:7449da0e006b v9.0.0775
patch 9.0.0775: MS-Windows: mouse scrolling not supported in the console
Commit: https://github.com/vim/vim/commit/2a46f81ec7739967265759838afe7972e5f81e5e
Author: Christopher Plewright <chris@createng.com>
Date: Sun Oct 16 19:47:45 2022 +0100
patch 9.0.0775: MS-Windows: mouse scrolling not supported in the console
Problem: MS-Windows: mouse scrolling not supported in the console.
Solution: Add event handling for mouse scroll events. (Christopher
Plewright, closes #11374)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sun, 16 Oct 2022 21:00:04 +0200 |
parents | 1207b6d6cf9e |
children | 5137a0968a5c |
line wrap: on
line diff
--- 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) {