diff --git a/format.c b/format.c index 7979e970..91d78f89 100644 --- a/format.c +++ b/format.c @@ -1962,6 +1962,23 @@ format_cb_pane_unseen_changes(struct format_tree *ft) return (NULL); } +/* Callback for pane_key_mode. */ +static void * +format_cb_pane_key_mode(struct format_tree *ft) +{ + if (ft->wp != NULL && ft->wp->screen != NULL) { + switch (ft->wp->screen->mode & EXTENDED_KEY_MODES) { + case MODE_KEYS_EXTENDED: + return (xstrdup("Ext 1")); + case MODE_KEYS_EXTENDED_2: + return (xstrdup("Ext 2")); + default: + return (xstrdup("VT10x")); + } + } + return (NULL); +} + /* Callback for pane_last. */ static void * format_cb_pane_last(struct format_tree *ft) @@ -2997,6 +3014,9 @@ static const struct format_table_entry format_table[] = { { "pane_input_off", FORMAT_TABLE_STRING, format_cb_pane_input_off }, + { "pane_key_mode", FORMAT_TABLE_STRING, + format_cb_pane_key_mode + }, { "pane_last", FORMAT_TABLE_STRING, format_cb_pane_last }, diff --git a/key-string.c b/key-string.c index 699d460f..04f0e5bf 100644 --- a/key-string.c +++ b/key-string.c @@ -56,12 +56,47 @@ static const struct { { "PPage", KEYC_PPAGE|KEYC_IMPLIED_META }, { "PageUp", KEYC_PPAGE|KEYC_IMPLIED_META }, { "PgUp", KEYC_PPAGE|KEYC_IMPLIED_META }, - { "Tab", '\011' }, { "BTab", KEYC_BTAB }, { "Space", ' ' }, { "BSpace", KEYC_BSPACE }, - { "Enter", '\r' }, - { "Escape", '\033' }, + + /* + * C0 control characters, with the exception of Tab, Enter, + * and Esc, should never appear as keys. We still render them, + * so to be able to spot them in logs in case of an abnormality. + */ + { "[NUL]", C0_NUL }, + { "[SOH]", C0_SOH }, + { "[STX]", C0_STX }, + { "[ETX]", C0_ETX }, + { "[EOT]", C0_EOT }, + { "[ENQ]", C0_ENQ }, + { "[ASC]", C0_ASC }, + { "[BEL]", C0_BEL }, + { "[BS]", C0_BS }, + { "Tab", C0_HT }, + { "[LF]", C0_LF }, + { "[VT]", C0_VT }, + { "[FF]", C0_FF }, + { "Enter", C0_CR }, + { "[SO]", C0_SO }, + { "[SI]", C0_SI }, + { "[DLE]", C0_DLE }, + { "[DC1]", C0_DC1 }, + { "[DC2]", C0_DC2 }, + { "[DC3]", C0_DC3 }, + { "[DC4]", C0_DC4 }, + { "[NAK]", C0_NAK }, + { "[SYN]", C0_SYN }, + { "[ETB]", C0_ETB }, + { "[CAN]", C0_CAN }, + { "[EM]", C0_EM }, + { "[SUB]", C0_SUB }, + { "Escape", C0_ESC }, + { "[FS]", C0_FS }, + { "[GS]", C0_GS }, + { "[RS]", C0_RS }, + { "[US]", C0_US }, /* Arrow keys. */ { "Up", KEYC_UP|KEYC_CURSOR|KEYC_IMPLIED_META }, @@ -206,7 +241,6 @@ key_string_get_modifiers(const char **string) key_code key_string_lookup_string(const char *string) { - static const char *other = "!#()+,-.0123456789:;<=>'\r\t\177`/"; key_code key, modifiers; u_int u, i; struct utf8_data ud, *udp; @@ -281,26 +315,6 @@ key_string_lookup_string(const char *string) key &= ~KEYC_IMPLIED_META; } - /* Convert the standard control keys. */ - if (key <= 127 && - (modifiers & KEYC_CTRL) && - strchr(other, key) == NULL && - key != 9 && - key != 13 && - key != 27) { - if (key >= 97 && key <= 122) - key -= 96; - else if (key >= 64 && key <= 95) - key -= 64; - else if (key == 32) - key = 0; - else if (key == 63) - key = 127; - else - return (KEYC_UNKNOWN); - modifiers &= ~KEYC_CTRL; - } - return (key|modifiers); } @@ -324,10 +338,6 @@ key_string_lookup_key(key_code key, int with_flags) goto out; } - /* Display C-@ as C-Space. */ - if ((key & (KEYC_MASK_KEY|KEYC_MASK_MODIFIERS)) == 0) - key = ' '|KEYC_CTRL; - /* Fill in the modifiers. */ if (key & KEYC_CTRL) strlcat(out, "C-", sizeof out); @@ -427,13 +437,8 @@ key_string_lookup_key(key_code key, int with_flags) goto out; } - /* Check for standard or control key. */ - if (key <= 32) { - if (key == 0 || key > 26) - xsnprintf(tmp, sizeof tmp, "C-%c", (int)(64 + key)); - else - xsnprintf(tmp, sizeof tmp, "C-%c", (int)(96 + key)); - } else if (key >= 32 && key <= 126) { + /* Printable ASCII keys. */ + if (key > 32 && key <= 126) { tmp[0] = key; tmp[1] = '\0'; } else if (key == 127) @@ -460,8 +465,6 @@ out: strlcat(out, "I", sizeof out); if (saved & KEYC_BUILD_MODIFIERS) strlcat(out, "B", sizeof out); - if (saved & KEYC_EXTENDED) - strlcat(out, "E", sizeof out); if (saved & KEYC_SENT) strlcat(out, "S", sizeof out); strlcat(out, "]", sizeof out); diff --git a/menu.c b/menu.c index 8d7b40a2..c1f3b211 100644 --- a/menu.c +++ b/menu.c @@ -335,7 +335,7 @@ menu_key_cb(struct client *c, void *data, struct key_event *event) c->flags |= CLIENT_REDRAWOVERLAY; return (0); case KEYC_PPAGE: - case '\002': /* C-b */ + case 'b'|KEYC_CTRL: if (md->choice < 6) md->choice = 0; else { @@ -394,13 +394,13 @@ menu_key_cb(struct client *c, void *data, struct key_event *event) } c->flags |= CLIENT_REDRAWOVERLAY; break; - case '\006': /* C-f */ + case 'f'|KEYC_CTRL: break; case '\r': goto chosen; case '\033': /* Escape */ - case '\003': /* C-c */ - case '\007': /* C-g */ + case 'c'|KEYC_CTRL: + case 'g'|KEYC_CTRL: case 'q': return (1); } diff --git a/mode-tree.c b/mode-tree.c index 50e65499..efa966dc 100644 --- a/mode-tree.c +++ b/mode-tree.c @@ -1088,22 +1088,22 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key, switch (*key) { case 'q': case '\033': /* Escape */ - case '\007': /* C-g */ + case 'g'|KEYC_CTRL: return (1); case KEYC_UP: case 'k': case KEYC_WHEELUP_PANE: - case '\020': /* C-p */ + case 'p'|KEYC_CTRL: mode_tree_up(mtd, 1); break; case KEYC_DOWN: case 'j': case KEYC_WHEELDOWN_PANE: - case '\016': /* C-n */ + case 'n'|KEYC_CTRL: mode_tree_down(mtd, 1); break; case KEYC_PPAGE: - case '\002': /* C-b */ + case 'b'|KEYC_CTRL: for (i = 0; i < mtd->height; i++) { if (mtd->current == 0) break; @@ -1111,7 +1111,7 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key, } break; case KEYC_NPAGE: - case '\006': /* C-f */ + case 'f'|KEYC_CTRL: for (i = 0; i < mtd->height; i++) { if (mtd->current == mtd->line_size - 1) break; @@ -1155,7 +1155,7 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key, for (i = 0; i < mtd->line_size; i++) mtd->line_list[i].item->tagged = 0; break; - case '\024': /* C-t */ + case 't'|KEYC_CTRL: for (i = 0; i < mtd->line_size; i++) { if ((mtd->line_list[i].item->parent == NULL && !mtd->line_list[i].item->no_tag) || @@ -1211,7 +1211,7 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key, break; case '?': case '/': - case '\023': /* C-s */ + case 's'|KEYC_CTRL: mtd->references++; status_prompt_set(c, NULL, "(search) ", "", mode_tree_search_callback, mode_tree_search_free, mtd, diff --git a/popup.c b/popup.c index 804dd6ef..6d126cf4 100644 --- a/popup.c +++ b/popup.c @@ -543,7 +543,7 @@ popup_key_cb(struct client *c, void *data, struct key_event *event) } if ((((pd->flags & (POPUP_CLOSEEXIT|POPUP_CLOSEEXITZERO)) == 0) || pd->job == NULL) && - (event->key == '\033' || event->key == '\003')) + (event->key == '\033' || event->key == ('c'|KEYC_CTRL))) return (1); if (pd->job != NULL) { if (KEYC_IS_MOUSE(event->key)) { diff --git a/screen-write.c b/screen-write.c index 554232eb..fe58ee48 100644 --- a/screen-write.c +++ b/screen-write.c @@ -326,8 +326,9 @@ screen_write_reset(struct screen_write_ctx *ctx) screen_write_scrollregion(ctx, 0, screen_size_y(s) - 1); s->mode = MODE_CURSOR|MODE_WRAP; + if (options_get_number(global_options, "extended-keys") == 2) - s->mode |= MODE_KEXTENDED; + s->mode = (s->mode & ~EXTENDED_KEY_MODES)|MODE_KEYS_EXTENDED; screen_write_clearscreen(ctx, 8); screen_write_set_cursor(ctx, 0, 0); diff --git a/screen.c b/screen.c index de072d1a..d51af6ac 100644 --- a/screen.c +++ b/screen.c @@ -107,8 +107,9 @@ screen_reinit(struct screen *s) s->rlower = screen_size_y(s) - 1; s->mode = MODE_CURSOR|MODE_WRAP|(s->mode & MODE_CRLF); + if (options_get_number(global_options, "extended-keys") == 2) - s->mode |= MODE_KEXTENDED; + s->mode = (s->mode & ~EXTENDED_KEY_MODES)|MODE_KEYS_EXTENDED; if (s->saved_grid != NULL) screen_alternate_off(s, NULL, 0); @@ -714,8 +715,10 @@ screen_mode_to_string(int mode) strlcat(tmp, "ORIGIN,", sizeof tmp); if (mode & MODE_CRLF) strlcat(tmp, "CRLF,", sizeof tmp); - if (mode & MODE_KEXTENDED) - strlcat(tmp, "KEXTENDED,", sizeof tmp); + if (mode & MODE_KEYS_EXTENDED) + strlcat(tmp, "KEYS_EXTENDED,", sizeof tmp); + if (mode & MODE_KEYS_EXTENDED_2) + strlcat(tmp, "KEYS_EXTENDED_2,", sizeof tmp); tmp[strlen(tmp) - 1] = '\0'; return (tmp); } diff --git a/status.c b/status.c index 4afac626..d0b4e3b5 100644 --- a/status.c +++ b/status.c @@ -839,19 +839,19 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key) { if (c->prompt_mode == PROMPT_ENTRY) { switch (key) { - case '\001': /* C-a */ - case '\003': /* C-c */ - case '\005': /* C-e */ - case '\007': /* C-g */ - case '\010': /* C-h */ + case 'a'|KEYC_CTRL: + case 'c'|KEYC_CTRL: + case 'e'|KEYC_CTRL: + case 'g'|KEYC_CTRL: + case 'h'|KEYC_CTRL: case '\011': /* Tab */ - case '\013': /* C-k */ - case '\016': /* C-n */ - case '\020': /* C-p */ - case '\024': /* C-t */ - case '\025': /* C-u */ - case '\027': /* C-w */ - case '\031': /* C-y */ + case 'k'|KEYC_CTRL: + case 'n'|KEYC_CTRL: + case 'p'|KEYC_CTRL: + case 't'|KEYC_CTRL: + case 'u'|KEYC_CTRL: + case 'w'|KEYC_CTRL: + case 'y'|KEYC_CTRL: case '\n': case '\r': case KEYC_LEFT|KEYC_CTRL: @@ -890,7 +890,7 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key) case 'S': c->prompt_mode = PROMPT_ENTRY; c->flags |= CLIENT_REDRAWSTATUS; - *new_key = '\025'; /* C-u */ + *new_key = 'u'|KEYC_CTRL; return (1); case 'i': case '\033': /* Escape */ @@ -911,7 +911,7 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key) return (1); case 'C': case 'D': - *new_key = '\013'; /* C-k */ + *new_key = 'k'|KEYC_CTRL; return (1); case KEYC_BSPACE: case 'X': @@ -924,7 +924,7 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key) *new_key = 'B'|KEYC_VI; return (1); case 'd': - *new_key = '\025'; /* C-u */ + *new_key = 'u'|KEYC_CTRL; return (1); case 'e': *new_key = 'e'|KEYC_VI; @@ -939,10 +939,10 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key) *new_key = 'W'|KEYC_VI; return (1); case 'p': - *new_key = '\031'; /* C-y */ + *new_key = 'y'|KEYC_CTRL; return (1); case 'q': - *new_key = '\003'; /* C-c */ + *new_key = 'c'|KEYC_CTRL; return (1); case 's': case KEYC_DC: @@ -966,8 +966,8 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key) case 'k': *new_key = KEYC_UP; return (1); - case '\010' /* C-h */: - case '\003' /* C-c */: + case 'h'|KEYC_CTRL: + case 'c'|KEYC_CTRL: case '\n': case '\r': return (1); @@ -1263,28 +1263,28 @@ status_prompt_key(struct client *c, key_code key) process_key: switch (key) { case KEYC_LEFT: - case '\002': /* C-b */ + case 'b'|KEYC_CTRL: if (c->prompt_index > 0) { c->prompt_index--; break; } break; case KEYC_RIGHT: - case '\006': /* C-f */ + case 'f'|KEYC_CTRL: if (c->prompt_index < size) { c->prompt_index++; break; } break; case KEYC_HOME: - case '\001': /* C-a */ + case 'a'|KEYC_CTRL: if (c->prompt_index != 0) { c->prompt_index = 0; break; } break; case KEYC_END: - case '\005': /* C-e */ + case 'e'|KEYC_CTRL: if (c->prompt_index != size) { c->prompt_index = size; break; @@ -1295,7 +1295,7 @@ process_key: goto changed; break; case KEYC_BSPACE: - case '\010': /* C-h */ + case 'h'|KEYC_CTRL: if (c->prompt_index != 0) { if (c->prompt_index == size) c->prompt_buffer[--c->prompt_index].size = 0; @@ -1310,7 +1310,7 @@ process_key: } break; case KEYC_DC: - case '\004': /* C-d */ + case 'd'|KEYC_CTRL: if (c->prompt_index != size) { memmove(c->prompt_buffer + c->prompt_index, c->prompt_buffer + c->prompt_index + 1, @@ -1319,17 +1319,17 @@ process_key: goto changed; } break; - case '\025': /* C-u */ + case 'u'|KEYC_CTRL: c->prompt_buffer[0].size = 0; c->prompt_index = 0; goto changed; - case '\013': /* C-k */ + case 'k'|KEYC_CTRL: if (c->prompt_index < size) { c->prompt_buffer[c->prompt_index].size = 0; goto changed; } break; - case '\027': /* C-w */ + case 'w'|KEYC_CTRL: separators = options_get_string(oo, "word-separators"); idx = c->prompt_index; @@ -1397,7 +1397,7 @@ process_key: status_prompt_backward_word(c, separators); goto changed; case KEYC_UP: - case '\020': /* C-p */ + case 'p'|KEYC_CTRL: histstr = status_prompt_up_history(c->prompt_hindex, c->prompt_type); if (histstr == NULL) @@ -1407,7 +1407,7 @@ process_key: c->prompt_index = utf8_strlen(c->prompt_buffer); goto changed; case KEYC_DOWN: - case '\016': /* C-n */ + case 'n'|KEYC_CTRL: histstr = status_prompt_down_history(c->prompt_hindex, c->prompt_type); if (histstr == NULL) @@ -1416,11 +1416,11 @@ process_key: c->prompt_buffer = utf8_fromcstr(histstr); c->prompt_index = utf8_strlen(c->prompt_buffer); goto changed; - case '\031': /* C-y */ + case 'y'|KEYC_CTRL: if (status_prompt_paste(c)) goto changed; break; - case '\024': /* C-t */ + case 't'|KEYC_CTRL: idx = c->prompt_index; if (idx < size) idx++; @@ -1443,12 +1443,12 @@ process_key: free(s); break; case '\033': /* Escape */ - case '\003': /* C-c */ - case '\007': /* C-g */ + case 'c'|KEYC_CTRL: + case 'g'|KEYC_CTRL: if (c->prompt_inputcb(c, c->prompt_data, NULL, 1) == 0) status_prompt_clear(c); break; - case '\022': /* C-r */ + case 'r'|KEYC_CTRL: if (~c->prompt_flags & PROMPT_INCREMENTAL) break; if (c->prompt_buffer[0].size == 0) { @@ -1459,7 +1459,7 @@ process_key: } else prefix = '-'; goto changed; - case '\023': /* C-s */ + case 's'|KEYC_CTRL: if (~c->prompt_flags & PROMPT_INCREMENTAL) break; if (c->prompt_buffer[0].size == 0) { diff --git a/tmux.1 b/tmux.1 index 3d1cb1ed..9ab65993 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3733,6 +3733,10 @@ Note that aliases are expanded when a command is parsed rather than when it is executed, so binding an alias with .Ic bind-key will bind the expanded form. +.It Ic copy-command Ar shell-command +Give the command to pipe to if the +.Ic copy-pipe +copy mode command is used without arguments. .It Ic default-terminal Ar terminal Set the default terminal for new windows created in this session - the default value of the @@ -3746,10 +3750,6 @@ be set to .Ql screen , .Ql tmux or a derivative of them. -.It Ic copy-command Ar shell-command -Give the command to pipe to if the -.Ic copy-pipe -copy mode command is used without arguments. .It Ic escape-time Ar time Set the time in milliseconds for which .Nm @@ -3771,22 +3771,53 @@ If enabled, the server will exit when there are no attached clients. .It Xo Ic extended-keys .Op Ic on | off | always .Xc -When -.Ic on -or -.Ic always , -the escape sequence to enable extended keys is sent to the terminal, if -.Nm -knows that it is supported. -.Nm -always recognises extended keys itself. -If this option is +Controls how modified keys (keys pressed together with Control, Meta, or Shift) +are reported. +This is the equivalent of the +.Ic modifyOtherKeys +.Xr xterm 1 +resource. +.Pp +When set to .Ic on , -.Nm -will only forward extended keys to applications when they request them; if +the program inside the pane can request one of two modes: mode 1 which changes +the sequence for only keys which lack an existing well-known representation; or +mode 2 which changes the sequence for all keys. +When set to .Ic always , +mode 1 output is forced and the program cannot change it. +When set to +.Ic off , +this feature is disabled and only standard keys are reported. +.Pp .Nm -will always forward the keys. +will always request extended keys itself if the terminal supports them. +See also the +.Ic extkeys +feature for the +.Ic terminal-features +option, the +.Ic extended-keys-format +option and the +.Ic pane_key_mode +variable. +.It Xo Ic extended-keys-format +.Op Ic csi-u | xterm +.Xc +Selects one of the two possible formats for reporting modified keys to +applications. +This is the equivalent of the +.Ic formatOtherKeys +.Xr xterm 1 +resource. +For example, C-S-a will be reported as +.Ql ^[[27;6;65~ +when set to +.Ic xterm , +and as +.Ql ^[[65;6u +when set to +.Ic csi-u . .It Xo Ic focus-events .Op Ic on | off .Xc @@ -5512,6 +5543,7 @@ The following variables are available, where appropriate: .It Li "pane_in_mode" Ta "" Ta "1 if pane is in a mode" .It Li "pane_index" Ta "#P" Ta "Index of pane" .It Li "pane_input_off" Ta "" Ta "1 if input to pane is disabled" +.It Li "pane_key_mode" Ta "" Ta "Extended key reporting mode in this pane" .It Li "pane_last" Ta "" Ta "1 if last pane" .It Li "pane_left" Ta "" Ta "Left of pane" .It Li "pane_marked" Ta "" Ta "1 if this is the marked pane" diff --git a/tmux.h b/tmux.h index beced79d..a60f89e9 100644 --- a/tmux.h +++ b/tmux.h @@ -138,8 +138,7 @@ struct winlink; #define KEYC_IMPLIED_META 0x08000000000000ULL #define KEYC_BUILD_MODIFIERS 0x10000000000000ULL #define KEYC_VI 0x20000000000000ULL -#define KEYC_EXTENDED 0x40000000000000ULL -#define KEYC_SENT 0x80000000000000ULL +#define KEYC_SENT 0x40000000000000ULL /* Masks for key bits. */ #define KEYC_MASK_MODIFIERS 0x00f00000000000ULL @@ -187,6 +186,42 @@ struct winlink; */ typedef unsigned long long key_code; +/* C0 control characters */ +enum { + C0_NUL, + C0_SOH, + C0_STX, + C0_ETX, + C0_EOT, + C0_ENQ, + C0_ASC, + C0_BEL, + C0_BS, + C0_HT, + C0_LF, + C0_VT, + C0_FF, + C0_CR, + C0_SO, + C0_SI, + C0_DLE, + C0_DC1, + C0_DC2, + C0_DC3, + C0_DC4, + C0_NAK, + C0_SYN, + C0_ETB, + C0_CAN, + C0_EM, + C0_SUB, + C0_ESC, + C0_FS, + C0_GS, + C0_RS, + C0_US +}; + /* Special key codes. */ enum { /* Focus events. */ @@ -582,14 +617,16 @@ enum tty_code_code { #define MODE_MOUSE_ALL 0x1000 #define MODE_ORIGIN 0x2000 #define MODE_CRLF 0x4000 -#define MODE_KEXTENDED 0x8000 +#define MODE_KEYS_EXTENDED 0x8000 #define MODE_CURSOR_VERY_VISIBLE 0x10000 #define MODE_CURSOR_BLINKING_SET 0x20000 +#define MODE_KEYS_EXTENDED_2 0x40000 #define ALL_MODES 0xffffff #define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD|MODE_MOUSE_BUTTON|MODE_MOUSE_ALL) #define MOTION_MOUSE_MODES (MODE_MOUSE_BUTTON|MODE_MOUSE_ALL) #define CURSOR_MODES (MODE_CURSOR|MODE_CURSOR_BLINKING|MODE_CURSOR_VERY_VISIBLE) +#define EXTENDED_KEY_MODES (MODE_KEYS_EXTENDED|MODE_KEYS_EXTENDED_2) /* Mouse protocol constants. */ #define MOUSE_PARAM_MAX 0xff diff --git a/tty-features.c b/tty-features.c index 42f83f41..110bc1f8 100644 --- a/tty-features.c +++ b/tty-features.c @@ -227,7 +227,7 @@ static const struct tty_feature tty_feature_sync = { /* Terminal supports extended keys. */ static const char *const tty_feature_extkeys_capabilities[] = { - "Eneks=\\E[>4;1m", + "Eneks=\\E[>4;2m", "Dseks=\\E[>4m", NULL }; diff --git a/tty-keys.c b/tty-keys.c index a04d951d..9555dc31 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -664,7 +664,7 @@ tty_keys_next(struct tty *tty) size_t len, size; cc_t bspace; int delay, expired = 0, n; - key_code key; + key_code key, onlykey; struct mouse_event m = { 0 }; struct key_event *event; @@ -801,6 +801,26 @@ first_key: key = (u_char)buf[0]; size = 1; } + + /* C-Space is special. */ + if ((key & KEYC_MASK_KEY) == C0_NUL) + key = ' ' | KEYC_CTRL | (key & KEYC_META); + + /* + * Fix up all C0 control codes that don't have a dedicated key into + * corresponding Ctrl keys. Convert characters in the A-Z range into + * lowercase, so ^A becomes a|CTRL. + */ + onlykey = key & KEYC_MASK_KEY; + if (onlykey < 0x20 && onlykey != C0_BS && + onlykey != C0_HT && onlykey != C0_CR && + onlykey != C0_ESC) { + onlykey |= 0x40; + if (onlykey >= 'A' && onlykey <= 'Z') + onlykey |= 0x20; + key = onlykey | KEYC_CTRL | (key & KEYC_META); + } + goto complete_key; partial_key: @@ -910,7 +930,6 @@ tty_keys_extended_key(struct tty *tty, const char *buf, size_t len, char tmp[64]; cc_t bspace; key_code nkey; - key_code onlykey; struct utf8_data ud; utf8_char uc; @@ -974,7 +993,13 @@ tty_keys_extended_key(struct tty *tty, const char *buf, size_t len, /* Update the modifiers. */ if (modifiers > 0) { modifiers--; - if (modifiers & 1) + /* + * The Shift modifier may not be reported in some input modes, + * which is unfortunate, as in general case determining if a + * character is shifted or not requires knowing the input + * keyboard layout. So we only fix up the trivial case. + */ + if (modifiers & 1 || (nkey >= 'A' && nkey <= 'Z')) nkey |= KEYC_SHIFT; if (modifiers & 2) nkey |= (KEYC_META|KEYC_IMPLIED_META); /* Alt */ @@ -984,34 +1009,15 @@ tty_keys_extended_key(struct tty *tty, const char *buf, size_t len, nkey |= (KEYC_META|KEYC_IMPLIED_META); /* Meta */ } - /* - * Don't allow both KEYC_CTRL and as an implied modifier. Also convert - * C-X into C-x and so on. - */ - if (nkey & KEYC_CTRL) { - onlykey = (nkey & KEYC_MASK_KEY); - if (onlykey < 32 && - onlykey != 9 && - onlykey != 13 && - onlykey != 27) - /* nothing */; - else if (onlykey >= 97 && onlykey <= 122) - onlykey -= 96; - else if (onlykey >= 64 && onlykey <= 95) - onlykey -= 64; - else if (onlykey == 32) - onlykey = 0; - else if (onlykey == 63) - onlykey = 127; - else - onlykey |= KEYC_CTRL; - nkey = onlykey|((nkey & KEYC_MASK_MODIFIERS) & ~KEYC_CTRL); - } + /* Convert S-Tab into Backtab. */ + if ((nkey & KEYC_MASK_KEY) == '\011' && (nkey & KEYC_SHIFT)) + nkey = KEYC_BTAB | (nkey & ~KEYC_MASK_KEY & ~KEYC_SHIFT); if (log_get_level() != 0) { log_debug("%s: extended key %.*s is %llx (%s)", c->name, (int)*size, buf, nkey, key_string_lookup_key(nkey, 1)); } + *key = nkey; return (0); }