neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

mouse.c (3254B)


      1 #include "nvim/math.h"
      2 #include "nvim/tui/termkey/termkey.h"
      3 #include "nvim/vterm/mouse.h"
      4 #include "nvim/vterm/vterm.h"
      5 #include "nvim/vterm/vterm_internal_defs.h"
      6 
      7 #include "vterm/mouse.c.generated.h"
      8 
      9 static void output_mouse(VTermState *state, int code, int pressed, int modifiers, int col, int row)
     10 {
     11  modifiers <<= 2;
     12 
     13  switch (state->mouse_protocol) {
     14  case MOUSE_X10:
     15    if (col + 0x21 > 0xff) {
     16      col = 0xff - 0x21;
     17    }
     18    if (row + 0x21 > 0xff) {
     19      row = 0xff - 0x21;
     20    }
     21 
     22    if (!pressed) {
     23      code = 3;
     24    }
     25 
     26    if (code & 0x80) {
     27      break;
     28    }
     29    vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "M%c%c%c",
     30                                   (code | modifiers) + 0x20, col + 0x21, row + 0x21);
     31    break;
     32 
     33  case MOUSE_UTF8: {
     34    char utf8[18];
     35    size_t len = 0;
     36 
     37    if (!pressed) {
     38      code = 3;
     39    }
     40 
     41    len += (size_t)fill_utf8((code | modifiers) + 0x20, utf8 + len);
     42    len += (size_t)fill_utf8(col + 0x21, utf8 + len);
     43    len += (size_t)fill_utf8(row + 0x21, utf8 + len);
     44    utf8[len] = 0;
     45 
     46    vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "M%s", utf8);
     47  }
     48  break;
     49 
     50  case MOUSE_SGR:
     51    vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "<%d;%d;%d%c",
     52                                   code | modifiers, col + 1, row + 1, pressed ? 'M' : 'm');
     53    break;
     54 
     55  case MOUSE_RXVT:
     56    if (!pressed) {
     57      code = 3;
     58    }
     59 
     60    vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "%d;%d;%dM",
     61                                   code | modifiers, col + 1, row + 1);
     62    break;
     63  }
     64 }
     65 
     66 void vterm_mouse_move(VTerm *vt, int row, int col, VTermModifier mod)
     67 {
     68  VTermState *state = vt->state;
     69 
     70  if (col == state->mouse_col && row == state->mouse_row) {
     71    return;
     72  }
     73 
     74  state->mouse_col = col;
     75  state->mouse_row = row;
     76 
     77  if ((state->mouse_flags & MOUSE_WANT_DRAG && state->mouse_buttons)
     78      || (state->mouse_flags & MOUSE_WANT_MOVE)) {
     79    if (state->mouse_buttons) {
     80      int button = xctz((uint64_t)state->mouse_buttons) + 1;
     81      if (button < 4) {
     82        output_mouse(state, button - 1 + 0x20, 1, (int)mod, col, row);
     83      } else if (button >= 8 && button < 12) {
     84        output_mouse(state, button - 8 + 0x80 + 0x20, 1, (int)mod, col, row);
     85      }
     86    } else {
     87      output_mouse(state, 3 + 0x20, 1, (int)mod, col, row);
     88    }
     89  }
     90 }
     91 
     92 void vterm_mouse_button(VTerm *vt, int button, bool pressed, VTermModifier mod)
     93 {
     94  VTermState *state = vt->state;
     95 
     96  int old_buttons = state->mouse_buttons;
     97 
     98  if ((button > 0 && button <= 3) || (button >= 8 && button <= 11)) {
     99    if (pressed) {
    100      state->mouse_buttons |= (1 << (button - 1));
    101    } else {
    102      state->mouse_buttons &= ~(1 << (button - 1));
    103    }
    104  }
    105 
    106  // Most of the time we don't get button releases from 4/5/6/7
    107  if (state->mouse_buttons == old_buttons && (button < 4 || button > 7)) {
    108    return;
    109  }
    110 
    111  if (!state->mouse_flags) {
    112    return;
    113  }
    114 
    115  if (button < 4) {
    116    output_mouse(state, button - 1, pressed, (int)mod, state->mouse_col, state->mouse_row);
    117  } else if (button < 8) {
    118    output_mouse(state, button - 4 + 0x40, pressed, (int)mod, state->mouse_col, state->mouse_row);
    119  } else if (button < 12) {
    120    output_mouse(state, button - 8 + 0x80, pressed, (int)mod, state->mouse_col, state->mouse_row);
    121  }
    122 }