1 /* $OpenBSD: input-keys.c,v 1.107 2025/01/02 10:34:45 nicm Exp $ */ 2 3 /* 4 * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 21 #include <stdint.h> 22 #include <stdlib.h> 23 #include <string.h> 24 25 #include "tmux.h" 26 27 /* 28 * This file is rather misleadingly named, it contains the code which takes a 29 * key code and translates it into something suitable to be sent to the 30 * application running in a pane (similar to input.c does in the other 31 * direction with output). 32 */ 33 34 static void input_key_mouse(struct window_pane *, struct mouse_event *); 35 36 /* Entry in the key tree. */ 37 struct input_key_entry { 38 key_code key; 39 const char *data; 40 41 RB_ENTRY(input_key_entry) entry; 42 }; 43 RB_HEAD(input_key_tree, input_key_entry); 44 45 /* Tree of input keys. */ 46 static int input_key_cmp(struct input_key_entry *, 47 struct input_key_entry *); 48 RB_GENERATE_STATIC(input_key_tree, input_key_entry, entry, input_key_cmp); 49 struct input_key_tree input_key_tree = RB_INITIALIZER(&input_key_tree); 50 51 /* List of default keys, the tree is built from this. */ 52 static struct input_key_entry input_key_defaults[] = { 53 /* Paste keys. */ 54 { .key = KEYC_PASTE_START, 55 .data = "\033[200~" 56 }, 57 { .key = KEYC_PASTE_END, 58 .data = "\033[201~" 59 }, 60 61 /* Function keys. */ 62 { .key = KEYC_F1, 63 .data = "\033OP" 64 }, 65 { .key = KEYC_F2, 66 .data = "\033OQ" 67 }, 68 { .key = KEYC_F3, 69 .data = "\033OR" 70 }, 71 { .key = KEYC_F4, 72 .data = "\033OS" 73 }, 74 { .key = KEYC_F5, 75 .data = "\033[15~" 76 }, 77 { .key = KEYC_F6, 78 .data = "\033[17~" 79 }, 80 { .key = KEYC_F7, 81 .data = "\033[18~" 82 }, 83 { .key = KEYC_F8, 84 .data = "\033[19~" 85 }, 86 { .key = KEYC_F9, 87 .data = "\033[20~" 88 }, 89 { .key = KEYC_F10, 90 .data = "\033[21~" 91 }, 92 { .key = KEYC_F11, 93 .data = "\033[23~" 94 }, 95 { .key = KEYC_F12, 96 .data = "\033[24~" 97 }, 98 { .key = KEYC_IC, 99 .data = "\033[2~" 100 }, 101 { .key = KEYC_DC, 102 .data = "\033[3~" 103 }, 104 { .key = KEYC_HOME, 105 .data = "\033[1~" 106 }, 107 { .key = KEYC_END, 108 .data = "\033[4~" 109 }, 110 { .key = KEYC_NPAGE, 111 .data = "\033[6~" 112 }, 113 { .key = KEYC_PPAGE, 114 .data = "\033[5~" 115 }, 116 { .key = KEYC_BTAB, 117 .data = "\033[Z" 118 }, 119 120 /* Arrow keys. */ 121 { .key = KEYC_UP|KEYC_CURSOR, 122 .data = "\033OA" 123 }, 124 { .key = KEYC_DOWN|KEYC_CURSOR, 125 .data = "\033OB" 126 }, 127 { .key = KEYC_RIGHT|KEYC_CURSOR, 128 .data = "\033OC" 129 }, 130 { .key = KEYC_LEFT|KEYC_CURSOR, 131 .data = "\033OD" 132 }, 133 { .key = KEYC_UP, 134 .data = "\033[A" 135 }, 136 { .key = KEYC_DOWN, 137 .data = "\033[B" 138 }, 139 { .key = KEYC_RIGHT, 140 .data = "\033[C" 141 }, 142 { .key = KEYC_LEFT, 143 .data = "\033[D" 144 }, 145 146 /* Keypad keys. */ 147 { .key = KEYC_KP_SLASH|KEYC_KEYPAD, 148 .data = "\033Oo" 149 }, 150 { .key = KEYC_KP_STAR|KEYC_KEYPAD, 151 .data = "\033Oj" 152 }, 153 { .key = KEYC_KP_MINUS|KEYC_KEYPAD, 154 .data = "\033Om" 155 }, 156 { .key = KEYC_KP_SEVEN|KEYC_KEYPAD, 157 .data = "\033Ow" 158 }, 159 { .key = KEYC_KP_EIGHT|KEYC_KEYPAD, 160 .data = "\033Ox" 161 }, 162 { .key = KEYC_KP_NINE|KEYC_KEYPAD, 163 .data = "\033Oy" 164 }, 165 { .key = KEYC_KP_PLUS|KEYC_KEYPAD, 166 .data = "\033Ok" 167 }, 168 { .key = KEYC_KP_FOUR|KEYC_KEYPAD, 169 .data = "\033Ot" 170 }, 171 { .key = KEYC_KP_FIVE|KEYC_KEYPAD, 172 .data = "\033Ou" 173 }, 174 { .key = KEYC_KP_SIX|KEYC_KEYPAD, 175 .data = "\033Ov" 176 }, 177 { .key = KEYC_KP_ONE|KEYC_KEYPAD, 178 .data = "\033Oq" 179 }, 180 { .key = KEYC_KP_TWO|KEYC_KEYPAD, 181 .data = "\033Or" 182 }, 183 { .key = KEYC_KP_THREE|KEYC_KEYPAD, 184 .data = "\033Os" 185 }, 186 { .key = KEYC_KP_ENTER|KEYC_KEYPAD, 187 .data = "\033OM" 188 }, 189 { .key = KEYC_KP_ZERO|KEYC_KEYPAD, 190 .data = "\033Op" 191 }, 192 { .key = KEYC_KP_PERIOD|KEYC_KEYPAD, 193 .data = "\033On" 194 }, 195 { .key = KEYC_KP_SLASH, 196 .data = "/" 197 }, 198 { .key = KEYC_KP_STAR, 199 .data = "*" 200 }, 201 { .key = KEYC_KP_MINUS, 202 .data = "-" 203 }, 204 { .key = KEYC_KP_SEVEN, 205 .data = "7" 206 }, 207 { .key = KEYC_KP_EIGHT, 208 .data = "8" 209 }, 210 { .key = KEYC_KP_NINE, 211 .data = "9" 212 }, 213 { .key = KEYC_KP_PLUS, 214 .data = "+" 215 }, 216 { .key = KEYC_KP_FOUR, 217 .data = "4" 218 }, 219 { .key = KEYC_KP_FIVE, 220 .data = "5" 221 }, 222 { .key = KEYC_KP_SIX, 223 .data = "6" 224 }, 225 { .key = KEYC_KP_ONE, 226 .data = "1" 227 }, 228 { .key = KEYC_KP_TWO, 229 .data = "2" 230 }, 231 { .key = KEYC_KP_THREE, 232 .data = "3" 233 }, 234 { .key = KEYC_KP_ENTER, 235 .data = "\n" 236 }, 237 { .key = KEYC_KP_ZERO, 238 .data = "0" 239 }, 240 { .key = KEYC_KP_PERIOD, 241 .data = "." 242 }, 243 244 /* Keys with an embedded modifier. */ 245 { .key = KEYC_F1|KEYC_BUILD_MODIFIERS, 246 .data = "\033[1;_P" 247 }, 248 { .key = KEYC_F2|KEYC_BUILD_MODIFIERS, 249 .data = "\033[1;_Q" 250 }, 251 { .key = KEYC_F3|KEYC_BUILD_MODIFIERS, 252 .data = "\033[1;_R" 253 }, 254 { .key = KEYC_F4|KEYC_BUILD_MODIFIERS, 255 .data = "\033[1;_S" 256 }, 257 { .key = KEYC_F5|KEYC_BUILD_MODIFIERS, 258 .data = "\033[15;_~" 259 }, 260 { .key = KEYC_F6|KEYC_BUILD_MODIFIERS, 261 .data = "\033[17;_~" 262 }, 263 { .key = KEYC_F7|KEYC_BUILD_MODIFIERS, 264 .data = "\033[18;_~" 265 }, 266 { .key = KEYC_F8|KEYC_BUILD_MODIFIERS, 267 .data = "\033[19;_~" 268 }, 269 { .key = KEYC_F9|KEYC_BUILD_MODIFIERS, 270 .data = "\033[20;_~" 271 }, 272 { .key = KEYC_F10|KEYC_BUILD_MODIFIERS, 273 .data = "\033[21;_~" 274 }, 275 { .key = KEYC_F11|KEYC_BUILD_MODIFIERS, 276 .data = "\033[23;_~" 277 }, 278 { .key = KEYC_F12|KEYC_BUILD_MODIFIERS, 279 .data = "\033[24;_~" 280 }, 281 { .key = KEYC_UP|KEYC_BUILD_MODIFIERS, 282 .data = "\033[1;_A" 283 }, 284 { .key = KEYC_DOWN|KEYC_BUILD_MODIFIERS, 285 .data = "\033[1;_B" 286 }, 287 { .key = KEYC_RIGHT|KEYC_BUILD_MODIFIERS, 288 .data = "\033[1;_C" 289 }, 290 { .key = KEYC_LEFT|KEYC_BUILD_MODIFIERS, 291 .data = "\033[1;_D" 292 }, 293 { .key = KEYC_HOME|KEYC_BUILD_MODIFIERS, 294 .data = "\033[1;_H" 295 }, 296 { .key = KEYC_END|KEYC_BUILD_MODIFIERS, 297 .data = "\033[1;_F" 298 }, 299 { .key = KEYC_PPAGE|KEYC_BUILD_MODIFIERS, 300 .data = "\033[5;_~" 301 }, 302 { .key = KEYC_NPAGE|KEYC_BUILD_MODIFIERS, 303 .data = "\033[6;_~" 304 }, 305 { .key = KEYC_IC|KEYC_BUILD_MODIFIERS, 306 .data = "\033[2;_~" 307 }, 308 { .key = KEYC_DC|KEYC_BUILD_MODIFIERS, 309 .data = "\033[3;_~" 310 }, 311 }; 312 static const key_code input_key_modifiers[] = { 313 0, 314 0, 315 KEYC_SHIFT, 316 KEYC_META|KEYC_IMPLIED_META, 317 KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META, 318 KEYC_CTRL, 319 KEYC_SHIFT|KEYC_CTRL, 320 KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL, 321 KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL 322 }; 323 324 /* Input key comparison function. */ 325 static int 326 input_key_cmp(struct input_key_entry *ike1, struct input_key_entry *ike2) 327 { 328 if (ike1->key < ike2->key) 329 return (-1); 330 if (ike1->key > ike2->key) 331 return (1); 332 return (0); 333 } 334 335 /* Look for key in tree. */ 336 static struct input_key_entry * 337 input_key_get(key_code key) 338 { 339 struct input_key_entry entry = { .key = key }; 340 341 return (RB_FIND(input_key_tree, &input_key_tree, &entry)); 342 } 343 344 /* Split a character into two UTF-8 bytes. */ 345 static size_t 346 input_key_split2(u_int c, u_char *dst) 347 { 348 if (c > 0x7f) { 349 dst[0] = (c >> 6) | 0xc0; 350 dst[1] = (c & 0x3f) | 0x80; 351 return (2); 352 } 353 dst[0] = c; 354 return (1); 355 } 356 357 /* Build input key tree. */ 358 void 359 input_key_build(void) 360 { 361 struct input_key_entry *ike, *new; 362 u_int i, j; 363 char *data; 364 key_code key; 365 366 for (i = 0; i < nitems(input_key_defaults); i++) { 367 ike = &input_key_defaults[i]; 368 if (~ike->key & KEYC_BUILD_MODIFIERS) { 369 RB_INSERT(input_key_tree, &input_key_tree, ike); 370 continue; 371 } 372 373 for (j = 2; j < nitems(input_key_modifiers); j++) { 374 key = (ike->key & ~KEYC_BUILD_MODIFIERS); 375 data = xstrdup(ike->data); 376 data[strcspn(data, "_")] = '0' + j; 377 378 new = xcalloc(1, sizeof *new); 379 new->key = key|input_key_modifiers[j]; 380 new->data = data; 381 RB_INSERT(input_key_tree, &input_key_tree, new); 382 } 383 } 384 385 RB_FOREACH(ike, input_key_tree, &input_key_tree) { 386 log_debug("%s: 0x%llx (%s) is %s", __func__, ike->key, 387 key_string_lookup_key(ike->key, 1), ike->data); 388 } 389 } 390 391 /* Translate a key code into an output key sequence for a pane. */ 392 int 393 input_key_pane(struct window_pane *wp, key_code key, struct mouse_event *m) 394 { 395 if (log_get_level() != 0) { 396 log_debug("writing key 0x%llx (%s) to %%%u", key, 397 key_string_lookup_key(key, 1), wp->id); 398 } 399 400 if (KEYC_IS_MOUSE(key)) { 401 if (m != NULL && m->wp != -1 && (u_int)m->wp == wp->id) 402 input_key_mouse(wp, m); 403 return (0); 404 } 405 return (input_key(wp->screen, wp->event, key)); 406 } 407 408 static void 409 input_key_write(const char *from, struct bufferevent *bev, const char *data, 410 size_t size) 411 { 412 log_debug("%s: %.*s", from, (int)size, data); 413 bufferevent_write(bev, data, size); 414 } 415 416 /* 417 * Encode and write an extended key escape sequence in one of the two 418 * possible formats, depending on the configured output mode. 419 */ 420 static int 421 input_key_extended(struct bufferevent *bev, key_code key) 422 { 423 char tmp[64], modifier; 424 struct utf8_data ud; 425 wchar_t wc; 426 427 switch (key & KEYC_MASK_MODIFIERS) { 428 case KEYC_SHIFT: 429 modifier = '2'; 430 break; 431 case KEYC_META: 432 modifier = '3'; 433 break; 434 case KEYC_SHIFT|KEYC_META: 435 modifier = '4'; 436 break; 437 case KEYC_CTRL: 438 modifier = '5'; 439 break; 440 case KEYC_SHIFT|KEYC_CTRL: 441 modifier = '6'; 442 break; 443 case KEYC_META|KEYC_CTRL: 444 modifier = '7'; 445 break; 446 case KEYC_SHIFT|KEYC_META|KEYC_CTRL: 447 modifier = '8'; 448 break; 449 default: 450 return (-1); 451 } 452 453 if (KEYC_IS_UNICODE(key)) { 454 utf8_to_data(key & KEYC_MASK_KEY, &ud); 455 if (utf8_towc(&ud, &wc) == UTF8_DONE) 456 key = wc; 457 else 458 return (-1); 459 } else 460 key &= KEYC_MASK_KEY; 461 462 if (options_get_number(global_options, "extended-keys-format") == 1) 463 xsnprintf(tmp, sizeof tmp, "\033[27;%c;%llu~", modifier, key); 464 else 465 xsnprintf(tmp, sizeof tmp, "\033[%llu;%cu", key, modifier); 466 467 input_key_write(__func__, bev, tmp, strlen(tmp)); 468 return (0); 469 } 470 471 /* 472 * Outputs the key in the "standard" mode. This is by far the most 473 * complicated output mode, with a lot of remapping in order to 474 * emulate quirks of terminals that today can be only found in museums. 475 */ 476 static int 477 input_key_vt10x(struct bufferevent *bev, key_code key) 478 { 479 struct utf8_data ud; 480 key_code onlykey; 481 char *p; 482 static const char *standard_map[2] = { 483 "1!9(0)=+;:'\",<.>/-8? 2", 484 "119900=+;;'',,..\x1f\x1f\x7f\x7f\0\0", 485 }; 486 487 log_debug("%s: key in %llx", __func__, key); 488 489 if (key & KEYC_META) 490 input_key_write(__func__, bev, "\033", 1); 491 492 /* 493 * There's no way to report modifiers for unicode keys in standard mode 494 * so lose the modifiers. 495 */ 496 if (KEYC_IS_UNICODE(key)) { 497 utf8_to_data(key, &ud); 498 input_key_write(__func__, bev, ud.data, ud.size); 499 return (0); 500 } 501 502 /* 503 * Prevent TAB, CR and LF from being swallowed by the C0 remapping 504 * logic. 505 */ 506 onlykey = key & KEYC_MASK_KEY; 507 if (onlykey == '\r' || onlykey == '\n' || onlykey == '\t') 508 key &= ~KEYC_CTRL; 509 510 /* 511 * Convert keys with Ctrl modifier into corresponding C0 control codes, 512 * with the exception of *some* keys, which are remapped into printable 513 * ASCII characters. 514 * 515 * There is no special handling for Shift modifier, which is pretty 516 * much redundant anyway, as no terminal will send <base key>|SHIFT, 517 * but only <shifted key>|SHIFT. 518 */ 519 if (key & KEYC_CTRL) { 520 p = strchr(standard_map[0], onlykey); 521 if (p != NULL) 522 key = standard_map[1][p - standard_map[0]]; 523 else if (onlykey >= '3' && onlykey <= '7') 524 key = onlykey - '\030'; 525 else if (onlykey >= '@' && onlykey <= '~') 526 key = onlykey & 0x1f; 527 else 528 return (-1); 529 } 530 531 log_debug("%s: key out %llx", __func__, key); 532 533 ud.data[0] = key & 0x7f; 534 input_key_write(__func__, bev, &ud.data[0], 1); 535 return (0); 536 } 537 538 /* Pick keys that are reported as vt10x keys in modifyOtherKeys=1 mode. */ 539 static int 540 input_key_mode1(struct bufferevent *bev, key_code key) 541 { 542 key_code onlykey; 543 544 log_debug("%s: key in %llx", __func__, key); 545 546 /* A regular or shifted key + Meta. */ 547 if ((key & (KEYC_CTRL | KEYC_META)) == KEYC_META) 548 return (input_key_vt10x(bev, key)); 549 550 /* 551 * As per 552 * https://invisible-island.net/xterm/modified-keys-us-pc105.html. 553 */ 554 onlykey = key & KEYC_MASK_KEY; 555 if ((key & KEYC_CTRL) && 556 (onlykey == ' ' || 557 onlykey == '/' || 558 onlykey == '@' || 559 onlykey == '^' || 560 (onlykey >= '2' && onlykey <= '8') || 561 (onlykey >= '@' && onlykey <= '~'))) 562 return (input_key_vt10x(bev, key)); 563 564 return (-1); 565 } 566 567 /* Translate a key code into an output key sequence. */ 568 int 569 input_key(struct screen *s, struct bufferevent *bev, key_code key) 570 { 571 struct input_key_entry *ike = NULL; 572 key_code newkey; 573 struct utf8_data ud; 574 575 /* Mouse keys need a pane. */ 576 if (KEYC_IS_MOUSE(key)) 577 return (0); 578 579 /* Literal keys go as themselves (can't be more than eight bits). */ 580 if (key & KEYC_LITERAL) { 581 ud.data[0] = (u_char)key; 582 input_key_write(__func__, bev, &ud.data[0], 1); 583 return (0); 584 } 585 586 /* Is this backspace? */ 587 if ((key & KEYC_MASK_KEY) == KEYC_BSPACE) { 588 newkey = options_get_number(global_options, "backspace"); 589 log_debug("%s: key 0x%llx is backspace -> 0x%llx", __func__, 590 key, newkey); 591 if ((key & KEYC_MASK_MODIFIERS) == 0) { 592 ud.data[0] = 255; 593 if ((newkey & KEYC_MASK_MODIFIERS) == 0) 594 ud.data[0] = newkey; 595 else if ((newkey & KEYC_MASK_MODIFIERS) == KEYC_CTRL) { 596 newkey &= KEYC_MASK_KEY; 597 if (newkey >= 'A' && newkey <= 'Z') 598 ud.data[0] = newkey - 0x40; 599 else if (newkey >= 'a' && newkey <= 'z') 600 ud.data[0] = newkey - 0x60; 601 } 602 if (ud.data[0] != 255) 603 input_key_write(__func__, bev, &ud.data[0], 1); 604 return (0); 605 } 606 key = newkey|(key & (KEYC_MASK_FLAGS|KEYC_MASK_MODIFIERS)); 607 } 608 609 /* Is this backtab? */ 610 if ((key & KEYC_MASK_KEY) == KEYC_BTAB) { 611 if (s->mode & MODE_KEYS_EXTENDED_2) { 612 /* When in xterm extended mode, remap into S-Tab. */ 613 key = '\011' | (key & ~KEYC_MASK_KEY) | KEYC_SHIFT; 614 } else { 615 /* Otherwise clear modifiers. */ 616 key &= ~KEYC_MASK_MODIFIERS; 617 } 618 } 619 620 /* 621 * A trivial case, that is a 7-bit key, excluding C0 control characters 622 * that can't be entered from the keyboard, and no modifiers; or a UTF-8 623 * key and no modifiers. 624 */ 625 if (!(key & ~KEYC_MASK_KEY)) { 626 if (key == C0_HT || 627 key == C0_CR || 628 key == C0_ESC || 629 (key >= 0x20 && key <= 0x7f)) { 630 ud.data[0] = key; 631 input_key_write(__func__, bev, &ud.data[0], 1); 632 return (0); 633 } 634 if (KEYC_IS_UNICODE(key)) { 635 utf8_to_data(key, &ud); 636 input_key_write(__func__, bev, ud.data, ud.size); 637 return (0); 638 } 639 } 640 641 /* 642 * Look up the standard VT10x keys in the tree. If not in application 643 * keypad or cursor mode, remove the respective flags from the key. 644 */ 645 if (~s->mode & MODE_KKEYPAD) 646 key &= ~KEYC_KEYPAD; 647 if (~s->mode & MODE_KCURSOR) 648 key &= ~KEYC_CURSOR; 649 if (ike == NULL) 650 ike = input_key_get(key); 651 if (ike == NULL && (key & KEYC_META) && (~key & KEYC_IMPLIED_META)) 652 ike = input_key_get(key & ~KEYC_META); 653 if (ike == NULL && (key & KEYC_CURSOR)) 654 ike = input_key_get(key & ~KEYC_CURSOR); 655 if (ike == NULL && (key & KEYC_KEYPAD)) 656 ike = input_key_get(key & ~KEYC_KEYPAD); 657 if (ike != NULL) { 658 log_debug("%s: found key 0x%llx: \"%s\"", __func__, key, 659 ike->data); 660 if (KEYC_IS_PASTE(key) && (~s->mode & MODE_BRACKETPASTE)) 661 return (0); 662 if ((key & KEYC_META) && (~key & KEYC_IMPLIED_META)) 663 input_key_write(__func__, bev, "\033", 1); 664 input_key_write(__func__, bev, ike->data, strlen(ike->data)); 665 return (0); 666 } 667 668 /* Ignore internal function key codes. */ 669 if ((key >= KEYC_BASE && key < KEYC_BASE_END) || 670 (key >= KEYC_USER && key < KEYC_USER_END)) { 671 log_debug("%s: ignoring key 0x%llx", __func__, key); 672 return (0); 673 } 674 675 /* 676 * No builtin key sequence; construct an extended key sequence 677 * depending on the client mode. 678 * 679 * If something invalid reaches here, an invalid output may be 680 * produced. For example Ctrl-Shift-2 is invalid (as there's 681 * no way to enter it). The correct form is Ctrl-Shift-@, at 682 * least in US English keyboard layout. 683 */ 684 switch (s->mode & EXTENDED_KEY_MODES) { 685 case MODE_KEYS_EXTENDED_2: 686 /* 687 * The simplest mode to handle - *all* modified keys are 688 * reported in the extended form. 689 */ 690 return (input_key_extended(bev, key)); 691 case MODE_KEYS_EXTENDED: 692 /* 693 * Some keys are still reported in standard mode, to maintain 694 * compatibility with applications unaware of extended keys. 695 */ 696 if (input_key_mode1(bev, key) == -1) 697 return (input_key_extended(bev, key)); 698 return (0); 699 default: 700 /* The standard mode. */ 701 return (input_key_vt10x(bev, key)); 702 } 703 } 704 705 /* Get mouse event string. */ 706 int 707 input_key_get_mouse(struct screen *s, struct mouse_event *m, u_int x, u_int y, 708 const char **rbuf, size_t *rlen) 709 { 710 static char buf[40]; 711 size_t len; 712 713 *rbuf = NULL; 714 *rlen = 0; 715 716 /* If this pane is not in button or all mode, discard motion events. */ 717 if (MOUSE_DRAG(m->b) && (s->mode & MOTION_MOUSE_MODES) == 0) 718 return (0); 719 if ((s->mode & ALL_MOUSE_MODES) == 0) 720 return (0); 721 722 /* 723 * If this event is a release event and not in all mode, discard it. 724 * In SGR mode we can tell absolutely because a release is normally 725 * shown by the last character. Without SGR, we check if the last 726 * buttons was also a release. 727 */ 728 if (m->sgr_type != ' ') { 729 if (MOUSE_DRAG(m->sgr_b) && 730 MOUSE_RELEASE(m->sgr_b) && 731 (~s->mode & MODE_MOUSE_ALL)) 732 return (0); 733 } else { 734 if (MOUSE_DRAG(m->b) && 735 MOUSE_RELEASE(m->b) && 736 MOUSE_RELEASE(m->lb) && 737 (~s->mode & MODE_MOUSE_ALL)) 738 return (0); 739 } 740 741 /* 742 * Use the SGR (1006) extension only if the application requested it 743 * and the underlying terminal also sent the event in this format (this 744 * is because an old style mouse release event cannot be converted into 745 * the new SGR format, since the released button is unknown). Otherwise 746 * pretend that tmux doesn't speak this extension, and fall back to the 747 * UTF-8 (1005) extension if the application requested, or to the 748 * legacy format. 749 */ 750 if (m->sgr_type != ' ' && (s->mode & MODE_MOUSE_SGR)) { 751 len = xsnprintf(buf, sizeof buf, "\033[<%u;%u;%u%c", 752 m->sgr_b, x + 1, y + 1, m->sgr_type); 753 } else if (s->mode & MODE_MOUSE_UTF8) { 754 if (m->b > MOUSE_PARAM_UTF8_MAX - MOUSE_PARAM_BTN_OFF || 755 x > MOUSE_PARAM_UTF8_MAX - MOUSE_PARAM_POS_OFF || 756 y > MOUSE_PARAM_UTF8_MAX - MOUSE_PARAM_POS_OFF) 757 return (0); 758 len = xsnprintf(buf, sizeof buf, "\033[M"); 759 len += input_key_split2(m->b + MOUSE_PARAM_BTN_OFF, &buf[len]); 760 len += input_key_split2(x + MOUSE_PARAM_POS_OFF, &buf[len]); 761 len += input_key_split2(y + MOUSE_PARAM_POS_OFF, &buf[len]); 762 } else { 763 if (m->b + MOUSE_PARAM_BTN_OFF > MOUSE_PARAM_MAX) 764 return (0); 765 766 len = xsnprintf(buf, sizeof buf, "\033[M"); 767 buf[len++] = m->b + MOUSE_PARAM_BTN_OFF; 768 769 /* 770 * The incoming x and y may be out of the range which can be 771 * supported by the "normal" mouse protocol. Clamp the 772 * coordinates to the supported range. 773 */ 774 if (x + MOUSE_PARAM_POS_OFF > MOUSE_PARAM_MAX) 775 buf[len++] = MOUSE_PARAM_MAX; 776 else 777 buf[len++] = x + MOUSE_PARAM_POS_OFF; 778 if (y + MOUSE_PARAM_POS_OFF > MOUSE_PARAM_MAX) 779 buf[len++] = MOUSE_PARAM_MAX; 780 else 781 buf[len++] = y + MOUSE_PARAM_POS_OFF; 782 } 783 784 *rbuf = buf; 785 *rlen = len; 786 return (1); 787 } 788 789 /* Translate mouse and output. */ 790 static void 791 input_key_mouse(struct window_pane *wp, struct mouse_event *m) 792 { 793 struct screen *s = wp->screen; 794 u_int x, y; 795 const char *buf; 796 size_t len; 797 798 /* Ignore events if no mouse mode or the pane is not visible. */ 799 if (m->ignore || (s->mode & ALL_MOUSE_MODES) == 0) 800 return; 801 if (cmd_mouse_at(wp, m, &x, &y, 0) != 0) 802 return; 803 if (!window_pane_visible(wp)) 804 return; 805 if (!input_key_get_mouse(s, m, x, y, &buf, &len)) 806 return; 807 log_debug("writing mouse %.*s to %%%u", (int)len, buf, wp->id); 808 input_key_write(__func__, wp->event, buf, len); 809 } 810