]> granicus.if.org Git - vim/commitdiff
patch 8.2.4674: cannot force getting MouseMove events v8.2.4674
authorErnie Rael <errael@raelity.com>
Sun, 3 Apr 2022 14:47:28 +0000 (15:47 +0100)
committerBram Moolenaar <Bram@vim.org>
Sun, 3 Apr 2022 14:47:28 +0000 (15:47 +0100)
Problem:    Cannot force getting MouseMove events.
Solution:   Add the 'mousemoveevent' option with implementaiton for the GUI.
            (Ernie Rael, closes #10044)

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

index d4c24bfcbdacbfbfeaad07f8adf046b0acd5712d..84d6984bf6000016ec903bd67d833807f3e472e9 100644 (file)
@@ -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 way it probably should in a Motif
 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.
 
 
index bdc25223f4fe1c54b3fcc7ea8d919e8984cbf72d..d5e5e6834df8c24fedd304b43c2534e6a77b613f 100644 (file)
@@ -5517,6 +5517,18 @@ A jump table for the options with a short description can be found at |Q_op|.
 
        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,
index 2a74883a94655ba135715b52f35698b2d15d255c..1b726f7390efbc375a520475b1c5d9e58ea98c38 100644 (file)
@@ -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
index 3e383a4b4e6aaa1d3b8fdbd854a51fe13620dbc1..3b8c0d0a8044c64c040b8be609e4f418aa76516d 100644 (file)
--- 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.
-       gui_send_mouse_event(MOUSE_MOVE, x, y, FALSE, 0);
+       || 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);
 }
 
 /*
index e34467514a5900388be725dc6f7fee1669c3421a..85f2fa816f6be84a5fcce80dad6cd3ef3e8bf8f4 100644 (file)
@@ -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
index 650c622d0c4ff1221af4ed9048ef18508fe3f449..9eb0e7859bbf53a5e7a831ed53bc22ee90443bec 100644 (file)
@@ -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,
index 7947288c726ce9650d3a521f99dc35d0f4c1db06..c5332b8c223b552823773b27677737dd9b2432b2 100644 (file)
@@ -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)
index 48ba14d2cafd5def2c3b2714d3e6cff275d1c134..c0534875371ef71b02adec4bb5fce2115e223a73 100644 (file)
@@ -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;
 }
 
index 9b92724b737a3f2e124034efaeec23f5f18e243c..602366f62f5cdd9b2d089d91e13f4200f5601690 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4674,
 /**/
     4673,
 /**/