From eb77122823f35c2296cc332aec7f4380db6dafe7 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 17 Jun 2022 07:28:16 +0800 Subject: [PATCH 1/2] fix(input): do no reinterpret mouse keys with ALT modifiers Remove check for MOD_MASK_META as it is for * *c_Esc* Note: If your key is hard to hit on your keyboard, train yourself to use CTRL-[. *c_META* *c_ALT* - ALT (|META|) acts like if the chord is not mapped. + ALT (|META|) may act like if the chord is not mapped. For example acts like x if does not have a command-line mode mapping. *c_CTRL-C* diff --git a/runtime/doc/insert.txt b/runtime/doc/insert.txt index a16d88b4e9..27f1fed751 100644 --- a/runtime/doc/insert.txt +++ b/runtime/doc/insert.txt @@ -39,7 +39,7 @@ char action ~ abbreviation. Note: If your key is hard to hit, try CTRL-[ instead. *i_META* *i_ALT* - ALT (|META|) acts like if the chord is not mapped. + ALT (|META|) may act like if the chord is not mapped. For example acts like x if does not have an insert-mode mapping. *i_CTRL-C* diff --git a/runtime/doc/intro.txt b/runtime/doc/intro.txt index 51e823b75f..92ba7b4079 100644 --- a/runtime/doc/intro.txt +++ b/runtime/doc/intro.txt @@ -383,8 +383,8 @@ Note: , ..., and will not work. - Nvim supports mapping multibyte chars with modifiers such as ``. Which combinations actually work depends on the the UI or host terminal. -- When a key is pressed using a meta or alt modifier and no mapping exists - for that keypress, Nvim behaves as though was pressed before the key. +- When a key is pressed using a meta or alt modifier and no mapping exists for + that keypress, Nvim may behave as though was pressed before the key. - It is possible to notate combined modifiers (e.g. for CTRL-ALT-T), but your terminal must encode the input for that to work. |tui-input| diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt index a74149d050..27c953a460 100644 --- a/runtime/doc/vim_diff.txt +++ b/runtime/doc/vim_diff.txt @@ -250,7 +250,7 @@ Input/Mappings: , , , , , , , , etc. Case-sensitive: and are two different keycodes. - ALT behaves like if not mapped. |i_ALT| |v_ALT| |c_ALT| + ALT may behave like if not mapped. |i_ALT| |v_ALT| |c_ALT| Normal commands: |gO| shows a filetype-defined "outline" of the current buffer. diff --git a/runtime/doc/visual.txt b/runtime/doc/visual.txt index 905ae49887..5383ea4f72 100644 --- a/runtime/doc/visual.txt +++ b/runtime/doc/visual.txt @@ -161,9 +161,10 @@ If you want to highlight exactly the same area as the last time, you can use *v_* In Visual mode: Stop Visual mode. *v_META* *v_ALT* - ALT (|META|) acts like if the chord is not mapped. + ALT (|META|) may act like if the chord is not mapped. For example acts like x if does not have a visual-mode mapping. + *v_CTRL-C* CTRL-C In Visual mode: Stop Visual mode. When insert mode is pending (the mode message shows diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 3e8591b2be..4a5841ca6e 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -30,6 +30,7 @@ #include "nvim/memline.h" #include "nvim/memory.h" #include "nvim/message.h" +#include "nvim/mouse.h" #include "nvim/move.h" #include "nvim/normal.h" #include "nvim/ops.h" @@ -1584,16 +1585,18 @@ int vgetc(void) vgetc_char = c; } - // If mappings are enabled (i.e., not Ctrl-v) and the user directly typed - // something with a meta- or alt- modifier that was not mapped, interpret - // as x rather than as an unbound meta keypress. #8213 - // In Terminal mode, however, this is not desirable. #16220 - if (!no_mapping && KeyTyped && !(State & MODE_TERMINAL) - && (mod_mask == MOD_MASK_ALT || mod_mask == MOD_MASK_META)) { + // If mappings are enabled (i.e., not i_CTRL-V) and the user directly typed something with + // MOD_MASK_ALT ( as x rather + // than as an unbound keypress. #8213 + // In Terminal mode, however, this is not desirable. #16202 #16220 + // Also do not do this for mouse keys, as terminals encode mouse events as CSI sequences, and + // MOD_MASK_ALT has a meaning even for unmapped mouse keys. + if (!no_mapping && KeyTyped && mod_mask == MOD_MASK_ALT && !(State & MODE_TERMINAL) + && !is_mouse_key(c)) { mod_mask = 0; int len = ins_char_typebuf(c, 0); (void)ins_char_typebuf(ESC, 0); - ungetchars(len + 3); // The ALT/META modifier takes three more bytes + ungetchars(len + 3); // K_SPECIAL KS_MODIFIER MOD_MASK_ALT takes 3 more bytes continue; } diff --git a/test/functional/editor/meta_key_spec.lua b/test/functional/editor/meta_key_spec.lua index 23964ca10f..825b20138a 100644 --- a/test/functional/editor/meta_key_spec.lua +++ b/test/functional/editor/meta_key_spec.lua @@ -91,7 +91,7 @@ describe('meta-keys #8226 #13042', function() command('tnoremap alt-j') feed('i xxx ') eq('meta-l xxx alt-j', exec_lua([[return _G.input_data]])) - -- Unmapped ALT-chord is sent to terminal as-is. #16220 + -- Unmapped ALT-chord is sent to terminal as-is. #16202 #16220 exec_lua([[_G.input_data = '']]) command('tunmap ') feed('') diff --git a/test/functional/ui/statusline_spec.lua b/test/functional/ui/statusline_spec.lua index 760760150c..69a2d2f4ed 100644 --- a/test/functional/ui/statusline_spec.lua +++ b/test/functional/ui/statusline_spec.lua @@ -21,11 +21,9 @@ describe('statusline clicks', function() command('set laststatus=2 mousemodel=extend') exec([=[ function! MyClickFunc(minwid, clicks, button, mods) - let mods = trim(a:mods) - if mods ==# '' - let g:testvar = printf("%d %d %s", a:minwid, a:clicks, a:button) - else - let g:testvar = printf("%d %d %s %s", a:minwid, a:clicks, a:button, mods) + let g:testvar = printf("%d %d %s", a:minwid, a:clicks, a:button) + if a:mods !=# ' ' + let g:testvar ..= '(' .. a:mods .. ')' endif endfunction ]=]) @@ -35,8 +33,20 @@ describe('statusline clicks', function() meths.set_option('statusline', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T') meths.input_mouse('left', 'press', '', 0, 6, 17) eq('0 1 l', eval("g:testvar")) + meths.input_mouse('left', 'press', '', 0, 6, 17) + eq('0 2 l', eval("g:testvar")) + meths.input_mouse('left', 'press', '', 0, 6, 17) + eq('0 3 l', eval("g:testvar")) + meths.input_mouse('left', 'press', '', 0, 6, 17) + eq('0 4 l', eval("g:testvar")) meths.input_mouse('right', 'press', '', 0, 6, 17) eq('0 1 r', eval("g:testvar")) + meths.input_mouse('right', 'press', '', 0, 6, 17) + eq('0 2 r', eval("g:testvar")) + meths.input_mouse('right', 'press', '', 0, 6, 17) + eq('0 3 r', eval("g:testvar")) + meths.input_mouse('right', 'press', '', 0, 6, 17) + eq('0 4 r', eval("g:testvar")) end) it('works for winbar', function() @@ -101,10 +111,30 @@ describe('statusline clicks', function() it("works with modifiers #18994", function() meths.set_option('statusline', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T') - meths.input_mouse('right', 'press', 's', 0, 6, 17) - eq('0 1 r s', eval("g:testvar")) - meths.input_mouse('left', 'press', 's', 0, 6, 17) - eq('0 1 l s', eval("g:testvar")) + -- Note: alternate between left and right mouse buttons to avoid triggering multiclicks + meths.input_mouse('left', 'press', 'S', 0, 6, 17) + eq('0 1 l(s )', eval("g:testvar")) + meths.input_mouse('right', 'press', 'S', 0, 6, 17) + eq('0 1 r(s )', eval("g:testvar")) + meths.input_mouse('left', 'press', 'A', 0, 6, 17) + eq('0 1 l( a )', eval("g:testvar")) + meths.input_mouse('right', 'press', 'A', 0, 6, 17) + eq('0 1 r( a )', eval("g:testvar")) + meths.input_mouse('left', 'press', 'AS', 0, 6, 17) + eq('0 1 l(s a )', eval("g:testvar")) + meths.input_mouse('right', 'press', 'AS', 0, 6, 17) + eq('0 1 r(s a )', eval("g:testvar")) + meths.input_mouse('left', 'press', 'T', 0, 6, 17) + eq('0 1 l( m)', eval("g:testvar")) + meths.input_mouse('right', 'press', 'T', 0, 6, 17) + eq('0 1 r( m)', eval("g:testvar")) + meths.input_mouse('left', 'press', 'TS', 0, 6, 17) + eq('0 1 l(s m)', eval("g:testvar")) + meths.input_mouse('right', 'press', 'TS', 0, 6, 17) + eq('0 1 r(s m)', eval("g:testvar")) + meths.input_mouse('left', 'press', 'C', 0, 6, 17) + eq('0 1 l( c )', eval("g:testvar")) + -- is for tag jump end) it("works for global statusline with vertical splits #19186", function() From 0cc41a61d1ac504bae4975021b95ce133268ce1a Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 25 Jul 2022 08:36:48 +0800 Subject: [PATCH 2/2] test: improve some input tests --- test/functional/terminal/tui_spec.lua | 7 +++++-- test/functional/ui/mouse_spec.lua | 12 +++--------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index dd88379344..bcd7ae50c8 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -436,8 +436,11 @@ describe('TUI', function() | {3:-- TERMINAL --} | ]]) - feed_data(':tab split\r:tabnew\r') - feed_data(':highlight Tabline ctermbg=NONE ctermfg=NONE cterm=underline\r') + child_session:request('nvim_command', [[ + tab split + tabnew + highlight Tabline ctermbg=NONE ctermfg=NONE cterm=underline + ]]) local attrs = screen:get_default_attr_ids() attrs[11] = {underline = true} screen:expect([[ diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua index 7305bd589b..e389b7ab89 100644 --- a/test/functional/ui/mouse_spec.lua +++ b/test/functional/ui/mouse_spec.lua @@ -1572,23 +1572,17 @@ describe('ui/mouse/input', function() meths.input_mouse('left', 'release', '', 0, 0, 0) end) - it('scroll keys are not translated into multiclicks #6211 #6989', function() + it('scroll keys are not translated into multiclicks and can be mapped #6211 #6989', function() meths.set_var('mouse_up', 0) meths.set_var('mouse_up2', 0) - meths.set_var('mouse_up3', 0) - meths.set_var('mouse_up4', 0) command('nnoremap let g:mouse_up += 1') command('nnoremap <2-ScrollWheelUp> let g:mouse_up2 += 1') - command('nnoremap <3-ScrollWheelUp> let g:mouse_up3 += 1') - command('nnoremap <4-ScrollWheelUp> let g:mouse_up4 += 1') - meths.input_mouse('wheel', 'up', '', 0, 0, 0) - meths.input_mouse('wheel', 'up', '', 0, 0, 0) + feed('<0,0>') + feed('<0,0>') meths.input_mouse('wheel', 'up', '', 0, 0, 0) meths.input_mouse('wheel', 'up', '', 0, 0, 0) eq(4, meths.get_var('mouse_up')) eq(0, meths.get_var('mouse_up2')) - eq(0, meths.get_var('mouse_up3')) - eq(0, meths.get_var('mouse_up4')) end) it('feeding does not use uninitialized memory #19480', function()