To: vim_dev@googlegroups.com Subject: Patch 8.2.4902 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.4902 Problem: Mouse wheel scrolling is inconsistent. Solution: Use the MS-Winows system setting. (closes #10368) Files: runtime/doc/scroll.txt, src/gui_w32.c, src/mouse.c, src/proto/mouse.pro, src/testing.c, src/testdir/test_gui.vim *** ../vim-8.2.4901/runtime/doc/scroll.txt 2019-12-12 11:49:06.000000000 +0000 --- runtime/doc/scroll.txt 2022-05-07 12:19:59.484288709 +0100 *************** *** 237,267 **** |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|. ! For the X11 GUIs (Motif, Athena and GTK) scrolling the wheel generates key presses , , and . For example, if you push the scroll wheel upwards a key press is generated causing the window to scroll upwards (while the text is actually moving downwards). The default action for these keys are: ! scroll three lines up ** scroll one page up ** scroll one page up ** ! scroll three lines down ** scroll one page down ** scroll one page down ** ! scroll six columns left ** scroll one page left ** scroll one page left ** ! scroll six columns right ** scroll one page right ** scroll one page right ** This should work in all modes, except when editing the command line. 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 --- 237,270 ---- |xterm-mouse-wheel|. By default only vertical scroll wheels are supported, but some GUIs also support horizontal scroll wheels. ! On MS-Windows, if the scroll action causes input focus -problems, see ! |intellimouse-wheel-problems|. ! For Win32 and the X11 GUIs (Motif and GTK) scrolling the wheel generates key presses , , and . For example, if you push the scroll wheel upwards a key press is generated causing the window to scroll upwards (while the text is actually moving downwards). The default action for these keys are: ! scroll N lines up ** scroll one page up ** scroll one page up ** ! scroll N lines down ** scroll one page down ** scroll one page down ** ! scroll N columns left ** scroll one page left ** scroll one page left ** ! scroll N columns right ** scroll one page right ** scroll one page right ** 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 *** ../vim-8.2.4901/src/gui_w32.c 2022-05-05 19:23:03.123905358 +0100 --- src/gui_w32.c 2022-05-07 12:22:29.435928763 +0100 *************** *** 230,235 **** --- 230,239 ---- # 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,4135 **** /* * Setup for the Intellimouse */ static void init_mouse_wheel(void) { ! // Reasonable default values. ! mouse_scroll_lines = 3; ! mouse_scroll_chars = 3; ! ! // 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); } - /* * Intellimouse wheel handler. * Treat a mouse wheel event as if it were a scroll request. --- 4121,4153 ---- /* * Setup for the Intellimouse */ + static long + mouse_vertical_scroll_step(void) + { + UINT val; + if (SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &val, 0)) + return (val != WHEEL_PAGESCROLL) ? (long)val : -1; + return 3; // Safe default; + } + + 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. * Treat a mouse wheel event as if it were a scroll request. *************** *** 4137,4152 **** 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 --- 4155,4164 ---- *************** *** 4185,4207 **** // 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(); --- 4197,4205 ---- *************** *** 4213,4220 **** 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), FALSE, kbd_modifiers); mch_enable_flush(); gui_may_flush(); --- 4211,4217 ---- modifiers |= MOUSE_ALT; mch_disable_flush(); ! gui_send_mouse_event(button, GET_X_LPARAM(param), GET_Y_LPARAM(param), FALSE, kbd_modifiers); mch_enable_flush(); gui_may_flush(); *************** *** 4296,4307 **** switch (param) { case SPI_SETWHEELSCROLLLINES: ! SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, ! &mouse_scroll_lines, 0); break; ! case SPI_GETWHEELSCROLLCHARS: ! SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, ! &mouse_scroll_chars, 0); break; case SPI_SETNONCLIENTMETRICS: set_tabline_font(); --- 4293,4302 ---- switch (param) { case SPI_SETWHEELSCROLLLINES: ! mouse_set_vert_scroll_step(mouse_vertical_scroll_step()); break; ! case SPI_SETWHEELSCROLLCHARS: ! mouse_set_hor_scroll_step(mouse_horizontal_scroll_step()); break; case SPI_SETNONCLIENTMETRICS: set_tabline_font(); *** ../vim-8.2.4901/src/mouse.c 2022-04-21 22:52:07.062317208 +0100 --- src/mouse.c 2022-05-07 12:22:44.275897105 +0100 *************** *** 13,18 **** --- 13,37 ---- #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,1113 **** // Don't scroll the window in which completion is being done. if (!pum_visible() || curwin != old_curwin) { 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)); else ! scroll_redraw(dir, 3L); # ifdef FEAT_PROP_POPUP if (WIN_IS_POPUP(curwin)) popup_set_firstline(curwin); --- 1120,1135 ---- // 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 (mouse_vert_step < 0 ! || mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)) ! step = (long)(curwin->w_botline - curwin->w_topline); else ! step = mouse_vert_step; ! scroll_redraw(dir, step); # ifdef FEAT_PROP_POPUP if (WIN_IS_POPUP(curwin)) popup_set_firstline(curwin); *************** *** 1116,1125 **** #ifdef FEAT_GUI else { ! int val, step = 6; ! if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)) step = curwin->w_width; val = curwin->w_leftcol + (dir == MSCR_RIGHT ? -step : step); if (val < 0) val = 0; --- 1138,1150 ---- #ifdef FEAT_GUI else { ! int val; ! 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,2012 **** } /* ! * Mouse scroll wheel: Default action is to scroll three lines, 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) */ --- 2030,2038 ---- } /* ! * 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,2039 **** curwin = wp; curbuf = curwin->w_buffer; } - if (cap->arg == MSCR_UP || cap->arg == MSCR_DOWN) { # ifdef FEAT_TERMINAL --- 2059,2064 ---- *************** *** 2043,2063 **** send_keys_to_term(curbuf->b_term, cap->cmdchar, mod_mask, FALSE); else # endif ! if (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) { cap->count1 = curwin->w_height / 2; if (cap->count1 == 0) cap->count1 = 1; } else ! cap->count1 = 3; cap->count0 = cap->count1; nv_scroll_line(cap); } --- 2068,2088 ---- send_keys_to_term(curbuf->b_term, cap->cmdchar, mod_mask, FALSE); else # endif ! 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 < mouse_vert_step * 2) { cap->count1 = curwin->w_height / 2; if (cap->count1 == 0) cap->count1 = 1; } else ! cap->count1 = mouse_vert_step; cap->count0 = cap->count1; nv_scroll_line(cap); } *************** *** 2072,2081 **** // Horizontal scroll - only allowed when 'wrap' is disabled if (!curwin->w_p_wrap) { ! int val, step = 6; ! if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)) step = curwin->w_width; val = curwin->w_leftcol + (cap->arg == MSCR_RIGHT ? -step : +step); if (val < 0) val = 0; --- 2097,2109 ---- // Horizontal scroll - only allowed when 'wrap' is disabled if (!curwin->w_p_wrap) { ! int val, step; ! 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; *** ../vim-8.2.4901/src/proto/mouse.pro 2021-06-03 19:34:52.954850543 +0100 --- src/proto/mouse.pro 2022-05-07 12:23:22.419818598 +0100 *************** *** 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); *** ../vim-8.2.4901/src/testing.c 2022-04-04 15:16:50.742014128 +0100 --- src/testing.c 2022-05-07 12:23:02.519859046 +0100 *************** *** 1393,1398 **** --- 1393,1403 ---- 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); } *** ../vim-8.2.4901/src/testdir/test_gui.vim 2022-04-29 16:43:56.219178196 +0100 --- src/testdir/test_gui.vim 2022-05-07 12:13:54.544962788 +0100 *************** *** 997,1002 **** --- 997,1003 ---- 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,1017 **** --- 1013,1019 ---- call test_gui_event('mouse', args) call feedkeys("H", 'Lx!') call assert_equal(4, line('.')) + set scrolloff& %d _ set nowrap *** ../vim-8.2.4901/src/version.c 2022-05-07 11:28:02.189974238 +0100 --- src/version.c 2022-05-07 12:17:34.944720466 +0100 *************** *** 748,749 **** --- 748,751 ---- { /* Add new patch number below this line */ + /**/ + 4902, /**/ -- hundred-and-one symptoms of being an internet addict: 125. You begin to wonder how often it REALLY is necessary to get up and shower or bathe. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///