diff --git a/arguments.c b/arguments.c index f7b6cbe1..026272af 100644 --- a/arguments.c +++ b/arguments.c @@ -37,6 +37,7 @@ TAILQ_HEAD(args_values, args_value); struct args_entry { u_char flag; struct args_values values; + u_int count; RB_ENTRY(args_entry) entry; }; @@ -173,6 +174,7 @@ args_print(struct args *args) size_t len; char *buf; int i; + u_int j; struct args_entry *entry; struct args_value *value; @@ -186,7 +188,8 @@ args_print(struct args *args) if (*buf == '\0') args_print_add(&buf, &len, "-"); - args_print_add(&buf, &len, "%c", entry->flag); + for (j = 0; j < entry->count; j++) + args_print_add(&buf, &len, "%c", entry->flag); } /* Then the flags with arguments. */ @@ -243,7 +246,12 @@ args_escape(const char *s) int args_has(struct args *args, u_char ch) { - return (args_find(args, ch) != NULL); + struct args_entry *entry; + + entry = args_find(args, ch); + if (entry == NULL) + return (0); + return (entry->count); } /* Set argument value in the arguments tree. */ @@ -257,9 +265,11 @@ args_set(struct args *args, u_char ch, const char *s) if (entry == NULL) { entry = xcalloc(1, sizeof *entry); entry->flag = ch; + entry->count = 1; TAILQ_INIT(&entry->values); RB_INSERT(args_tree, &args->tree, entry); - } + } else + entry->count++; if (s != NULL) { value = xcalloc(1, sizeof *value); diff --git a/cmd-send-keys.c b/cmd-send-keys.c index fd1c1ab9..9ed50d3d 100644 --- a/cmd-send-keys.c +++ b/cmd-send-keys.c @@ -33,8 +33,8 @@ const struct cmd_entry cmd_send_keys_entry = { .name = "send-keys", .alias = "send", - .args = { "lXRMN:t:", 0, -1 }, - .usage = "[-lXRM] [-N repeat-count] " CMD_TARGET_PANE_USAGE " key ...", + .args = { "HlXRMN:t:", 0, -1 }, + .usage = "[-HlXRM] [-N repeat-count] " CMD_TARGET_PANE_USAGE " key ...", .target = { 't', CMD_FIND_PANE, 0 }, @@ -56,9 +56,9 @@ const struct cmd_entry cmd_send_prefix_entry = { }; static struct cmdq_item * -cmd_send_keys_inject(struct client *c, struct cmd_find_state *fs, - struct cmdq_item *item, key_code key) +cmd_send_keys_inject_key(struct client *c, struct cmdq_item *item, key_code key) { + struct cmd_find_state *fs = &item->target; struct window_mode_entry *wme; struct key_table *table; struct key_binding *bd; @@ -81,6 +81,44 @@ cmd_send_keys_inject(struct client *c, struct cmd_find_state *fs, return (item); } +static struct cmdq_item * +cmd_send_keys_inject_string(struct client *c, struct cmdq_item *item, + struct args *args, int i) +{ + const char *s = args->argv[i]; + struct utf8_data *ud, *uc; + wchar_t wc; + key_code key; + char *endptr; + long n; + int literal; + + if (args_has(args, 'H')) { + n = strtol(s, &endptr, 16); + if (*s =='\0' || n < 0 || n > 0xff || *endptr != '\0') + return (item); + return (cmd_send_keys_inject_key(c, item, KEYC_LITERAL|n)); + } + + literal = args_has(args, 'l'); + if (!literal) { + key = key_string_lookup_string(s); + if (key != KEYC_NONE && key != KEYC_UNKNOWN) + return (cmd_send_keys_inject_key(c, item, key)); + literal = 1; + } + if (literal) { + ud = utf8_fromcstr(s); + for (uc = ud; uc->size != 0; uc++) { + if (utf8_combine(uc, &wc) != UTF8_DONE) + continue; + item = cmd_send_keys_inject_key(c, item, wc); + } + free(ud); + } + return (item); +} + static enum cmd_retval cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item) { @@ -90,11 +128,8 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item) struct session *s = item->target.s; struct winlink *wl = item->target.wl; struct mouse_event *m = &item->shared->mouse; - struct cmd_find_state *fs = &item->target; struct window_mode_entry *wme = TAILQ_FIRST(&wp->modes); - struct utf8_data *ud, *uc; - wchar_t wc; - int i, literal; + int i; key_code key; u_int np = 1; char *cause = NULL; @@ -141,7 +176,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item) key = options_get_number(s->options, "prefix2"); else key = options_get_number(s->options, "prefix"); - cmd_send_keys_inject(c, fs, item, key); + cmd_send_keys_inject_key(c, item, key); return (CMD_RETURN_NORMAL); } @@ -151,28 +186,8 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item) } for (; np != 0; np--) { - for (i = 0; i < args->argc; i++) { - literal = args_has(args, 'l'); - if (!literal) { - key = key_string_lookup_string(args->argv[i]); - if (key != KEYC_NONE && key != KEYC_UNKNOWN) { - item = cmd_send_keys_inject(c, fs, item, - key); - } else - literal = 1; - } - if (literal) { - ud = utf8_fromcstr(args->argv[i]); - for (uc = ud; uc->size != 0; uc++) { - if (utf8_combine(uc, &wc) != UTF8_DONE) - continue; - item = cmd_send_keys_inject(c, fs, item, - wc); - } - free(ud); - } - } - + for (i = 0; i < args->argc; i++) + item = cmd_send_keys_inject_string(c, item, args, i); } return (CMD_RETURN_NORMAL); diff --git a/format.c b/format.c index 8d2d8db8..eb7a9e53 100644 --- a/format.c +++ b/format.c @@ -2317,6 +2317,8 @@ format_defaults_pane(struct format_tree *ft, struct window_pane *wp) !!(wp->base.mode & MODE_KKEYPAD)); format_add(ft, "wrap_flag", "%d", !!(wp->base.mode & MODE_WRAP)); + format_add(ft, "origin_flag", "%d", + !!(wp->base.mode & MODE_ORIGIN)); format_add(ft, "mouse_any_flag", "%d", !!(wp->base.mode & ALL_MOUSE_MODES)); @@ -2326,6 +2328,10 @@ format_defaults_pane(struct format_tree *ft, struct window_pane *wp) !!(wp->base.mode & MODE_MOUSE_BUTTON)); format_add(ft, "mouse_all_flag", "%d", !!(wp->base.mode & MODE_MOUSE_ALL)); + format_add(ft, "mouse_utf8_flag", "%d", + !!(wp->base.mode & MODE_MOUSE_UTF8)); + format_add(ft, "mouse_sgr_flag", "%d", + !!(wp->base.mode & MODE_MOUSE_SGR)); format_add_cb(ft, "pane_tabs", format_cb_pane_tabs); } diff --git a/input-keys.c b/input-keys.c index f0a38c09..9e47a553 100644 --- a/input-keys.c +++ b/input-keys.c @@ -172,6 +172,13 @@ input_key(struct window_pane *wp, key_code key, struct mouse_event *m) return; } + /* Literal keys go as themselves (can't be more than eight bits). */ + if (key & KEYC_LITERAL) { + ud.data[0] = (u_char)key; + bufferevent_write(wp->event, &ud.data[0], 1); + return; + } + /* * If this is a normal 7-bit key, just send it, with a leading escape * if necessary. If it is a UTF-8 key, split it and send it. diff --git a/key-string.c b/key-string.c index 8442727d..a1ef4f51 100644 --- a/key-string.c +++ b/key-string.c @@ -284,6 +284,12 @@ key_string_lookup_key(key_code key) return (out); } + /* Literal keys are themselves. */ + if (key & KEYC_LITERAL) { + snprintf(out, sizeof out, "%c", (int)(key & 0xff)); + return (out); + } + /* * Special case: display C-@ as C-Space. Could do this below in * the (key >= 0 && key <= 32), but this way we let it be found diff --git a/tmux.1 b/tmux.1 index 20edd876..bb978655 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2627,7 +2627,7 @@ With only .Ar key-table . .It Xo Ic send-keys -.Op Fl lMRX +.Op Fl HlMRX .Op Fl N Ar repeat-count .Op Fl t Ar target-pane .Ar key Ar ... @@ -2642,10 +2642,16 @@ or .Ql NPage ) to send; if the string is not recognised as a key, it is sent as a series of characters. +All arguments are sent sequentially from first to last. +.Pp The .Fl l -flag disables key name lookup and sends the keys literally. -All arguments are sent sequentially from first to last. +flag disables key name lookup and processes the keys as literal UTF-8 +characters. +The +.Fl H +flag expects each key to be a hexadecimal number for an ASCII character. +.Pp The .Fl R flag causes the terminal state to be reset. @@ -4185,11 +4191,14 @@ The following variables are available, where appropriate: .It Li "mouse_all_flag" Ta "" Ta "Pane mouse all flag" .It Li "mouse_any_flag" Ta "" Ta "Pane mouse any flag" .It Li "mouse_button_flag" Ta "" Ta "Pane mouse button flag" +.It Li "mouse_line" Ta "" Ta "Line under mouse, if any" +.It Li "mouse_sgr_flag" Ta "" Ta "Pane mouse SGR flag" .It Li "mouse_standard_flag" Ta "" Ta "Pane mouse standard flag" +.It Li "mouse_utf8_flag" Ta "" Ta "Pane mouse UTF-8 flag" +.It Li "mouse_word" Ta "" Ta "Word under mouse, if any" .It Li "mouse_x" Ta "" Ta "Mouse X position, if any" .It Li "mouse_y" Ta "" Ta "Mouse Y position, if any" -.It Li "mouse_word" Ta "" Ta "Word under mouse, if any" -.It Li "mouse_line" Ta "" Ta "Line under mouse, if any" +.It Li "origin_flag" Ta "" Ta "Pane origin flag" .It Li "pane_active" Ta "" Ta "1 if active pane" .It Li "pane_at_bottom" Ta "" Ta "1 if pane is at the bottom of window" .It Li "pane_at_left" Ta "" Ta "1 if pane is at the left of window" diff --git a/tmux.h b/tmux.h index edc6de1f..4efdd7cb 100644 --- a/tmux.h +++ b/tmux.h @@ -113,9 +113,10 @@ struct winlink; #define KEYC_CTRL 0x400000000000ULL #define KEYC_SHIFT 0x800000000000ULL #define KEYC_XTERM 0x1000000000000ULL +#define KEYC_LITERAL 0x2000000000000ULL /* Mask to obtain key w/o modifiers. */ -#define KEYC_MASK_MOD (KEYC_ESCAPE|KEYC_CTRL|KEYC_SHIFT|KEYC_XTERM) +#define KEYC_MASK_MOD (KEYC_ESCAPE|KEYC_CTRL|KEYC_SHIFT|KEYC_XTERM|KEYC_LITERAL) #define KEYC_MASK_KEY (~KEYC_MASK_MOD) /* Is this a mouse key? */