1*2f106d38Snicm /* $OpenBSD: input-keys.c,v 1.107 2025/01/02 10:34:45 nicm Exp $ */ 2311827fbSnicm 3311827fbSnicm /* 498ca8272Snicm * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> 5311827fbSnicm * 6311827fbSnicm * Permission to use, copy, modify, and distribute this software for any 7311827fbSnicm * purpose with or without fee is hereby granted, provided that the above 8311827fbSnicm * copyright notice and this permission notice appear in all copies. 9311827fbSnicm * 10311827fbSnicm * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11311827fbSnicm * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12311827fbSnicm * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13311827fbSnicm * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14311827fbSnicm * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15311827fbSnicm * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16311827fbSnicm * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17311827fbSnicm */ 18311827fbSnicm 19311827fbSnicm #include <sys/types.h> 20311827fbSnicm 21311827fbSnicm #include <stdint.h> 22311827fbSnicm #include <stdlib.h> 23311827fbSnicm #include <string.h> 24311827fbSnicm 25311827fbSnicm #include "tmux.h" 26311827fbSnicm 279f8989e0Snicm /* 289f8989e0Snicm * This file is rather misleadingly named, it contains the code which takes a 299f8989e0Snicm * key code and translates it into something suitable to be sent to the 309f8989e0Snicm * application running in a pane (similar to input.c does in the other 319f8989e0Snicm * direction with output). 329f8989e0Snicm */ 339f8989e0Snicm 34413e5e52Snicm static void input_key_mouse(struct window_pane *, struct mouse_event *); 35e048bb79Snicm 369265d1acSnicm /* Entry in the key tree. */ 379265d1acSnicm struct input_key_entry { 38885a4698Snicm key_code key; 39311827fbSnicm const char *data; 40311827fbSnicm 419265d1acSnicm RB_ENTRY(input_key_entry) entry; 42311827fbSnicm }; 439265d1acSnicm RB_HEAD(input_key_tree, input_key_entry); 44311827fbSnicm 459265d1acSnicm /* Tree of input keys. */ 469265d1acSnicm static int input_key_cmp(struct input_key_entry *, 479265d1acSnicm struct input_key_entry *); 489265d1acSnicm RB_GENERATE_STATIC(input_key_tree, input_key_entry, entry, input_key_cmp); 499265d1acSnicm struct input_key_tree input_key_tree = RB_INITIALIZER(&input_key_tree); 509265d1acSnicm 519265d1acSnicm /* List of default keys, the tree is built from this. */ 529265d1acSnicm static struct input_key_entry input_key_defaults[] = { 53b99601f2Snicm /* Paste keys. */ 549265d1acSnicm { .key = KEYC_PASTE_START, 559265d1acSnicm .data = "\033[200~" 569265d1acSnicm }, 579265d1acSnicm { .key = KEYC_PASTE_END, 589265d1acSnicm .data = "\033[201~" 599265d1acSnicm }, 60b99601f2Snicm 61311827fbSnicm /* Function keys. */ 629265d1acSnicm { .key = KEYC_F1, 639265d1acSnicm .data = "\033OP" 649265d1acSnicm }, 659265d1acSnicm { .key = KEYC_F2, 669265d1acSnicm .data = "\033OQ" 679265d1acSnicm }, 689265d1acSnicm { .key = KEYC_F3, 699265d1acSnicm .data = "\033OR" 709265d1acSnicm }, 719265d1acSnicm { .key = KEYC_F4, 729265d1acSnicm .data = "\033OS" 739265d1acSnicm }, 749265d1acSnicm { .key = KEYC_F5, 759265d1acSnicm .data = "\033[15~" 769265d1acSnicm }, 779265d1acSnicm { .key = KEYC_F6, 789265d1acSnicm .data = "\033[17~" 799265d1acSnicm }, 809265d1acSnicm { .key = KEYC_F7, 819265d1acSnicm .data = "\033[18~" 829265d1acSnicm }, 839265d1acSnicm { .key = KEYC_F8, 849265d1acSnicm .data = "\033[19~" 859265d1acSnicm }, 869265d1acSnicm { .key = KEYC_F9, 879265d1acSnicm .data = "\033[20~" 889265d1acSnicm }, 899265d1acSnicm { .key = KEYC_F10, 909265d1acSnicm .data = "\033[21~" 919265d1acSnicm }, 929265d1acSnicm { .key = KEYC_F11, 939265d1acSnicm .data = "\033[23~" 949265d1acSnicm }, 959265d1acSnicm { .key = KEYC_F12, 969265d1acSnicm .data = "\033[24~" 979265d1acSnicm }, 989265d1acSnicm { .key = KEYC_IC, 999265d1acSnicm .data = "\033[2~" 1009265d1acSnicm }, 1019265d1acSnicm { .key = KEYC_DC, 1029265d1acSnicm .data = "\033[3~" 1039265d1acSnicm }, 1049265d1acSnicm { .key = KEYC_HOME, 1059265d1acSnicm .data = "\033[1~" 1069265d1acSnicm }, 1079265d1acSnicm { .key = KEYC_END, 1089265d1acSnicm .data = "\033[4~" 1099265d1acSnicm }, 1109265d1acSnicm { .key = KEYC_NPAGE, 1119265d1acSnicm .data = "\033[6~" 1129265d1acSnicm }, 1139265d1acSnicm { .key = KEYC_PPAGE, 1149265d1acSnicm .data = "\033[5~" 1159265d1acSnicm }, 1169265d1acSnicm { .key = KEYC_BTAB, 1179265d1acSnicm .data = "\033[Z" 1189265d1acSnicm }, 119311827fbSnicm 1209265d1acSnicm /* Arrow keys. */ 1219265d1acSnicm { .key = KEYC_UP|KEYC_CURSOR, 1229265d1acSnicm .data = "\033OA" 1239265d1acSnicm }, 1249265d1acSnicm { .key = KEYC_DOWN|KEYC_CURSOR, 1259265d1acSnicm .data = "\033OB" 1269265d1acSnicm }, 1279265d1acSnicm { .key = KEYC_RIGHT|KEYC_CURSOR, 1289265d1acSnicm .data = "\033OC" 1299265d1acSnicm }, 1309265d1acSnicm { .key = KEYC_LEFT|KEYC_CURSOR, 1319265d1acSnicm .data = "\033OD" 1329265d1acSnicm }, 1339265d1acSnicm { .key = KEYC_UP, 1349265d1acSnicm .data = "\033[A" 1359265d1acSnicm }, 1369265d1acSnicm { .key = KEYC_DOWN, 1379265d1acSnicm .data = "\033[B" 1389265d1acSnicm }, 1399265d1acSnicm { .key = KEYC_RIGHT, 1409265d1acSnicm .data = "\033[C" 1419265d1acSnicm }, 1429265d1acSnicm { .key = KEYC_LEFT, 1439265d1acSnicm .data = "\033[D" 1449265d1acSnicm }, 145ceb8a03dSnicm 1469265d1acSnicm /* Keypad keys. */ 1479265d1acSnicm { .key = KEYC_KP_SLASH|KEYC_KEYPAD, 1489265d1acSnicm .data = "\033Oo" 1499265d1acSnicm }, 1509265d1acSnicm { .key = KEYC_KP_STAR|KEYC_KEYPAD, 1519265d1acSnicm .data = "\033Oj" 1529265d1acSnicm }, 1539265d1acSnicm { .key = KEYC_KP_MINUS|KEYC_KEYPAD, 1549265d1acSnicm .data = "\033Om" 1559265d1acSnicm }, 1569265d1acSnicm { .key = KEYC_KP_SEVEN|KEYC_KEYPAD, 1579265d1acSnicm .data = "\033Ow" 1589265d1acSnicm }, 1599265d1acSnicm { .key = KEYC_KP_EIGHT|KEYC_KEYPAD, 1609265d1acSnicm .data = "\033Ox" 1619265d1acSnicm }, 1629265d1acSnicm { .key = KEYC_KP_NINE|KEYC_KEYPAD, 1639265d1acSnicm .data = "\033Oy" 1649265d1acSnicm }, 1659265d1acSnicm { .key = KEYC_KP_PLUS|KEYC_KEYPAD, 1669265d1acSnicm .data = "\033Ok" 1679265d1acSnicm }, 1689265d1acSnicm { .key = KEYC_KP_FOUR|KEYC_KEYPAD, 1699265d1acSnicm .data = "\033Ot" 1709265d1acSnicm }, 1719265d1acSnicm { .key = KEYC_KP_FIVE|KEYC_KEYPAD, 1729265d1acSnicm .data = "\033Ou" 1739265d1acSnicm }, 1749265d1acSnicm { .key = KEYC_KP_SIX|KEYC_KEYPAD, 1759265d1acSnicm .data = "\033Ov" 1769265d1acSnicm }, 1779265d1acSnicm { .key = KEYC_KP_ONE|KEYC_KEYPAD, 1789265d1acSnicm .data = "\033Oq" 1799265d1acSnicm }, 1809265d1acSnicm { .key = KEYC_KP_TWO|KEYC_KEYPAD, 1819265d1acSnicm .data = "\033Or" 1829265d1acSnicm }, 1839265d1acSnicm { .key = KEYC_KP_THREE|KEYC_KEYPAD, 1849265d1acSnicm .data = "\033Os" 1859265d1acSnicm }, 1869265d1acSnicm { .key = KEYC_KP_ENTER|KEYC_KEYPAD, 1879265d1acSnicm .data = "\033OM" 1889265d1acSnicm }, 1899265d1acSnicm { .key = KEYC_KP_ZERO|KEYC_KEYPAD, 1909265d1acSnicm .data = "\033Op" 1919265d1acSnicm }, 1929265d1acSnicm { .key = KEYC_KP_PERIOD|KEYC_KEYPAD, 1939265d1acSnicm .data = "\033On" 1949265d1acSnicm }, 1959265d1acSnicm { .key = KEYC_KP_SLASH, 1969265d1acSnicm .data = "/" 1979265d1acSnicm }, 1989265d1acSnicm { .key = KEYC_KP_STAR, 1999265d1acSnicm .data = "*" 2009265d1acSnicm }, 2019265d1acSnicm { .key = KEYC_KP_MINUS, 2029265d1acSnicm .data = "-" 2039265d1acSnicm }, 2049265d1acSnicm { .key = KEYC_KP_SEVEN, 2059265d1acSnicm .data = "7" 2069265d1acSnicm }, 2079265d1acSnicm { .key = KEYC_KP_EIGHT, 2089265d1acSnicm .data = "8" 2099265d1acSnicm }, 2109265d1acSnicm { .key = KEYC_KP_NINE, 2119265d1acSnicm .data = "9" 2129265d1acSnicm }, 2139265d1acSnicm { .key = KEYC_KP_PLUS, 2149265d1acSnicm .data = "+" 2159265d1acSnicm }, 2169265d1acSnicm { .key = KEYC_KP_FOUR, 2179265d1acSnicm .data = "4" 2189265d1acSnicm }, 2199265d1acSnicm { .key = KEYC_KP_FIVE, 2209265d1acSnicm .data = "5" 2219265d1acSnicm }, 2229265d1acSnicm { .key = KEYC_KP_SIX, 2239265d1acSnicm .data = "6" 2249265d1acSnicm }, 2259265d1acSnicm { .key = KEYC_KP_ONE, 2269265d1acSnicm .data = "1" 2279265d1acSnicm }, 2289265d1acSnicm { .key = KEYC_KP_TWO, 2299265d1acSnicm .data = "2" 2309265d1acSnicm }, 2319265d1acSnicm { .key = KEYC_KP_THREE, 2329265d1acSnicm .data = "3" 2339265d1acSnicm }, 2349265d1acSnicm { .key = KEYC_KP_ENTER, 2359265d1acSnicm .data = "\n" 2369265d1acSnicm }, 2379265d1acSnicm { .key = KEYC_KP_ZERO, 2389265d1acSnicm .data = "0" 2399265d1acSnicm }, 2409265d1acSnicm { .key = KEYC_KP_PERIOD, 2419265d1acSnicm .data = "." 2429265d1acSnicm }, 243311827fbSnicm 2449265d1acSnicm /* Keys with an embedded modifier. */ 2455416581eSnicm { .key = KEYC_F1|KEYC_BUILD_MODIFIERS, 2469265d1acSnicm .data = "\033[1;_P" 2479265d1acSnicm }, 2485416581eSnicm { .key = KEYC_F2|KEYC_BUILD_MODIFIERS, 2499265d1acSnicm .data = "\033[1;_Q" 2509265d1acSnicm }, 2515416581eSnicm { .key = KEYC_F3|KEYC_BUILD_MODIFIERS, 2529265d1acSnicm .data = "\033[1;_R" 2539265d1acSnicm }, 2545416581eSnicm { .key = KEYC_F4|KEYC_BUILD_MODIFIERS, 2559265d1acSnicm .data = "\033[1;_S" 2569265d1acSnicm }, 2575416581eSnicm { .key = KEYC_F5|KEYC_BUILD_MODIFIERS, 2589265d1acSnicm .data = "\033[15;_~" 2599265d1acSnicm }, 2605416581eSnicm { .key = KEYC_F6|KEYC_BUILD_MODIFIERS, 2619265d1acSnicm .data = "\033[17;_~" 2629265d1acSnicm }, 2635416581eSnicm { .key = KEYC_F7|KEYC_BUILD_MODIFIERS, 2649265d1acSnicm .data = "\033[18;_~" 2659265d1acSnicm }, 2665416581eSnicm { .key = KEYC_F8|KEYC_BUILD_MODIFIERS, 2679265d1acSnicm .data = "\033[19;_~" 2689265d1acSnicm }, 2695416581eSnicm { .key = KEYC_F9|KEYC_BUILD_MODIFIERS, 2709265d1acSnicm .data = "\033[20;_~" 2719265d1acSnicm }, 2725416581eSnicm { .key = KEYC_F10|KEYC_BUILD_MODIFIERS, 2739265d1acSnicm .data = "\033[21;_~" 2749265d1acSnicm }, 2755416581eSnicm { .key = KEYC_F11|KEYC_BUILD_MODIFIERS, 2769265d1acSnicm .data = "\033[23;_~" 2779265d1acSnicm }, 2785416581eSnicm { .key = KEYC_F12|KEYC_BUILD_MODIFIERS, 2799265d1acSnicm .data = "\033[24;_~" 2809265d1acSnicm }, 2815416581eSnicm { .key = KEYC_UP|KEYC_BUILD_MODIFIERS, 2829265d1acSnicm .data = "\033[1;_A" 2839265d1acSnicm }, 2845416581eSnicm { .key = KEYC_DOWN|KEYC_BUILD_MODIFIERS, 2859265d1acSnicm .data = "\033[1;_B" 2869265d1acSnicm }, 2875416581eSnicm { .key = KEYC_RIGHT|KEYC_BUILD_MODIFIERS, 2889265d1acSnicm .data = "\033[1;_C" 2899265d1acSnicm }, 2905416581eSnicm { .key = KEYC_LEFT|KEYC_BUILD_MODIFIERS, 2919265d1acSnicm .data = "\033[1;_D" 2929265d1acSnicm }, 2935416581eSnicm { .key = KEYC_HOME|KEYC_BUILD_MODIFIERS, 2949265d1acSnicm .data = "\033[1;_H" 2959265d1acSnicm }, 2965416581eSnicm { .key = KEYC_END|KEYC_BUILD_MODIFIERS, 2979265d1acSnicm .data = "\033[1;_F" 2989265d1acSnicm }, 2995416581eSnicm { .key = KEYC_PPAGE|KEYC_BUILD_MODIFIERS, 3009265d1acSnicm .data = "\033[5;_~" 3019265d1acSnicm }, 3025416581eSnicm { .key = KEYC_NPAGE|KEYC_BUILD_MODIFIERS, 3039265d1acSnicm .data = "\033[6;_~" 3049265d1acSnicm }, 3055416581eSnicm { .key = KEYC_IC|KEYC_BUILD_MODIFIERS, 3069265d1acSnicm .data = "\033[2;_~" 3079265d1acSnicm }, 3085416581eSnicm { .key = KEYC_DC|KEYC_BUILD_MODIFIERS, 309dce21a56Snicm .data = "\033[3;_~" 3103c4ca0e6Snicm }, 311311827fbSnicm }; 3129265d1acSnicm static const key_code input_key_modifiers[] = { 3139265d1acSnicm 0, 3149265d1acSnicm 0, 3155416581eSnicm KEYC_SHIFT, 3165416581eSnicm KEYC_META|KEYC_IMPLIED_META, 3175416581eSnicm KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META, 3185416581eSnicm KEYC_CTRL, 3195416581eSnicm KEYC_SHIFT|KEYC_CTRL, 3205416581eSnicm KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL, 3215416581eSnicm KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL 3229265d1acSnicm }; 3239265d1acSnicm 3249265d1acSnicm /* Input key comparison function. */ 3259265d1acSnicm static int 3269265d1acSnicm input_key_cmp(struct input_key_entry *ike1, struct input_key_entry *ike2) 3279265d1acSnicm { 3289265d1acSnicm if (ike1->key < ike2->key) 3299265d1acSnicm return (-1); 3309265d1acSnicm if (ike1->key > ike2->key) 3319265d1acSnicm return (1); 3329265d1acSnicm return (0); 3339265d1acSnicm } 334311827fbSnicm 3355416581eSnicm /* Look for key in tree. */ 3365416581eSnicm static struct input_key_entry * 3375416581eSnicm input_key_get(key_code key) 3385416581eSnicm { 3395416581eSnicm struct input_key_entry entry = { .key = key }; 3405416581eSnicm 3415416581eSnicm return (RB_FIND(input_key_tree, &input_key_tree, &entry)); 3425416581eSnicm } 3435416581eSnicm 344f5015ed6Snicm /* Split a character into two UTF-8 bytes. */ 345f5015ed6Snicm static size_t 3469265d1acSnicm input_key_split2(u_int c, u_char *dst) 347f5015ed6Snicm { 348f5015ed6Snicm if (c > 0x7f) { 349f5015ed6Snicm dst[0] = (c >> 6) | 0xc0; 350f5015ed6Snicm dst[1] = (c & 0x3f) | 0x80; 351f5015ed6Snicm return (2); 352f5015ed6Snicm } 353f5015ed6Snicm dst[0] = c; 354f5015ed6Snicm return (1); 355f5015ed6Snicm } 356f5015ed6Snicm 3579265d1acSnicm /* Build input key tree. */ 3589265d1acSnicm void 3599265d1acSnicm input_key_build(void) 3609265d1acSnicm { 3619265d1acSnicm struct input_key_entry *ike, *new; 3629265d1acSnicm u_int i, j; 3639265d1acSnicm char *data; 3645416581eSnicm key_code key; 3659265d1acSnicm 3669265d1acSnicm for (i = 0; i < nitems(input_key_defaults); i++) { 3679265d1acSnicm ike = &input_key_defaults[i]; 3685416581eSnicm if (~ike->key & KEYC_BUILD_MODIFIERS) { 3699265d1acSnicm RB_INSERT(input_key_tree, &input_key_tree, ike); 3709265d1acSnicm continue; 3719265d1acSnicm } 3729265d1acSnicm 3739265d1acSnicm for (j = 2; j < nitems(input_key_modifiers); j++) { 3745416581eSnicm key = (ike->key & ~KEYC_BUILD_MODIFIERS); 3759265d1acSnicm data = xstrdup(ike->data); 3769265d1acSnicm data[strcspn(data, "_")] = '0' + j; 3779265d1acSnicm 3789265d1acSnicm new = xcalloc(1, sizeof *new); 3795416581eSnicm new->key = key|input_key_modifiers[j]; 3809265d1acSnicm new->data = data; 3819265d1acSnicm RB_INSERT(input_key_tree, &input_key_tree, new); 3829265d1acSnicm } 3839265d1acSnicm } 3849265d1acSnicm 3859265d1acSnicm RB_FOREACH(ike, input_key_tree, &input_key_tree) { 3869265d1acSnicm log_debug("%s: 0x%llx (%s) is %s", __func__, ike->key, 3875416581eSnicm key_string_lookup_key(ike->key, 1), ike->data); 3889265d1acSnicm } 3899265d1acSnicm } 3909265d1acSnicm 39129ebed37Snicm /* Translate a key code into an output key sequence for a pane. */ 39229ebed37Snicm int 39329ebed37Snicm input_key_pane(struct window_pane *wp, key_code key, struct mouse_event *m) 39429ebed37Snicm { 3959265d1acSnicm if (log_get_level() != 0) { 39629ebed37Snicm log_debug("writing key 0x%llx (%s) to %%%u", key, 3975416581eSnicm key_string_lookup_key(key, 1), wp->id); 3989265d1acSnicm } 39929ebed37Snicm 40029ebed37Snicm if (KEYC_IS_MOUSE(key)) { 40129ebed37Snicm if (m != NULL && m->wp != -1 && (u_int)m->wp == wp->id) 40229ebed37Snicm input_key_mouse(wp, m); 40329ebed37Snicm return (0); 40429ebed37Snicm } 4059265d1acSnicm return (input_key(wp->screen, wp->event, key)); 40629ebed37Snicm } 40729ebed37Snicm 408090e14efSnicm static void 409be6be6edSnicm input_key_write(const char *from, struct bufferevent *bev, const char *data, 410090e14efSnicm size_t size) 411090e14efSnicm { 412090e14efSnicm log_debug("%s: %.*s", from, (int)size, data); 413090e14efSnicm bufferevent_write(bev, data, size); 414090e14efSnicm } 415090e14efSnicm 416719f5715Snicm /* 417719f5715Snicm * Encode and write an extended key escape sequence in one of the two 418719f5715Snicm * possible formats, depending on the configured output mode. 419719f5715Snicm */ 420719f5715Snicm static int 421719f5715Snicm input_key_extended(struct bufferevent *bev, key_code key) 422311827fbSnicm { 423a16e511eSnicm char tmp[64], modifier; 424719f5715Snicm struct utf8_data ud; 425719f5715Snicm wchar_t wc; 426311827fbSnicm 427719f5715Snicm switch (key & KEYC_MASK_MODIFIERS) { 428a16e511eSnicm case KEYC_SHIFT: 429a16e511eSnicm modifier = '2'; 430a16e511eSnicm break; 431a16e511eSnicm case KEYC_META: 432a16e511eSnicm modifier = '3'; 433a16e511eSnicm break; 434a16e511eSnicm case KEYC_SHIFT|KEYC_META: 435a16e511eSnicm modifier = '4'; 436a16e511eSnicm break; 437a16e511eSnicm case KEYC_CTRL: 438a16e511eSnicm modifier = '5'; 439a16e511eSnicm break; 440a16e511eSnicm case KEYC_SHIFT|KEYC_CTRL: 441a16e511eSnicm modifier = '6'; 442a16e511eSnicm break; 443a16e511eSnicm case KEYC_META|KEYC_CTRL: 444a16e511eSnicm modifier = '7'; 445a16e511eSnicm break; 446a16e511eSnicm case KEYC_SHIFT|KEYC_META|KEYC_CTRL: 447a16e511eSnicm modifier = '8'; 448a16e511eSnicm break; 449cf415eadSnicm default: 450719f5715Snicm return (-1); 451a16e511eSnicm } 452719f5715Snicm 453719f5715Snicm if (KEYC_IS_UNICODE(key)) { 454719f5715Snicm utf8_to_data(key & KEYC_MASK_KEY, &ud); 455719f5715Snicm if (utf8_towc(&ud, &wc) == UTF8_DONE) 456719f5715Snicm key = wc; 457719f5715Snicm else 458719f5715Snicm return (-1); 459719f5715Snicm } else 460719f5715Snicm key &= KEYC_MASK_KEY; 461719f5715Snicm 462719f5715Snicm if (options_get_number(global_options, "extended-keys-format") == 1) 463719f5715Snicm xsnprintf(tmp, sizeof tmp, "\033[27;%c;%llu~", modifier, key); 464719f5715Snicm else 465719f5715Snicm xsnprintf(tmp, sizeof tmp, "\033[%llu;%cu", key, modifier); 466719f5715Snicm 467090e14efSnicm input_key_write(__func__, bev, tmp, strlen(tmp)); 468a16e511eSnicm return (0); 469719f5715Snicm } 470a16e511eSnicm 471719f5715Snicm /* 472719f5715Snicm * Outputs the key in the "standard" mode. This is by far the most 473719f5715Snicm * complicated output mode, with a lot of remapping in order to 474719f5715Snicm * emulate quirks of terminals that today can be only found in museums. 475719f5715Snicm */ 476719f5715Snicm static int 477719f5715Snicm input_key_vt10x(struct bufferevent *bev, key_code key) 478719f5715Snicm { 479719f5715Snicm struct utf8_data ud; 480719f5715Snicm key_code onlykey; 481719f5715Snicm char *p; 482719f5715Snicm static const char *standard_map[2] = { 483719f5715Snicm "1!9(0)=+;:'\",<.>/-8? 2", 484719f5715Snicm "119900=+;;'',,..\x1f\x1f\x7f\x7f\0\0", 485719f5715Snicm }; 486719f5715Snicm 487719f5715Snicm log_debug("%s: key in %llx", __func__, key); 488719f5715Snicm 489719f5715Snicm if (key & KEYC_META) 490719f5715Snicm input_key_write(__func__, bev, "\033", 1); 491719f5715Snicm 492719f5715Snicm /* 493719f5715Snicm * There's no way to report modifiers for unicode keys in standard mode 494719f5715Snicm * so lose the modifiers. 495719f5715Snicm */ 496719f5715Snicm if (KEYC_IS_UNICODE(key)) { 497719f5715Snicm utf8_to_data(key, &ud); 498719f5715Snicm input_key_write(__func__, bev, ud.data, ud.size); 499719f5715Snicm return (0); 500719f5715Snicm } 501719f5715Snicm 502482624f4Snicm /* 503482624f4Snicm * Prevent TAB, CR and LF from being swallowed by the C0 remapping 504482624f4Snicm * logic. 505482624f4Snicm */ 5063be60a96Snicm onlykey = key & KEYC_MASK_KEY; 507482624f4Snicm if (onlykey == '\r' || onlykey == '\n' || onlykey == '\t') 508719f5715Snicm key &= ~KEYC_CTRL; 509719f5715Snicm 510719f5715Snicm /* 511719f5715Snicm * Convert keys with Ctrl modifier into corresponding C0 control codes, 512719f5715Snicm * with the exception of *some* keys, which are remapped into printable 513719f5715Snicm * ASCII characters. 514719f5715Snicm * 515719f5715Snicm * There is no special handling for Shift modifier, which is pretty 516719f5715Snicm * much redundant anyway, as no terminal will send <base key>|SHIFT, 517719f5715Snicm * but only <shifted key>|SHIFT. 518719f5715Snicm */ 519719f5715Snicm if (key & KEYC_CTRL) { 520719f5715Snicm p = strchr(standard_map[0], onlykey); 521719f5715Snicm if (p != NULL) 522719f5715Snicm key = standard_map[1][p - standard_map[0]]; 523719f5715Snicm else if (onlykey >= '3' && onlykey <= '7') 524719f5715Snicm key = onlykey - '\030'; 525719f5715Snicm else if (onlykey >= '@' && onlykey <= '~') 526719f5715Snicm key = onlykey & 0x1f; 527719f5715Snicm else 528a16e511eSnicm return (-1); 529a16e511eSnicm } 530a16e511eSnicm 531719f5715Snicm log_debug("%s: key out %llx", __func__, key); 532719f5715Snicm 533719f5715Snicm ud.data[0] = key & 0x7f; 534719f5715Snicm input_key_write(__func__, bev, &ud.data[0], 1); 535719f5715Snicm return (0); 536719f5715Snicm } 537719f5715Snicm 538719f5715Snicm /* Pick keys that are reported as vt10x keys in modifyOtherKeys=1 mode. */ 539719f5715Snicm static int 540719f5715Snicm input_key_mode1(struct bufferevent *bev, key_code key) 541719f5715Snicm { 542719f5715Snicm key_code onlykey; 543719f5715Snicm 544719f5715Snicm log_debug("%s: key in %llx", __func__, key); 545719f5715Snicm 546429aa45eSnicm /* A regular or shifted key + Meta. */ 547429aa45eSnicm if ((key & (KEYC_CTRL | KEYC_META)) == KEYC_META) 548429aa45eSnicm return (input_key_vt10x(bev, key)); 549429aa45eSnicm 550719f5715Snicm /* 551719f5715Snicm * As per 552719f5715Snicm * https://invisible-island.net/xterm/modified-keys-us-pc105.html. 553719f5715Snicm */ 554719f5715Snicm onlykey = key & KEYC_MASK_KEY; 555429aa45eSnicm if ((key & KEYC_CTRL) && 556de3e4ea1Snicm (onlykey == ' ' || 557de3e4ea1Snicm onlykey == '/' || 558de3e4ea1Snicm onlykey == '@' || 559de3e4ea1Snicm onlykey == '^' || 560719f5715Snicm (onlykey >= '2' && onlykey <= '8') || 561719f5715Snicm (onlykey >= '@' && onlykey <= '~'))) 562719f5715Snicm return (input_key_vt10x(bev, key)); 563719f5715Snicm 564719f5715Snicm return (-1); 565719f5715Snicm } 566719f5715Snicm 567719f5715Snicm /* Translate a key code into an output key sequence. */ 568719f5715Snicm int 569719f5715Snicm input_key(struct screen *s, struct bufferevent *bev, key_code key) 570719f5715Snicm { 571719f5715Snicm struct input_key_entry *ike = NULL; 572719f5715Snicm key_code newkey; 573719f5715Snicm struct utf8_data ud; 574719f5715Snicm 575719f5715Snicm /* Mouse keys need a pane. */ 576719f5715Snicm if (KEYC_IS_MOUSE(key)) 577719f5715Snicm return (0); 578719f5715Snicm 579719f5715Snicm /* Literal keys go as themselves (can't be more than eight bits). */ 580719f5715Snicm if (key & KEYC_LITERAL) { 581719f5715Snicm ud.data[0] = (u_char)key; 582719f5715Snicm input_key_write(__func__, bev, &ud.data[0], 1); 583719f5715Snicm return (0); 584719f5715Snicm } 585719f5715Snicm 586719f5715Snicm /* Is this backspace? */ 587719f5715Snicm if ((key & KEYC_MASK_KEY) == KEYC_BSPACE) { 588719f5715Snicm newkey = options_get_number(global_options, "backspace"); 589*2f106d38Snicm log_debug("%s: key 0x%llx is backspace -> 0x%llx", __func__, 590*2f106d38Snicm key, newkey); 591*2f106d38Snicm if ((key & KEYC_MASK_MODIFIERS) == 0) { 592*2f106d38Snicm ud.data[0] = 255; 593*2f106d38Snicm if ((newkey & KEYC_MASK_MODIFIERS) == 0) 594*2f106d38Snicm ud.data[0] = newkey; 595*2f106d38Snicm else if ((newkey & KEYC_MASK_MODIFIERS) == KEYC_CTRL) { 596*2f106d38Snicm newkey &= KEYC_MASK_KEY; 597*2f106d38Snicm if (newkey >= 'A' && newkey <= 'Z') 598*2f106d38Snicm ud.data[0] = newkey - 0x40; 599*2f106d38Snicm else if (newkey >= 'a' && newkey <= 'z') 600*2f106d38Snicm ud.data[0] = newkey - 0x60; 601*2f106d38Snicm } 602*2f106d38Snicm if (ud.data[0] != 255) 603*2f106d38Snicm input_key_write(__func__, bev, &ud.data[0], 1); 604*2f106d38Snicm return (0); 605*2f106d38Snicm } 606*2f106d38Snicm key = newkey|(key & (KEYC_MASK_FLAGS|KEYC_MASK_MODIFIERS)); 607719f5715Snicm } 608719f5715Snicm 609719f5715Snicm /* Is this backtab? */ 610719f5715Snicm if ((key & KEYC_MASK_KEY) == KEYC_BTAB) { 6119e4e6261Snicm if (s->mode & MODE_KEYS_EXTENDED_2) { 612719f5715Snicm /* When in xterm extended mode, remap into S-Tab. */ 613719f5715Snicm key = '\011' | (key & ~KEYC_MASK_KEY) | KEYC_SHIFT; 614719f5715Snicm } else { 615719f5715Snicm /* Otherwise clear modifiers. */ 616719f5715Snicm key &= ~KEYC_MASK_MODIFIERS; 617719f5715Snicm } 618719f5715Snicm } 619719f5715Snicm 620719f5715Snicm /* 621719f5715Snicm * A trivial case, that is a 7-bit key, excluding C0 control characters 622719f5715Snicm * that can't be entered from the keyboard, and no modifiers; or a UTF-8 623719f5715Snicm * key and no modifiers. 624719f5715Snicm */ 625719f5715Snicm if (!(key & ~KEYC_MASK_KEY)) { 6264aaf2c8dSnicm if (key == C0_HT || 6274aaf2c8dSnicm key == C0_CR || 6284aaf2c8dSnicm key == C0_ESC || 629719f5715Snicm (key >= 0x20 && key <= 0x7f)) { 630719f5715Snicm ud.data[0] = key; 631719f5715Snicm input_key_write(__func__, bev, &ud.data[0], 1); 632719f5715Snicm return (0); 633719f5715Snicm } 634719f5715Snicm if (KEYC_IS_UNICODE(key)) { 635719f5715Snicm utf8_to_data(key, &ud); 636719f5715Snicm input_key_write(__func__, bev, ud.data, ud.size); 637719f5715Snicm return (0); 638719f5715Snicm } 639719f5715Snicm } 640719f5715Snicm 641719f5715Snicm /* 642719f5715Snicm * Look up the standard VT10x keys in the tree. If not in application 643719f5715Snicm * keypad or cursor mode, remove the respective flags from the key. 644719f5715Snicm */ 645719f5715Snicm if (~s->mode & MODE_KKEYPAD) 646719f5715Snicm key &= ~KEYC_KEYPAD; 647719f5715Snicm if (~s->mode & MODE_KCURSOR) 648719f5715Snicm key &= ~KEYC_CURSOR; 649719f5715Snicm if (ike == NULL) 650719f5715Snicm ike = input_key_get(key); 651719f5715Snicm if (ike == NULL && (key & KEYC_META) && (~key & KEYC_IMPLIED_META)) 652719f5715Snicm ike = input_key_get(key & ~KEYC_META); 653719f5715Snicm if (ike == NULL && (key & KEYC_CURSOR)) 654719f5715Snicm ike = input_key_get(key & ~KEYC_CURSOR); 655719f5715Snicm if (ike == NULL && (key & KEYC_KEYPAD)) 656719f5715Snicm ike = input_key_get(key & ~KEYC_KEYPAD); 657719f5715Snicm if (ike != NULL) { 658719f5715Snicm log_debug("%s: found key 0x%llx: \"%s\"", __func__, key, 659719f5715Snicm ike->data); 660a1f482feSnicm if (KEYC_IS_PASTE(key) && (~s->mode & MODE_BRACKETPASTE)) 661719f5715Snicm return (0); 662719f5715Snicm if ((key & KEYC_META) && (~key & KEYC_IMPLIED_META)) 663719f5715Snicm input_key_write(__func__, bev, "\033", 1); 664719f5715Snicm input_key_write(__func__, bev, ike->data, strlen(ike->data)); 665719f5715Snicm return (0); 666719f5715Snicm } 667719f5715Snicm 6683be60a96Snicm /* Ignore internal function key codes. */ 6693be60a96Snicm if ((key >= KEYC_BASE && key < KEYC_BASE_END) || 6703be60a96Snicm (key >= KEYC_USER && key < KEYC_USER_END)) { 6713be60a96Snicm log_debug("%s: ignoring key 0x%llx", __func__, key); 6723be60a96Snicm return (0); 6733be60a96Snicm } 6743be60a96Snicm 675719f5715Snicm /* 676719f5715Snicm * No builtin key sequence; construct an extended key sequence 677719f5715Snicm * depending on the client mode. 678719f5715Snicm * 679719f5715Snicm * If something invalid reaches here, an invalid output may be 680719f5715Snicm * produced. For example Ctrl-Shift-2 is invalid (as there's 681719f5715Snicm * no way to enter it). The correct form is Ctrl-Shift-@, at 682719f5715Snicm * least in US English keyboard layout. 683719f5715Snicm */ 684719f5715Snicm switch (s->mode & EXTENDED_KEY_MODES) { 685719f5715Snicm case MODE_KEYS_EXTENDED_2: 686719f5715Snicm /* 687719f5715Snicm * The simplest mode to handle - *all* modified keys are 688719f5715Snicm * reported in the extended form. 689719f5715Snicm */ 690719f5715Snicm return (input_key_extended(bev, key)); 691719f5715Snicm case MODE_KEYS_EXTENDED: 692719f5715Snicm /* 693719f5715Snicm * Some keys are still reported in standard mode, to maintain 694719f5715Snicm * compatibility with applications unaware of extended keys. 695719f5715Snicm */ 696719f5715Snicm if (input_key_mode1(bev, key) == -1) 697719f5715Snicm return (input_key_extended(bev, key)); 698719f5715Snicm return (0); 699719f5715Snicm default: 700719f5715Snicm /* The standard mode. */ 701719f5715Snicm return (input_key_vt10x(bev, key)); 702719f5715Snicm } 703719f5715Snicm } 704719f5715Snicm 70529724ccbSnicm /* Get mouse event string. */ 70629724ccbSnicm int 70729724ccbSnicm input_key_get_mouse(struct screen *s, struct mouse_event *m, u_int x, u_int y, 70829724ccbSnicm const char **rbuf, size_t *rlen) 709311827fbSnicm { 71029724ccbSnicm static char buf[40]; 711699995ddSnicm size_t len; 712fdcac80eSnicm 71329724ccbSnicm *rbuf = NULL; 71429724ccbSnicm *rlen = 0; 715e048bb79Snicm 7169f26c5b1Snicm /* If this pane is not in button or all mode, discard motion events. */ 71713e036e4Snicm if (MOUSE_DRAG(m->b) && (s->mode & MOTION_MOUSE_MODES) == 0) 71829724ccbSnicm return (0); 71957d747eeSnicm if ((s->mode & ALL_MOUSE_MODES) == 0) 72057d747eeSnicm return (0); 721e048bb79Snicm 7226c0777c5Snicm /* 7239f26c5b1Snicm * If this event is a release event and not in all mode, discard it. 7249f26c5b1Snicm * In SGR mode we can tell absolutely because a release is normally 7259f26c5b1Snicm * shown by the last character. Without SGR, we check if the last 7269f26c5b1Snicm * buttons was also a release. 7279f26c5b1Snicm */ 7289f26c5b1Snicm if (m->sgr_type != ' ') { 7299f26c5b1Snicm if (MOUSE_DRAG(m->sgr_b) && 7304e5846a2Snicm MOUSE_RELEASE(m->sgr_b) && 73113e036e4Snicm (~s->mode & MODE_MOUSE_ALL)) 73229724ccbSnicm return (0); 7339f26c5b1Snicm } else { 7349f26c5b1Snicm if (MOUSE_DRAG(m->b) && 7354e5846a2Snicm MOUSE_RELEASE(m->b) && 7364e5846a2Snicm MOUSE_RELEASE(m->lb) && 73713e036e4Snicm (~s->mode & MODE_MOUSE_ALL)) 73829724ccbSnicm return (0); 7399f26c5b1Snicm } 7409f26c5b1Snicm 7419f26c5b1Snicm /* 742e048bb79Snicm * Use the SGR (1006) extension only if the application requested it 743e048bb79Snicm * and the underlying terminal also sent the event in this format (this 744e048bb79Snicm * is because an old style mouse release event cannot be converted into 745e048bb79Snicm * the new SGR format, since the released button is unknown). Otherwise 746e048bb79Snicm * pretend that tmux doesn't speak this extension, and fall back to the 7473b213501Snicm * UTF-8 (1005) extension if the application requested, or to the 7486c0777c5Snicm * legacy format. 7496c0777c5Snicm */ 7509f26c5b1Snicm if (m->sgr_type != ' ' && (s->mode & MODE_MOUSE_SGR)) { 751e5f4d2afSnicm len = xsnprintf(buf, sizeof buf, "\033[<%u;%u;%u%c", 752e048bb79Snicm m->sgr_b, x + 1, y + 1, m->sgr_type); 7539f26c5b1Snicm } else if (s->mode & MODE_MOUSE_UTF8) { 75481e6b289Snicm if (m->b > MOUSE_PARAM_UTF8_MAX - MOUSE_PARAM_BTN_OFF || 75581e6b289Snicm x > MOUSE_PARAM_UTF8_MAX - MOUSE_PARAM_POS_OFF || 75681e6b289Snicm y > MOUSE_PARAM_UTF8_MAX - MOUSE_PARAM_POS_OFF) 75729724ccbSnicm return (0); 7583b213501Snicm len = xsnprintf(buf, sizeof buf, "\033[M"); 75981e6b289Snicm len += input_key_split2(m->b + MOUSE_PARAM_BTN_OFF, &buf[len]); 76081e6b289Snicm len += input_key_split2(x + MOUSE_PARAM_POS_OFF, &buf[len]); 76181e6b289Snicm len += input_key_split2(y + MOUSE_PARAM_POS_OFF, &buf[len]); 762699995ddSnicm } else { 76381e6b289Snicm if (m->b + MOUSE_PARAM_BTN_OFF > MOUSE_PARAM_MAX) 76429724ccbSnicm return (0); 76581e6b289Snicm 766699995ddSnicm len = xsnprintf(buf, sizeof buf, "\033[M"); 76781e6b289Snicm buf[len++] = m->b + MOUSE_PARAM_BTN_OFF; 76881e6b289Snicm 76981e6b289Snicm /* 77081e6b289Snicm * The incoming x and y may be out of the range which can be 77181e6b289Snicm * supported by the "normal" mouse protocol. Clamp the 77281e6b289Snicm * coordinates to the supported range. 77381e6b289Snicm */ 77481e6b289Snicm if (x + MOUSE_PARAM_POS_OFF > MOUSE_PARAM_MAX) 77581e6b289Snicm buf[len++] = MOUSE_PARAM_MAX; 77681e6b289Snicm else 77781e6b289Snicm buf[len++] = x + MOUSE_PARAM_POS_OFF; 77881e6b289Snicm if (y + MOUSE_PARAM_POS_OFF > MOUSE_PARAM_MAX) 77981e6b289Snicm buf[len++] = MOUSE_PARAM_MAX; 78081e6b289Snicm else 78181e6b289Snicm buf[len++] = y + MOUSE_PARAM_POS_OFF; 782699995ddSnicm } 78329724ccbSnicm 78429724ccbSnicm *rbuf = buf; 78529724ccbSnicm *rlen = len; 78629724ccbSnicm return (1); 78729724ccbSnicm } 78829724ccbSnicm 78929724ccbSnicm /* Translate mouse and output. */ 79029724ccbSnicm static void 79129724ccbSnicm input_key_mouse(struct window_pane *wp, struct mouse_event *m) 79229724ccbSnicm { 79329724ccbSnicm struct screen *s = wp->screen; 79429724ccbSnicm u_int x, y; 79529724ccbSnicm const char *buf; 79629724ccbSnicm size_t len; 79729724ccbSnicm 79829724ccbSnicm /* Ignore events if no mouse mode or the pane is not visible. */ 79929724ccbSnicm if (m->ignore || (s->mode & ALL_MOUSE_MODES) == 0) 80029724ccbSnicm return; 80129724ccbSnicm if (cmd_mouse_at(wp, m, &x, &y, 0) != 0) 80229724ccbSnicm return; 80329724ccbSnicm if (!window_pane_visible(wp)) 80429724ccbSnicm return; 80529724ccbSnicm if (!input_key_get_mouse(s, m, x, y, &buf, &len)) 80629724ccbSnicm return; 807302fe310Snicm log_debug("writing mouse %.*s to %%%u", (int)len, buf, wp->id); 808090e14efSnicm input_key_write(__func__, wp->event, buf, len); 809311827fbSnicm } 810