Skip to content

Commit

Permalink
patch 8.2.4674: cannot force getting MouseMove events
Browse files Browse the repository at this point in the history
Problem:    Cannot force getting MouseMove events.
Solution:   Add the 'mousemoveevent' option with implementaiton for the GUI.
            (Ernie Rael, closes #10044)
  • Loading branch information
errael authored and brammool committed Apr 3, 2022
1 parent 8ef6997 commit c4cb544
Show file tree
Hide file tree
Showing 9 changed files with 165 additions and 15 deletions.
4 changes: 4 additions & 0 deletions runtime/doc/gui.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.


Expand Down
12 changes: 12 additions & 0 deletions runtime/doc/options.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
26 changes: 24 additions & 2 deletions runtime/doc/testing.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
25 changes: 20 additions & 5 deletions src/gui.c
Original file line number Diff line number Diff line change
Expand Up @@ -3142,13 +3142,26 @@ gui_send_mouse_event(
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);
Expand Down Expand Up @@ -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);
}

/*
Expand Down
3 changes: 3 additions & 0 deletions src/option.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 7 additions & 0 deletions src/optiondefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
72 changes: 72 additions & 0 deletions src/testdir/test_gui.vim
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
29 changes: 21 additions & 8 deletions src/testing.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
2 changes: 2 additions & 0 deletions src/version.c
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,8 @@ static char *(features[]) =

static int included_patches[] =
{ /* Add new patch number below this line */
/**/
4674,
/**/
4673,
/**/
Expand Down

0 comments on commit c4cb544

Please sign in to comment.