Skip to content

Commit 06a1f82

Browse files
committed
feat(terminal): forward X1 and X2 mouse events
Ref: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Other-buttons
1 parent 44dbfcf commit 06a1f82

File tree

4 files changed

+93
-24
lines changed

4 files changed

+93
-24
lines changed

src/nvim/terminal.c

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -792,17 +792,23 @@ static int terminal_execute(VimState *state, int key)
792792
case K_LEFTMOUSE:
793793
case K_LEFTDRAG:
794794
case K_LEFTRELEASE:
795-
case K_MOUSEMOVE:
796795
case K_MIDDLEMOUSE:
797796
case K_MIDDLEDRAG:
798797
case K_MIDDLERELEASE:
799798
case K_RIGHTMOUSE:
800799
case K_RIGHTDRAG:
801800
case K_RIGHTRELEASE:
801+
case K_X1MOUSE:
802+
case K_X1DRAG:
803+
case K_X1RELEASE:
804+
case K_X2MOUSE:
805+
case K_X2DRAG:
806+
case K_X2RELEASE:
802807
case K_MOUSEDOWN:
803808
case K_MOUSEUP:
804809
case K_MOUSELEFT:
805810
case K_MOUSERIGHT:
811+
case K_MOUSEMOVE:
806812
if (send_mouse_event(s->term, key)) {
807813
return 0;
808814
}
@@ -1804,8 +1810,6 @@ static bool send_mouse_event(Terminal *term, int c)
18041810
pressed = true; FALLTHROUGH;
18051811
case K_LEFTRELEASE:
18061812
button = 1; break;
1807-
case K_MOUSEMOVE:
1808-
button = 0; break;
18091813
case K_MIDDLEDRAG:
18101814
case K_MIDDLEMOUSE:
18111815
pressed = true; FALLTHROUGH;
@@ -1816,6 +1820,16 @@ static bool send_mouse_event(Terminal *term, int c)
18161820
pressed = true; FALLTHROUGH;
18171821
case K_RIGHTRELEASE:
18181822
button = 3; break;
1823+
case K_X1DRAG:
1824+
case K_X1MOUSE:
1825+
pressed = true; FALLTHROUGH;
1826+
case K_X1RELEASE:
1827+
button = 8; break;
1828+
case K_X2DRAG:
1829+
case K_X2MOUSE:
1830+
pressed = true; FALLTHROUGH;
1831+
case K_X2RELEASE:
1832+
button = 9; break;
18191833
case K_MOUSEDOWN:
18201834
pressed = true; button = 4; break;
18211835
case K_MOUSEUP:
@@ -1824,6 +1838,8 @@ static bool send_mouse_event(Terminal *term, int c)
18241838
pressed = true; button = 7; break;
18251839
case K_MOUSERIGHT:
18261840
pressed = true; button = 6; break;
1841+
case K_MOUSEMOVE:
1842+
button = 0; break;
18271843
default:
18281844
return false;
18291845
}

src/nvim/vterm/mouse.c

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include "nvim/math.h"
12
#include "nvim/tui/termkey/termkey.h"
23
#include "nvim/vterm/mouse.h"
34
#include "nvim/vterm/vterm.h"
@@ -24,6 +25,9 @@ static void output_mouse(VTermState *state, int code, int pressed, int modifiers
2425
code = 3;
2526
}
2627

28+
if (code & 0x80) {
29+
break;
30+
}
2731
vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "M%c%c%c",
2832
(code | modifiers) + 0x20, col + 0x21, row + 0x21);
2933
break;
@@ -74,11 +78,16 @@ void vterm_mouse_move(VTerm *vt, int row, int col, VTermModifier mod)
7478

7579
if ((state->mouse_flags & MOUSE_WANT_DRAG && state->mouse_buttons)
7680
|| (state->mouse_flags & MOUSE_WANT_MOVE)) {
77-
int button = state->mouse_buttons & 0x01 ? 1
78-
: state->mouse_buttons & 0x02 ? 2
79-
: state->mouse_buttons &
80-
0x04 ? 3 : 4;
81-
output_mouse(state, button - 1 + 0x20, 1, (int)mod, col, row);
81+
if (state->mouse_buttons) {
82+
int button = xctz((uint64_t)state->mouse_buttons) + 1;
83+
if (button < 4) {
84+
output_mouse(state, button - 1 + 0x20, 1, (int)mod, col, row);
85+
} else if (button >= 8 && button < 12) {
86+
output_mouse(state, button - 8 + 0x80 + 0x20, 1, (int)mod, col, row);
87+
}
88+
} else {
89+
output_mouse(state, 3 + 0x20, 1, (int)mod, col, row);
90+
}
8291
}
8392
}
8493

@@ -88,16 +97,16 @@ void vterm_mouse_button(VTerm *vt, int button, bool pressed, VTermModifier mod)
8897

8998
int old_buttons = state->mouse_buttons;
9099

91-
if (button > 0 && button <= 3) {
100+
if ((button > 0 && button <= 3) || (button >= 8 && button <= 11)) {
92101
if (pressed) {
93102
state->mouse_buttons |= (1 << (button - 1));
94103
} else {
95104
state->mouse_buttons &= ~(1 << (button - 1));
96105
}
97106
}
98107

99-
// Most of the time we don't get button releases from 4/5
100-
if (state->mouse_buttons == old_buttons && button < 4) {
108+
// Most of the time we don't get button releases from 4/5/6/7
109+
if (state->mouse_buttons == old_buttons && (button < 4 || button > 7)) {
101110
return;
102111
}
103112

@@ -109,5 +118,7 @@ void vterm_mouse_button(VTerm *vt, int button, bool pressed, VTermModifier mod)
109118
output_mouse(state, button - 1, pressed, (int)mod, state->mouse_col, state->mouse_row);
110119
} else if (button < 8) {
111120
output_mouse(state, button - 4 + 0x40, pressed, (int)mod, state->mouse_col, state->mouse_row);
121+
} else if (button < 12) {
122+
output_mouse(state, button - 8 + 0x80, pressed, (int)mod, state->mouse_col, state->mouse_row);
112123
}
113124
}

test/functional/terminal/buffer_spec.lua

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -594,18 +594,36 @@ describe('terminal input', function()
594594
'<S-End>',
595595
'<C-End>',
596596
'<End>',
597-
'<C-LeftMouse>',
598-
'<C-LeftRelease>',
599-
'<2-LeftMouse>',
600-
'<2-LeftRelease>',
601-
'<S-RightMouse>',
602-
'<S-RightRelease>',
603-
'<2-RightMouse>',
604-
'<2-RightRelease>',
605-
'<M-MiddleMouse>',
606-
'<M-MiddleRelease>',
607-
'<2-MiddleMouse>',
608-
'<2-MiddleRelease>',
597+
'<C-LeftMouse><0,0>',
598+
'<C-LeftDrag><0,1>',
599+
'<C-LeftRelease><0,1>',
600+
'<2-LeftMouse><0,1>',
601+
'<2-LeftDrag><0,0>',
602+
'<2-LeftRelease><0,0>',
603+
'<M-MiddleMouse><0,0>',
604+
'<M-MiddleDrag><0,1>',
605+
'<M-MiddleRelease><0,1>',
606+
'<2-MiddleMouse><0,1>',
607+
'<2-MiddleDrag><0,0>',
608+
'<2-MiddleRelease><0,0>',
609+
'<S-RightMouse><0,0>',
610+
'<S-RightDrag><0,1>',
611+
'<S-RightRelease><0,1>',
612+
'<2-RightMouse><0,1>',
613+
'<2-RightDrag><0,0>',
614+
'<2-RightRelease><0,0>',
615+
'<S-X1Mouse><0,0>',
616+
'<S-X1Drag><0,1>',
617+
'<S-X1Release><0,1>',
618+
'<2-X1Mouse><0,1>',
619+
'<2-X1Drag><0,0>',
620+
'<2-X1Release><0,0>',
621+
'<S-X2Mouse><0,0>',
622+
'<S-X2Drag><0,1>',
623+
'<S-X2Release><0,1>',
624+
'<2-X2Mouse><0,1>',
625+
'<2-X2Drag><0,0>',
626+
'<2-X2Release><0,0>',
609627
'<S-ScrollWheelUp>',
610628
'<S-ScrollWheelDown>',
611629
'<ScrollWheelUp>',
@@ -622,7 +640,7 @@ describe('terminal input', function()
622640
{5:[No Name] 0,0-1 All}|
623641
%s^ {MATCH: *}|
624642
{3:-- TERMINAL --} |
625-
]]):format(key))
643+
]]):format(key:gsub('<%d+,%d+>$', '')))
626644
end
627645
end)
628646

test/unit/vterm_spec.lua

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2079,6 +2079,18 @@ putglyph 1f3f4,200d,2620,fe0f 2 0,4]])
20792079
mousebtn('u', 1, vt)
20802080
expect_output('\x1b[<0;301;301m')
20812081

2082+
-- Button 8 on SGR extended encoding mode
2083+
mousebtn('d', 8, vt)
2084+
expect_output('\x1b[<128;301;301M')
2085+
mousebtn('u', 8, vt)
2086+
expect_output('\x1b[<128;301;301m')
2087+
2088+
-- Button 9 on SGR extended encoding mode
2089+
mousebtn('d', 9, vt)
2090+
expect_output('\x1b[<129;301;301M')
2091+
mousebtn('u', 9, vt)
2092+
expect_output('\x1b[<129;301;301m')
2093+
20822094
-- DECRQM on SGR extended encoding mode
20832095
push('\x1b[?1005$p', vt)
20842096
expect_output('\x1b[?1005;2$y')
@@ -2094,6 +2106,18 @@ putglyph 1f3f4,200d,2620,fe0f 2 0,4]])
20942106
mousebtn('u', 1, vt)
20952107
expect_output('\x1b[3;301;301M')
20962108

2109+
-- Button 8 on rxvt extended encoding mode
2110+
mousebtn('d', 8, vt)
2111+
expect_output('\x1b[128;301;301M')
2112+
mousebtn('u', 8, vt)
2113+
expect_output('\x1b[3;301;301M')
2114+
2115+
-- Button 9 on rxvt extended encoding mode
2116+
mousebtn('d', 9, vt)
2117+
expect_output('\x1b[129;301;301M')
2118+
mousebtn('u', 9, vt)
2119+
expect_output('\x1b[3;301;301M')
2120+
20972121
-- DECRQM on rxvt extended encoding mode
20982122
push('\x1b[?1005$p', vt)
20992123
expect_output('\x1b[?1005;2$y')

0 commit comments

Comments
 (0)