neovim

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

driver-csi.c (24955B)


      1 #include <assert.h>
      2 #include <stdint.h>
      3 #include <string.h>
      4 
      5 #include "nvim/memory.h"
      6 #include "nvim/tui/termkey/driver-csi.h"
      7 #include "nvim/tui/termkey/termkey-internal.h"
      8 #include "nvim/tui/termkey/termkey_defs.h"
      9 
     10 #include "tui/termkey/driver-csi.c.generated.h"
     11 
     12 // There are 64 codes 0x40 - 0x7F
     13 static int keyinfo_initialised = 0;
     14 static struct keyinfo ss3s[64];
     15 static char ss3_kpalts[64];
     16 
     17 typedef TermKeyResult CsiHandler(TermKey *tk, TermKeyKey *key, int cmd, TermKeyCsiParam *params,
     18                                 int nparams);
     19 static CsiHandler *csi_handlers[64];
     20 
     21 // Handler for CSI/SS3 cmd keys
     22 
     23 static struct keyinfo csi_ss3s[64];
     24 
     25 static TermKeyResult handle_csi_ss3_full(TermKey *tk, TermKeyKey *key, int cmd,
     26                                         TermKeyCsiParam *params, int nparams)
     27 {
     28  TermKeyResult result = TERMKEY_RES_KEY;
     29 
     30  if (nparams > 1 && params[1].param != NULL) {
     31    int arg = 0;
     32    int subparam = 0;
     33    size_t nsubparams = 1;
     34    result = termkey_interpret_csi_param(params[1], &arg, &subparam, &nsubparams);
     35    if (result != TERMKEY_RES_KEY) {
     36      return result;
     37    }
     38 
     39    if (nsubparams > 0) {
     40      key->event = parse_key_event(subparam);
     41      if (key->event == TERMKEY_EVENT_UNKNOWN) {
     42        return TERMKEY_RES_NONE;
     43      }
     44    }
     45 
     46    key->modifiers = arg - 1;
     47  } else {
     48    key->modifiers = 0;
     49  }
     50 
     51  key->type = csi_ss3s[cmd - 0x40].type;
     52  key->code.sym = csi_ss3s[cmd - 0x40].sym;
     53  key->modifiers &= ~(csi_ss3s[cmd - 0x40].modifier_mask);
     54  key->modifiers |= csi_ss3s[cmd - 0x40].modifier_set;
     55 
     56  if (key->code.sym == TERMKEY_SYM_UNKNOWN) {
     57    result = TERMKEY_RES_NONE;
     58  }
     59 
     60  return result;
     61 }
     62 
     63 static void register_csi_ss3_full(TermKeyType type, TermKeySym sym, int modifier_set,
     64                                  int modifier_mask, unsigned char cmd)
     65 {
     66  if (cmd < 0x40 || cmd >= 0x80) {
     67    return;
     68  }
     69 
     70  csi_ss3s[cmd - 0x40].type = type;
     71  csi_ss3s[cmd - 0x40].sym = sym;
     72  csi_ss3s[cmd - 0x40].modifier_set = modifier_set;
     73  csi_ss3s[cmd - 0x40].modifier_mask = modifier_mask;
     74 
     75  csi_handlers[cmd - 0x40] = &handle_csi_ss3_full;
     76 }
     77 
     78 static void register_csi_ss3(TermKeyType type, TermKeySym sym, unsigned char cmd)
     79 {
     80  register_csi_ss3_full(type, sym, 0, 0, cmd);
     81 }
     82 
     83 /// Handler for SS3 keys with kpad alternate representations
     84 static void register_ss3kpalt(TermKeyType type, TermKeySym sym, unsigned char cmd, char kpalt)
     85 {
     86  if (cmd < 0x40 || cmd >= 0x80) {
     87    return;
     88  }
     89 
     90  ss3s[cmd - 0x40].type = type;
     91  ss3s[cmd - 0x40].sym = sym;
     92  ss3s[cmd - 0x40].modifier_set = 0;
     93  ss3s[cmd - 0x40].modifier_mask = 0;
     94  ss3_kpalts[cmd - 0x40] = kpalt;
     95 }
     96 
     97 // Handler for CSI number ~ function keys
     98 
     99 #define NCSIFUNCS 35  // This value must be increased if more CSI function keys are added
    100 static struct keyinfo csifuncs[NCSIFUNCS];
    101 
    102 static TermKeyResult handle_csifunc(TermKey *tk, TermKeyKey *key, int cmd, TermKeyCsiParam *params,
    103                                    int nparams)
    104 {
    105  if (nparams == 0) {
    106    return TERMKEY_RES_NONE;
    107  }
    108 
    109  TermKeyResult result = TERMKEY_RES_KEY;
    110  int args[3];
    111 
    112  if (nparams > 1 && params[1].param != NULL) {
    113    int subparam = 0;
    114    size_t nsubparams = 1;
    115    result = termkey_interpret_csi_param(params[1], &args[1], &subparam, &nsubparams);
    116    if (result != TERMKEY_RES_KEY) {
    117      return result;
    118    }
    119 
    120    if (nsubparams > 0) {
    121      key->event = parse_key_event(subparam);
    122      if (key->event == TERMKEY_EVENT_UNKNOWN) {
    123        return TERMKEY_RES_NONE;
    124      }
    125    }
    126 
    127    key->modifiers = args[1] - 1;
    128  } else {
    129    key->modifiers = 0;
    130  }
    131 
    132  key->type = TERMKEY_TYPE_KEYSYM;
    133 
    134  result = termkey_interpret_csi_param(params[0], &args[0], NULL, NULL);
    135  if (result != TERMKEY_RES_KEY) {
    136    return result;
    137  }
    138 
    139  if (args[0] == 27 && nparams > 2 && params[2].param != NULL) {
    140    result = termkey_interpret_csi_param(params[2], &args[2], NULL, NULL);
    141    if (result != TERMKEY_RES_KEY) {
    142      return result;
    143    }
    144 
    145    int mod = key->modifiers;
    146    (*tk->method.emit_codepoint)(tk, args[2], key);
    147    key->modifiers |= mod;
    148  } else if (args[0] >= 0 && args[0] < NCSIFUNCS) {
    149    key->type = csifuncs[args[0]].type;
    150    key->code.sym = csifuncs[args[0]].sym;
    151    key->modifiers &= ~(csifuncs[args[0]].modifier_mask);
    152    key->modifiers |= csifuncs[args[0]].modifier_set;
    153  } else {
    154    key->code.sym = TERMKEY_SYM_UNKNOWN;
    155  }
    156 
    157  if (key->code.sym == TERMKEY_SYM_UNKNOWN) {
    158 #ifdef DEBUG
    159    fprintf(stderr, "CSI: Unknown function key %ld\n", arg[0]);
    160 #endif
    161    result = TERMKEY_RES_NONE;
    162  }
    163 
    164  return result;
    165 }
    166 
    167 static void register_csifunc(TermKeyType type, TermKeySym sym, int number)
    168 {
    169  if (number >= NCSIFUNCS) {
    170    return;
    171  }
    172 
    173  csifuncs[number].type = type;
    174  csifuncs[number].sym = sym;
    175  csifuncs[number].modifier_set = 0;
    176  csifuncs[number].modifier_mask = 0;
    177 
    178  csi_handlers['~' - 0x40] = &handle_csifunc;
    179 }
    180 
    181 /// Handler for CSI u extended Unicode keys
    182 static TermKeyResult handle_csi_u(TermKey *tk, TermKeyKey *key, int cmd, TermKeyCsiParam *params,
    183                                  int nparams)
    184 {
    185  switch (cmd) {
    186  case 'u': {
    187    int args[2];
    188    if (nparams > 1 && params[1].param != NULL) {
    189      int subparam = 0;
    190      size_t nsubparams = 1;
    191      if (termkey_interpret_csi_param(params[1], &args[1], &subparam,
    192                                      &nsubparams) != TERMKEY_RES_KEY) {
    193        return TERMKEY_RES_ERROR;
    194      }
    195 
    196      if (nsubparams > 0) {
    197        key->event = parse_key_event(subparam);
    198        if (key->event == TERMKEY_EVENT_UNKNOWN) {
    199          return TERMKEY_RES_NONE;
    200        }
    201      }
    202 
    203      key->modifiers = args[1] - 1;
    204    } else {
    205      key->modifiers = 0;
    206    }
    207 
    208    if (termkey_interpret_csi_param(params[0], &args[0], NULL, NULL) != TERMKEY_RES_KEY) {
    209      return TERMKEY_RES_ERROR;
    210    }
    211 
    212    int mod = key->modifiers;
    213    key->type = TERMKEY_TYPE_KEYSYM;
    214    (*tk->method.emit_codepoint)(tk, args[0], key);
    215    key->modifiers |= mod;
    216 
    217    return TERMKEY_RES_KEY;
    218  }
    219  default:
    220    return TERMKEY_RES_NONE;
    221  }
    222 }
    223 
    224 /// Handler for CSI M / CSI m mouse events in SGR and rxvt encodings
    225 /// Note: This does not handle X10 encoding
    226 static TermKeyResult handle_csi_m(TermKey *tk, TermKeyKey *key, int cmd, TermKeyCsiParam *params,
    227                                  int nparams)
    228 {
    229  int initial = cmd >> 8;
    230  cmd &= 0xff;
    231 
    232  switch (cmd) {
    233  case 'M':
    234  case 'm':
    235    break;
    236  default:
    237    return TERMKEY_RES_NONE;
    238  }
    239 
    240  if (nparams < 3) {
    241    return TERMKEY_RES_NONE;
    242  }
    243 
    244  int args[3];
    245  for (size_t i = 0; i < 3; i++) {
    246    if (termkey_interpret_csi_param(params[i], &args[i], NULL, NULL) != TERMKEY_RES_KEY) {
    247      return TERMKEY_RES_ERROR;
    248    }
    249  }
    250 
    251  if (!initial) {  // rxvt protocol
    252    key->type = TERMKEY_TYPE_MOUSE;
    253    key->code.mouse[0] = (char)args[0];
    254 
    255    key->modifiers = (key->code.mouse[0] & 0x1c) >> 2;
    256    key->code.mouse[0] &= ~0x1c;
    257 
    258    termkey_key_set_linecol(key, args[1], args[2]);
    259 
    260    return TERMKEY_RES_KEY;
    261  }
    262 
    263  if (initial == '<') {  // SGR protocol
    264    key->type = TERMKEY_TYPE_MOUSE;
    265    key->code.mouse[0] = (char)args[0];
    266 
    267    key->modifiers = (key->code.mouse[0] & 0x1c) >> 2;
    268    key->code.mouse[0] &= ~0x1c;
    269 
    270    termkey_key_set_linecol(key, args[1], args[2]);
    271 
    272    if (cmd == 'm') {  // release
    273      key->code.mouse[3] |= 0x80;
    274    }
    275 
    276    return TERMKEY_RES_KEY;
    277  }
    278 
    279  return TERMKEY_RES_NONE;
    280 }
    281 
    282 TermKeyResult termkey_interpret_mouse(TermKey *tk, const TermKeyKey *key, TermKeyMouseEvent *event,
    283                                      int *button, int *line, int *col)
    284 {
    285  if (key->type != TERMKEY_TYPE_MOUSE) {
    286    return TERMKEY_RES_NONE;
    287  }
    288 
    289  if (button) {
    290    *button = 0;
    291  }
    292 
    293  termkey_key_get_linecol(key, line, col);
    294 
    295  if (!event) {
    296    return TERMKEY_RES_KEY;
    297  }
    298 
    299  int btn = 0;
    300 
    301  int code = (unsigned char)key->code.mouse[0];
    302 
    303  int drag = code & 0x20;
    304 
    305  code &= ~0x3c;
    306 
    307  switch (code) {
    308  case 0:
    309  case 1:
    310  case 2:
    311    *event = drag ? TERMKEY_MOUSE_DRAG : TERMKEY_MOUSE_PRESS;
    312    btn = code + 1;
    313    break;
    314 
    315  case 3:
    316    *event = TERMKEY_MOUSE_RELEASE;
    317    // no button hint
    318    break;
    319 
    320  case 64:
    321  case 65:
    322  case 66:
    323  case 67:
    324    *event = drag ? TERMKEY_MOUSE_DRAG : TERMKEY_MOUSE_PRESS;
    325    btn = code + 4 - 64;
    326    break;
    327 
    328  case 128:
    329  case 129:
    330    *event = drag ? TERMKEY_MOUSE_DRAG : TERMKEY_MOUSE_PRESS;
    331    btn = code + 8 - 128;
    332    break;
    333 
    334  default:
    335    *event = TERMKEY_MOUSE_UNKNOWN;
    336  }
    337 
    338  if (button) {
    339    *button = btn;
    340  }
    341 
    342  if (key->code.mouse[3] & 0x80) {
    343    *event = TERMKEY_MOUSE_RELEASE;
    344  }
    345 
    346  return TERMKEY_RES_KEY;
    347 }
    348 
    349 /// Handler for CSI ? R position reports
    350 /// A plain CSI R with no arguments is probably actually <F3>
    351 static TermKeyResult handle_csi_R(TermKey *tk, TermKeyKey *key, int cmd, TermKeyCsiParam *params,
    352                                  int nparams)
    353 {
    354  switch (cmd) {
    355  case 'R'|'?' << 8:
    356      if (nparams < 2) {
    357      return TERMKEY_RES_NONE;
    358      }
    359 
    360      int args[2];
    361    if (termkey_interpret_csi_param(params[0], &args[0], NULL, NULL) != TERMKEY_RES_KEY) {
    362      return TERMKEY_RES_ERROR;
    363    }
    364 
    365    if (termkey_interpret_csi_param(params[1], &args[1], NULL, NULL) != TERMKEY_RES_KEY) {
    366      return TERMKEY_RES_ERROR;
    367    }
    368 
    369    key->type = TERMKEY_TYPE_POSITION;
    370    termkey_key_set_linecol(key, args[1], args[0]);
    371    return TERMKEY_RES_KEY;
    372 
    373  default:
    374    return handle_csi_ss3_full(tk, key, cmd, params, nparams);
    375  }
    376 }
    377 
    378 TermKeyResult termkey_interpret_position(TermKey *tk, const TermKeyKey *key, int *line, int *col)
    379 {
    380  if (key->type != TERMKEY_TYPE_POSITION) {
    381    return TERMKEY_RES_NONE;
    382  }
    383 
    384  termkey_key_get_linecol(key, line, col);
    385 
    386  return TERMKEY_RES_KEY;
    387 }
    388 
    389 /// Handler for CSI $y mode status reports
    390 static TermKeyResult handle_csi_y(TermKey *tk, TermKeyKey *key, int cmd, TermKeyCsiParam *params,
    391                                  int nparams)
    392 {
    393  switch (cmd) {
    394  case 'y'|'$' << 16:
    395      case 'y'|'$' << 16 | '?' << 8:
    396      if (nparams < 2) {
    397      return TERMKEY_RES_NONE;
    398      }
    399 
    400      int args[2];
    401    if (termkey_interpret_csi_param(params[0], &args[0], NULL, NULL) != TERMKEY_RES_KEY) {
    402      return TERMKEY_RES_ERROR;
    403    }
    404 
    405    if (termkey_interpret_csi_param(params[1], &args[1], NULL, NULL) != TERMKEY_RES_KEY) {
    406      return TERMKEY_RES_ERROR;
    407    }
    408 
    409    key->type = TERMKEY_TYPE_MODEREPORT;
    410    key->code.mouse[0] = (char)(cmd >> 8);
    411    key->code.mouse[1] = (char)(args[0] >> 8);
    412    key->code.mouse[2] = (char)(args[0] & 0xff);
    413    key->code.mouse[3] = (char)args[1];
    414    return TERMKEY_RES_KEY;
    415 
    416  default:
    417    return TERMKEY_RES_NONE;
    418  }
    419 }
    420 
    421 TermKeyResult termkey_interpret_modereport(TermKey *tk, const TermKeyKey *key, int *initial,
    422                                           int *mode, int *value)
    423 {
    424  if (key->type != TERMKEY_TYPE_MODEREPORT) {
    425    return TERMKEY_RES_NONE;
    426  }
    427 
    428  if (initial) {
    429    *initial = (unsigned char)key->code.mouse[0];
    430  }
    431 
    432  if (mode) {
    433    *mode = ((uint8_t)key->code.mouse[1] << 8) | (uint8_t)key->code.mouse[2];
    434  }
    435 
    436  if (value) {
    437    *value = (unsigned char)key->code.mouse[3];
    438  }
    439 
    440  return TERMKEY_RES_KEY;
    441 }
    442 
    443 #define CHARAT(i) (tk->buffer[tk->buffstart + (i)])
    444 
    445 static TermKeyEvent parse_key_event(int n)
    446 {
    447  switch (n) {
    448  case 1:
    449    return TERMKEY_EVENT_PRESS;
    450  case 2:
    451    return TERMKEY_EVENT_REPEAT;
    452  case 3:
    453    return TERMKEY_EVENT_RELEASE;
    454  default:
    455    return TERMKEY_EVENT_UNKNOWN;
    456  }
    457 }
    458 
    459 static TermKeyResult parse_csi(TermKey *tk, size_t introlen, size_t *csi_len,
    460                               TermKeyCsiParam params[], size_t *nargs, unsigned *commandp)
    461 {
    462  size_t csi_end = introlen;
    463 
    464  while (csi_end < tk->buffcount) {
    465    if (CHARAT(csi_end) >= 0x40 && CHARAT(csi_end) < 0x80) {
    466      break;
    467    }
    468    csi_end++;
    469  }
    470 
    471  if (csi_end >= tk->buffcount) {
    472    return TERMKEY_RES_AGAIN;
    473  }
    474 
    475  unsigned char cmd = CHARAT(csi_end);
    476  *commandp = cmd;
    477 
    478  char present = 0;
    479  int argi = 0;
    480 
    481  size_t p = introlen;
    482 
    483  // See if there is an initial byte
    484  if (CHARAT(p) >= '<' && CHARAT(p) <= '?') {
    485    *commandp |= (unsigned)(CHARAT(p) << 8);
    486    p++;
    487  }
    488 
    489  // Now attempt to parse out up number;number;... separated values
    490  while (p < csi_end) {
    491    unsigned char c = CHARAT(p);
    492 
    493    if (c >= '0' && c < ';') {
    494      if (!present) {
    495        params[argi].param = &CHARAT(p);
    496        present = 1;
    497      }
    498    } else if (c == ';') {
    499      if (!present) {
    500        params[argi].param = NULL;
    501        params[argi].length = 0;
    502      } else {
    503        params[argi].length = (size_t)(&CHARAT(p) - params[argi].param);
    504      }
    505      present = 0;
    506      argi++;
    507 
    508      if (argi >= 16) {
    509        break;
    510      }
    511    } else if (c >= 0x20 && c <= 0x2f) {
    512      *commandp |= (unsigned)(c << 16);
    513      break;
    514    }
    515 
    516    p++;
    517  }
    518 
    519  if (present) {
    520    params[argi].length = (size_t)(&CHARAT(p) - params[argi].param);
    521    argi++;
    522  }
    523 
    524  *nargs = (size_t)argi;
    525  *csi_len = csi_end + 1;
    526 
    527  return TERMKEY_RES_KEY;
    528 }
    529 
    530 TermKeyResult termkey_interpret_csi(TermKey *tk, const TermKeyKey *key, TermKeyCsiParam params[],
    531                                    size_t *nparams, unsigned *cmd)
    532 {
    533  size_t dummy;
    534 
    535  if (tk->hightide == 0) {
    536    return TERMKEY_RES_NONE;
    537  }
    538  if (key->type != TERMKEY_TYPE_UNKNOWN_CSI) {
    539    return TERMKEY_RES_NONE;
    540  }
    541 
    542  return parse_csi(tk, 0, &dummy, params, nparams, cmd);
    543 }
    544 
    545 TermKeyResult termkey_interpret_csi_param(TermKeyCsiParam param, int *paramp, int subparams[],
    546                                          size_t *nsubparams)
    547 {
    548  if (paramp == NULL) {
    549    return TERMKEY_RES_ERROR;
    550  }
    551 
    552  if (param.param == NULL) {
    553    *paramp = -1;
    554    if (nsubparams) {
    555      *nsubparams = 0;
    556    }
    557    return TERMKEY_RES_KEY;
    558  }
    559 
    560  int arg = 0;
    561  size_t i = 0;
    562  size_t capacity = nsubparams ? *nsubparams : 0;
    563  size_t length = 0;
    564  for (; i < param.length && length <= capacity; i++) {
    565    unsigned char c = param.param[i];
    566    if (c == ':') {
    567      if (length == 0) {
    568        *paramp = arg;
    569      } else if (subparams != NULL) {
    570        subparams[length - 1] = arg;
    571      }
    572 
    573      arg = 0;
    574      length++;
    575      continue;
    576    }
    577 
    578    assert(c >= '0' && c <= '9');
    579    arg = (10 * arg) + (c - '0');
    580  }
    581 
    582  if (length == 0) {
    583    *paramp = arg;
    584  } else if (subparams != NULL) {
    585    subparams[length - 1] = arg;
    586  }
    587 
    588  if (nsubparams) {
    589    *nsubparams = length;
    590  }
    591 
    592  return TERMKEY_RES_KEY;
    593 }
    594 
    595 static int register_keys(void)
    596 {
    597  int i;
    598 
    599  for (i = 0; i < 64; i++) {
    600    csi_ss3s[i].sym = TERMKEY_SYM_UNKNOWN;
    601    ss3s[i].sym = TERMKEY_SYM_UNKNOWN;
    602    ss3_kpalts[i] = 0;
    603  }
    604 
    605  for (i = 0; i < NCSIFUNCS; i++) {
    606    csifuncs[i].sym = TERMKEY_SYM_UNKNOWN;
    607  }
    608 
    609  register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_UP,    'A');
    610  register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_DOWN,  'B');
    611  register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_RIGHT, 'C');
    612  register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_LEFT,  'D');
    613  register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_BEGIN, 'E');
    614  register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_END,   'F');
    615  register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_HOME,  'H');
    616  register_csi_ss3(TERMKEY_TYPE_FUNCTION, 1, 'P');
    617  register_csi_ss3(TERMKEY_TYPE_FUNCTION, 2, 'Q');
    618  register_csi_ss3(TERMKEY_TYPE_FUNCTION, 3, 'R');
    619  register_csi_ss3(TERMKEY_TYPE_FUNCTION, 4, 'S');
    620 
    621  register_csi_ss3_full(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_TAB, TERMKEY_KEYMOD_SHIFT,
    622                        TERMKEY_KEYMOD_SHIFT, 'Z');
    623 
    624  register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPENTER,  'M', 0);
    625  register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPEQUALS, 'X', '=');
    626  register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPMULT,   'j', '*');
    627  register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPPLUS,   'k', '+');
    628  register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPCOMMA,  'l', ',');
    629  register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPMINUS,  'm', '-');
    630  register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPPERIOD, 'n', '.');
    631  register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPDIV,    'o', '/');
    632  register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP0,      'p', '0');
    633  register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP1,      'q', '1');
    634  register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP2,      'r', '2');
    635  register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP3,      's', '3');
    636  register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP4,      't', '4');
    637  register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP5,      'u', '5');
    638  register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP6,      'v', '6');
    639  register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP7,      'w', '7');
    640  register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP8,      'x', '8');
    641  register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP9,      'y', '9');
    642 
    643  register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_FIND,      1);
    644  register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_INSERT,    2);
    645  register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_DELETE,    3);
    646  register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_SELECT,    4);
    647  register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PAGEUP,    5);
    648  register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PAGEDOWN,  6);
    649  register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_HOME,      7);
    650  register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_END,       8);
    651 
    652  register_csifunc(TERMKEY_TYPE_FUNCTION, 1,  11);
    653  register_csifunc(TERMKEY_TYPE_FUNCTION, 2,  12);
    654  register_csifunc(TERMKEY_TYPE_FUNCTION, 3,  13);
    655  register_csifunc(TERMKEY_TYPE_FUNCTION, 4,  14);
    656  register_csifunc(TERMKEY_TYPE_FUNCTION, 5,  15);
    657  register_csifunc(TERMKEY_TYPE_FUNCTION, 6,  17);
    658  register_csifunc(TERMKEY_TYPE_FUNCTION, 7,  18);
    659  register_csifunc(TERMKEY_TYPE_FUNCTION, 8,  19);
    660  register_csifunc(TERMKEY_TYPE_FUNCTION, 9,  20);
    661  register_csifunc(TERMKEY_TYPE_FUNCTION, 10, 21);
    662  register_csifunc(TERMKEY_TYPE_FUNCTION, 11, 23);
    663  register_csifunc(TERMKEY_TYPE_FUNCTION, 12, 24);
    664  register_csifunc(TERMKEY_TYPE_FUNCTION, 13, 25);
    665  register_csifunc(TERMKEY_TYPE_FUNCTION, 14, 26);
    666  register_csifunc(TERMKEY_TYPE_FUNCTION, 15, 28);
    667  register_csifunc(TERMKEY_TYPE_FUNCTION, 16, 29);
    668  register_csifunc(TERMKEY_TYPE_FUNCTION, 17, 31);
    669  register_csifunc(TERMKEY_TYPE_FUNCTION, 18, 32);
    670  register_csifunc(TERMKEY_TYPE_FUNCTION, 19, 33);
    671  register_csifunc(TERMKEY_TYPE_FUNCTION, 20, 34);
    672 
    673  csi_handlers['u' - 0x40] = &handle_csi_u;
    674 
    675  csi_handlers['M' - 0x40] = &handle_csi_m;
    676  csi_handlers['m' - 0x40] = &handle_csi_m;
    677 
    678  csi_handlers['R' - 0x40] = &handle_csi_R;
    679 
    680  csi_handlers['y' - 0x40] = &handle_csi_y;
    681 
    682  keyinfo_initialised = 1;
    683  return 1;
    684 }
    685 
    686 void *new_driver_csi(TermKey *tk, TerminfoEntry *term)
    687 {
    688  if (!keyinfo_initialised) {
    689    if (!register_keys()) {
    690      return NULL;
    691    }
    692  }
    693 
    694  TermKeyCsi *csi = xmalloc(sizeof *csi);
    695 
    696  csi->tk = tk;
    697  csi->saved_string_id = 0;
    698  csi->saved_string = NULL;
    699 
    700  return csi;
    701 }
    702 
    703 void free_driver_csi(void *info)
    704 {
    705  TermKeyCsi *csi = info;
    706 
    707  if (csi->saved_string) {
    708    xfree(csi->saved_string);
    709  }
    710 
    711  xfree(csi);
    712 }
    713 
    714 static TermKeyResult peekkey_csi_csi(TermKey *tk, TermKeyCsi *csi, size_t introlen, TermKeyKey *key,
    715                                     int force, size_t *nbytep)
    716 {
    717  size_t csi_len;
    718  size_t nparams = 16;
    719  TermKeyCsiParam params[16];
    720  unsigned cmd;
    721 
    722  TermKeyResult ret = parse_csi(tk, introlen, &csi_len, params, &nparams, &cmd);
    723 
    724  if (ret == TERMKEY_RES_AGAIN) {
    725    if (!force) {
    726      return TERMKEY_RES_AGAIN;
    727    }
    728 
    729    (*tk->method.emit_codepoint)(tk, '[', key);
    730    key->modifiers |= TERMKEY_KEYMOD_ALT;
    731    *nbytep = introlen;
    732    return TERMKEY_RES_KEY;
    733  }
    734 
    735  if (cmd == 'M' && nparams < 3) {  // Mouse in X10 encoding consumes the next 3 bytes also
    736    tk->buffstart += csi_len;
    737    tk->buffcount -= csi_len;
    738 
    739    TermKeyResult mouse_result = (*tk->method.peekkey_mouse)(tk, key, nbytep);
    740 
    741    tk->buffstart -= csi_len;
    742    tk->buffcount += csi_len;
    743 
    744    if (mouse_result == TERMKEY_RES_KEY) {
    745      *nbytep += csi_len;
    746    }
    747 
    748    return mouse_result;
    749  }
    750 
    751  TermKeyResult result = TERMKEY_RES_NONE;
    752 
    753  // We know from the logic above that cmd must be >= 0x40 and < 0x80
    754  if (csi_handlers[(cmd & 0xff) - 0x40]) {
    755    result = (*csi_handlers[(cmd & 0xff) - 0x40])(tk, key, (int)cmd, params, (int)nparams);
    756  }
    757 
    758  if (result == TERMKEY_RES_NONE) {
    759 #ifdef DEBUG
    760    switch (args) {
    761    case 0:
    762      fprintf(stderr, "CSI: Unknown cmd=%c\n", (char)cmd);
    763      break;
    764    case 1:
    765      fprintf(stderr, "CSI: Unknown arg1=%ld cmd=%c\n", arg[0], (char)cmd);
    766      break;
    767    case 2:
    768      fprintf(stderr, "CSI: Unknown arg1=%ld arg2=%ld cmd=%c\n", arg[0], arg[1], (char)cmd);
    769      break;
    770    case 3:
    771      fprintf(stderr, "CSI: Unknown arg1=%ld arg2=%ld arg3=%ld cmd=%c\n", arg[0], arg[1], arg[2],
    772              (char)cmd);
    773      break;
    774    default:
    775      fprintf(stderr, "CSI: Unknown arg1=%ld arg2=%ld arg3=%ld ... args=%d cmd=%c\n", arg[0],
    776              arg[1], arg[2], args, (char)cmd);
    777      break;
    778    }
    779 #endif
    780    key->type = TERMKEY_TYPE_UNKNOWN_CSI;
    781    key->code.number = (int)cmd;
    782    key->modifiers = 0;
    783 
    784    tk->hightide = csi_len - introlen;
    785    *nbytep = introlen;  // Do not yet eat the data bytes
    786    return TERMKEY_RES_KEY;
    787  }
    788 
    789  *nbytep = csi_len;
    790  return result;
    791 }
    792 
    793 static TermKeyResult peekkey_ss3(TermKey *tk, TermKeyCsi *csi, size_t introlen, TermKeyKey *key,
    794                                 int force, size_t *nbytep)
    795 {
    796  if (tk->buffcount < introlen + 1) {
    797    if (!force) {
    798      return TERMKEY_RES_AGAIN;
    799    }
    800 
    801    (*tk->method.emit_codepoint)(tk, 'O', key);
    802    key->modifiers |= TERMKEY_KEYMOD_ALT;
    803    *nbytep = tk->buffcount;
    804    return TERMKEY_RES_KEY;
    805  }
    806 
    807  unsigned char cmd = CHARAT(introlen);
    808 
    809  if (cmd < 0x40 || cmd >= 0x80) {
    810    return TERMKEY_RES_NONE;
    811  }
    812 
    813  key->type = csi_ss3s[cmd - 0x40].type;
    814  key->code.sym = csi_ss3s[cmd - 0x40].sym;
    815  key->modifiers = csi_ss3s[cmd - 0x40].modifier_set;
    816 
    817  if (key->code.sym == TERMKEY_SYM_UNKNOWN) {
    818    if (tk->flags & TERMKEY_FLAG_CONVERTKP && ss3_kpalts[cmd - 0x40]) {
    819      key->type = TERMKEY_TYPE_UNICODE;
    820      key->code.codepoint = (unsigned char)ss3_kpalts[cmd - 0x40];
    821      key->modifiers = 0;
    822 
    823      key->utf8[0] = (char)key->code.codepoint;
    824      key->utf8[1] = 0;
    825    } else {
    826      key->type = ss3s[cmd - 0x40].type;
    827      key->code.sym = ss3s[cmd - 0x40].sym;
    828      key->modifiers = ss3s[cmd - 0x40].modifier_set;
    829    }
    830  }
    831 
    832  if (key->code.sym == TERMKEY_SYM_UNKNOWN) {
    833 #ifdef DEBUG
    834    fprintf(stderr, "CSI: Unknown SS3 %c (0x%02x)\n", (char)cmd, cmd);
    835 #endif
    836    return TERMKEY_RES_NONE;
    837  }
    838 
    839  *nbytep = introlen + 1;
    840 
    841  return TERMKEY_RES_KEY;
    842 }
    843 
    844 static TermKeyResult peekkey_ctrlstring(TermKey *tk, TermKeyCsi *csi, size_t introlen,
    845                                        TermKeyKey *key, int force, size_t *nbytep)
    846 {
    847  size_t str_end = introlen;
    848 
    849  while (str_end < tk->buffcount) {
    850    if (CHARAT(str_end) == 0x07) {  // BEL
    851      break;
    852    }
    853    if (CHARAT(str_end) == 0x9c) {  // ST
    854      break;
    855    }
    856    if (CHARAT(str_end) == 0x1b
    857        && (str_end + 1) < tk->buffcount
    858        && CHARAT(str_end + 1) == 0x5c) {  // ESC-prefixed ST
    859      break;
    860    }
    861 
    862    str_end++;
    863  }
    864 
    865  if (str_end >= tk->buffcount) {
    866    return TERMKEY_RES_AGAIN;
    867  }
    868 
    869 #ifdef DEBUG
    870  fprintf(stderr, "Found a control string: %.*s",
    871          str_end - introlen, tk->buffer + tk->buffstart + introlen);
    872 #endif
    873 
    874  *nbytep = str_end + 1;
    875  if (CHARAT(str_end) == 0x1b) {
    876    (*nbytep)++;
    877  }
    878 
    879  if (csi->saved_string) {
    880    xfree(csi->saved_string);
    881  }
    882 
    883  size_t len = str_end - introlen;
    884 
    885  csi->saved_string_id++;
    886  csi->saved_string = xmalloc(len + 1);
    887 
    888  strncpy(csi->saved_string, (char *)tk->buffer + tk->buffstart + introlen, len);  // NOLINT(runtime/printf)
    889  csi->saved_string[len] = 0;
    890 
    891  char type = CHARAT(introlen - 1) & 0x1f;
    892  switch (type) {
    893  case 0x10:
    894    key->type = TERMKEY_TYPE_DCS;
    895    break;
    896  case 0x1d:
    897    key->type = TERMKEY_TYPE_OSC;
    898    break;
    899  case 0x1f:
    900    key->type = TERMKEY_TYPE_APC;
    901    break;
    902  default:
    903    // Unreachable
    904    abort();
    905  }
    906 
    907  key->code.number = csi->saved_string_id;
    908  key->modifiers = 0;
    909 
    910  return TERMKEY_RES_KEY;
    911 }
    912 
    913 TermKeyResult peekkey_csi(TermKey *tk, void *info, TermKeyKey *key, int force, size_t *nbytep)
    914 {
    915  if (tk->buffcount == 0) {
    916    return tk->is_closed ? TERMKEY_RES_EOF : TERMKEY_RES_NONE;
    917  }
    918 
    919  TermKeyCsi *csi = info;
    920 
    921  switch (CHARAT(0)) {
    922  case 0x1b:
    923    if (tk->buffcount < 2) {
    924      return TERMKEY_RES_NONE;
    925    }
    926 
    927    switch (CHARAT(1)) {
    928    case 0x4f:  // ESC-prefixed SS3
    929      return peekkey_ss3(tk, csi, 2, key, force, nbytep);
    930 
    931    case 0x50:  // ESC-prefixed DCS
    932    case 0x5d:  // ESC-prefixed OSC
    933    case 0x5f:  // ESC-prefixed APC
    934      return peekkey_ctrlstring(tk, csi, 2, key, force, nbytep);
    935 
    936    case 0x5b:  // ESC-prefixed CSI
    937      return peekkey_csi_csi(tk, csi, 2, key, force, nbytep);
    938    }
    939 
    940    return TERMKEY_RES_NONE;
    941 
    942  case 0x8f:  // SS3
    943    return peekkey_ss3(tk, csi, 1, key, force, nbytep);
    944 
    945  case 0x90:  // DCS
    946  case 0x9d:  // OSC
    947    return peekkey_ctrlstring(tk, csi, 1, key, force, nbytep);
    948 
    949  case 0x9b:  // CSI
    950    return peekkey_csi_csi(tk, csi, 1, key, force, nbytep);
    951  }
    952 
    953  return TERMKEY_RES_NONE;
    954 }