mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-04 01:34:25 +00:00 
			
		
		
		
	feat(terminal): forward X1 and X2 mouse events
Ref: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Other-buttons
This commit is contained in:
		@@ -792,17 +792,23 @@ static int terminal_execute(VimState *state, int key)
 | 
				
			|||||||
  case K_LEFTMOUSE:
 | 
					  case K_LEFTMOUSE:
 | 
				
			||||||
  case K_LEFTDRAG:
 | 
					  case K_LEFTDRAG:
 | 
				
			||||||
  case K_LEFTRELEASE:
 | 
					  case K_LEFTRELEASE:
 | 
				
			||||||
  case K_MOUSEMOVE:
 | 
					 | 
				
			||||||
  case K_MIDDLEMOUSE:
 | 
					  case K_MIDDLEMOUSE:
 | 
				
			||||||
  case K_MIDDLEDRAG:
 | 
					  case K_MIDDLEDRAG:
 | 
				
			||||||
  case K_MIDDLERELEASE:
 | 
					  case K_MIDDLERELEASE:
 | 
				
			||||||
  case K_RIGHTMOUSE:
 | 
					  case K_RIGHTMOUSE:
 | 
				
			||||||
  case K_RIGHTDRAG:
 | 
					  case K_RIGHTDRAG:
 | 
				
			||||||
  case K_RIGHTRELEASE:
 | 
					  case K_RIGHTRELEASE:
 | 
				
			||||||
 | 
					  case K_X1MOUSE:
 | 
				
			||||||
 | 
					  case K_X1DRAG:
 | 
				
			||||||
 | 
					  case K_X1RELEASE:
 | 
				
			||||||
 | 
					  case K_X2MOUSE:
 | 
				
			||||||
 | 
					  case K_X2DRAG:
 | 
				
			||||||
 | 
					  case K_X2RELEASE:
 | 
				
			||||||
  case K_MOUSEDOWN:
 | 
					  case K_MOUSEDOWN:
 | 
				
			||||||
  case K_MOUSEUP:
 | 
					  case K_MOUSEUP:
 | 
				
			||||||
  case K_MOUSELEFT:
 | 
					  case K_MOUSELEFT:
 | 
				
			||||||
  case K_MOUSERIGHT:
 | 
					  case K_MOUSERIGHT:
 | 
				
			||||||
 | 
					  case K_MOUSEMOVE:
 | 
				
			||||||
    if (send_mouse_event(s->term, key)) {
 | 
					    if (send_mouse_event(s->term, key)) {
 | 
				
			||||||
      return 0;
 | 
					      return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -1804,8 +1810,6 @@ static bool send_mouse_event(Terminal *term, int c)
 | 
				
			|||||||
      pressed = true; FALLTHROUGH;
 | 
					      pressed = true; FALLTHROUGH;
 | 
				
			||||||
    case K_LEFTRELEASE:
 | 
					    case K_LEFTRELEASE:
 | 
				
			||||||
      button = 1; break;
 | 
					      button = 1; break;
 | 
				
			||||||
    case K_MOUSEMOVE:
 | 
					 | 
				
			||||||
      button = 0; break;
 | 
					 | 
				
			||||||
    case K_MIDDLEDRAG:
 | 
					    case K_MIDDLEDRAG:
 | 
				
			||||||
    case K_MIDDLEMOUSE:
 | 
					    case K_MIDDLEMOUSE:
 | 
				
			||||||
      pressed = true; FALLTHROUGH;
 | 
					      pressed = true; FALLTHROUGH;
 | 
				
			||||||
@@ -1816,6 +1820,16 @@ static bool send_mouse_event(Terminal *term, int c)
 | 
				
			|||||||
      pressed = true; FALLTHROUGH;
 | 
					      pressed = true; FALLTHROUGH;
 | 
				
			||||||
    case K_RIGHTRELEASE:
 | 
					    case K_RIGHTRELEASE:
 | 
				
			||||||
      button = 3; break;
 | 
					      button = 3; break;
 | 
				
			||||||
 | 
					    case K_X1DRAG:
 | 
				
			||||||
 | 
					    case K_X1MOUSE:
 | 
				
			||||||
 | 
					      pressed = true; FALLTHROUGH;
 | 
				
			||||||
 | 
					    case K_X1RELEASE:
 | 
				
			||||||
 | 
					      button = 8; break;
 | 
				
			||||||
 | 
					    case K_X2DRAG:
 | 
				
			||||||
 | 
					    case K_X2MOUSE:
 | 
				
			||||||
 | 
					      pressed = true; FALLTHROUGH;
 | 
				
			||||||
 | 
					    case K_X2RELEASE:
 | 
				
			||||||
 | 
					      button = 9; break;
 | 
				
			||||||
    case K_MOUSEDOWN:
 | 
					    case K_MOUSEDOWN:
 | 
				
			||||||
      pressed = true; button = 4; break;
 | 
					      pressed = true; button = 4; break;
 | 
				
			||||||
    case K_MOUSEUP:
 | 
					    case K_MOUSEUP:
 | 
				
			||||||
@@ -1824,6 +1838,8 @@ static bool send_mouse_event(Terminal *term, int c)
 | 
				
			|||||||
      pressed = true; button = 7; break;
 | 
					      pressed = true; button = 7; break;
 | 
				
			||||||
    case K_MOUSERIGHT:
 | 
					    case K_MOUSERIGHT:
 | 
				
			||||||
      pressed = true; button = 6; break;
 | 
					      pressed = true; button = 6; break;
 | 
				
			||||||
 | 
					    case K_MOUSEMOVE:
 | 
				
			||||||
 | 
					      button = 0; break;
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,3 +1,4 @@
 | 
				
			|||||||
 | 
					#include "nvim/math.h"
 | 
				
			||||||
#include "nvim/tui/termkey/termkey.h"
 | 
					#include "nvim/tui/termkey/termkey.h"
 | 
				
			||||||
#include "nvim/vterm/mouse.h"
 | 
					#include "nvim/vterm/mouse.h"
 | 
				
			||||||
#include "nvim/vterm/vterm.h"
 | 
					#include "nvim/vterm/vterm.h"
 | 
				
			||||||
@@ -24,6 +25,9 @@ static void output_mouse(VTermState *state, int code, int pressed, int modifiers
 | 
				
			|||||||
      code = 3;
 | 
					      code = 3;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (code & 0x80) {
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "M%c%c%c",
 | 
					    vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "M%c%c%c",
 | 
				
			||||||
                                   (code | modifiers) + 0x20, col + 0x21, row + 0x21);
 | 
					                                   (code | modifiers) + 0x20, col + 0x21, row + 0x21);
 | 
				
			||||||
    break;
 | 
					    break;
 | 
				
			||||||
@@ -74,11 +78,16 @@ void vterm_mouse_move(VTerm *vt, int row, int col, VTermModifier mod)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  if ((state->mouse_flags & MOUSE_WANT_DRAG && state->mouse_buttons)
 | 
					  if ((state->mouse_flags & MOUSE_WANT_DRAG && state->mouse_buttons)
 | 
				
			||||||
      || (state->mouse_flags & MOUSE_WANT_MOVE)) {
 | 
					      || (state->mouse_flags & MOUSE_WANT_MOVE)) {
 | 
				
			||||||
    int button = state->mouse_buttons & 0x01 ? 1
 | 
					    if (state->mouse_buttons) {
 | 
				
			||||||
                                             : state->mouse_buttons & 0x02 ? 2
 | 
					      int button = xctz((uint64_t)state->mouse_buttons) + 1;
 | 
				
			||||||
                                                                           : state->mouse_buttons &
 | 
					      if (button < 4) {
 | 
				
			||||||
                 0x04 ? 3 : 4;
 | 
					        output_mouse(state, button - 1 + 0x20, 1, (int)mod, col, row);
 | 
				
			||||||
    output_mouse(state, button - 1 + 0x20, 1, (int)mod, col, row);
 | 
					      } else if (button >= 8 && button < 12) {
 | 
				
			||||||
 | 
					        output_mouse(state, button - 8 + 0x80 + 0x20, 1, (int)mod, col, row);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      output_mouse(state, 3 + 0x20, 1, (int)mod, col, row);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -88,7 +97,7 @@ void vterm_mouse_button(VTerm *vt, int button, bool pressed, VTermModifier mod)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  int old_buttons = state->mouse_buttons;
 | 
					  int old_buttons = state->mouse_buttons;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (button > 0 && button <= 3) {
 | 
					  if ((button > 0 && button <= 3) || (button >= 8 && button <= 11)) {
 | 
				
			||||||
    if (pressed) {
 | 
					    if (pressed) {
 | 
				
			||||||
      state->mouse_buttons |= (1 << (button - 1));
 | 
					      state->mouse_buttons |= (1 << (button - 1));
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
@@ -96,8 +105,8 @@ void vterm_mouse_button(VTerm *vt, int button, bool pressed, VTermModifier mod)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Most of the time we don't get button releases from 4/5
 | 
					  // Most of the time we don't get button releases from 4/5/6/7
 | 
				
			||||||
  if (state->mouse_buttons == old_buttons && button < 4) {
 | 
					  if (state->mouse_buttons == old_buttons && (button < 4 || button > 7)) {
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -109,5 +118,7 @@ void vterm_mouse_button(VTerm *vt, int button, bool pressed, VTermModifier mod)
 | 
				
			|||||||
    output_mouse(state, button - 1, pressed, (int)mod, state->mouse_col, state->mouse_row);
 | 
					    output_mouse(state, button - 1, pressed, (int)mod, state->mouse_col, state->mouse_row);
 | 
				
			||||||
  } else if (button < 8) {
 | 
					  } else if (button < 8) {
 | 
				
			||||||
    output_mouse(state, button - 4 + 0x40, pressed, (int)mod, state->mouse_col, state->mouse_row);
 | 
					    output_mouse(state, button - 4 + 0x40, pressed, (int)mod, state->mouse_col, state->mouse_row);
 | 
				
			||||||
 | 
					  } else if (button < 12) {
 | 
				
			||||||
 | 
					    output_mouse(state, button - 8 + 0x80, pressed, (int)mod, state->mouse_col, state->mouse_row);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -594,18 +594,36 @@ describe('terminal input', function()
 | 
				
			|||||||
      '<S-End>',
 | 
					      '<S-End>',
 | 
				
			||||||
      '<C-End>',
 | 
					      '<C-End>',
 | 
				
			||||||
      '<End>',
 | 
					      '<End>',
 | 
				
			||||||
      '<C-LeftMouse>',
 | 
					      '<C-LeftMouse><0,0>',
 | 
				
			||||||
      '<C-LeftRelease>',
 | 
					      '<C-LeftDrag><0,1>',
 | 
				
			||||||
      '<2-LeftMouse>',
 | 
					      '<C-LeftRelease><0,1>',
 | 
				
			||||||
      '<2-LeftRelease>',
 | 
					      '<2-LeftMouse><0,1>',
 | 
				
			||||||
      '<S-RightMouse>',
 | 
					      '<2-LeftDrag><0,0>',
 | 
				
			||||||
      '<S-RightRelease>',
 | 
					      '<2-LeftRelease><0,0>',
 | 
				
			||||||
      '<2-RightMouse>',
 | 
					      '<M-MiddleMouse><0,0>',
 | 
				
			||||||
      '<2-RightRelease>',
 | 
					      '<M-MiddleDrag><0,1>',
 | 
				
			||||||
      '<M-MiddleMouse>',
 | 
					      '<M-MiddleRelease><0,1>',
 | 
				
			||||||
      '<M-MiddleRelease>',
 | 
					      '<2-MiddleMouse><0,1>',
 | 
				
			||||||
      '<2-MiddleMouse>',
 | 
					      '<2-MiddleDrag><0,0>',
 | 
				
			||||||
      '<2-MiddleRelease>',
 | 
					      '<2-MiddleRelease><0,0>',
 | 
				
			||||||
 | 
					      '<S-RightMouse><0,0>',
 | 
				
			||||||
 | 
					      '<S-RightDrag><0,1>',
 | 
				
			||||||
 | 
					      '<S-RightRelease><0,1>',
 | 
				
			||||||
 | 
					      '<2-RightMouse><0,1>',
 | 
				
			||||||
 | 
					      '<2-RightDrag><0,0>',
 | 
				
			||||||
 | 
					      '<2-RightRelease><0,0>',
 | 
				
			||||||
 | 
					      '<S-X1Mouse><0,0>',
 | 
				
			||||||
 | 
					      '<S-X1Drag><0,1>',
 | 
				
			||||||
 | 
					      '<S-X1Release><0,1>',
 | 
				
			||||||
 | 
					      '<2-X1Mouse><0,1>',
 | 
				
			||||||
 | 
					      '<2-X1Drag><0,0>',
 | 
				
			||||||
 | 
					      '<2-X1Release><0,0>',
 | 
				
			||||||
 | 
					      '<S-X2Mouse><0,0>',
 | 
				
			||||||
 | 
					      '<S-X2Drag><0,1>',
 | 
				
			||||||
 | 
					      '<S-X2Release><0,1>',
 | 
				
			||||||
 | 
					      '<2-X2Mouse><0,1>',
 | 
				
			||||||
 | 
					      '<2-X2Drag><0,0>',
 | 
				
			||||||
 | 
					      '<2-X2Release><0,0>',
 | 
				
			||||||
      '<S-ScrollWheelUp>',
 | 
					      '<S-ScrollWheelUp>',
 | 
				
			||||||
      '<S-ScrollWheelDown>',
 | 
					      '<S-ScrollWheelDown>',
 | 
				
			||||||
      '<ScrollWheelUp>',
 | 
					      '<ScrollWheelUp>',
 | 
				
			||||||
@@ -622,7 +640,7 @@ describe('terminal input', function()
 | 
				
			|||||||
        {5:[No Name]                       0,0-1          All}|
 | 
					        {5:[No Name]                       0,0-1          All}|
 | 
				
			||||||
        %s^ {MATCH: *}|
 | 
					        %s^ {MATCH: *}|
 | 
				
			||||||
        {3:-- TERMINAL --}                                    |
 | 
					        {3:-- TERMINAL --}                                    |
 | 
				
			||||||
      ]]):format(key))
 | 
					      ]]):format(key:gsub('<%d+,%d+>$', '')))
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end)
 | 
					  end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2079,6 +2079,18 @@ putglyph 1f3f4,200d,2620,fe0f 2 0,4]])
 | 
				
			|||||||
    mousebtn('u', 1, vt)
 | 
					    mousebtn('u', 1, vt)
 | 
				
			||||||
    expect_output('\x1b[<0;301;301m')
 | 
					    expect_output('\x1b[<0;301;301m')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    -- Button 8 on SGR extended encoding mode
 | 
				
			||||||
 | 
					    mousebtn('d', 8, vt)
 | 
				
			||||||
 | 
					    expect_output('\x1b[<128;301;301M')
 | 
				
			||||||
 | 
					    mousebtn('u', 8, vt)
 | 
				
			||||||
 | 
					    expect_output('\x1b[<128;301;301m')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    -- Button 9 on SGR extended encoding mode
 | 
				
			||||||
 | 
					    mousebtn('d', 9, vt)
 | 
				
			||||||
 | 
					    expect_output('\x1b[<129;301;301M')
 | 
				
			||||||
 | 
					    mousebtn('u', 9, vt)
 | 
				
			||||||
 | 
					    expect_output('\x1b[<129;301;301m')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    -- DECRQM on SGR extended encoding mode
 | 
					    -- DECRQM on SGR extended encoding mode
 | 
				
			||||||
    push('\x1b[?1005$p', vt)
 | 
					    push('\x1b[?1005$p', vt)
 | 
				
			||||||
    expect_output('\x1b[?1005;2$y')
 | 
					    expect_output('\x1b[?1005;2$y')
 | 
				
			||||||
@@ -2094,6 +2106,18 @@ putglyph 1f3f4,200d,2620,fe0f 2 0,4]])
 | 
				
			|||||||
    mousebtn('u', 1, vt)
 | 
					    mousebtn('u', 1, vt)
 | 
				
			||||||
    expect_output('\x1b[3;301;301M')
 | 
					    expect_output('\x1b[3;301;301M')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    -- Button 8 on rxvt extended encoding mode
 | 
				
			||||||
 | 
					    mousebtn('d', 8, vt)
 | 
				
			||||||
 | 
					    expect_output('\x1b[128;301;301M')
 | 
				
			||||||
 | 
					    mousebtn('u', 8, vt)
 | 
				
			||||||
 | 
					    expect_output('\x1b[3;301;301M')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    -- Button 9 on rxvt extended encoding mode
 | 
				
			||||||
 | 
					    mousebtn('d', 9, vt)
 | 
				
			||||||
 | 
					    expect_output('\x1b[129;301;301M')
 | 
				
			||||||
 | 
					    mousebtn('u', 9, vt)
 | 
				
			||||||
 | 
					    expect_output('\x1b[3;301;301M')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    -- DECRQM on rxvt extended encoding mode
 | 
					    -- DECRQM on rxvt extended encoding mode
 | 
				
			||||||
    push('\x1b[?1005$p', vt)
 | 
					    push('\x1b[?1005$p', vt)
 | 
				
			||||||
    expect_output('\x1b[?1005;2$y')
 | 
					    expect_output('\x1b[?1005;2$y')
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user