changeset 28297:4190b932e6ca v8.2.4674

patch 8.2.4674: cannot force getting MouseMove events Commit: https://github.com/vim/vim/commit/c4cb544cd5beaa864b3893e4b8d0085393c7dbce Author: Ernie Rael <errael@raelity.com> Date: Sun Apr 3 15:47:28 2022 +0100 patch 8.2.4674: cannot force getting MouseMove events Problem: Cannot force getting MouseMove events. Solution: Add the 'mousemoveevent' option with implementaiton for the GUI. (Ernie Rael, closes #10044)
author Bram Moolenaar <Bram@vim.org>
date Sun, 03 Apr 2022 17:00:04 +0200
parents b87dde76b66b
children 02ec20ca3576
files runtime/doc/gui.txt runtime/doc/options.txt runtime/doc/testing.txt src/gui.c src/option.h src/optiondefs.h src/testdir/test_gui.vim src/testing.c src/version.c
diffstat 9 files changed, 165 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/gui.txt
+++ b/runtime/doc/gui.txt
@@ -261,6 +261,7 @@ Other options that are relevant:
 'mousefocus'	window focus follows mouse pointer |gui-mouse-focus|
 'mousemodel'	what mouse button does which action
 'mousehide'	hide mouse pointer while typing text
+'mousemoveevent' enable mouse move events so that <MouseMove> can be mapped
 'selectmode'	whether to start Select mode or Visual mode
 
 A quick way to set these is with the ":behave" command.
@@ -406,6 +407,9 @@ These mappings make selection work the w
 application, with shift-left mouse allowing for extending the visual area
 rather than the right mouse button.
 
+<MouseMove> may be mapped, but 'mousemoveevent' must be enabled to use the
+mapping.
+
 Mouse mapping with modifiers does not work for modeless selection.
 
 
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -5517,6 +5517,18 @@ A jump table for the options with a shor
 
 	The 'mousemodel' option is set by the |:behave| command.
 
+						*'mousemoveevent'* *'mousemev'*
+'mousemoveevent' 'mousemev'  boolean	(default off)
+			global
+			{only works in the GUI}
+	When on, mouse move events are delivered to the input queue and are
+	available for mapping. The default, off, avoids the mouse movement
+	overhead except when needed. See |gui-mouse-mapping|.
+	Warning: Setting this option can make pending mappings to be aborted
+	when the mouse is moved.
+	Currently only works in the GUI, may be made to work in a terminal
+	later.
+
 					*'mouseshape'* *'mouses'* *E547*
 'mouseshape' 'mouses'	string	(default "i-r:beam,s:updown,sd:udsizing,
 					vs:leftright,vd:lrsizing,m:no,
--- a/runtime/doc/testing.txt
+++ b/runtime/doc/testing.txt
@@ -131,8 +131,8 @@ test_gui_event({event}, {args})
 		    forward:	set to 1 for forward search.
 
 		"mouse":
-		  Inject a mouse button click event.  The supported items in
-		  {args} are:
+		  Inject either a mouse button click, or a mouse move, event.
+		  The supported items in {args} are:
 		    button:	mouse button.  The supported values are:
 				    0	right mouse button
 				    1	middle mouse button
@@ -151,6 +151,28 @@ test_gui_event({event}, {args})
 				    4	shift is pressed
 				    8	alt is pressed
 				   16	ctrl is pressed
+		    move:	Optional; if used and TRUE then a mouse move
+			        event can be generated.
+				Only {args} row: and col: are used and
+				required; they are interpreted as pixels.
+				Only results in an event when 'mousemoveevent'
+				is set or a popup uses mouse move events.
+
+		"scrollbar":
+		  Set or drag the left, right or horizontal scrollbar.  Only
+		  works when the scrollbar actually exists.  The supported
+		  items in {args} are:
+		    which:	scrollbar. The supported values are:
+				    left  Left scrollbar of the current window
+				    right Right scrollbar of the current window
+				    hor   Horizontal scrollbar
+		    value:	amount to scroll.  For the vertical scrollbars
+				the value can be 1 to the line-count of the
+				buffer.  For the horizontal scrollbar the
+				value can be between 1 and the maximum line
+				length, assuming 'wrap' is not set.
+		    dragging:	1 to drag the scrollbar and 0 to click in the
+				scrollbar.
 
 		"scrollbar":
 		  Set or drag the left, right or horizontal scrollbar.  Only
--- a/src/gui.c
+++ b/src/gui.c
@@ -3142,13 +3142,26 @@ button_set:
 		if (hold_gui_events)
 		    return;
 
+		row = gui_xy2colrow(x, y, &col);
+		// Don't report a mouse move unless moved to a
+		// different character position.
+		if (button == MOUSE_MOVE)
+		{
+		    if (row == prev_row && col == prev_col)
+			return;
+		    else
+		    {
+			prev_row = row >= 0 ? row : 0;
+			prev_col = col;
+		    }
+		}
+
 		string[3] = CSI;
 		string[4] = KS_EXTRA;
 		string[5] = (int)button_char;
 
 		// Pass the pointer coordinates of the scroll event so that we
 		// know which window to scroll.
-		row = gui_xy2colrow(x, y, &col);
 		string[6] = (char_u)(col / 128 + ' ' + 1);
 		string[7] = (char_u)(col % 128 + ' ' + 1);
 		string[8] = (char_u)(row / 128 + ' ' + 1);
@@ -4967,12 +4980,14 @@ gui_mouse_moved(int x, int y)
     // apply 'mousefocus' and pointer shape
     gui_mouse_focus(x, y);
 
+    if (p_mousemev
 #ifdef FEAT_PROP_POPUP
-    if (popup_uses_mouse_move)
-	// Generate a mouse-moved event, so that the popup can perhaps be
-	// closed, just like in the terminal.
+	|| popup_uses_mouse_move
+#endif
+   )
+	// Generate a mouse-moved event. For a <MouseMove> mapping. Or so the
+	// popup can perhaps be closed, just like in the terminal.
 	gui_send_mouse_event(MOUSE_MOVE, x, y, FALSE, 0);
-#endif
 }
 
 /*
--- a/src/option.h
+++ b/src/option.h
@@ -760,6 +760,9 @@ EXTERN int	p_mousef;	// 'mousefocus'
 EXTERN int	p_mh;		// 'mousehide'
 #endif
 EXTERN char_u	*p_mousem;	// 'mousemodel'
+#ifdef FEAT_GUI
+EXTERN int	p_mousemev;	// 'mousemoveevent'
+#endif
 EXTERN long	p_mouset;	// 'mousetime'
 EXTERN int	p_more;		// 'more'
 #ifdef FEAT_MZSCHEME
--- a/src/optiondefs.h
+++ b/src/optiondefs.h
@@ -1746,6 +1746,13 @@ static struct vimoption options[] =
 # endif
 #endif
 				(char_u *)0L} SCTX_INIT},
+    {"mousemoveevent",   "mousemev",   P_BOOL|P_VI_DEF,
+#ifdef FEAT_GUI
+			    (char_u *)&p_mousemev, PV_NONE,
+#else
+			    (char_u *)NULL, PV_NONE,
+#endif
+			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"mouseshape",  "mouses",  P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
 #ifdef FEAT_MOUSESHAPE
 			    (char_u *)&p_mouseshape, PV_NONE,
--- a/src/testdir/test_gui.vim
+++ b/src/testdir/test_gui.vim
@@ -1194,6 +1194,78 @@ func Test_gui_mouse_event()
   set mousemodel&
 endfunc
 
+func Test_gui_mouse_move_event()
+  let args = #{move: 1, button: 0, multiclick: 0, modifiers: 0}
+
+  " default, do not generate mouse move events
+  set mousemev&
+  call assert_false(&mousemev)
+
+  let n_event = 0
+  nnoremap <special> <MouseMove> :let n_event += 1<CR>
+
+  " start at mouse pos (1,1), clear counter
+  call extend(args, #{row: 1, col:1})
+  call test_gui_event('mouse', args)
+  call feedkeys('', 'Lx!')
+  let n_event = 0
+
+  call extend(args, #{row: 30, col:300})
+  call test_gui_event('mouse', args)
+  call feedkeys('', 'Lx!')
+
+  call extend(args, #{row: 100, col:300})
+  call test_gui_event('mouse', args)
+  call feedkeys('', 'Lx!')
+
+  " no events since mousemev off
+  call assert_equal(0, n_event)
+
+  " turn on mouse events and try the same thing
+  set mousemev
+  call extend(args, #{row: 1, col:1})
+  call test_gui_event('mouse', args)
+  call feedkeys('', 'Lx!')
+  let n_event = 0
+
+  call extend(args, #{row: 30, col:300})
+  call test_gui_event('mouse', args)
+  call feedkeys('', 'Lx!')
+
+  call extend(args, #{row: 100, col:300})
+  call test_gui_event('mouse', args)
+  call feedkeys('', 'Lx!')
+
+  call assert_equal(2, n_event)
+
+  " wiggle the mouse around, shouldn't get events
+  call extend(args, #{row: 1, col:1})
+  call test_gui_event('mouse', args)
+  call feedkeys('', 'Lx!')
+  let n_event = 0
+
+  call extend(args, #{row: 1, col:2})
+  call test_gui_event('mouse', args)
+  call feedkeys('', 'Lx!')
+
+  call extend(args, #{row: 2, col:2})
+  call test_gui_event('mouse', args)
+  call feedkeys('', 'Lx!')
+
+  call extend(args, #{row: 2, col:1})
+  call test_gui_event('mouse', args)
+  call feedkeys('', 'Lx!')
+
+  call extend(args, #{row: 1, col:1})
+  call test_gui_event('mouse', args)
+  call feedkeys('', 'Lx!')
+
+  call assert_equal(0, n_event)
+
+  unmap <MouseMove>
+  set mousemev&
+endfunc
+
 " Test for 'guitablabel' and 'guitabtooltip' options
 func TestGuiTabLabel()
   call add(g:TabLabels, v:lnum + 100)
--- a/src/testing.c
+++ b/src/testing.c
@@ -1368,22 +1368,35 @@ test_gui_mouse_event(dict_T *args)
     int		col;
     int		repeated_click;
     int_u	mods;
+    int		move;
 
-    if (dict_find(args, (char_u *)"button", -1) == NULL
-	    || dict_find(args, (char_u *)"row", -1) == NULL
-	    || dict_find(args, (char_u *)"col", -1) == NULL
+    if (dict_find(args, (char_u *)"row", -1) == NULL
+	    || dict_find(args, (char_u *)"col", -1) == NULL)
+	return FALSE;
+
+    // Note: "move" is optional, requires fewer arguments
+    move = (int)dict_get_bool(args, (char_u *)"move", FALSE);
+
+    if (!move && (dict_find(args, (char_u *)"button", -1) == NULL
 	    || dict_find(args, (char_u *)"multiclick", -1) == NULL
-	    || dict_find(args, (char_u *)"modifiers", -1) == NULL)
+	    || dict_find(args, (char_u *)"modifiers", -1) == NULL))
 	return FALSE;
 
-    button = (int)dict_get_number(args, (char_u *)"button");
     row = (int)dict_get_number(args, (char_u *)"row");
     col = (int)dict_get_number(args, (char_u *)"col");
-    repeated_click = (int)dict_get_number(args, (char_u *)"multiclick");
-    mods = (int)dict_get_number(args, (char_u *)"modifiers");
 
-    gui_send_mouse_event(button, TEXT_X(col - 1), TEXT_Y(row - 1),
+    if (move)
+	gui_mouse_moved(col, row);
+    else
+    {
+	button = (int)dict_get_number(args, (char_u *)"button");
+	repeated_click = (int)dict_get_number(args, (char_u *)"multiclick");
+	mods = (int)dict_get_number(args, (char_u *)"modifiers");
+
+	gui_send_mouse_event(button, TEXT_X(col - 1), TEXT_Y(row - 1),
 							repeated_click, mods);
+    }
+
     return TRUE;
 }
 
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    4674,
+/**/
     4673,
 /**/
     4672,