feat(tui): recognize sidescroll events (#19992)

Ref https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Other-buttons
This works in xterm and kitty.
CSI < 66 ; x ; y M sequence is for ScrollWheelLeft.
CSI < 67 ; x ; y M sequence is for ScrollWheelRight.
This commit is contained in:
zeertzjq 2022-08-30 10:55:00 +08:00 committed by GitHub
parent 7f20d61e00
commit 568737d5b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 206 additions and 2 deletions

View File

@ -398,6 +398,14 @@ static void forward_mouse_event(TermInput *input, TermKeyKey *key)
button = last_pressed_button; button = last_pressed_button;
} }
if (ev == TERMKEY_MOUSE_UNKNOWN && !(key->code.mouse[0] & 0x20)) {
int code = key->code.mouse[0] & ~0x3c;
if (code == 66 || code == 67) {
ev = TERMKEY_MOUSE_PRESS;
button = code - 60;
}
}
if (button == 0 || (ev != TERMKEY_MOUSE_PRESS && ev != TERMKEY_MOUSE_DRAG if (button == 0 || (ev != TERMKEY_MOUSE_PRESS && ev != TERMKEY_MOUSE_DRAG
&& ev != TERMKEY_MOUSE_RELEASE)) { && ev != TERMKEY_MOUSE_RELEASE)) {
return; return;
@ -431,8 +439,11 @@ static void forward_mouse_event(TermInput *input, TermKeyKey *key)
if (button == 4) { if (button == 4) {
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "ScrollWheelUp"); len += (size_t)snprintf(buf + len, sizeof(buf) - len, "ScrollWheelUp");
} else if (button == 5) { } else if (button == 5) {
len += (size_t)snprintf(buf + len, sizeof(buf) - len, len += (size_t)snprintf(buf + len, sizeof(buf) - len, "ScrollWheelDown");
"ScrollWheelDown"); } else if (button == 6) {
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "ScrollWheelLeft");
} else if (button == 7) {
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "ScrollWheelRight");
} else { } else {
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "Mouse"); len += (size_t)snprintf(buf + len, sizeof(buf) - len, "Mouse");
last_pressed_button = button; last_pressed_button = button;

View File

@ -297,6 +297,199 @@ describe('TUI', function()
]], attrs) ]], attrs)
end) end)
it('accepts mouse wheel events #19992', function()
child_session:request('nvim_command', [[
set number nostartofline nowrap mousescroll=hor:1,ver:1
call setline(1, repeat([join(range(10), '----')], 10))
vsplit
]])
screen:expect([[
{11: 1 }{1:0}----1----2----3----4│{11: 1 }0----1----2----3----|
{11: 2 }0----1----2----3----4│{11: 2 }0----1----2----3----|
{11: 3 }0----1----2----3----4│{11: 3 }0----1----2----3----|
{11: 4 }0----1----2----3----4│{11: 4 }0----1----2----3----|
{5:[No Name] [+] }{1:[No Name] [+] }|
|
{3:-- TERMINAL --} |
]])
-- <ScrollWheelDown> in active window
feed_data('\027[<65;8;1M')
screen:expect([[
{11: 2 }{1:0}----1----2----3----4│{11: 1 }0----1----2----3----|
{11: 3 }0----1----2----3----4│{11: 2 }0----1----2----3----|
{11: 4 }0----1----2----3----4│{11: 3 }0----1----2----3----|
{11: 5 }0----1----2----3----4│{11: 4 }0----1----2----3----|
{5:[No Name] [+] }{1:[No Name] [+] }|
|
{3:-- TERMINAL --} |
]])
-- <ScrollWheelDown> in inactive window
feed_data('\027[<65;48;1M')
screen:expect([[
{11: 2 }{1:0}----1----2----3----4│{11: 2 }0----1----2----3----|
{11: 3 }0----1----2----3----4│{11: 3 }0----1----2----3----|
{11: 4 }0----1----2----3----4│{11: 4 }0----1----2----3----|
{11: 5 }0----1----2----3----4│{11: 5 }0----1----2----3----|
{5:[No Name] [+] }{1:[No Name] [+] }|
|
{3:-- TERMINAL --} |
]])
-- <ScrollWheelRight> in active window
feed_data('\027[<67;8;1M')
screen:expect([[
{11: 2 }{1:-}---1----2----3----4-│{11: 2 }0----1----2----3----|
{11: 3 }----1----2----3----4-│{11: 3 }0----1----2----3----|
{11: 4 }----1----2----3----4-│{11: 4 }0----1----2----3----|
{11: 5 }----1----2----3----4-│{11: 5 }0----1----2----3----|
{5:[No Name] [+] }{1:[No Name] [+] }|
|
{3:-- TERMINAL --} |
]])
-- <ScrollWheelRight> in inactive window
feed_data('\027[<67;48;1M')
screen:expect([[
{11: 2 }{1:-}---1----2----3----4-│{11: 2 }----1----2----3----4|
{11: 3 }----1----2----3----4-│{11: 3 }----1----2----3----4|
{11: 4 }----1----2----3----4-│{11: 4 }----1----2----3----4|
{11: 5 }----1----2----3----4-│{11: 5 }----1----2----3----4|
{5:[No Name] [+] }{1:[No Name] [+] }|
|
{3:-- TERMINAL --} |
]])
-- <S-ScrollWheelDown> in active window
feed_data('\027[<69;8;1M')
screen:expect([[
{11: 5 }{1:-}---1----2----3----4-│{11: 2 }----1----2----3----4|
{11: 6 }----1----2----3----4-│{11: 3 }----1----2----3----4|
{11: 7 }----1----2----3----4-│{11: 4 }----1----2----3----4|
{11: 8 }----1----2----3----4-│{11: 5 }----1----2----3----4|
{5:[No Name] [+] }{1:[No Name] [+] }|
|
{3:-- TERMINAL --} |
]])
-- <S-ScrollWheelDown> in inactive window
feed_data('\027[<69;48;1M')
screen:expect([[
{11: 5 }{1:-}---1----2----3----4-│{11: 5 }----1----2----3----4|
{11: 6 }----1----2----3----4-│{11: 6 }----1----2----3----4|
{11: 7 }----1----2----3----4-│{11: 7 }----1----2----3----4|
{11: 8 }----1----2----3----4-│{11: 8 }----1----2----3----4|
{5:[No Name] [+] }{1:[No Name] [+] }|
|
{3:-- TERMINAL --} |
]])
-- <S-ScrollWheelRight> in active window
feed_data('\027[<71;8;1M')
screen:expect([[
{11: 5 }{1:-}---6----7----8----9 │{11: 5 }----1----2----3----4|
{11: 6 }----6----7----8----9 │{11: 6 }----1----2----3----4|
{11: 7 }----6----7----8----9 │{11: 7 }----1----2----3----4|
{11: 8 }----6----7----8----9 │{11: 8 }----1----2----3----4|
{5:[No Name] [+] }{1:[No Name] [+] }|
|
{3:-- TERMINAL --} |
]])
-- <S-ScrollWheelRight> in inactive window
feed_data('\027[<71;48;1M')
screen:expect([[
{11: 5 }{1:-}---6----7----8----9 │{11: 5 }5----6----7----8----|
{11: 6 }----6----7----8----9 │{11: 6 }5----6----7----8----|
{11: 7 }----6----7----8----9 │{11: 7 }5----6----7----8----|
{11: 8 }----6----7----8----9 │{11: 8 }5----6----7----8----|
{5:[No Name] [+] }{1:[No Name] [+] }|
|
{3:-- TERMINAL --} |
]])
-- <ScrollWheelUp> in active window
feed_data('\027[<64;8;1M')
screen:expect([[
{11: 4 }----6----7----8----9 │{11: 5 }5----6----7----8----|
{11: 5 }{1:-}---6----7----8----9 │{11: 6 }5----6----7----8----|
{11: 6 }----6----7----8----9 │{11: 7 }5----6----7----8----|
{11: 7 }----6----7----8----9 │{11: 8 }5----6----7----8----|
{5:[No Name] [+] }{1:[No Name] [+] }|
|
{3:-- TERMINAL --} |
]])
-- <ScrollWheelUp> in inactive window
feed_data('\027[<64;48;1M')
screen:expect([[
{11: 4 }----6----7----8----9 │{11: 4 }5----6----7----8----|
{11: 5 }{1:-}---6----7----8----9 │{11: 5 }5----6----7----8----|
{11: 6 }----6----7----8----9 │{11: 6 }5----6----7----8----|
{11: 7 }----6----7----8----9 │{11: 7 }5----6----7----8----|
{5:[No Name] [+] }{1:[No Name] [+] }|
|
{3:-- TERMINAL --} |
]])
-- <ScrollWheelLeft> in active window
feed_data('\027[<66;8;1M')
screen:expect([[
{11: 4 }5----6----7----8----9│{11: 4 }5----6----7----8----|
{11: 5 }5{1:-}---6----7----8----9│{11: 5 }5----6----7----8----|
{11: 6 }5----6----7----8----9│{11: 6 }5----6----7----8----|
{11: 7 }5----6----7----8----9│{11: 7 }5----6----7----8----|
{5:[No Name] [+] }{1:[No Name] [+] }|
|
{3:-- TERMINAL --} |
]])
-- <ScrollWheelLeft> in inactive window
feed_data('\027[<66;48;1M')
screen:expect([[
{11: 4 }5----6----7----8----9│{11: 4 }-5----6----7----8---|
{11: 5 }5{1:-}---6----7----8----9│{11: 5 }-5----6----7----8---|
{11: 6 }5----6----7----8----9│{11: 6 }-5----6----7----8---|
{11: 7 }5----6----7----8----9│{11: 7 }-5----6----7----8---|
{5:[No Name] [+] }{1:[No Name] [+] }|
|
{3:-- TERMINAL --} |
]])
-- <S-ScrollWheelUp> in active window
feed_data('\027[<68;8;1M')
screen:expect([[
{11: 1 }5----6----7----8----9│{11: 4 }-5----6----7----8---|
{11: 2 }5----6----7----8----9│{11: 5 }-5----6----7----8---|
{11: 3 }5----6----7----8----9│{11: 6 }-5----6----7----8---|
{11: 4 }5{1:-}---6----7----8----9│{11: 7 }-5----6----7----8---|
{5:[No Name] [+] }{1:[No Name] [+] }|
|
{3:-- TERMINAL --} |
]])
-- <S-ScrollWheelUp> in inactive window
feed_data('\027[<68;48;1M')
screen:expect([[
{11: 1 }5----6----7----8----9│{11: 1 }-5----6----7----8---|
{11: 2 }5----6----7----8----9│{11: 2 }-5----6----7----8---|
{11: 3 }5----6----7----8----9│{11: 3 }-5----6----7----8---|
{11: 4 }5{1:-}---6----7----8----9│{11: 4 }-5----6----7----8---|
{5:[No Name] [+] }{1:[No Name] [+] }|
|
{3:-- TERMINAL --} |
]])
-- <S-ScrollWheelLeft> in active window
feed_data('\027[<70;8;1M')
screen:expect([[
{11: 1 }0----1----2----3----4│{11: 1 }-5----6----7----8---|
{11: 2 }0----1----2----3----4│{11: 2 }-5----6----7----8---|
{11: 3 }0----1----2----3----4│{11: 3 }-5----6----7----8---|
{11: 4 }0----1----2----3----{1:4}│{11: 4 }-5----6----7----8---|
{5:[No Name] [+] }{1:[No Name] [+] }|
|
{3:-- TERMINAL --} |
]])
-- <S-ScrollWheelLeft> in inactive window
feed_data('\027[<70;48;1M')
screen:expect([[
{11: 1 }0----1----2----3----4│{11: 1 }0----1----2----3----|
{11: 2 }0----1----2----3----4│{11: 2 }0----1----2----3----|
{11: 3 }0----1----2----3----4│{11: 3 }0----1----2----3----|
{11: 4 }0----1----2----3----{1:4}│{11: 4 }0----1----2----3----|
{5:[No Name] [+] }{1:[No Name] [+] }|
|
{3:-- TERMINAL --} |
]])
end)
it('accepts keypad keys from kitty keyboard protocol #19180', function() it('accepts keypad keys from kitty keyboard protocol #19180', function()
feed_data('i') feed_data('i')
feed_data(funcs.nr2char(57399)) -- KP_0 feed_data(funcs.nr2char(57399)) -- KP_0