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 }