]> granicus.if.org Git - vim/commitdiff
patch 8.2.4902: mouse wheel scrolling is inconsistent v8.2.4902
authorLemonBoy <thatlemon@gmail.com>
Sat, 7 May 2022 11:25:40 +0000 (12:25 +0100)
committerBram Moolenaar <Bram@vim.org>
Sat, 7 May 2022 11:25:40 +0000 (12:25 +0100)
Problem:    Mouse wheel scrolling is inconsistent.
Solution:   Use the MS-Winows system setting. (closes #10368)

runtime/doc/scroll.txt
src/gui_w32.c
src/mouse.c
src/proto/mouse.pro
src/testdir/test_gui.vim
src/testing.c
src/version.c

index 941e5bd1f3377d55d7817135ed5e2824e872388d..0126195155c169a637eb5db24ceb54b02bf7ec64 100644 (file)
@@ -237,31 +237,34 @@ it works depends on your system.  It might also work in an xterm
 |xterm-mouse-wheel|.  By default only vertical scroll wheels are supported,
 but some GUIs also support horizontal scroll wheels.
 
-For the Win32 GUI the scroll action is hard coded.  It works just like
-dragging the scrollbar of the current window.  How many lines are scrolled
-depends on your mouse driver.  If the scroll action causes input focus
-problems, see |intellimouse-wheel-problems|.
+On MS-Windows, if the scroll action causes input focus -problems, see
+|intellimouse-wheel-problems|.
 
-For the X11 GUIs (Motif and GTK) scrolling the wheel generates key
+For Win32 and the X11 GUIs (Motif and GTK) scrolling the wheel generates key
 presses <ScrollWheelUp>, <ScrollWheelDown>, <ScrollWheelLeft> and
 <ScrollWheelRight>.  For example, if you push the scroll wheel upwards a
 <ScrollWheelUp> key press is generated causing the window to scroll upwards
 (while the text is actually moving downwards).  The default action for these
 keys are:
-    <ScrollWheelUp>        scroll three lines up       *<ScrollWheelUp>*
+    <ScrollWheelUp>        scroll N lines up           *<ScrollWheelUp>*
     <S-ScrollWheelUp>      scroll one page up          *<S-ScrollWheelUp>*
     <C-ScrollWheelUp>      scroll one page up          *<C-ScrollWheelUp>*
-    <ScrollWheelDown>      scroll three lines down     *<ScrollWheelDown>*
+    <ScrollWheelDown>      scroll N lines down         *<ScrollWheelDown>*
     <S-ScrollWheelDown>            scroll one page down        *<S-ScrollWheelDown>*
     <C-ScrollWheelDown>            scroll one page down        *<C-ScrollWheelDown>*
-    <ScrollWheelLeft>      scroll six columns left     *<ScrollWheelLeft>*
+    <ScrollWheelLeft>      scroll N columns left       *<ScrollWheelLeft>*
     <S-ScrollWheelLeft>            scroll one page left        *<S-ScrollWheelLeft>*
     <C-ScrollWheelLeft>            scroll one page left        *<C-ScrollWheelLeft>*
-    <ScrollWheelRight>     scroll six columns right    *<ScrollWheelRight>*
+    <ScrollWheelRight>     scroll N columns right      *<ScrollWheelRight>*
     <S-ScrollWheelRight>    scroll one page right      *<S-ScrollWheelRight>*
     <C-ScrollWheelRight>    scroll one page right      *<C-ScrollWheelRight>*
 This should work in all modes, except when editing the command line.
 
+The value of N depends on the system.  By default Vim scrolls three lines when
+moving vertically, and six columns when moving horizontally.  On MS-Windows
+the amount of lines and columns for each scroll action is taken from the
+system-wide settings.
+
 Note that horizontal scrolling only works if 'nowrap' is set.  Also, unless
 the "h" flag in 'guioptions' is set, the cursor moves to the longest visible
 line if the cursor line is about to be scrolled off the screen (similarly to
index c6a8b6d6e7bc7a0c9ea98d497342d24cc1961d8e..7bca9e7aca9c5897c62165c38f3567282c62fac6 100644 (file)
@@ -230,6 +230,10 @@ gui_mch_set_rendering_options(char_u *s)
 # define SPI_GETWHEELSCROLLCHARS       0x006C
 #endif
 
+#ifndef SPI_SETWHEELSCROLLCHARS
+# define SPI_SETWHEELSCROLLCHARS       0x006D
+#endif
+
 #ifdef PROTO
 /*
  * Define a few things for generating prototypes.  This is just to avoid
@@ -4117,18 +4121,32 @@ gui_mswin_get_menu_height(
 /*
  * Setup for the Intellimouse
  */
-    static void
-init_mouse_wheel(void)
+    static long
+mouse_vertical_scroll_step(void)
 {
-    // Reasonable default values.
-    mouse_scroll_lines = 3;
-    mouse_scroll_chars = 3;
+    UINT val;
+    if (SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &val, 0))
+       return (val != WHEEL_PAGESCROLL) ? (long)val : -1;
+    return 3; // Safe default;
+}
 
-    // if NT 4.0+ (or Win98) get scroll lines directly from system
-    SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &mouse_scroll_lines, 0);
-    SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &mouse_scroll_chars, 0);
+    static long
+mouse_horizontal_scroll_step(void)
+{
+    UINT val;
+    if (SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &val, 0))
+       return (long)val;
+    return 3; // Safe default;
 }
 
+    static void
+init_mouse_wheel(void)
+{
+    // Get the default values for the horizontal and vertical scroll steps from
+    // the system.
+    mouse_set_vert_scroll_step(mouse_vertical_scroll_step());
+    mouse_set_hor_scroll_step(mouse_horizontal_scroll_step());
+}
 
 /*
  * Intellimouse wheel handler.
@@ -4137,16 +4155,10 @@ init_mouse_wheel(void)
     static void
 _OnMouseWheel(HWND hwnd, short zDelta, LPARAM param, int horizontal)
 {
-    int                i;
-    int                amount;
     int                button;
     win_T      *wp;
     int                modifiers, kbd_modifiers;
 
-    // Initializes mouse_scroll_chars too.
-    if (mouse_scroll_lines == 0)
-       init_mouse_wheel();
-
     wp = gui_mouse_window(FIND_POPUP);
 
 #ifdef FEAT_PROP_POPUP
@@ -4185,23 +4197,9 @@ _OnMouseWheel(HWND hwnd, short zDelta, LPARAM param, int horizontal)
     // Translate the scroll event into an event that Vim can process so that
     // the user has a chance to map the scrollwheel buttons.
     if (horizontal)
-    {
        button = zDelta >= 0 ? MOUSE_6 : MOUSE_7;
-       if (mouse_scroll_chars > 0
-                              && mouse_scroll_chars < MAX(wp->w_width - 2, 1))
-           amount = mouse_scroll_chars;
-       else
-           amount = MAX(wp->w_width - 2, 1);
-    }
     else
-    {
        button = zDelta >= 0 ? MOUSE_4 : MOUSE_5;
-       if (mouse_scroll_lines > 0
-                             && mouse_scroll_lines < MAX(wp->w_height - 2, 1))
-           amount = mouse_scroll_lines;
-       else
-           amount = MAX(wp->w_height - 2, 1);
-    }
 
     kbd_modifiers = get_active_modifiers();
 
@@ -4213,8 +4211,7 @@ _OnMouseWheel(HWND hwnd, short zDelta, LPARAM param, int horizontal)
        modifiers |= MOUSE_ALT;
 
     mch_disable_flush();
-    for (i = amount; i > 0; --i)
-       gui_send_mouse_event(button, GET_X_LPARAM(param), GET_Y_LPARAM(param),
+    gui_send_mouse_event(button, GET_X_LPARAM(param), GET_Y_LPARAM(param),
                FALSE, kbd_modifiers);
     mch_enable_flush();
     gui_may_flush();
@@ -4296,12 +4293,10 @@ _OnSettingChange(UINT param)
     switch (param)
     {
        case SPI_SETWHEELSCROLLLINES:
-           SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0,
-                   &mouse_scroll_lines, 0);
+           mouse_set_vert_scroll_step(mouse_vertical_scroll_step());
            break;
-       case SPI_GETWHEELSCROLLCHARS:
-           SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0,
-                   &mouse_scroll_chars, 0);
+       case SPI_SETWHEELSCROLLCHARS:
+           mouse_set_hor_scroll_step(mouse_horizontal_scroll_step());
            break;
        case SPI_SETNONCLIENTMETRICS:
            set_tabline_font();
index a0c5156052bcb89dae102931b461bb1b4199ffc3..57b0f1405b74fa15f40e0cc371bc77823a7010ec 100644 (file)
 
 #include "vim.h"
 
+/*
+ * Horiziontal and vertical steps used when scrolling.
+ * When negative scroll by a whole page.
+ */
+static long mouse_hor_step = 6;
+static long mouse_vert_step = 3;
+
+    void
+mouse_set_vert_scroll_step(long step)
+{
+    mouse_vert_step = step;
+}
+
+    void
+mouse_set_hor_scroll_step(long step)
+{
+    mouse_hor_step = step;
+}
+
 #ifdef CHECK_DOUBLE_CLICK
 /*
  * Return the duration from t1 to t2 in milliseconds.
@@ -1101,13 +1120,16 @@ ins_mousescroll(int dir)
     // Don't scroll the window in which completion is being done.
     if (!pum_visible() || curwin != old_curwin)
     {
+       long step;
+
        if (dir == MSCR_DOWN || dir == MSCR_UP)
        {
-           if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
-               scroll_redraw(dir,
-                       (long)(curwin->w_botline - curwin->w_topline));
+           if (mouse_vert_step < 0
+                   || mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
+               step = (long)(curwin->w_botline - curwin->w_topline);
            else
-               scroll_redraw(dir, 3L);
+               step = mouse_vert_step;
+           scroll_redraw(dir, step);
 # ifdef FEAT_PROP_POPUP
        if (WIN_IS_POPUP(curwin))
            popup_set_firstline(curwin);
@@ -1116,10 +1138,13 @@ ins_mousescroll(int dir)
 #ifdef FEAT_GUI
        else
        {
-           int val, step = 6;
+           int val;
 
-           if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
+           if (mouse_hor_step < 0
+                   || mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
                step = curwin->w_width;
+           else
+               step = mouse_hor_step;
            val = curwin->w_leftcol + (dir == MSCR_RIGHT ? -step : step);
            if (val < 0)
                val = 0;
@@ -2005,8 +2030,9 @@ retnomove:
 }
 
 /*
- * Mouse scroll wheel: Default action is to scroll three lines, or one page
- * when Shift or Ctrl is used.
+ * Mouse scroll wheel: Default action is to scroll mouse_vert_step lines (or
+ * mouse_hor_step, depending on the scroll direction), or one page when Shift or
+ * Ctrl is used.
  * K_MOUSEUP (cap->arg == 1) or K_MOUSEDOWN (cap->arg == 0) or
  * K_MOUSELEFT (cap->arg == -1) or K_MOUSERIGHT (cap->arg == -2)
  */
@@ -2033,7 +2059,6 @@ nv_mousescroll(cmdarg_T *cap)
        curwin = wp;
        curbuf = curwin->w_buffer;
     }
-
     if (cap->arg == MSCR_UP || cap->arg == MSCR_DOWN)
     {
 # ifdef FEAT_TERMINAL
@@ -2043,21 +2068,21 @@ nv_mousescroll(cmdarg_T *cap)
            send_keys_to_term(curbuf->b_term, cap->cmdchar, mod_mask, FALSE);
        else
 # endif
-       if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
+       if (mouse_vert_step < 0 || mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
        {
            (void)onepage(cap->arg ? FORWARD : BACKWARD, 1L);
        }
        else
        {
            // Don't scroll more than half the window height.
-           if (curwin->w_height < 6)
+           if (curwin->w_height < mouse_vert_step * 2)
            {
                cap->count1 = curwin->w_height / 2;
                if (cap->count1 == 0)
                    cap->count1 = 1;
            }
            else
-               cap->count1 = 3;
+               cap->count1 = mouse_vert_step;
            cap->count0 = cap->count1;
            nv_scroll_line(cap);
        }
@@ -2072,10 +2097,13 @@ nv_mousescroll(cmdarg_T *cap)
        // Horizontal scroll - only allowed when 'wrap' is disabled
        if (!curwin->w_p_wrap)
        {
-           int val, step = 6;
+           int val, step;
 
-           if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
+           if (mouse_hor_step < 0
+                   || mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
                step = curwin->w_width;
+           else
+               step = mouse_hor_step;
            val = curwin->w_leftcol + (cap->arg == MSCR_RIGHT ? -step : +step);
            if (val < 0)
                val = 0;
index 37a2f07cb6baf80160c0129141a78d7facce5fe3..249e7f2408cd1b86f69bd0b09c1e777306d1a933 100644 (file)
@@ -1,4 +1,6 @@
 /* mouse.c */
+void mouse_set_vert_scroll_step(long step);
+void mouse_set_hor_scroll_step(long step);
 int do_mouse(oparg_T *oap, int c, int dir, long count, int fixindent);
 void ins_mouse(int c);
 void ins_mousescroll(int dir);
index 993954b5a16ceb2aef656421725ad1d7f257c01e..bc3c6980554b36a38826fca321c9d02f19211db8 100644 (file)
@@ -997,6 +997,7 @@ func Test_gui_mouse_event()
   call assert_equal(['one two abc three', 'four five posix'], getline(1, '$'))
 
   %d _
+  set scrolloff=0
   call setline(1, range(1, 100))
   " scroll up
   let args = #{button: 0x200, row: 2, col: 1, multiclick: 0, modifiers: 0}
@@ -1012,6 +1013,7 @@ func Test_gui_mouse_event()
   call test_gui_event('mouse', args)
   call feedkeys("H", 'Lx!')
   call assert_equal(4, line('.'))
+  set scrolloff&
 
   %d _
   set nowrap
index 33401230216efadef74622243cbe6676be726034..572dcdcffe2e63b0bc1b72be0df517746f3d9212 100644 (file)
@@ -1393,6 +1393,11 @@ test_gui_mouse_event(dict_T *args)
        repeated_click = (int)dict_get_number(args, (char_u *)"multiclick");
        mods = (int)dict_get_number(args, (char_u *)"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);
     }
index 647011ae13ac6155d6a29e8c4fe701f9ec64aafa..5ee96b61780615bf830807f717dab05e033cd557 100644 (file)
@@ -746,6 +746,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4902,
 /**/
     4901,
 /**/