From 000129201c54d4ba391f7473d0c183f000246c3e Mon Sep 17 00:00:00 2001 From: errael Date: Thu, 7 Nov 2024 00:21:28 -0800 Subject: [PATCH] perf(mouse): only generate for a new cell positon (#31103) Problem: Can receive dozens of events for same cell position. #30965 Solution: Leverage check_multiclick() to detect if cell position is unchanged. --- src/nvim/os/input.c | 54 ++++++++++++++++++++----------- test/functional/ui/mouse_spec.lua | 24 +++++++++++--- 2 files changed, 54 insertions(+), 24 deletions(-) diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index 7c5293a8b8..f77a25768d 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -290,8 +290,9 @@ size_t input_enqueue(String keys) = trans_special(&ptr, (size_t)(end - ptr), (char *)buf, FSK_KEYCODE, true, NULL); if (new_size) { - new_size = handle_mouse_event(&ptr, buf, new_size); - input_enqueue_raw((char *)buf, new_size); + if ((new_size = handle_mouse_event(&ptr, buf, new_size))) { + input_enqueue_raw((char *)buf, new_size); + } continue; } @@ -326,7 +327,7 @@ size_t input_enqueue(String keys) return rv; } -static uint8_t check_multiclick(int code, int grid, int row, int col) +static uint8_t check_multiclick(int code, int grid, int row, int col, bool *skip_event) { static int orig_num_clicks = 0; static int orig_mouse_code = 0; @@ -335,24 +336,29 @@ static uint8_t check_multiclick(int code, int grid, int row, int col) static int orig_mouse_row = 0; static uint64_t orig_mouse_time = 0; // time of previous mouse click - if ((code >= KE_MOUSEDOWN && code <= KE_MOUSERIGHT) || code == KE_MOUSEMOVE) { + if (code >= KE_MOUSEDOWN && code <= KE_MOUSERIGHT) { return 0; } - // For click events the number of clicks is updated. - if (code == KE_LEFTMOUSE || code == KE_RIGHTMOUSE || code == KE_MIDDLEMOUSE - || code == KE_X1MOUSE || code == KE_X2MOUSE) { + bool no_move = orig_mouse_grid == grid && orig_mouse_col == col && orig_mouse_row == row; + + if (code == KE_MOUSEMOVE) { + if (no_move) { + *skip_event = true; + return 0; + } + } else if (code == KE_LEFTMOUSE || code == KE_RIGHTMOUSE || code == KE_MIDDLEMOUSE + || code == KE_X1MOUSE || code == KE_X2MOUSE) { + // For click events the number of clicks is updated. uint64_t mouse_time = os_hrtime(); // time of current mouse click (ns) // compute the time elapsed since the previous mouse click and // convert p_mouse from ms to ns uint64_t timediff = mouse_time - orig_mouse_time; uint64_t mouset = (uint64_t)p_mouset * 1000000; if (code == orig_mouse_code + && no_move && timediff < mouset - && orig_num_clicks != 4 - && orig_mouse_grid == grid - && orig_mouse_col == col - && orig_mouse_row == row) { + && orig_num_clicks != 4) { orig_num_clicks++; } else { orig_num_clicks = 1; @@ -367,12 +373,14 @@ static uint8_t check_multiclick(int code, int grid, int row, int col) orig_mouse_row = row; uint8_t modifiers = 0; - if (orig_num_clicks == 2) { - modifiers |= MOD_MASK_2CLICK; - } else if (orig_num_clicks == 3) { - modifiers |= MOD_MASK_3CLICK; - } else if (orig_num_clicks == 4) { - modifiers |= MOD_MASK_4CLICK; + if (code != KE_MOUSEMOVE) { + if (orig_num_clicks == 2) { + modifiers |= MOD_MASK_2CLICK; + } else if (orig_num_clicks == 3) { + modifiers |= MOD_MASK_3CLICK; + } else if (orig_num_clicks == 4) { + modifiers |= MOD_MASK_4CLICK; + } } return modifiers; } @@ -421,8 +429,12 @@ static unsigned handle_mouse_event(const char **ptr, uint8_t *buf, unsigned bufs *ptr += advance; } + bool skip_event = false; uint8_t modifiers = check_multiclick(mouse_code, mouse_grid, - mouse_row, mouse_col); + mouse_row, mouse_col, &skip_event); + if (skip_event) { + return 0; + } if (modifiers) { if (buf[1] != KS_MODIFIER) { @@ -443,7 +455,11 @@ static unsigned handle_mouse_event(const char **ptr, uint8_t *buf, unsigned bufs void input_enqueue_mouse(int code, uint8_t modifier, int grid, int row, int col) { - modifier |= check_multiclick(code, grid, row, col); + bool skip_event = false; + modifier |= check_multiclick(code, grid, row, col, &skip_event); + if (skip_event) { + return; + } uint8_t buf[7]; uint8_t *p = buf; if (modifier) { diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua index bc18680749..09aa3f17b3 100644 --- a/test/functional/ui/mouse_spec.lua +++ b/test/functional/ui/mouse_spec.lua @@ -1908,19 +1908,33 @@ describe('ui/mouse/input', function() eq(0, api.nvim_get_var('mouse_up2')) end) - it(' is not translated into multiclicks and can be mapped', function() + it(' to different locations can be mapped', function() api.nvim_set_var('mouse_move', 0) api.nvim_set_var('mouse_move2', 0) command('nnoremap let g:mouse_move += 1') command('nnoremap <2-MouseMove> let g:mouse_move2 += 1') - feed('<0,0>') - feed('<0,0>') - api.nvim_input_mouse('move', '', '', 0, 0, 0) - api.nvim_input_mouse('move', '', '', 0, 0, 0) + feed('<1,0>') + feed('<2,0>') + api.nvim_input_mouse('move', '', '', 0, 0, 3) + api.nvim_input_mouse('move', '', '', 0, 0, 4) eq(4, api.nvim_get_var('mouse_move')) eq(0, api.nvim_get_var('mouse_move2')) end) + it(' to same location does not generate events #31103', function() + api.nvim_input_mouse('move', '', '', 0, 0, 3) + api.nvim_set_var('mouse_move', 0) + api.nvim_set_var('mouse_move2', 0) + command('nnoremap let g:mouse_move += 1') + command('nnoremap <2-MouseMove> let g:mouse_move2 += 1') + feed('<3,0>') + feed('<3,0>') + api.nvim_input_mouse('move', '', '', 0, 0, 3) + api.nvim_input_mouse('move', '', '', 0, 0, 3) + eq(0, api.nvim_get_var('mouse_move')) + eq(0, api.nvim_get_var('mouse_move2')) + end) + it('feeding in Normal mode does not use uninitialized memory #19480', function() feed('') n.poke_eventloop()