mirror of
https://github.com/tmux/tmux.git
synced 2026-09-19 11:28:08 +00:00
Compare commits
31 Commits
kitty-keys
...
osc133_lin
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
df134f38bd | ||
|
|
a8b05dd7d7 | ||
|
|
676ad44c96 | ||
|
|
71865a58d1 | ||
|
|
9837766857 | ||
|
|
6294be4986 | ||
|
|
c5a5b99788 | ||
|
|
e23219ec04 | ||
|
|
0f29c47278 | ||
|
|
7c9fdcb770 | ||
|
|
0330d8ac57 | ||
|
|
0a7788b66f | ||
|
|
458d045bd2 | ||
|
|
a81154d6d9 | ||
|
|
cffc86dae5 | ||
|
|
4cfd155ffc | ||
|
|
670ea5d083 | ||
|
|
eaeb234dd4 | ||
|
|
5948722d5a | ||
|
|
d8ad7cd9c5 | ||
|
|
b49cc2d936 | ||
|
|
abb7108e25 | ||
|
|
d080378464 | ||
|
|
473eca949a | ||
|
|
f0eaa5e9d6 | ||
|
|
f44246c764 | ||
|
|
5d4d41da57 | ||
|
|
bacbb4d9d8 | ||
|
|
07a3a16ae7 | ||
|
|
f41288ee27 | ||
|
|
457b6cbefd |
12
CHANGES
12
CHANGES
@@ -111,18 +111,6 @@ CHANGES FROM 3.7c TO 3.8
|
||||
|
||||
* Change show-options and show-hooks to use formats and add a -F flag to each.
|
||||
|
||||
* Add support for the Kitty keyboard protocol. When extended-keys is on,
|
||||
tmux uses it with terminals which support it, detected when a client
|
||||
attaches or set with a new kittykeys terminal feature, and standard
|
||||
extended keys or VT10x keys with other terminals, so terminals with
|
||||
different capabilities may be attached at the same time. Programs inside
|
||||
tmux may ask for either the Kitty protocol or modifyOtherKeys and get keys
|
||||
in the form they asked for. The Kitty protocol can report the Super and
|
||||
Hyper modifiers (key name prefixes s- and H-).
|
||||
|
||||
* Add a client_key_mode format giving the extended key reporting mode in
|
||||
use for a client, alongside the existing pane_key_mode for a pane.
|
||||
|
||||
* Allow individual terminal features to be disabled by adding @ to their names
|
||||
in terminal-features, and add a utf8 feature for terminals which support
|
||||
UTF-8 output.
|
||||
|
||||
@@ -171,7 +171,6 @@ dist_tmux_SOURCES = \
|
||||
grid.c \
|
||||
hooks.c \
|
||||
hyperlinks.c \
|
||||
input-kitty.c \
|
||||
input-keys.c \
|
||||
input.c \
|
||||
job.c \
|
||||
@@ -213,7 +212,6 @@ dist_tmux_SOURCES = \
|
||||
tty-acs.c \
|
||||
tty-draw.c \
|
||||
tty-features.c \
|
||||
tty-kitty.c \
|
||||
tty-keys.c \
|
||||
tty-term.c \
|
||||
tty.c \
|
||||
|
||||
@@ -30,8 +30,8 @@ const struct cmd_entry cmd_copy_mode_entry = {
|
||||
.name = "copy-mode",
|
||||
.alias = NULL,
|
||||
|
||||
.args = { "dekHMqSs:t:u", 0, 0, NULL },
|
||||
.usage = "[-dekHMqSu] [-s src-pane] " CMD_TARGET_PANE_USAGE,
|
||||
.args = { "UcdekHMqSs:t:u", 0, 0, NULL },
|
||||
.usage = "[-UcdekHMqSu] [-s src-pane] " CMD_TARGET_PANE_USAGE,
|
||||
|
||||
.source = { 's', CMD_FIND_PANE, 0 },
|
||||
.target = { 't', CMD_FIND_PANE, 0 },
|
||||
|
||||
45
format.c
45
format.c
@@ -1617,41 +1617,6 @@ format_cb_client_height(struct format_tree *ft)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for client_key_mode. */
|
||||
static void *
|
||||
format_cb_client_key_mode(struct format_tree *ft)
|
||||
{
|
||||
struct client *c = ft->c;
|
||||
const char *mode;
|
||||
char *s;
|
||||
int kitty, eks;
|
||||
|
||||
if (c == NULL || (~c->tty.flags & TTY_STARTED))
|
||||
return (NULL);
|
||||
|
||||
if (c->tty.flags & TTY_KKBPUSHED) {
|
||||
xasprintf(&s, "Kitty %u", c->tty.kitty_keys);
|
||||
return (s);
|
||||
}
|
||||
|
||||
/* This mirrors the choice made in tty_update_features(). */
|
||||
kitty = ((c->tty.term->flags & TERM_KITTYKEYS) != 0);
|
||||
eks = (options_get_number(global_options, "extended-keys") != 0);
|
||||
if (kitty)
|
||||
eks = 0;
|
||||
if (eks && tty_term_has(c->tty.term, TTYC_ENEKS))
|
||||
mode = "Ext";
|
||||
else
|
||||
mode = "VT10x";
|
||||
|
||||
/* The terminal supports Kitty keys but they are not in use. */
|
||||
if (kitty) {
|
||||
xasprintf(&s, "%s (Kitty)", mode);
|
||||
return (s);
|
||||
}
|
||||
return (xstrdup(mode));
|
||||
}
|
||||
|
||||
/* Callback for client_key_table. */
|
||||
static void *
|
||||
format_cb_client_key_table(struct format_tree *ft)
|
||||
@@ -2522,14 +2487,7 @@ format_cb_pane_unseen_changes(struct format_tree *ft)
|
||||
static void *
|
||||
format_cb_pane_key_mode(struct format_tree *ft)
|
||||
{
|
||||
char *s;
|
||||
|
||||
if (ft->wp != NULL && ft->wp->screen != NULL) {
|
||||
if (ft->wp->screen->kitty_keys.flags != 0) {
|
||||
xasprintf(&s, "Kitty %u",
|
||||
ft->wp->screen->kitty_keys.flags);
|
||||
return (s);
|
||||
}
|
||||
switch (ft->wp->screen->mode & EXTENDED_KEY_MODES) {
|
||||
case MODE_KEYS_EXTENDED:
|
||||
return (xstrdup("Ext 1"));
|
||||
@@ -3684,9 +3642,6 @@ static const struct format_table_entry format_table[] = {
|
||||
{ "client_height", FORMAT_TABLE_STRING,
|
||||
format_cb_client_height
|
||||
},
|
||||
{ "client_key_mode", FORMAT_TABLE_STRING,
|
||||
format_cb_client_key_mode
|
||||
},
|
||||
{ "client_key_table", FORMAT_TABLE_STRING,
|
||||
format_cb_client_key_table
|
||||
},
|
||||
|
||||
2
grid.c
2
grid.c
@@ -1760,6 +1760,8 @@ grid_line_flags_string(int flags)
|
||||
strlcat(s, "START_OUTPUT,", sizeof s);
|
||||
if (flags & GRID_LINE_END_OUTPUT)
|
||||
strlcat(s, "END_OUTPUT,", sizeof s);
|
||||
if (flags & GRID_LINE_END_OUTPUT_STATUS)
|
||||
strlcat(s, "END_OUTPUT_STATUS,", sizeof s);
|
||||
if (flags & GRID_LINE_HYPERLINK)
|
||||
strlcat(s, "HYPERLINK,", sizeof s);
|
||||
if (*s == '\0')
|
||||
|
||||
11
input-keys.c
11
input-keys.c
@@ -464,8 +464,7 @@ input_key_extended(struct bufferevent *bev, key_code key)
|
||||
} else
|
||||
key &= KEYC_MASK_KEY;
|
||||
|
||||
if (options_get_number(global_options, "extended-keys-format") ==
|
||||
EXTENDED_KEYS_XTERM)
|
||||
if (options_get_number(global_options, "extended-keys-format") == 1)
|
||||
xsnprintf(tmp, sizeof tmp, "\033[27;%c;%llu~", modifier, key);
|
||||
else
|
||||
xsnprintf(tmp, sizeof tmp, "\033[%llu;%cu", key, modifier);
|
||||
@@ -589,10 +588,6 @@ input_key(struct screen *s, struct bufferevent *bev, key_code key)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Kitty keys take precedence if the application asked for them. */
|
||||
if (input_key_kitty(s, bev, key) == 0)
|
||||
return (0);
|
||||
|
||||
/* Is this backspace? */
|
||||
if ((key & KEYC_MASK_KEY) == KEYC_BSPACE) {
|
||||
newkey = options_get_number(global_options, "backspace");
|
||||
@@ -682,10 +677,6 @@ input_key(struct screen *s, struct bufferevent *bev, key_code key)
|
||||
log_debug("%s: ignoring key 0x%llx", __func__, key);
|
||||
return (0);
|
||||
}
|
||||
if (key & (KEYC_SUPER|KEYC_HYPER))
|
||||
return (input_key_vt10x(bev, key));
|
||||
if (s->kitty_keys.flags & KITTY_KEY_SUPPORTED)
|
||||
return (input_key_vt10x(bev, key));
|
||||
|
||||
/*
|
||||
* No builtin key sequence; construct an extended key sequence
|
||||
|
||||
313
input-kitty.c
313
input-kitty.c
@@ -1,313 +0,0 @@
|
||||
/* $OpenBSD$ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2026 Michael Grant <mgrant@grant.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
/* Track pane keyboard state and encode keys for applications. */
|
||||
|
||||
struct input_kitty_key {
|
||||
key_code key;
|
||||
u_int number;
|
||||
char final;
|
||||
};
|
||||
|
||||
static const struct input_kitty_key input_kitty_keys[] = {
|
||||
{ C0_ESC, 27, 'u' },
|
||||
{ C0_CR, 13, 'u' },
|
||||
{ C0_HT, 9, 'u' },
|
||||
{ KEYC_BSPACE, 127, 'u' },
|
||||
{ KEYC_IC, 2, '~' },
|
||||
{ KEYC_DC, 3, '~' },
|
||||
{ KEYC_LEFT, 1, 'D' },
|
||||
{ KEYC_RIGHT, 1, 'C' },
|
||||
{ KEYC_UP, 1, 'A' },
|
||||
{ KEYC_DOWN, 1, 'B' },
|
||||
{ KEYC_PPAGE, 5, '~' },
|
||||
{ KEYC_NPAGE, 6, '~' },
|
||||
{ KEYC_HOME, 1, 'H' },
|
||||
{ KEYC_END, 1, 'F' },
|
||||
{ KEYC_F1, 1, 'P' },
|
||||
{ KEYC_F2, 1, 'Q' },
|
||||
{ KEYC_F3, 13, '~' },
|
||||
{ KEYC_F4, 1, 'S' },
|
||||
{ KEYC_F5, 15, '~' },
|
||||
{ KEYC_F6, 17, '~' },
|
||||
{ KEYC_F7, 18, '~' },
|
||||
{ KEYC_F8, 19, '~' },
|
||||
{ KEYC_F9, 20, '~' },
|
||||
{ KEYC_F10, 21, '~' },
|
||||
{ KEYC_F11, 23, '~' },
|
||||
{ KEYC_F12, 24, '~' },
|
||||
{ KEYC_CAPSLOCK, 57358, 'u' },
|
||||
{ KEYC_SCROLLLOCK, 57359, 'u' },
|
||||
{ KEYC_NUMLOCK, 57360, 'u' },
|
||||
{ KEYC_PRINTSCREEN, 57361, 'u' },
|
||||
{ KEYC_PAUSE, 57362, 'u' },
|
||||
{ KEYC_MENU, 57363, 'u' },
|
||||
{ KEYC_F13, 57376, 'u' },
|
||||
{ KEYC_F14, 57377, 'u' },
|
||||
{ KEYC_F15, 57378, 'u' },
|
||||
{ KEYC_F16, 57379, 'u' },
|
||||
{ KEYC_F17, 57380, 'u' },
|
||||
{ KEYC_F18, 57381, 'u' },
|
||||
{ KEYC_F19, 57382, 'u' },
|
||||
{ KEYC_F20, 57383, 'u' },
|
||||
{ KEYC_F21, 57384, 'u' },
|
||||
{ KEYC_F22, 57385, 'u' },
|
||||
{ KEYC_F23, 57386, 'u' },
|
||||
{ KEYC_F24, 57387, 'u' },
|
||||
{ KEYC_F25, 57388, 'u' },
|
||||
{ KEYC_F26, 57389, 'u' },
|
||||
{ KEYC_F27, 57390, 'u' },
|
||||
{ KEYC_F28, 57391, 'u' },
|
||||
{ KEYC_F29, 57392, 'u' },
|
||||
{ KEYC_F30, 57393, 'u' },
|
||||
{ KEYC_F31, 57394, 'u' },
|
||||
{ KEYC_F32, 57395, 'u' },
|
||||
{ KEYC_F33, 57396, 'u' },
|
||||
{ KEYC_F34, 57397, 'u' },
|
||||
{ KEYC_F35, 57398, 'u' },
|
||||
{ KEYC_KP_ZERO|KEYC_KEYPAD, 57399, 'u' },
|
||||
{ KEYC_KP_ONE|KEYC_KEYPAD, 57400, 'u' },
|
||||
{ KEYC_KP_TWO|KEYC_KEYPAD, 57401, 'u' },
|
||||
{ KEYC_KP_THREE|KEYC_KEYPAD, 57402, 'u' },
|
||||
{ KEYC_KP_FOUR|KEYC_KEYPAD, 57403, 'u' },
|
||||
{ KEYC_KP_FIVE|KEYC_KEYPAD, 57404, 'u' },
|
||||
{ KEYC_KP_SIX|KEYC_KEYPAD, 57405, 'u' },
|
||||
{ KEYC_KP_SEVEN|KEYC_KEYPAD, 57406, 'u' },
|
||||
{ KEYC_KP_EIGHT|KEYC_KEYPAD, 57407, 'u' },
|
||||
{ KEYC_KP_NINE|KEYC_KEYPAD, 57408, 'u' },
|
||||
{ KEYC_KP_PERIOD|KEYC_KEYPAD, 57409, 'u' },
|
||||
{ KEYC_KP_SLASH|KEYC_KEYPAD, 57410, 'u' },
|
||||
{ KEYC_KP_STAR|KEYC_KEYPAD, 57411, 'u' },
|
||||
{ KEYC_KP_MINUS|KEYC_KEYPAD, 57412, 'u' },
|
||||
{ KEYC_KP_PLUS|KEYC_KEYPAD, 57413, 'u' },
|
||||
{ KEYC_KP_ENTER|KEYC_KEYPAD, 57414, 'u' },
|
||||
{ KEYC_KP_EQUAL|KEYC_KEYPAD, 57415, 'u' },
|
||||
{ KEYC_KP_SEPARATOR|KEYC_KEYPAD, 57416, 'u' },
|
||||
{ KEYC_KP_LEFT|KEYC_KEYPAD, 57417, 'u' },
|
||||
{ KEYC_KP_RIGHT|KEYC_KEYPAD, 57418, 'u' },
|
||||
{ KEYC_KP_UP|KEYC_KEYPAD, 57419, 'u' },
|
||||
{ KEYC_KP_DOWN|KEYC_KEYPAD, 57420, 'u' },
|
||||
{ KEYC_KP_PPAGE|KEYC_KEYPAD, 57421, 'u' },
|
||||
{ KEYC_KP_NPAGE|KEYC_KEYPAD, 57422, 'u' },
|
||||
{ KEYC_KP_HOME|KEYC_KEYPAD, 57423, 'u' },
|
||||
{ KEYC_KP_END|KEYC_KEYPAD, 57424, 'u' },
|
||||
{ KEYC_KP_IC|KEYC_KEYPAD, 57425, 'u' },
|
||||
{ KEYC_KP_DC|KEYC_KEYPAD, 57426, 'u' },
|
||||
{ KEYC_KP_BEGIN|KEYC_KEYPAD, 57427, '~' },
|
||||
{ KEYC_MEDIA_PLAY, 57428, 'u' },
|
||||
{ KEYC_MEDIA_PAUSE, 57429, 'u' },
|
||||
{ KEYC_MEDIA_PLAYPAUSE, 57430, 'u' },
|
||||
{ KEYC_MEDIA_REVERSE, 57431, 'u' },
|
||||
{ KEYC_MEDIA_STOP, 57432, 'u' },
|
||||
{ KEYC_MEDIA_FASTFORWARD, 57433, 'u' },
|
||||
{ KEYC_MEDIA_REWIND, 57434, 'u' },
|
||||
{ KEYC_MEDIA_NEXT, 57435, 'u' },
|
||||
{ KEYC_MEDIA_PREVIOUS, 57436, 'u' },
|
||||
{ KEYC_MEDIA_RECORD, 57437, 'u' },
|
||||
{ KEYC_VOLUME_DOWN, 57438, 'u' },
|
||||
{ KEYC_VOLUME_UP, 57439, 'u' },
|
||||
{ KEYC_VOLUME_MUTE, 57440, 'u' },
|
||||
{ KEYC_LEFT_SHIFT, 57441, 'u' },
|
||||
{ KEYC_LEFT_CTRL, 57442, 'u' },
|
||||
{ KEYC_LEFT_ALT, 57443, 'u' },
|
||||
{ KEYC_LEFT_SUPER, 57444, 'u' },
|
||||
{ KEYC_LEFT_HYPER, 57445, 'u' },
|
||||
{ KEYC_LEFT_META, 57446, 'u' },
|
||||
{ KEYC_RIGHT_SHIFT, 57447, 'u' },
|
||||
{ KEYC_RIGHT_CTRL, 57448, 'u' },
|
||||
{ KEYC_RIGHT_ALT, 57449, 'u' },
|
||||
{ KEYC_RIGHT_SUPER, 57450, 'u' },
|
||||
{ KEYC_RIGHT_HYPER, 57451, 'u' },
|
||||
{ KEYC_RIGHT_META, 57452, 'u' },
|
||||
{ KEYC_ISO_LEVEL3_SHIFT, 57453, 'u' },
|
||||
{ KEYC_ISO_LEVEL5_SHIFT, 57454, 'u' }
|
||||
};
|
||||
|
||||
void
|
||||
input_kitty_reset(struct screen *s)
|
||||
{
|
||||
memset(&s->kitty_keys, 0, sizeof s->kitty_keys);
|
||||
}
|
||||
|
||||
void
|
||||
input_kitty_alternate_on(struct screen *s)
|
||||
{
|
||||
s->saved_kitty_keys = s->kitty_keys;
|
||||
input_kitty_reset(s);
|
||||
}
|
||||
|
||||
void
|
||||
input_kitty_alternate_off(struct screen *s)
|
||||
{
|
||||
s->kitty_keys = s->saved_kitty_keys;
|
||||
memset(&s->saved_kitty_keys, 0, sizeof s->saved_kitty_keys);
|
||||
}
|
||||
|
||||
void
|
||||
input_kitty_set(struct screen *s, u_int flags, int mode)
|
||||
{
|
||||
flags &= KITTY_KEY_SUPPORTED;
|
||||
if (mode == 2)
|
||||
s->kitty_keys.flags |= flags;
|
||||
else if (mode == 3)
|
||||
s->kitty_keys.flags &= ~flags;
|
||||
else
|
||||
s->kitty_keys.flags = flags;
|
||||
}
|
||||
|
||||
void
|
||||
input_kitty_push(struct screen *s, u_int flags)
|
||||
{
|
||||
s->kitty_keys.saved_flags = s->kitty_keys.flags;
|
||||
s->kitty_keys.have_saved = 1;
|
||||
s->kitty_keys.flags = flags & KITTY_KEY_SUPPORTED;
|
||||
}
|
||||
|
||||
void
|
||||
input_kitty_pop(struct screen *s, u_int count)
|
||||
{
|
||||
if (count == 0)
|
||||
return;
|
||||
if (s->kitty_keys.have_saved && count == 1)
|
||||
s->kitty_keys.flags = s->kitty_keys.saved_flags;
|
||||
else
|
||||
s->kitty_keys.flags = 0;
|
||||
s->kitty_keys.have_saved = 0;
|
||||
}
|
||||
|
||||
static u_int
|
||||
input_kitty_modifiers(key_code key)
|
||||
{
|
||||
u_int modifiers = 1;
|
||||
|
||||
if (key & KEYC_SHIFT)
|
||||
modifiers += 1;
|
||||
if (key & KEYC_META)
|
||||
modifiers += 2;
|
||||
if (key & KEYC_CTRL)
|
||||
modifiers += 4;
|
||||
if (key & KEYC_SUPER)
|
||||
modifiers += 8;
|
||||
if (key & KEYC_HYPER)
|
||||
modifiers += 16;
|
||||
return (modifiers);
|
||||
}
|
||||
|
||||
static const struct input_kitty_key *
|
||||
input_kitty_lookup(key_code key)
|
||||
{
|
||||
key_code lookup;
|
||||
u_int i;
|
||||
|
||||
lookup = key & (KEYC_MASK_KEY|KEYC_KEYPAD);
|
||||
for (i = 0; i < nitems(input_kitty_keys); i++) {
|
||||
if (input_kitty_keys[i].key == lookup)
|
||||
return (&input_kitty_keys[i]);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
int
|
||||
input_key_kitty(struct screen *s, struct bufferevent *bev, key_code key)
|
||||
{
|
||||
const struct input_kitty_key *ikk;
|
||||
struct utf8_data ud;
|
||||
wchar_t wc;
|
||||
key_code modifiers, onlykey;
|
||||
u_int flags, number, modifier;
|
||||
char tmp[64];
|
||||
size_t size;
|
||||
|
||||
flags = s->kitty_keys.flags & KITTY_KEY_SUPPORTED;
|
||||
if (flags == 0)
|
||||
return (-1);
|
||||
if ((key & KEYC_MASK_KEY) == KEYC_BTAB)
|
||||
key = C0_HT|(key & ~KEYC_MASK_KEY)|KEYC_SHIFT;
|
||||
|
||||
modifiers = key & (KEYC_SHIFT|KEYC_META|KEYC_CTRL|KEYC_SUPER|KEYC_HYPER);
|
||||
ikk = input_kitty_lookup(key);
|
||||
if (ikk != NULL) {
|
||||
if ((flags & KITTY_KEY_REPORT_ALL) == 0) {
|
||||
if (ikk->key == C0_CR || ikk->key == C0_HT ||
|
||||
ikk->key == KEYC_BSPACE)
|
||||
return (-1);
|
||||
if (ikk->final != 'u' &&
|
||||
(modifiers & (KEYC_SUPER|KEYC_HYPER)) == 0)
|
||||
return (-1);
|
||||
}
|
||||
number = ikk->number;
|
||||
modifier = input_kitty_modifiers(key);
|
||||
if (ikk->final == 'u') {
|
||||
if (modifier == 1)
|
||||
size = xsnprintf(tmp, sizeof tmp, "\033[%uu", number);
|
||||
else
|
||||
size = xsnprintf(tmp, sizeof tmp, "\033[%u;%uu",
|
||||
number, modifier);
|
||||
} else if (ikk->final == '~') {
|
||||
if (modifier == 1)
|
||||
size = xsnprintf(tmp, sizeof tmp, "\033[%u~", number);
|
||||
else
|
||||
size = xsnprintf(tmp, sizeof tmp, "\033[%u;%u~",
|
||||
number, modifier);
|
||||
} else {
|
||||
if (modifier == 1)
|
||||
size = xsnprintf(tmp, sizeof tmp, "\033[%c",
|
||||
ikk->final);
|
||||
else
|
||||
size = xsnprintf(tmp, sizeof tmp, "\033[1;%u%c",
|
||||
modifier, ikk->final);
|
||||
}
|
||||
goto write;
|
||||
}
|
||||
|
||||
if ((flags & KITTY_KEY_REPORT_ALL) == 0 &&
|
||||
(modifiers & (KEYC_META|KEYC_CTRL|KEYC_SUPER|KEYC_HYPER)) == 0)
|
||||
return (-1);
|
||||
|
||||
onlykey = key & KEYC_MASK_KEY;
|
||||
if (KEYC_IS_UNICODE(key)) {
|
||||
utf8_to_data(onlykey, &ud);
|
||||
if (utf8_towc(&ud, &wc) != UTF8_DONE)
|
||||
return (-1);
|
||||
number = wc;
|
||||
} else if (onlykey <= 0x7f)
|
||||
number = onlykey;
|
||||
else
|
||||
return (-1);
|
||||
if ((key & KEYC_SHIFT) && number >= 'A' && number <= 'Z')
|
||||
number += 'a' - 'A';
|
||||
|
||||
modifier = input_kitty_modifiers(key);
|
||||
if (modifier == 1)
|
||||
size = xsnprintf(tmp, sizeof tmp, "\033[%uu", number);
|
||||
else
|
||||
size = xsnprintf(tmp, sizeof tmp, "\033[%u;%uu", number,
|
||||
modifier);
|
||||
|
||||
write:
|
||||
log_debug("%s: %.*s", __func__, (int)size, tmp);
|
||||
bufferevent_write(bev, tmp, size);
|
||||
return (0);
|
||||
}
|
||||
100
input.c
100
input.c
@@ -279,10 +279,6 @@ enum input_csi_type {
|
||||
INPUT_CSI_HPA,
|
||||
INPUT_CSI_ICH,
|
||||
INPUT_CSI_IL,
|
||||
INPUT_CSI_KITTY_POP,
|
||||
INPUT_CSI_KITTY_PUSH,
|
||||
INPUT_CSI_KITTY_QUERY,
|
||||
INPUT_CSI_KITTY_SET,
|
||||
INPUT_CSI_MODOFF,
|
||||
INPUT_CSI_MODSET,
|
||||
INPUT_CSI_QUERY,
|
||||
@@ -348,11 +344,7 @@ static const struct input_table_entry input_csi_table[] = {
|
||||
{ 'r', "", INPUT_CSI_DECSTBM },
|
||||
{ 's', "", INPUT_CSI_SCP },
|
||||
{ 't', "", INPUT_CSI_WINOPS },
|
||||
{ 'u', "", INPUT_CSI_RCP },
|
||||
{ 'u', "<", INPUT_CSI_KITTY_POP },
|
||||
{ 'u', "=", INPUT_CSI_KITTY_SET },
|
||||
{ 'u', ">", INPUT_CSI_KITTY_PUSH },
|
||||
{ 'u', "?", INPUT_CSI_KITTY_QUERY }
|
||||
{ 'u', "", INPUT_CSI_RCP }
|
||||
};
|
||||
|
||||
/* Input transition. */
|
||||
@@ -1565,33 +1557,6 @@ input_csi_dispatch(struct input_ctx *ictx)
|
||||
if (options_get_number(global_options, "extended-keys") == 2)
|
||||
screen_write_mode_set(sctx, MODE_KEYS_EXTENDED);
|
||||
break;
|
||||
case INPUT_CSI_KITTY_QUERY:
|
||||
if (options_get_number(global_options, "extended-keys") == 0)
|
||||
break;
|
||||
input_reply(ictx, 1, "\033[?%uu", s->kitty_keys.flags);
|
||||
break;
|
||||
case INPUT_CSI_KITTY_SET:
|
||||
if (options_get_number(global_options, "extended-keys") == 0)
|
||||
break;
|
||||
n = input_get(ictx, 0, 0, 0);
|
||||
m = input_get(ictx, 1, 1, 1);
|
||||
if (n >= 0 && m >= 1 && m <= 3)
|
||||
input_kitty_set(s, n, m);
|
||||
break;
|
||||
case INPUT_CSI_KITTY_PUSH:
|
||||
if (options_get_number(global_options, "extended-keys") == 0)
|
||||
break;
|
||||
n = input_get(ictx, 0, 0, 0);
|
||||
if (n >= 0)
|
||||
input_kitty_push(s, n);
|
||||
break;
|
||||
case INPUT_CSI_KITTY_POP:
|
||||
if (options_get_number(global_options, "extended-keys") == 0)
|
||||
break;
|
||||
n = input_get(ictx, 0, 1, 1);
|
||||
if (n >= 0)
|
||||
input_kitty_pop(s, n);
|
||||
break;
|
||||
case INPUT_CSI_WINOPS:
|
||||
input_csi_dispatch_winops(ictx);
|
||||
break;
|
||||
@@ -3229,13 +3194,14 @@ input_osc_112(struct input_ctx *ictx, const char *p)
|
||||
|
||||
/* Parse the OSC 133 D exit status. */
|
||||
static int
|
||||
input_osc_133_exit_status(const char *p)
|
||||
input_osc_133_exit_status(const char *p, int *present)
|
||||
{
|
||||
const char *end;
|
||||
char *copy;
|
||||
const char *errstr;
|
||||
char *endptr;
|
||||
long long status;
|
||||
|
||||
*present = 0;
|
||||
if (p[1] != ';' || p[2] == '\0' || strchr(p + 2, '=') == p + 2)
|
||||
return (0);
|
||||
end = strchr(p + 2, ';');
|
||||
@@ -3249,9 +3215,11 @@ input_osc_133_exit_status(const char *p)
|
||||
free(copy);
|
||||
return (0);
|
||||
}
|
||||
status = strtonum(copy, 0, 255, &errstr);
|
||||
*present = 1;
|
||||
errno = 0;
|
||||
status = (int)strtol(copy, &endptr, 10);
|
||||
free(copy);
|
||||
if (errstr != NULL)
|
||||
if (errno != 0 || endptr == copy || status < 0 || status > 255)
|
||||
return (255);
|
||||
return (status);
|
||||
}
|
||||
@@ -3296,6 +3264,22 @@ input_fire_command_event(struct window_pane *wp, const char *name)
|
||||
events_fire(name, ep);
|
||||
}
|
||||
|
||||
/* Check if an OSC 133 prompt is secondary or a continuation. */
|
||||
static int
|
||||
input_osc_133_secondary_prompt(const char *p)
|
||||
{
|
||||
const char *cp;
|
||||
|
||||
while ((cp = strstr(p, ";k=")) != NULL) {
|
||||
cp += 3;
|
||||
if ((*cp == 's' || *cp == 'c') &&
|
||||
(cp[1] == '\0' || cp[1] == ';'))
|
||||
return (1);
|
||||
p = cp;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Handle the OSC 133 sequence. */
|
||||
static void
|
||||
input_osc_133(struct input_ctx *ictx, const char *p)
|
||||
@@ -3305,8 +3289,7 @@ input_osc_133(struct input_ctx *ictx, const char *p)
|
||||
struct grid *gd = s->grid;
|
||||
u_int line = s->cy + gd->hsize;
|
||||
struct grid_line *gl = NULL;
|
||||
const char *cp;
|
||||
int status;
|
||||
int status, status_present;
|
||||
|
||||
if (line < gd->hsize + gd->sy)
|
||||
gl = grid_get_line(gd, line);
|
||||
@@ -3315,9 +3298,14 @@ input_osc_133(struct input_ctx *ictx, const char *p)
|
||||
case 'A':
|
||||
case 'N':
|
||||
if (gl != NULL) {
|
||||
memset(&gl->osc133_data, 0, sizeof gl->osc133_data);
|
||||
gl->osc133_data.prompt_col = s->cx;
|
||||
gl->flags |= GRID_LINE_START_PROMPT;
|
||||
if (!(gl->flags & (GRID_LINE_START_PROMPT|
|
||||
GRID_LINE_SECOND_PROMPT))) {
|
||||
gl->osc133_data.prompt_col = s->cx;
|
||||
if (input_osc_133_secondary_prompt(p))
|
||||
gl->flags |= GRID_LINE_SECOND_PROMPT;
|
||||
else
|
||||
gl->flags |= GRID_LINE_START_PROMPT;
|
||||
}
|
||||
}
|
||||
if (wp != NULL) {
|
||||
wp->last_prompt_time = time(NULL);
|
||||
@@ -3326,23 +3314,25 @@ input_osc_133(struct input_ctx *ictx, const char *p)
|
||||
break;
|
||||
case 'P':
|
||||
if (gl != NULL) {
|
||||
cp = strstr(p, ";k=s");
|
||||
if (cp != NULL && (cp[4] == ';' || cp[4] == '\0'))
|
||||
gl->flags |= GRID_LINE_SECOND_PROMPT;
|
||||
else
|
||||
gl->flags |= GRID_LINE_START_PROMPT;
|
||||
gl->osc133_data.prompt_col = s->cx;
|
||||
if (!(gl->flags & (GRID_LINE_START_PROMPT|
|
||||
GRID_LINE_SECOND_PROMPT))) {
|
||||
gl->osc133_data.prompt_col = s->cx;
|
||||
if (input_osc_133_secondary_prompt(p))
|
||||
gl->flags |= GRID_LINE_SECOND_PROMPT;
|
||||
else
|
||||
gl->flags |= GRID_LINE_START_PROMPT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'B':
|
||||
case 'I':
|
||||
if (gl != NULL) {
|
||||
if (gl != NULL && !(gl->flags & GRID_LINE_START_COMMAND)) {
|
||||
gl->flags |= GRID_LINE_START_COMMAND;
|
||||
gl->osc133_data.cmd_col = s->cx;
|
||||
}
|
||||
break;
|
||||
case 'C':
|
||||
if (gl != NULL) {
|
||||
if (gl != NULL && !(gl->flags & GRID_LINE_START_OUTPUT)) {
|
||||
gl->flags |= GRID_LINE_START_OUTPUT;
|
||||
gl->osc133_data.out_start_col = s->cx;
|
||||
}
|
||||
@@ -3355,7 +3345,7 @@ input_osc_133(struct input_ctx *ictx, const char *p)
|
||||
}
|
||||
break;
|
||||
case 'D':
|
||||
status = input_osc_133_exit_status(p);
|
||||
status = input_osc_133_exit_status(p, &status_present);
|
||||
if (wp != NULL) {
|
||||
wp->cmd_end_time = time(NULL);
|
||||
wp->flags &= ~PANE_CMDRUNNING;
|
||||
@@ -3364,6 +3354,8 @@ input_osc_133(struct input_ctx *ictx, const char *p)
|
||||
}
|
||||
if (gl != NULL) {
|
||||
gl->flags |= GRID_LINE_END_OUTPUT;
|
||||
if (status_present)
|
||||
gl->flags |= GRID_LINE_END_OUTPUT_STATUS;
|
||||
gl->osc133_data.out_end_col = s->cx;
|
||||
gl->osc133_data.exit_status = status;
|
||||
}
|
||||
|
||||
@@ -52,7 +52,9 @@
|
||||
" '#{?#{m/r:(copy|view)-mode,#{pane_mode}},Go To Top,}' '<' {send -X history-top}" \
|
||||
" '#{?#{m/r:(copy|view)-mode,#{pane_mode}},Go To Bottom,}' '>' {send -X history-bottom}" \
|
||||
" ''" \
|
||||
" '#{?#{==:#{pane_mode},copy-mode},#{?copy_line_numbers,Hide Line Numbers,Show Line Numbers},}' 'L' {send -X line-numbers-toggle}" \
|
||||
" '#{?#{==:#{pane_mode},copy-mode},#{?copy_line_numbers,Line Numbers Off,Line Numbers On},}' 'L' {send -X line-numbers-toggle}" \
|
||||
" '#{?#{==:#{pane_mode},copy-mode},#{?copy_fold_view,Fold View Off,Fold View On},}' 'O' {send -X fold-view-toggle}" \
|
||||
" '#{?#{==:#{pane_mode},copy-mode},Edit,}' 'e' {if -F '#{selection_present}' {send -X open-selection} {send -X open-output}}" \
|
||||
" '#{?#{==:#{pane_mode},copy-mode},#{?refresh_active,Refresh Off,Refresh On},}' 'r' {send -X refresh-toggle}" \
|
||||
" ''" \
|
||||
" '#{?#{&&:#{buffer_size},#{!:#{pane_in_mode}}},Paste #[underscore]#{=/9/...:buffer_sample},}' 'p' {paste-buffer}" \
|
||||
@@ -575,6 +577,7 @@ key_bindings_init(void)
|
||||
"bind -Tcopy-mode C-l { send -X recentre-top-bottom }",
|
||||
"bind -Tcopy-mode M-l { send -X cursor-centre-horizontal }",
|
||||
"bind -Tcopy-mode C-n { send -X cursor-down }",
|
||||
"bind -Tcopy-mode C-o { send -X select-output }",
|
||||
"bind -Tcopy-mode C-p { send -X cursor-up }",
|
||||
"bind -Tcopy-mode C-r { command-prompt -P -T search -ip'(search up)' -I'#{pane_search_string}' { send -X search-backward-incremental -- '%%' } }",
|
||||
"bind -Tcopy-mode C-s { command-prompt -P -T search -ip'(search down)' -I'#{pane_search_string}' { send -X search-forward-incremental -- '%%' } }",
|
||||
@@ -583,15 +586,19 @@ key_bindings_init(void)
|
||||
"bind -Tcopy-mode Escape { send -X cancel }",
|
||||
"bind -Tcopy-mode C-[ { send -X cancel }",
|
||||
"bind -Tcopy-mode Space { send -X page-down }",
|
||||
"bind -Tcopy-mode Tab { send -X toggle-output }",
|
||||
"bind -Tcopy-mode BTab { send -X toggle-output -a }",
|
||||
"bind -Tcopy-mode , { send -X jump-reverse }",
|
||||
"bind -Tcopy-mode \\; { send -X jump-again }",
|
||||
"bind -Tcopy-mode F { command-prompt -P -1p'(jump backward)' { send -X jump-backward -- '%%' } }",
|
||||
"bind -Tcopy-mode L { send -X line-numbers-toggle }",
|
||||
"bind -Tcopy-mode N { send -X search-reverse }",
|
||||
"bind -Tcopy-mode O { send -X fold-view-toggle }",
|
||||
"bind -Tcopy-mode P { send -X toggle-position }",
|
||||
"bind -Tcopy-mode R { send -X rectangle-toggle }",
|
||||
"bind -Tcopy-mode T { command-prompt -P -1p'(jump to backward)' { send -X jump-to-backward -- '%%' } }",
|
||||
"bind -Tcopy-mode X { send -X set-mark }",
|
||||
"bind -Tcopy-mode e { if -F '#{selection_present}' { send -X open-selection } { send -X open-output } }",
|
||||
"bind -Tcopy-mode f { command-prompt -P -1p'(jump forward)' { send -X jump-forward -- '%%' } }",
|
||||
"bind -Tcopy-mode g { command-prompt -P -p'(goto line)' { send -X goto-line -- '%%' } }",
|
||||
"bind -Tcopy-mode n { send -X search-again }",
|
||||
@@ -600,7 +607,7 @@ key_bindings_init(void)
|
||||
"bind -Tcopy-mode t { command-prompt -P -1p'(jump to forward)' { send -X jump-to-forward -- '%%' } }",
|
||||
"bind -Tcopy-mode Home { send -X start-of-line }",
|
||||
"bind -Tcopy-mode End { send -X end-of-line }",
|
||||
"bind -Tcopy-mode MouseDown1Pane select-pane",
|
||||
"bind -Tcopy-mode MouseDown1Pane { select-pane; send -X toggle-output -m }",
|
||||
"bind -Tcopy-mode MouseDrag1Pane { select-pane; send -X begin-selection }",
|
||||
"bind -Tcopy-mode MouseDragEnd1Pane { send -X copy-pipe-and-cancel }",
|
||||
"bind -Tcopy-mode WheelUpPane { select-pane; send -N5 -X scroll-up }",
|
||||
@@ -660,6 +667,8 @@ key_bindings_init(void)
|
||||
"bind -Tcopy-mode-vi Escape { send -X clear-selection }",
|
||||
"bind -Tcopy-mode-vi C-[ { send -X clear-selection }",
|
||||
"bind -Tcopy-mode-vi Space { send -X begin-selection }",
|
||||
"bind -Tcopy-mode-vi Tab { send -X toggle-output }",
|
||||
"bind -Tcopy-mode-vi BTab { send -X toggle-output -a }",
|
||||
"bind -Tcopy-mode-vi '$' { send -X end-of-line }",
|
||||
"bind -Tcopy-mode-vi , { send -X jump-reverse }",
|
||||
"bind -Tcopy-mode-vi / { command-prompt -P -T search -p'(search down)' { send -X search-forward -- '%%' } }",
|
||||
@@ -687,7 +696,10 @@ key_bindings_init(void)
|
||||
"bind -Tcopy-mode-vi K { send -X scroll-up }",
|
||||
"bind -Tcopy-mode-vi L { send -X bottom-line }",
|
||||
"bind -Tcopy-mode-vi M { send -X middle-line }",
|
||||
"bind -Tcopy-mode-vi M-e { if -F '#{selection_present}' { send -X open-selection } { send -X open-output } }",
|
||||
"bind -Tcopy-mode-vi M-o { send -X select-output }",
|
||||
"bind -Tcopy-mode-vi N { send -X search-reverse }",
|
||||
"bind -Tcopy-mode-vi O { send -X fold-view-toggle }",
|
||||
"bind -Tcopy-mode-vi P { send -X toggle-position }",
|
||||
"bind -Tcopy-mode-vi T { command-prompt -P -1p'(jump to backward)' { send -X jump-to-backward -- '%%' } }",
|
||||
"bind -Tcopy-mode-vi V { send -X select-line }",
|
||||
@@ -715,7 +727,7 @@ key_bindings_init(void)
|
||||
"bind -Tcopy-mode-vi % { send -X next-matching-bracket }",
|
||||
"bind -Tcopy-mode-vi Home { send -X start-of-line }",
|
||||
"bind -Tcopy-mode-vi End { send -X end-of-line }",
|
||||
"bind -Tcopy-mode-vi MouseDown1Pane { select-pane }",
|
||||
"bind -Tcopy-mode-vi MouseDown1Pane { select-pane; send -X toggle-output -m }",
|
||||
"bind -Tcopy-mode-vi MouseDrag1Pane { select-pane; send -X begin-selection }",
|
||||
"bind -Tcopy-mode-vi MouseDragEnd1Pane { send -X copy-pipe-and-cancel }",
|
||||
"bind -Tcopy-mode-vi WheelUpPane { select-pane; send -N5 -X scroll-up }",
|
||||
|
||||
82
key-string.c
82
key-string.c
@@ -45,29 +45,6 @@ static const struct {
|
||||
{ "F10", KEYC_F10|KEYC_IMPLIED_META },
|
||||
{ "F11", KEYC_F11|KEYC_IMPLIED_META },
|
||||
{ "F12", KEYC_F12|KEYC_IMPLIED_META },
|
||||
{ "F13", KEYC_F13|KEYC_IMPLIED_META },
|
||||
{ "F14", KEYC_F14|KEYC_IMPLIED_META },
|
||||
{ "F15", KEYC_F15|KEYC_IMPLIED_META },
|
||||
{ "F16", KEYC_F16|KEYC_IMPLIED_META },
|
||||
{ "F17", KEYC_F17|KEYC_IMPLIED_META },
|
||||
{ "F18", KEYC_F18|KEYC_IMPLIED_META },
|
||||
{ "F19", KEYC_F19|KEYC_IMPLIED_META },
|
||||
{ "F20", KEYC_F20|KEYC_IMPLIED_META },
|
||||
{ "F21", KEYC_F21|KEYC_IMPLIED_META },
|
||||
{ "F22", KEYC_F22|KEYC_IMPLIED_META },
|
||||
{ "F23", KEYC_F23|KEYC_IMPLIED_META },
|
||||
{ "F24", KEYC_F24|KEYC_IMPLIED_META },
|
||||
{ "F25", KEYC_F25|KEYC_IMPLIED_META },
|
||||
{ "F26", KEYC_F26|KEYC_IMPLIED_META },
|
||||
{ "F27", KEYC_F27|KEYC_IMPLIED_META },
|
||||
{ "F28", KEYC_F28|KEYC_IMPLIED_META },
|
||||
{ "F29", KEYC_F29|KEYC_IMPLIED_META },
|
||||
{ "F30", KEYC_F30|KEYC_IMPLIED_META },
|
||||
{ "F31", KEYC_F31|KEYC_IMPLIED_META },
|
||||
{ "F32", KEYC_F32|KEYC_IMPLIED_META },
|
||||
{ "F33", KEYC_F33|KEYC_IMPLIED_META },
|
||||
{ "F34", KEYC_F34|KEYC_IMPLIED_META },
|
||||
{ "F35", KEYC_F35|KEYC_IMPLIED_META },
|
||||
{ "IC", KEYC_IC|KEYC_IMPLIED_META },
|
||||
{ "Insert", KEYC_IC|KEYC_IMPLIED_META },
|
||||
{ "DC", KEYC_DC|KEYC_IMPLIED_META },
|
||||
@@ -145,54 +122,6 @@ static const struct {
|
||||
{ "KPEnter", KEYC_KP_ENTER|KEYC_KEYPAD },
|
||||
{ "KP0", KEYC_KP_ZERO|KEYC_KEYPAD },
|
||||
{ "KP.", KEYC_KP_PERIOD|KEYC_KEYPAD },
|
||||
{ "KP=", KEYC_KP_EQUAL|KEYC_KEYPAD },
|
||||
{ "KP,", KEYC_KP_SEPARATOR|KEYC_KEYPAD },
|
||||
{ "KPLeft", KEYC_KP_LEFT|KEYC_KEYPAD },
|
||||
{ "KPRight", KEYC_KP_RIGHT|KEYC_KEYPAD },
|
||||
{ "KPUp", KEYC_KP_UP|KEYC_KEYPAD },
|
||||
{ "KPDown", KEYC_KP_DOWN|KEYC_KEYPAD },
|
||||
{ "KPPageUp", KEYC_KP_PPAGE|KEYC_KEYPAD },
|
||||
{ "KPPageDown", KEYC_KP_NPAGE|KEYC_KEYPAD },
|
||||
{ "KPHome", KEYC_KP_HOME|KEYC_KEYPAD },
|
||||
{ "KPEnd", KEYC_KP_END|KEYC_KEYPAD },
|
||||
{ "KPInsert", KEYC_KP_IC|KEYC_KEYPAD },
|
||||
{ "KPDelete", KEYC_KP_DC|KEYC_KEYPAD },
|
||||
{ "KPBegin", KEYC_KP_BEGIN|KEYC_KEYPAD },
|
||||
|
||||
/* Other function keys. */
|
||||
{ "CapsLock", KEYC_CAPSLOCK },
|
||||
{ "ScrollLock", KEYC_SCROLLLOCK },
|
||||
{ "NumLock", KEYC_NUMLOCK },
|
||||
{ "PrintScreen", KEYC_PRINTSCREEN },
|
||||
{ "Pause", KEYC_PAUSE },
|
||||
{ "Menu", KEYC_MENU },
|
||||
{ "MediaPlay", KEYC_MEDIA_PLAY },
|
||||
{ "MediaPause", KEYC_MEDIA_PAUSE },
|
||||
{ "MediaPlayPause", KEYC_MEDIA_PLAYPAUSE },
|
||||
{ "MediaReverse", KEYC_MEDIA_REVERSE },
|
||||
{ "MediaStop", KEYC_MEDIA_STOP },
|
||||
{ "MediaFastForward", KEYC_MEDIA_FASTFORWARD },
|
||||
{ "MediaRewind", KEYC_MEDIA_REWIND },
|
||||
{ "MediaNext", KEYC_MEDIA_NEXT },
|
||||
{ "MediaPrevious", KEYC_MEDIA_PREVIOUS },
|
||||
{ "MediaRecord", KEYC_MEDIA_RECORD },
|
||||
{ "VolumeDown", KEYC_VOLUME_DOWN },
|
||||
{ "VolumeUp", KEYC_VOLUME_UP },
|
||||
{ "VolumeMute", KEYC_VOLUME_MUTE },
|
||||
{ "LeftShift", KEYC_LEFT_SHIFT },
|
||||
{ "LeftControl", KEYC_LEFT_CTRL },
|
||||
{ "LeftAlt", KEYC_LEFT_ALT },
|
||||
{ "LeftSuper", KEYC_LEFT_SUPER },
|
||||
{ "LeftHyper", KEYC_LEFT_HYPER },
|
||||
{ "LeftMeta", KEYC_LEFT_META },
|
||||
{ "RightShift", KEYC_RIGHT_SHIFT },
|
||||
{ "RightControl", KEYC_RIGHT_CTRL },
|
||||
{ "RightAlt", KEYC_RIGHT_ALT },
|
||||
{ "RightSuper", KEYC_RIGHT_SUPER },
|
||||
{ "RightHyper", KEYC_RIGHT_HYPER },
|
||||
{ "RightMeta", KEYC_RIGHT_META },
|
||||
{ "ISOLevel3Shift", KEYC_ISO_LEVEL3_SHIFT },
|
||||
{ "ISOLevel5Shift", KEYC_ISO_LEVEL5_SHIFT },
|
||||
|
||||
/* Mouse keys. */
|
||||
KEYC_MOUSE_STRING(MOUSEDOWN1, MouseDown1),
|
||||
@@ -297,13 +226,8 @@ key_string_get_modifiers(const char **string)
|
||||
modifiers |= KEYC_META;
|
||||
break;
|
||||
case 'S':
|
||||
modifiers |= KEYC_SHIFT;
|
||||
break;
|
||||
case 's':
|
||||
modifiers |= KEYC_SUPER;
|
||||
break;
|
||||
case 'H':
|
||||
modifiers |= KEYC_HYPER;
|
||||
modifiers |= KEYC_SHIFT;
|
||||
break;
|
||||
default:
|
||||
*string = NULL;
|
||||
@@ -425,10 +349,6 @@ key_string_lookup_key(key_code key, int with_flags)
|
||||
strlcat(out, "M-", sizeof out);
|
||||
if (key & KEYC_SHIFT)
|
||||
strlcat(out, "S-", sizeof out);
|
||||
if (key & KEYC_SUPER)
|
||||
strlcat(out, "s-", sizeof out);
|
||||
if (key & KEYC_HYPER)
|
||||
strlcat(out, "H-", sizeof out);
|
||||
key &= KEYC_MASK_KEY;
|
||||
|
||||
/* Handle no key. */
|
||||
|
||||
@@ -104,7 +104,7 @@ static const char *options_table_extended_keys_list[] = {
|
||||
"off", "on", "always", NULL
|
||||
};
|
||||
static const char *options_table_extended_keys_format_list[] = {
|
||||
"csi-u", "xterm", "kitty", NULL
|
||||
"csi-u", "xterm", NULL
|
||||
};
|
||||
static const char *options_table_allow_passthrough_list[] = {
|
||||
"off", "on", "all", NULL
|
||||
@@ -115,7 +115,6 @@ static const char *options_table_theme_list[] = {
|
||||
static const char *options_table_copy_mode_line_numbers_list[] = {
|
||||
"off", "default", "absolute", "relative", "hybrid", NULL
|
||||
};
|
||||
|
||||
/* Status line format. */
|
||||
#define OPTIONS_TABLE_STATUS_FORMAT1 \
|
||||
"#[align=left range=left #{E:status-left-style}]" \
|
||||
@@ -1385,6 +1384,13 @@ const struct options_table_entry options_table[] = {
|
||||
.text = "Style of search matches in copy mode."
|
||||
},
|
||||
|
||||
{ .name = "copy-mode-exit-status-format",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
|
||||
.default_str = "#{?exit_status,#[fg=themered]!, }",
|
||||
.text = "Format of OSC 133 exit status indicator in copy mode."
|
||||
},
|
||||
|
||||
{ .name = "copy-mode-current-match-style",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_WINDOW,
|
||||
|
||||
@@ -1400,12 +1400,6 @@ options_push_changes(const char *name)
|
||||
TAILQ_FOREACH(loop, &clients, entry)
|
||||
server_client_set_key_table(loop, NULL);
|
||||
}
|
||||
if (strcmp(name, "extended-keys") == 0) {
|
||||
TAILQ_FOREACH(loop, &clients, entry) {
|
||||
if (loop->tty.flags & TTY_STARTED)
|
||||
tty_update_features(&loop->tty);
|
||||
}
|
||||
}
|
||||
if (strcmp(name, "user-keys") == 0) {
|
||||
TAILQ_FOREACH(loop, &clients, entry) {
|
||||
if (loop->tty.flags & TTY_OPENED)
|
||||
|
||||
81
regress/collapse-output.sh
Normal file
81
regress/collapse-output.sh
Normal file
@@ -0,0 +1,81 @@
|
||||
#!/bin/sh
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
|
||||
$TMUX kill-server 2>/dev/null
|
||||
$TMUX new-session -d -x80 -y20 "sh -c 'printf \"\\033]133;A\\007p\\$ \\033]133;B\\007echo hi\\n\\033]133;C\\007hello\\n\\033]133;D;0\\007separator\\n\\033]133;A\\007p\\$ \\033]133;B\\007\"; exec sleep 100'" || exit 1
|
||||
sleep 1
|
||||
|
||||
$TMUX copy-mode -c || exit 1
|
||||
$TMUX send-keys -X search-backward hello || exit 1
|
||||
hidden=$($TMUX display-message -p '#{copy_cursor_line}')
|
||||
[ "$hidden" != hello ] || exit 1
|
||||
$TMUX send-keys -X search-backward separator || exit 1
|
||||
hidden=$($TMUX display-message -p '#{copy_cursor_line}')
|
||||
[ "$hidden" != separator ] || exit 1
|
||||
|
||||
$TMUX send-keys BTab || exit 1
|
||||
$TMUX send-keys -X search-backward hello || exit 1
|
||||
shown=$($TMUX display-message -p '#{copy_cursor_line}')
|
||||
[ "$shown" = hello ] || exit 1
|
||||
$TMUX send-keys -X select-line || exit 1
|
||||
$TMUX send-keys -X copy-selection || exit 1
|
||||
selected=$($TMUX show-buffer)
|
||||
[ "$selected" = hello ] || exit 1
|
||||
$TMUX send-keys -X cancel || exit 1
|
||||
|
||||
$TMUX kill-server
|
||||
$TMUX new-session -d -x80 -y20 "sh -c 'printf \"first\\n\\033]133;D;0\\007separator\\n\\033]133;A\\007p\\$ \\033]133;B\\007\"; exec sleep 100'" || exit 1
|
||||
sleep 1
|
||||
|
||||
$TMUX copy-mode -c || exit 1
|
||||
$TMUX send-keys -X search-backward separator || exit 1
|
||||
hidden=$($TMUX display-message -p '#{copy_cursor_line}')
|
||||
[ "$hidden" != separator ] || exit 1
|
||||
$TMUX send-keys BTab || exit 1
|
||||
$TMUX send-keys -X search-backward separator || exit 1
|
||||
shown=$($TMUX display-message -p '#{copy_cursor_line}')
|
||||
[ "$shown" = separator ] || exit 1
|
||||
$TMUX send-keys -X cancel || exit 1
|
||||
|
||||
$TMUX kill-server
|
||||
$TMUX new-session -d -x80 -y20 "sh -c 'printf \"\\033]133;A\\007P> \\033]133;B\\007for i in 1 2 3; do\\n\\033]133;A;k=s\\007> \\033]133;B\\007echo \\$i\\n\\033]133;P;k=s\\007> \\033]133;B\\007done\\033]133;C\\007\\nRESULT\\n\\033]133;D;0\\007separator\\n\\033]133;A\\007P> \\033]133;B\\007\"; exec sleep 100'" || exit 1
|
||||
sleep 1
|
||||
|
||||
$TMUX copy-mode -c || exit 1
|
||||
$TMUX send-keys -X search-backward RESULT || exit 1
|
||||
hidden=$($TMUX display-message -p '#{copy_cursor_line}')
|
||||
[ "$hidden" != RESULT ] || exit 1
|
||||
$TMUX send-keys -X search-backward 'echo $i' || exit 1
|
||||
shown=$($TMUX display-message -p '#{copy_cursor_line}')
|
||||
[ "$shown" = 'echo $i' ] || exit 1
|
||||
$TMUX send-keys -X cancel || exit 1
|
||||
|
||||
$TMUX copy-mode -U || exit 1
|
||||
$TMUX send-keys -X search-backward RESULT || exit 1
|
||||
$TMUX send-keys Tab || exit 1
|
||||
cursor=$($TMUX display-message -p '#{copy_cursor_line}')
|
||||
[ "$cursor" = done ] || exit 1
|
||||
$TMUX send-keys -X cancel || exit 1
|
||||
|
||||
$TMUX kill-server
|
||||
$TMUX new-session -d -x80 -y20 "sh -c 'printf \"\\033]133;A\\007P0> \\033]133;B\\007\\r\\n\\033]133;D;0\\007empty-separator\\n\\033]133;A\\007P1> \\033]133;B\\007\"; exec sleep 100'" || exit 1
|
||||
sleep 1
|
||||
|
||||
$TMUX copy-mode -c || exit 1
|
||||
collapsed=$($TMUX capture-pane -p)
|
||||
case "$collapsed" in
|
||||
*"+ P0>"*) ;;
|
||||
*) exit 1 ;;
|
||||
esac
|
||||
$TMUX send-keys -X search-backward empty-separator || exit 1
|
||||
hidden=$($TMUX display-message -p '#{copy_cursor_line}')
|
||||
[ "$hidden" != empty-separator ] || exit 1
|
||||
$TMUX send-keys -X cancel || exit 1
|
||||
|
||||
$TMUX kill-server 2>/dev/null
|
||||
exit 0
|
||||
102
regress/copy-mode-exit-status.sh
Normal file
102
regress/copy-mode-exit-status.sh
Normal file
@@ -0,0 +1,102 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Check OSC 133 exit status indicators in copy mode using a real client.
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
LC_ALL=C.UTF-8
|
||||
export TERM LC_ALL
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -LtestB$$ -f/dev/null"
|
||||
|
||||
fail() {
|
||||
echo "$*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
capture() {
|
||||
$TMUX capture-pane -pS0 -E- >$TMP || exit 1
|
||||
}
|
||||
|
||||
check_grep() {
|
||||
grep -Fq "$1" $TMP || fail "missing pattern: $1"
|
||||
}
|
||||
|
||||
check_no_grep() {
|
||||
grep -Fq "$1" $TMP && fail "unexpected pattern: $1"
|
||||
}
|
||||
|
||||
$TMUX kill-server 2>/dev/null
|
||||
$TMUX2 kill-server 2>/dev/null
|
||||
|
||||
TMP=$(mktemp)
|
||||
trap "rm -f $TMP; $TMUX kill-server 2>/dev/null; $TMUX2 kill-server 2>/dev/null" 0 1 15
|
||||
|
||||
$TMUX2 new-session -d -x80 -y10 \
|
||||
"printf '\033]133;A\007p\$ \033]133;B\007one\n\033]133;C\007out1\n\033]133;D;0\007\033]133;A\007p\$ \033]133;B\007two\n\033]133;C\007out2\n\033]133;D;123\007\033]133;A\007p\$ \033]133;B\007silent\n\033]133;C\007\033]133;D;7\007\033]133;A\007p\$ \033]133;B\007three\n\033]133;C\007out3\n\033]133;D\007\033]133;A\007p\$ \033]133;B\007'; exec sleep 100" || \
|
||||
exit 1
|
||||
$TMUX2 set -g status off || exit 1
|
||||
$TMUX2 set -g copy-mode-position-format '#[align=left]POS' || exit 1
|
||||
$TMUX2 list-keys -Tcopy-mode O | grep -Fq 'fold-view-toggle' || exit 1
|
||||
$TMUX2 list-keys -Tcopy-mode-vi O | grep -Fq 'fold-view-toggle' || exit 1
|
||||
|
||||
$TMUX new-session -d -x80 -y10 || exit 1
|
||||
$TMUX set -g status off || exit 1
|
||||
$TMUX send -l "$TMUX2 attach" || exit 1
|
||||
$TMUX send Enter || exit 1
|
||||
sleep 1
|
||||
|
||||
$TMUX2 copy-mode -U || exit 1
|
||||
$TMUX2 send -X history-top || exit 1
|
||||
sleep 1
|
||||
capture
|
||||
check_grep "!- p\$ two"
|
||||
check_grep "! p\$ silent"
|
||||
check_no_grep "!+ p\$ silent"
|
||||
check_grep "POS"
|
||||
|
||||
# Rebuilding with collapsed output must not expand copy-mode formats before
|
||||
# the viewport has been restored for the shorter backing grid.
|
||||
$TMUX2 send -X collapse-output -a || exit 1
|
||||
sleep 1
|
||||
capture
|
||||
check_grep "!+ p\$ two"
|
||||
check_grep "! p\$ silent"
|
||||
check_no_grep "!+ p\$ silent"
|
||||
$TMUX2 send -X line-numbers-on || exit 1
|
||||
sleep 1
|
||||
capture
|
||||
check_grep " 3 !+ p\$ two"
|
||||
$TMUX2 send -X fold-view-toggle || exit 1
|
||||
[ "$($TMUX2 display -p '#{copy_fold_view}')" = 0 ] || exit 1
|
||||
sleep 1
|
||||
capture
|
||||
check_grep "out2"
|
||||
check_no_grep "!+ p\$ two"
|
||||
check_grep " 3 p\$ two"
|
||||
$TMUX2 send -X fold-view-toggle || exit 1
|
||||
[ "$($TMUX2 display -p '#{copy_fold_view}')" = 1 ] || exit 1
|
||||
sleep 1
|
||||
capture
|
||||
check_grep " 3 !- p\$ two"
|
||||
|
||||
# A format wider than the standard three-column gutter is not truncated.
|
||||
$TMUX2 send -X cancel || exit 1
|
||||
$TMUX2 set -g copy-mode-exit-status-format \
|
||||
'#[align=right]#{?exit_status,!#{exit_status}, }' || exit 1
|
||||
$TMUX2 copy-mode -c || exit 1
|
||||
$TMUX2 send -X history-top || exit 1
|
||||
sleep 1
|
||||
capture
|
||||
check_grep "!123+ p\$ two"
|
||||
|
||||
$TMUX2 send -X select-line || exit 1
|
||||
$TMUX2 send -X copy-selection || exit 1
|
||||
selection=$($TMUX2 show-buffer)
|
||||
case $selection in
|
||||
*RC=*) fail "exit status was copied" ;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
@@ -5,9 +5,12 @@
|
||||
start_pane alternate 10 3 'MAIN\033[?1049hALT\033[?1049lZ\n'
|
||||
check_capture alternate 'MAINZ'
|
||||
|
||||
start_pane osc133 20 8 'xx\033]133;A\007p>\033]133;B\007cmd\nxy\033]133;P;k=s\007more\nzz\033]133;C\007out\033]133;D;7\007\nq\033]133;C\007bad\033]133;D;-1\007\nqq\033]133;C\007big\033]133;D;300\007\nzzz\033]133;C\007ok\033]133;D\007\n'
|
||||
start_pane osc133 20 12 'xx\033]133;A\007p>\033]133;B\007cmd\nxy\033]133;P;k=s\007more\nxz\033]133;A;k=s\007more\nxw\033]133;P;k=c\007more\nxv\033]133;A;k=c\007more\nzz\033]133;C\007out\033]133;D;7\007\nq\033]133;C\007bad\033]133;D;-1\007\nqq\033]133;C\007big\033]133;D;300\007\nzzz\033]133;C\007ok\033]133;D\007\n'
|
||||
check_capture osc133 'xxp>cmd
|
||||
xymore
|
||||
xzmore
|
||||
xwmore
|
||||
xvmore
|
||||
zzout
|
||||
qbad
|
||||
qqbig
|
||||
@@ -15,10 +18,13 @@ zzzok'
|
||||
check_raw_matches osc133 \
|
||||
'L 0 \(0\) flags=START_PROMPT,START_COMMAND\[[0-9a-f]+\].* osc133=2,4,0,0,0' \
|
||||
'L 1 \(1\) flags=SECOND_PROMPT\[[0-9a-f]+\].* osc133=2,0,0,0,0' \
|
||||
'L 2 \(2\) flags=START_OUTPUT,END_OUTPUT\[[0-9a-f]+\].* osc133=0,0,2,5,7' \
|
||||
'L 3 \(3\) flags=START_OUTPUT,END_OUTPUT\[[0-9a-f]+\].* osc133=0,0,1,4,255' \
|
||||
'L 4 \(4\) flags=START_OUTPUT,END_OUTPUT\[[0-9a-f]+\].* osc133=0,0,2,5,255' \
|
||||
'L 5 \(5\) flags=START_OUTPUT,END_OUTPUT\[[0-9a-f]+\].* osc133=0,0,3,5,0'
|
||||
'L 2 \(2\) flags=SECOND_PROMPT\[[0-9a-f]+\].* osc133=2,0,0,0,0' \
|
||||
'L 3 \(3\) flags=SECOND_PROMPT\[[0-9a-f]+\].* osc133=2,0,0,0,0' \
|
||||
'L 4 \(4\) flags=SECOND_PROMPT\[[0-9a-f]+\].* osc133=2,0,0,0,0' \
|
||||
'L 5 \(5\) flags=START_OUTPUT,END_OUTPUT,END_OUTPUT_STATUS\[[0-9a-f]+\].* osc133=0,0,2,5,7' \
|
||||
'L 6 \(6\) flags=START_OUTPUT,END_OUTPUT,END_OUTPUT_STATUS\[[0-9a-f]+\].* osc133=0,0,1,4,255' \
|
||||
'L 7 \(7\) flags=START_OUTPUT,END_OUTPUT,END_OUTPUT_STATUS\[[0-9a-f]+\].* osc133=0,0,2,5,255' \
|
||||
'L 8 \(8\) flags=START_OUTPUT,END_OUTPUT\[[0-9a-f]+\].* osc133=0,0,3,5,0'
|
||||
|
||||
$TMUX kill-server 2>/dev/null
|
||||
exit $exit_status
|
||||
|
||||
@@ -1,146 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Test per-client keyboard protocol detection and pane-side encoding.
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
KCONF=$(mktemp)
|
||||
LCONF=$(mktemp)
|
||||
OUT=$(mktemp)
|
||||
TMP=$(mktemp)
|
||||
SOCKETS="testKmc$$ testKka$$ testKua$$ testKrt$$ testKru$$ testKlq$$ testKlu$$"
|
||||
|
||||
printf '%s\n' 'set -g extended-keys on' >"$KCONF"
|
||||
printf '%s\n' 'set -g extended-keys off' >"$LCONF"
|
||||
|
||||
cleanup()
|
||||
{
|
||||
rm -f "$KCONF" "$LCONF" "$OUT" "$TMP"
|
||||
for socket in $SOCKETS; do
|
||||
$TEST_TMUX -L"$socket" kill-server 2>/dev/null
|
||||
done
|
||||
}
|
||||
trap cleanup 0 1 15
|
||||
|
||||
wait_for_mode()
|
||||
{
|
||||
tmux=$1
|
||||
wanted=$2
|
||||
i=0
|
||||
while [ "$($tmux display-message -pt: '#{pane_key_mode}')" != "$wanted" ] &&
|
||||
[ "$i" -lt 50 ]; do
|
||||
sleep 0.1
|
||||
i=$((i + 1))
|
||||
done
|
||||
[ "$($tmux display-message -pt: '#{pane_key_mode}')" = "$wanted" ]
|
||||
}
|
||||
|
||||
wait_for_output()
|
||||
{
|
||||
i=0
|
||||
while [ ! -s "$1" ] && [ "$i" -lt 50 ]; do
|
||||
sleep 0.1
|
||||
i=$((i + 1))
|
||||
done
|
||||
[ -s "$1" ]
|
||||
}
|
||||
|
||||
client_mode()
|
||||
{
|
||||
tmux=$1
|
||||
session=$2
|
||||
|
||||
if [ -z "$session" ]; then
|
||||
$tmux list-clients -F '#{client_key_mode}'
|
||||
else
|
||||
$tmux list-clients -F '#{client_session}:#{client_key_mode}' |
|
||||
sed -n "s/^$session://p"
|
||||
fi
|
||||
}
|
||||
|
||||
wait_for_client_mode()
|
||||
{
|
||||
tmux=$1
|
||||
session=$2
|
||||
wanted=$3
|
||||
i=0
|
||||
while [ "$(client_mode "$tmux" "$session")" != "$wanted" ] &&
|
||||
[ "$i" -lt 50 ]; do
|
||||
sleep 0.1
|
||||
i=$((i + 1))
|
||||
done
|
||||
[ "$(client_mode "$tmux" "$session")" = "$wanted" ]
|
||||
}
|
||||
|
||||
# Each client must be negotiated independently. A tmux with extended-keys off
|
||||
# stands in for a terminal without Kitty keys, since it does not answer the
|
||||
# query.
|
||||
M="$TEST_TMUX -LtestKmc$$ -f$KCONF"
|
||||
KA="$TEST_TMUX -LtestKka$$ -f$KCONF"
|
||||
UA="$TEST_TMUX -LtestKua$$ -f$LCONF"
|
||||
$M new-session -d -x80 -y24 -s kitty || exit 1
|
||||
$M new-session -d -x80 -y24 -s csiu || exit 1
|
||||
$KA new-session -d -x80 -y24 "$M attach-session -t kitty" || exit 1
|
||||
$UA new-session -d -x80 -y24 "$M attach-session -t csiu" || exit 1
|
||||
wait_for_mode "$KA" 'Kitty 1' || exit 1
|
||||
|
||||
# Each client must report the protocol its own terminal negotiated.
|
||||
wait_for_client_mode "$M" kitty 'Kitty 1' || exit 1
|
||||
wait_for_client_mode "$M" csiu 'Ext' || exit 1
|
||||
|
||||
uc=$($M list-clients -F '#{client_name} #{client_session}' |
|
||||
awk '$2 == "csiu" { print $1 }')
|
||||
[ -n "$uc" ] || exit 1
|
||||
$M command-prompt -t"$uc" -k 'display-message -pl "%%"' >"$TMP" &
|
||||
pid=$!
|
||||
sleep 0.2
|
||||
$UA send-keys Escape '[97;5u'
|
||||
wait "$pid"
|
||||
[ "$(tr -d '[:space:]' <"$TMP")" = 'C-a' ] || exit 1
|
||||
|
||||
# A Kitty-capable terminal must still be reported when it is not in use.
|
||||
$M set-option -g extended-keys off
|
||||
wait_for_client_mode "$M" kitty 'VT10x (Kitty)' || exit 1
|
||||
wait_for_client_mode "$M" csiu 'VT10x' || exit 1
|
||||
$M set-option -g extended-keys on
|
||||
wait_for_client_mode "$M" kitty 'Kitty 1' || exit 1
|
||||
|
||||
$KA kill-server 2>/dev/null
|
||||
$UA kill-server 2>/dev/null
|
||||
$M kill-server 2>/dev/null
|
||||
|
||||
# Standard extended input must be translated for a Kitty-requesting pane.
|
||||
: >"$OUT"
|
||||
R="$TEST_TMUX -LtestKrt$$ -f$KCONF"
|
||||
RU="$TEST_TMUX -LtestKru$$ -f$LCONF"
|
||||
$R new-session -d -x80 -y24 \
|
||||
"stty raw -echo; printf '\033[>1u'; dd bs=1 count=7 2>/dev/null | od -An -v -t x1 >'$OUT'; sleep 5" || exit 1
|
||||
$RU new-session -d -x80 -y24 "$R attach-session" || exit 1
|
||||
wait_for_client_mode "$R" '' 'Ext' || exit 1
|
||||
$RU send-keys C-a
|
||||
wait_for_output "$OUT" || exit 1
|
||||
[ "$(tr -d ' \n' <"$OUT")" = '1b5b39373b3575' ] || exit 1
|
||||
$RU kill-server 2>/dev/null
|
||||
$R kill-server 2>/dev/null
|
||||
|
||||
# An application is told the Kitty flags it asked for even when a client that
|
||||
# only supports VT10x is attached, and keys from that client are encoded as it
|
||||
# asked.
|
||||
: >"$OUT"
|
||||
: >"$TMP"
|
||||
printf '%s\n' "set -as terminal-overrides ',*:Eneks@:Dseks@'" >>"$KCONF"
|
||||
LQ="$TEST_TMUX -LtestKlq$$ -f$KCONF"
|
||||
LU="$TEST_TMUX -LtestKlu$$ -f$LCONF"
|
||||
$LQ new-session -d -x80 -y24 \
|
||||
"stty raw -echo; sleep 2; printf '\033[>1u\033[?u'; dd bs=1 count=5 2>/dev/null | od -An -v -t x1 >'$OUT'; dd bs=1 count=7 2>/dev/null | od -An -v -t x1 >'$TMP'; sleep 5" || exit 1
|
||||
$LU new-session -d -x80 -y24 "$LQ attach-session" || exit 1
|
||||
wait_for_output "$OUT" || exit 1
|
||||
[ "$(tr -d ' \n' <"$OUT")" = '1b5b3f3175' ] || exit 1
|
||||
wait_for_client_mode "$LQ" '' 'VT10x' || exit 1
|
||||
$LU send-keys C-a
|
||||
wait_for_output "$TMP" || exit 1
|
||||
[ "$(tr -d ' \n' <"$TMP")" = '1b5b39373b3575' ] || exit 1
|
||||
|
||||
exit 0
|
||||
@@ -1,116 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Test client-side Kitty keyboard protocol support: an outer tmux acts as a
|
||||
# Kitty-capable terminal for the inner tmux which is the one under test. The
|
||||
# inner tmux queries the outer one, the outer one replies, and the inner one
|
||||
# then parses the key sequences sent to it.
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
CONF=$(mktemp)
|
||||
TMP=$(mktemp)
|
||||
|
||||
printf '%s\n' 'set -g extended-keys on' >"$CONF"
|
||||
|
||||
TMUX="$TEST_TMUX -LtestKIA$$ -f$CONF"
|
||||
TMUX2="$TEST_TMUX -LtestKIB$$ -f$CONF"
|
||||
|
||||
trap 'rm -f "$CONF" "$TMP"; $TMUX kill-server 2>/dev/null; \
|
||||
$TMUX2 kill-server 2>/dev/null' 0 1 15
|
||||
|
||||
$TMUX2 new-session -d -x80 -y24 || exit 1
|
||||
$TMUX new-session -d -x80 -y24 "$TMUX2 attach" || exit 1
|
||||
|
||||
exit_status=0
|
||||
|
||||
wait_for_mode()
|
||||
{
|
||||
i=0
|
||||
while [ "$($TMUX display-message -pt: '#{pane_key_mode}')" != "$1" ] &&
|
||||
[ "$i" -lt 50 ]; do
|
||||
sleep 0.1
|
||||
i=$((i + 1))
|
||||
done
|
||||
[ "$($TMUX display-message -pt: '#{pane_key_mode}')" = "$1" ]
|
||||
}
|
||||
|
||||
assert_key()
|
||||
{
|
||||
keys=$1
|
||||
expected=$2
|
||||
|
||||
$TMUX2 command-prompt -k 'display-message -pl "%%"' >"$TMP" &
|
||||
sleep 0.15
|
||||
# Send raw bytes so the outer tmux does not encode them itself.
|
||||
raw=$(printf '%s' "$keys" | sed -e 's/Escape /\\033/g' -e 's/ //g')
|
||||
$TMUX send-keys -H $(printf "$raw" | od -An -v -t x1)
|
||||
wait
|
||||
|
||||
actual=$(tr -d '[:space:]' <"$TMP")
|
||||
if [ "$actual" = "$expected" ]; then
|
||||
[ -n "$VERBOSE" ] && echo "[PASS] $keys -> $actual"
|
||||
else
|
||||
echo "[FAIL] $keys -> $expected (got '$actual')"
|
||||
exit_status=1
|
||||
fi
|
||||
}
|
||||
|
||||
# The inner tmux must detect the outer one and push its flags.
|
||||
if ! wait_for_mode 'Kitty 1'; then
|
||||
echo "[FAIL] inner tmux did not enable the Kitty protocol"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Modifiers, including the Kitty-only Super and Hyper.
|
||||
assert_key 'Escape [97;2u' 'S-a'
|
||||
assert_key 'Escape [97;3u' 'M-a'
|
||||
assert_key 'Escape [97;5u' 'C-a'
|
||||
assert_key 'Escape [97;6u' 'C-S-a'
|
||||
assert_key 'Escape [97;7u' 'C-M-a'
|
||||
assert_key 'Escape [97;9u' 's-a'
|
||||
assert_key 'Escape [97;17u' 'H-a'
|
||||
assert_key 'Escape [65;2u' 'S-A'
|
||||
|
||||
# Keys with a dedicated tmux key code.
|
||||
assert_key 'Escape [9;5u' 'C-Tab'
|
||||
assert_key 'Escape [9;2u' 'BTab'
|
||||
assert_key 'Escape [13;5u' 'C-Enter'
|
||||
assert_key 'Escape [27u' 'Escape'
|
||||
assert_key 'Escape [32;5u' 'C-Space'
|
||||
assert_key 'Escape [127;5u' 'C-BSpace'
|
||||
|
||||
# Keys with a CSI final byte other than u.
|
||||
assert_key 'Escape [1;5A' 'C-Up'
|
||||
assert_key 'Escape [1;3D' 'M-Left'
|
||||
assert_key 'Escape [1;5H' 'C-Home'
|
||||
assert_key 'Escape [1;5P' 'C-F1'
|
||||
|
||||
# Functional and non-ASCII keys.
|
||||
assert_key 'Escape [57399;5u' 'C-KP0'
|
||||
assert_key 'Escape [233;5u' 'C-é'
|
||||
|
||||
# The alternate key and associated text fields are not requested but must be
|
||||
# ignored if a terminal sends them anyway.
|
||||
assert_key 'Escape [97:65;2u' 'S-a'
|
||||
assert_key 'Escape [97:65:97;5u' 'C-a'
|
||||
assert_key 'Escape [97;5;97u' 'C-a'
|
||||
|
||||
# A repeat event is a key press, a release event is dropped. The C-b that
|
||||
# follows shows that the sequence was consumed and not passed through.
|
||||
assert_key 'Escape [97;5:1u' 'C-a'
|
||||
assert_key 'Escape [97;5:2u' 'C-a'
|
||||
assert_key 'Escape [97;5:3u Escape [98;5u' 'C-b'
|
||||
|
||||
# The Meta modifier bit is not representable and is dropped.
|
||||
assert_key 'Escape [97;33u Escape [98;5u' 'C-b'
|
||||
|
||||
# Lock modifiers are ignored rather than dropping the key.
|
||||
assert_key 'Escape [97;65u' 'a'
|
||||
assert_key 'Escape [97;129u' 'a'
|
||||
|
||||
$TMUX kill-server 2>/dev/null
|
||||
$TMUX2 kill-server 2>/dev/null
|
||||
|
||||
exit $exit_status
|
||||
@@ -1,85 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Test the Kitty keyboard protocol against a real terminal rather than against
|
||||
# another copy of tmux. This drives kitty through its remote control interface
|
||||
# so that kitty itself encodes the key presses.
|
||||
#
|
||||
# This has to be run by hand from this directory. The Makefile runs tests with
|
||||
# env -i, which removes DISPLAY and HOME, so kitty cannot start and this exits
|
||||
# immediately without testing anything. It is also skipped unless kitty is
|
||||
# installed and is new enough to have send-key.
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
|
||||
command -v kitty >/dev/null 2>&1 || exit 0
|
||||
[ -n "$DISPLAY" ] || [ -n "$WAYLAND_DISPLAY" ] || exit 0
|
||||
kitty @ --help 2>/dev/null | grep -q 'send-key' || exit 0
|
||||
|
||||
DIR=$(mktemp -d)
|
||||
CONF=$DIR/conf
|
||||
SOCKET=$DIR/kitty
|
||||
OUT=$DIR/out
|
||||
TMUX="$TEST_TMUX -LtestKrt$$ -f$CONF"
|
||||
|
||||
printf '%s\n' 'set -g extended-keys on' \
|
||||
'set -g extended-keys-format kitty' >"$CONF"
|
||||
|
||||
cleanup()
|
||||
{
|
||||
$TMUX kill-server 2>/dev/null
|
||||
rm -rf "$DIR"
|
||||
}
|
||||
trap cleanup 0 1 15
|
||||
|
||||
kitty -o allow_remote_control=yes --listen-on "unix:$SOCKET" \
|
||||
-o confirm_os_window_close=0 -e \
|
||||
$TMUX new-session -s r "sleep 120" >"$DIR/err" 2>&1 &
|
||||
|
||||
# The terminfo entry for kitty may be missing, so treat a server which never
|
||||
# appears as a reason to skip rather than as a failure.
|
||||
i=0
|
||||
while ! $TMUX has-session -t r 2>/dev/null && [ "$i" -lt 150 ]; do
|
||||
sleep 0.1
|
||||
i=$((i + 1))
|
||||
done
|
||||
$TMUX has-session -t r 2>/dev/null || exit 0
|
||||
|
||||
# The client must negotiate the protocol with the real terminal.
|
||||
i=0
|
||||
while [ "$($TMUX list-clients -F '#{client_key_mode}')" != 'Kitty 1' ] &&
|
||||
[ "$i" -lt 100 ]; do
|
||||
sleep 0.1
|
||||
i=$((i + 1))
|
||||
done
|
||||
[ "$($TMUX list-clients -F '#{client_key_mode}')" = 'Kitty 1' ] || exit 1
|
||||
|
||||
# kitty encodes the key, tmux parses it and encodes it again for the pane.
|
||||
try_key()
|
||||
{
|
||||
key=$1
|
||||
expected=$2
|
||||
|
||||
: >"$OUT"
|
||||
$TMUX respawn-pane -k -t r: \
|
||||
"stty raw -echo; printf '\033[>1u'; dd bs=1 count=7 2>/dev/null | od -An -v -t x1 >'$OUT'; sleep 20" || return 1
|
||||
sleep 1
|
||||
kitty @ --to "unix:$SOCKET" send-key "$key" 2>/dev/null || return 1
|
||||
i=0
|
||||
while [ ! -s "$OUT" ] && [ "$i" -lt 50 ]; do
|
||||
sleep 0.1
|
||||
i=$((i + 1))
|
||||
done
|
||||
[ "$(tr -d ' \n' <"$OUT")" = "$expected" ]
|
||||
}
|
||||
|
||||
try_key ctrl+a '1b5b39373b3575' || exit 1
|
||||
try_key alt+a '1b5b39373b3375' || exit 1
|
||||
try_key ctrl+shift+a '1b5b39373b3675' || exit 1
|
||||
|
||||
# Super cannot be represented by the standard extended keys at all, so this
|
||||
# only succeeds if the whole chain used the Kitty protocol.
|
||||
try_key super+a '1b5b39373b3975' || exit 1
|
||||
|
||||
exit 0
|
||||
@@ -1,108 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Test pane-side Kitty keyboard protocol state and key encoding. This uses
|
||||
# synthetic protocol sequences and does not require a particular terminal.
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
CONF=$(mktemp)
|
||||
OUT=$(mktemp)
|
||||
TMUX="$TEST_TMUX -LtestK$$ -f$CONF"
|
||||
|
||||
trap 'rm -f "$CONF" "$OUT"; $TMUX kill-server 2>/dev/null' 0 1 15
|
||||
|
||||
printf '%s\n' 'set -g extended-keys on' >"$CONF"
|
||||
|
||||
wait_for_output()
|
||||
{
|
||||
i=0
|
||||
while [ ! -s "$OUT" ] && [ "$i" -lt 50 ]; do
|
||||
sleep 0.1
|
||||
i=$((i + 1))
|
||||
done
|
||||
[ -s "$OUT" ]
|
||||
}
|
||||
|
||||
wait_for_mode()
|
||||
{
|
||||
wanted=$1
|
||||
i=0
|
||||
while [ "$($TMUX display-message -pt: '#{pane_key_mode}')" != "$wanted" ] &&
|
||||
[ "$i" -lt 50 ]; do
|
||||
sleep 0.1
|
||||
i=$((i + 1))
|
||||
done
|
||||
[ "$($TMUX display-message -pt: '#{pane_key_mode}')" = "$wanted" ]
|
||||
}
|
||||
|
||||
check_output()
|
||||
{
|
||||
expected=$1
|
||||
actual=$(tr -d ' \n' <"$OUT")
|
||||
if [ "$actual" != "$expected" ]; then
|
||||
echo "expected $expected, got $actual"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
$TMUX new-session -d -x80 -y24 \
|
||||
"stty raw -echo; printf '\033[>1u'; dd bs=1 count=7 2>/dev/null | od -An -v -t x1 >'$OUT'; sleep 5" || exit 1
|
||||
wait_for_mode 'Kitty 1'
|
||||
$TMUX send-keys -t: C-S-a
|
||||
wait_for_output
|
||||
check_output 1b5b39373b3675
|
||||
|
||||
: >"$OUT"
|
||||
$TMUX respawn-pane -k -t: \
|
||||
"stty raw -echo; printf '\033[>1u'; dd bs=1 count=7 2>/dev/null | od -An -v -t x1 >'$OUT'; sleep 5"
|
||||
wait_for_mode 'Kitty 1'
|
||||
$TMUX send-keys -t: s-a
|
||||
wait_for_output
|
||||
check_output 1b5b39373b3975
|
||||
|
||||
: >"$OUT"
|
||||
$TMUX respawn-pane -k -t: \
|
||||
"stty raw -echo; printf '\033[>8u'; dd bs=1 count=5 2>/dev/null | od -An -v -t x1 >'$OUT'; sleep 5"
|
||||
wait_for_mode 'Kitty 8'
|
||||
$TMUX send-keys -t: a
|
||||
wait_for_output
|
||||
check_output 1b5b393775
|
||||
|
||||
: >"$OUT"
|
||||
$TMUX respawn-pane -k -t: \
|
||||
"stty raw -echo; printf '\033[>1u\033[?u'; dd bs=1 count=5 2>/dev/null | od -An -v -t x1 >'$OUT'; sleep 5"
|
||||
wait_for_output
|
||||
check_output 1b5b3f3175
|
||||
|
||||
: >"$OUT"
|
||||
$TMUX respawn-pane -k -t: \
|
||||
"stty raw -echo; printf '\033[>4;2m\033[?u'; dd bs=1 count=5 2>/dev/null | od -An -v -t x1 >'$OUT'; sleep 5"
|
||||
wait_for_output
|
||||
check_output 1b5b3f3075
|
||||
|
||||
: >"$OUT"
|
||||
$TMUX respawn-pane -k -t: \
|
||||
"stty raw -echo; printf '\033[>1u\033[>8u\033[<u\033[?u\033[>8u\033[<2u\033[?u'; dd bs=1 count=10 2>/dev/null | od -An -v -t x1 >'$OUT'; sleep 5"
|
||||
wait_for_output
|
||||
check_output 1b5b3f31751b5b3f3075
|
||||
|
||||
: >"$OUT"
|
||||
# "always" forces modifyOtherKeys mode 1, not Kitty keys.
|
||||
$TMUX set-option -g extended-keys always
|
||||
$TMUX respawn-pane -k -t: \
|
||||
"stty raw -echo; printf '\033[>0u\033[?u'; dd bs=1 count=5 2>/dev/null | od -An -v -t x1 >'$OUT'; sleep 5"
|
||||
wait_for_output
|
||||
check_output 1b5b3f3075
|
||||
wait_for_mode 'Ext 1'
|
||||
$TMUX set-option -g extended-keys on
|
||||
|
||||
: >"$OUT"
|
||||
$TMUX respawn-pane -k -t: \
|
||||
"stty raw -echo; printf '\033[>1u\033[?u\033[?1049h\033[?u\033[>8u\033[?u\033[?1049l\033[?u'; dd bs=1 count=20 2>/dev/null | od -An -v -t x1 >'$OUT'; sleep 5"
|
||||
wait_for_output
|
||||
check_output 1b5b3f31751b5b3f30751b5b3f38751b5b3f3175
|
||||
|
||||
$TMUX kill-server 2>/dev/null
|
||||
exit 0
|
||||
131
regress/output-commands.sh
Executable file
131
regress/output-commands.sh
Executable file
@@ -0,0 +1,131 @@
|
||||
#!/bin/sh
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -L${TEST_SOCKET:-testO$$} -f/dev/null"
|
||||
OUT=/tmp/tmux-output-commands-$$
|
||||
EXPECTED=$(printf 'one\ntwo')
|
||||
|
||||
cleanup()
|
||||
{
|
||||
$TMUX kill-server 2>/dev/null
|
||||
rm -f "$OUT"
|
||||
}
|
||||
trap cleanup EXIT HUP INT TERM
|
||||
|
||||
$TMUX kill-server 2>/dev/null
|
||||
$TMUX new-session -d -x80 -y20 "sh -c 'printf \"\\033]133;A\\007p\\$ \\033]133;B\\007echo\\n\\033]133;C\\007one\\ntwo\\n\\033]133;D;0\\007separator\\n\\033]133;A\\007p\\$ \\033]133;B\\007broken\\n\\033]133;C\\007unfinished\"; exec sleep 100'" || exit 1
|
||||
sleep 1
|
||||
|
||||
$TMUX copy-mode || exit 1
|
||||
$TMUX send-keys -X copy-output || exit 1
|
||||
[ "$($TMUX show-buffer)" = unfinished ] || exit 1
|
||||
|
||||
$TMUX send-keys -X pipe-output "wc -c >$OUT" || exit 1
|
||||
sleep 1
|
||||
[ "$(cat "$OUT")" = 10 ] || exit 1
|
||||
|
||||
$TMUX send-keys -X copy-pipe-output "wc -c >$OUT" output || exit 1
|
||||
sleep 1
|
||||
[ "$(cat "$OUT")" = 10 ] || exit 1
|
||||
[ "$($TMUX show-buffer)" = unfinished ] || exit 1
|
||||
|
||||
$TMUX send-keys -X select-output || exit 1
|
||||
$TMUX send-keys -X copy-selection || exit 1
|
||||
[ "$($TMUX show-buffer)" = unfinished ] || exit 1
|
||||
$TMUX send-keys -X cancel || exit 1
|
||||
|
||||
$TMUX copy-mode || exit 1
|
||||
$TMUX send-keys -X select-output || exit 1
|
||||
$TMUX send-keys -X pipe-selection "wc -c >$OUT" || exit 1
|
||||
sleep 1
|
||||
[ "$(cat "$OUT")" = 10 ] || exit 1
|
||||
$TMUX send-keys -X cancel || exit 1
|
||||
|
||||
$TMUX copy-mode || exit 1
|
||||
$TMUX send-keys -X search-backward separator || exit 1
|
||||
$TMUX send-keys -X copy-output || exit 1
|
||||
[ "$($TMUX show-buffer)" = "$EXPECTED" ] || exit 1
|
||||
$TMUX send-keys -X cancel || exit 1
|
||||
|
||||
$TMUX copy-mode -c || exit 1
|
||||
$TMUX send-keys -X search-backward echo || exit 1
|
||||
$TMUX send-keys -X select-output || exit 1
|
||||
$TMUX send-keys -X copy-selection || exit 1
|
||||
[ "$($TMUX show-buffer)" = "$EXPECTED" ] || exit 1
|
||||
$TMUX send-keys -X cancel || exit 1
|
||||
|
||||
$TMUX copy-mode || exit 1
|
||||
$TMUX send-keys -X search-backward one || exit 1
|
||||
$TMUX send-keys -X copy-output || exit 1
|
||||
[ "$($TMUX show-buffer)" = "$EXPECTED" ] || exit 1
|
||||
$TMUX send-keys -X cancel || exit 1
|
||||
|
||||
$TMUX new-window -d -n plain "printf 'alpha\\nbeta\\n'; exec sleep 100" || exit 1
|
||||
sleep 1
|
||||
$TMUX copy-mode -t :plain || exit 1
|
||||
$TMUX send-keys -t :plain.0 -X copy-output -a || exit 1
|
||||
all=$($TMUX show-buffer)
|
||||
case "$all" in
|
||||
*alpha*beta*) ;;
|
||||
*) exit 1 ;;
|
||||
esac
|
||||
$TMUX send-keys -t :plain.0 -X cancel || exit 1
|
||||
|
||||
$TMUX set-buffer -b keep unchanged || exit 1
|
||||
$TMUX copy-mode -t :plain || exit 1
|
||||
$TMUX send-keys -t :plain.0 -X copy-output || exit 1
|
||||
[ "$($TMUX show-buffer -b keep)" = unchanged ] || exit 1
|
||||
$TMUX send-keys -t :plain.0 -X cancel || exit 1
|
||||
|
||||
$TMUX new-window -d -n empty "printf '\\033]133;A\\007p\\$ \\033]133;B\\007echo\\033]133;C\\007one\\n\\033]133;D;0\\007\\033]133;A\\007p\\$ \\033]133;B\\007true\\033]133;C\\033]133;D;0\\007'; exec sleep 100" || exit 1
|
||||
sleep 1
|
||||
$TMUX copy-mode -t :empty || exit 1
|
||||
$TMUX send-keys -t :empty.0 -X copy-output || exit 1
|
||||
[ "$($TMUX show-buffer)" = one ] || exit 1
|
||||
$TMUX send-keys -t :empty.0 -X cancel || exit 1
|
||||
|
||||
$TMUX new-window -d -n prompt "printf '\\033]133;A\\007p\\$ \\033]133;B\\007echo\\033]133;C\\007one\\n\\033]133;D;0\\007\\033]133;A\\007p\\$ \\033]133;B\\007'; exec sleep 100" || exit 1
|
||||
sleep 1
|
||||
$TMUX copy-mode -t :prompt || exit 1
|
||||
$TMUX send-keys -t :prompt.0 -X copy-output || exit 1
|
||||
[ "$($TMUX show-buffer)" = one ] || exit 1
|
||||
$TMUX send-keys -t :prompt.0 -X cancel || exit 1
|
||||
|
||||
$TMUX copy-mode -c -t :prompt || exit 1
|
||||
$TMUX send-keys -t :prompt.0 -X expand-output || exit 1
|
||||
$TMUX send-keys -t :prompt.0 -X -N 100 cursor-down || exit 1
|
||||
$TMUX send-keys -t :prompt.0 -X select-output || exit 1
|
||||
[ "$($TMUX display-message -p -t :prompt.0 '#{selection_present}')" = 1 ] || exit 1
|
||||
$TMUX send-keys -t :prompt.0 -X copy-selection || exit 1
|
||||
[ "$($TMUX show-buffer)" = one ] || exit 1
|
||||
$TMUX send-keys -t :prompt.0 -X cancel || exit 1
|
||||
|
||||
$TMUX copy-mode -t :prompt || exit 1
|
||||
$TMUX send-keys -t :prompt.0 -X -N 100 cursor-down || exit 1
|
||||
$TMUX send-keys -t :prompt.0 C-o || exit 1
|
||||
[ "$($TMUX display-message -p -t :prompt.0 '#{selection_present}')" = 1 ] || exit 1
|
||||
$TMUX send-keys -t :prompt.0 -X copy-selection || exit 1
|
||||
[ "$($TMUX show-buffer)" = one ] || exit 1
|
||||
$TMUX send-keys -t :prompt.0 -X cancel || exit 1
|
||||
|
||||
$TMUX new-window -d -n same "printf '\\033]133;A\\007p\\$ \\033]133;B\\007echo\\n\\033]133;C\\007one\\033]133;D;0\\007\\033]133;A\\007p\\$ \\033]133;B\\007'; exec sleep 100" || exit 1
|
||||
sleep 1
|
||||
$TMUX copy-mode -t :same || exit 1
|
||||
$TMUX send-keys -t :same.0 -X search-backward one || exit 1
|
||||
$TMUX send-keys -t :same.0 -X select-output || exit 1
|
||||
$TMUX send-keys -t :same.0 -X copy-selection || exit 1
|
||||
[ "$($TMUX show-buffer)" = one ] || exit 1
|
||||
$TMUX send-keys -t :same.0 -X cancel || exit 1
|
||||
|
||||
$TMUX new-window -d -n clear "printf 'old1\\nold2\\nold3\\nold4\\nold5\\nold6\\n\\033]133;A\\007p\\$ \\033]133;B\\007echo 1; clear; ps\\n\\033]133;C\\0071\\n\\033[H\\033[2JPID TTY\\n1 pts/0\\n\\033]133;D;0\\007separator\\n\\033]133;A\\007p\\$ \\033]133;B\\007'; exec sleep 100" || exit 1
|
||||
sleep 1
|
||||
$TMUX copy-mode -t :clear || exit 1
|
||||
$TMUX send-keys -t :clear.0 C-o || exit 1
|
||||
$TMUX send-keys -t :clear.0 -X copy-selection || exit 1
|
||||
[ "$($TMUX show-buffer)" = "$(printf 'PID TTY\n1 pts/0')" ] || exit 1
|
||||
$TMUX send-keys -t :clear.0 -X cancel || exit 1
|
||||
|
||||
exit 0
|
||||
@@ -439,7 +439,6 @@ screen_write_reset(struct screen_write_ctx *ctx)
|
||||
|
||||
if (options_get_number(global_options, "extended-keys") == 2)
|
||||
s->mode = (s->mode & ~EXTENDED_KEY_MODES)|MODE_KEYS_EXTENDED;
|
||||
input_kitty_reset(s);
|
||||
|
||||
screen_write_clearscreen(ctx, 8);
|
||||
screen_write_set_cursor(ctx, 0, 0);
|
||||
|
||||
6
screen.c
6
screen.c
@@ -88,8 +88,6 @@ screen_init(struct screen *s, u_int sx, u_int sy, u_int hlimit)
|
||||
s->default_cstyle = SCREEN_CURSOR_DEFAULT;
|
||||
s->mode = MODE_CURSOR;
|
||||
s->default_mode = 0;
|
||||
memset(&s->kitty_keys, 0, sizeof s->kitty_keys);
|
||||
memset(&s->saved_kitty_keys, 0, sizeof s->saved_kitty_keys);
|
||||
s->ccolour = -1;
|
||||
s->default_ccolour = -1;
|
||||
s->tabs = NULL;
|
||||
@@ -120,9 +118,9 @@ screen_reinit(struct screen *s, int check)
|
||||
|
||||
if (options_get_number(global_options, "extended-keys") == 2)
|
||||
s->mode = (s->mode & ~EXTENDED_KEY_MODES)|MODE_KEYS_EXTENDED;
|
||||
|
||||
if (SCREEN_IS_ALTERNATE(s))
|
||||
screen_alternate_off(s, NULL, 0);
|
||||
input_kitty_reset(s);
|
||||
s->saved_cx = UINT_MAX;
|
||||
s->saved_cy = UINT_MAX;
|
||||
|
||||
@@ -700,7 +698,6 @@ screen_alternate_on(struct screen *s, struct grid_cell *gc, int cursor)
|
||||
|
||||
if (SCREEN_IS_ALTERNATE(s))
|
||||
return 0;
|
||||
input_kitty_alternate_on(s);
|
||||
sx = screen_size_x(s);
|
||||
sy = screen_size_y(s);
|
||||
|
||||
@@ -761,7 +758,6 @@ screen_alternate_off(struct screen *s, struct grid_cell *gc, int cursor)
|
||||
s->cy = screen_size_y(s) - 1;
|
||||
return 0;
|
||||
}
|
||||
input_kitty_alternate_off(s);
|
||||
|
||||
/* Restore the saved grid. */
|
||||
grid_duplicate_lines(s->grid, screen_hsize(s), s->saved_grid, 0,
|
||||
|
||||
@@ -2194,7 +2194,6 @@ server_client_reset_state(struct client *c)
|
||||
log_debug("%s: client %s mode %s", __func__, c->name,
|
||||
screen_mode_to_string(mode));
|
||||
}
|
||||
tty_update_kitty(tty, s);
|
||||
|
||||
/* Reset region and margin. */
|
||||
tty_region_off(tty);
|
||||
|
||||
6
spawn.c
6
spawn.c
@@ -701,7 +701,7 @@ spawn_editor_finish(struct window_pane *wp)
|
||||
|
||||
struct spawn_editor_state *
|
||||
spawn_editor(struct client *c, const char *buf, size_t len,
|
||||
spawn_finish_edit_cb cb, void *arg)
|
||||
const char *editor, spawn_finish_edit_cb cb, void *arg)
|
||||
{
|
||||
struct spawn_editor_state *es;
|
||||
struct spawn_context sc = { 0 };
|
||||
@@ -715,13 +715,13 @@ spawn_editor(struct client *c, const char *buf, size_t len,
|
||||
FILE *f;
|
||||
char *cmd, *cause = NULL;
|
||||
char path[] = _PATH_TMP "tmux.XXXXXXXX";
|
||||
const char *editor;
|
||||
int fd;
|
||||
|
||||
if (w->modal != NULL)
|
||||
return (NULL);
|
||||
|
||||
editor = options_get_string(global_options, "editor");
|
||||
if (editor == NULL)
|
||||
editor = options_get_string(global_options, "editor");
|
||||
fd = mkstemp(path);
|
||||
if (fd == -1)
|
||||
return (NULL);
|
||||
|
||||
181
tmux.1
181
tmux.1
@@ -2006,6 +2006,25 @@ Same as
|
||||
.Ic copy\-pipe
|
||||
but also exit copy mode.
|
||||
.It Xo
|
||||
.Ic copy\-pipe\-output
|
||||
.Op Fl aCP
|
||||
.Op Ar command
|
||||
.Op Ar prefix
|
||||
.Xc
|
||||
Copy the current OSC 133 command output, pipe it to
|
||||
.Ar command ,
|
||||
and clear the selection.
|
||||
.Ar prefix
|
||||
is used to name the new paste buffer.
|
||||
.It Xo
|
||||
.Ic copy\-output
|
||||
.Op Fl aCP
|
||||
.Op Ar prefix
|
||||
.Xc
|
||||
Copy the current OSC 133 command output and clear the selection.
|
||||
.Ar prefix
|
||||
is used to name the new paste buffer.
|
||||
.It Xo
|
||||
.Ic copy\-selection
|
||||
.Op Fl CP
|
||||
.Op Ar prefix
|
||||
@@ -2171,6 +2190,27 @@ Hide line numbers in copy mode.
|
||||
.Xc
|
||||
Toggle line numbers in copy mode.
|
||||
.It Xo
|
||||
.Ic collapse\-output
|
||||
.Op Fl a
|
||||
.Xc
|
||||
Collapse the output for the command on the cursor line.
|
||||
With
|
||||
.Fl a ,
|
||||
collapse all command output in the copy-mode buffer.
|
||||
Text before the first OSC 133 prompt is treated as an initial command output
|
||||
region.
|
||||
.It Xo
|
||||
.Ic expand\-output
|
||||
.Op Fl a
|
||||
.Xc
|
||||
Expand the output for the command on the cursor line.
|
||||
With
|
||||
.Fl a ,
|
||||
expand all command output in the copy-mode buffer.
|
||||
.Pp
|
||||
The Tab key toggles output for the command on the cursor line and S-Tab
|
||||
toggles all command output.
|
||||
.It Xo
|
||||
.Ic middle\-line
|
||||
(vi: M)
|
||||
(emacs: M\-r)
|
||||
@@ -2224,6 +2264,32 @@ but treat all non-whitespace characters as part of a word.
|
||||
.Xc
|
||||
Switch at which end of the selection the cursor sits.
|
||||
.It Xo
|
||||
.Ic open\-output
|
||||
.Op Fl a
|
||||
.Op Ar command
|
||||
.Xc
|
||||
Open the current OSC 133 command output in an editor.
|
||||
If
|
||||
.Ar command
|
||||
is given, it is used as the editor command; otherwise, the
|
||||
.Ic editor
|
||||
option is used.
|
||||
.It Xo
|
||||
.Ic open\-selection
|
||||
.Op Ar command
|
||||
.Xc
|
||||
Open the current selection in an editor.
|
||||
If
|
||||
.Ar command
|
||||
is given, it is used as the editor command; otherwise, the
|
||||
.Ic editor
|
||||
option is used.
|
||||
In emacs mode,
|
||||
.Ql e ,
|
||||
and in vi mode,
|
||||
.Ql M\-e ,
|
||||
opens the selection if one is present, otherwise the command output.
|
||||
.It Xo
|
||||
.Ic page\-down
|
||||
(vi: C\-f)
|
||||
(emacs: PageDown)
|
||||
@@ -2264,6 +2330,21 @@ Same as
|
||||
.Ic pipe
|
||||
but also exit copy mode.
|
||||
.It Xo
|
||||
.Ic pipe\-output
|
||||
.Op Fl a
|
||||
.Op Ar command
|
||||
.Xc
|
||||
Pipe the current OSC 133 command output to
|
||||
.Ar command
|
||||
and clear the selection.
|
||||
.It Xo
|
||||
.Ic pipe\-selection
|
||||
.Op Ar command
|
||||
.Xc
|
||||
Pipe the selected text to
|
||||
.Ar command
|
||||
and clear the selection.
|
||||
.It Xo
|
||||
.Ic previous\-matching\-bracket
|
||||
(emacs: M\-C\-b)
|
||||
.Xc
|
||||
@@ -2453,6 +2534,15 @@ Search forward for the specified plain text.
|
||||
Repeat the last search in the reverse direction (forward becomes backward and
|
||||
backward becomes forward).
|
||||
.It Xo
|
||||
.Ic select\-output
|
||||
.Op Fl a
|
||||
.Xc
|
||||
Select the current OSC 133 command output.
|
||||
The default emacs binding is
|
||||
.Ql C\-o
|
||||
and the default vi binding is
|
||||
.Ql M\-o .
|
||||
.It Xo
|
||||
.Ic select\-line
|
||||
(vi: V)
|
||||
.Xc
|
||||
@@ -2496,6 +2586,20 @@ Toggle the visibility of the position indicator in the top right.
|
||||
Move to the top line.
|
||||
.El
|
||||
.Pp
|
||||
The output commands use OSC 133 output text from the
|
||||
.Ql C
|
||||
marker up to its matching
|
||||
.Ql D
|
||||
marker.
|
||||
If there is no
|
||||
.Ql D
|
||||
marker, the output ends at the end of the copy-mode buffer.
|
||||
At the following prompt or below it, they use the most recent nonempty output.
|
||||
With
|
||||
.Fl a ,
|
||||
they use the entire copy-mode buffer instead.
|
||||
If no output range can be found, they do nothing.
|
||||
.Pp
|
||||
The search commands come in several varieties:
|
||||
.Ql search\-forward
|
||||
and
|
||||
@@ -2603,12 +2707,19 @@ The synopsis for the
|
||||
command is:
|
||||
.Bl -tag -width Ds
|
||||
.It Xo Ic copy\-mode
|
||||
.Op Fl dekHMqSu
|
||||
.Op Fl UcdekHMqSu
|
||||
.Op Fl s Ar src\-pane
|
||||
.Op Fl t Ar target\-pane
|
||||
.Xc
|
||||
Enter copy mode.
|
||||
.Pp
|
||||
.Fl c
|
||||
enters copy mode with OSC 133 command output collapsed.
|
||||
.Fl U
|
||||
enters copy mode with OSC 133 output controls shown and all output expanded.
|
||||
When output is collapsed, the prompt and entered command are shown and text
|
||||
from the output start marker to the next primary prompt marker is hidden.
|
||||
.Pp
|
||||
.Fl u
|
||||
enters copy mode and scrolls one page up and
|
||||
.Fl d
|
||||
@@ -4907,30 +5018,14 @@ If enabled, the server will exit when there are no attached clients.
|
||||
.It Xo Ic extended\-keys
|
||||
.Op Ic on | off | always
|
||||
.Xc
|
||||
Controls how modified keys are reported.
|
||||
When enabled,
|
||||
.Nm
|
||||
uses the Kitty keyboard protocol with terminals which support it, and the
|
||||
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 with other terminals which support extended keys.
|
||||
Each client uses the best that its terminal supports, so clients with different
|
||||
terminals may be attached at the same time.
|
||||
resource.
|
||||
.Pp
|
||||
Programs inside panes may request either the Kitty keyboard protocol or
|
||||
.Ic modifyOtherKeys ,
|
||||
and keys are sent to each program in the form it requested, whichever client
|
||||
they were typed on.
|
||||
The Kitty keyboard protocol can report the Super and Hyper modifiers, whose key
|
||||
name prefixes are
|
||||
.Ql s-
|
||||
and
|
||||
.Ql H- ;
|
||||
its disambiguate and report-all enhancements are supported.
|
||||
.Pp
|
||||
For
|
||||
.Ic modifyOtherKeys ,
|
||||
when set to
|
||||
When set to
|
||||
.Ic on ,
|
||||
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
|
||||
@@ -4939,35 +5034,26 @@ When set to
|
||||
.Ic always ,
|
||||
modes 1 and 2 can still be requested by applications, but mode 1 will be forced
|
||||
instead of the standard mode.
|
||||
This applies only to applications inside panes; it does not force the Kitty
|
||||
keyboard protocol or change what
|
||||
.Nm
|
||||
requests from the terminal.
|
||||
When set to
|
||||
.Ic off ,
|
||||
this feature is disabled and only standard keys are reported.
|
||||
.Pp
|
||||
.Nm
|
||||
will always request extended keys itself if the terminal supports them.
|
||||
Support for the Kitty keyboard protocol is detected when a client attaches.
|
||||
See also the
|
||||
.Ic kittykeys
|
||||
and
|
||||
.Ic extkeys
|
||||
features for the
|
||||
feature for the
|
||||
.Ic terminal\-features
|
||||
option, the
|
||||
.Ic extended\-keys\-format
|
||||
option and the
|
||||
.Ic pane_key_mode
|
||||
and
|
||||
.Ic client_key_mode
|
||||
variables.
|
||||
variable.
|
||||
.It Xo Ic extended\-keys\-format
|
||||
.Op Ic csi\-u | xterm | kitty
|
||||
.Op Ic csi\-u | xterm
|
||||
.Xc
|
||||
Selects the format for reporting modified keys to programs which request
|
||||
.Ic modifyOtherKeys .
|
||||
Selects one of the two possible formats for reporting modified keys to
|
||||
applications.
|
||||
This is the equivalent of the
|
||||
.Ic formatOtherKeys
|
||||
.Xr xterm 1
|
||||
@@ -4980,11 +5066,6 @@ and as
|
||||
.Ql \[ha][[65;6u
|
||||
when set to
|
||||
.Ic csi\-u .
|
||||
.Ic kitty
|
||||
is accepted for compatibility and is the same as
|
||||
.Ic csi\-u ;
|
||||
programs which request the Kitty keyboard protocol receive it whatever this
|
||||
option is set to.
|
||||
.It Xo Ic focus\-events
|
||||
.Op Ic on | off
|
||||
.Xc
|
||||
@@ -5133,9 +5214,6 @@ Ignore function keys from
|
||||
and use the
|
||||
.Nm
|
||||
internal set only.
|
||||
.It kittykeys
|
||||
Supports the Kitty keyboard protocol.
|
||||
This is added automatically if the terminal answers the Kitty keyboard query.
|
||||
.It margins
|
||||
Supports DECSLRM margins.
|
||||
.It mouse
|
||||
@@ -5842,6 +5920,20 @@ section.
|
||||
.It Ic copy\-mode\-position\-format Ar format
|
||||
Format of the position indicator in copy mode.
|
||||
.Pp
|
||||
.It Ic copy\-mode\-exit\-status\-format Ar format
|
||||
Format of the OSC 133 exit status indicator in the copy-mode gutter.
|
||||
The default displays a theme red
|
||||
.Ql !
|
||||
for a nonzero status and a space otherwise.
|
||||
The gutter grows to fit the expanded format.
|
||||
The format is drawn to the left of the collapse control, and its alignment
|
||||
applies within that area.
|
||||
The format is expanded with
|
||||
.Ql exit_status
|
||||
and
|
||||
.Ql exit_status_present ,
|
||||
which is set only when the OSC 133 end-of-output marker includes a status.
|
||||
.Pp
|
||||
.It Ic copy\-mode\-position\-style Ar style
|
||||
Set the style of the position indicator in copy mode.
|
||||
For how to specify
|
||||
@@ -7342,7 +7434,6 @@ The following variables are available, where appropriate:
|
||||
.It Li "client_discarded" Ta "" Ta "Bytes discarded when client behind"
|
||||
.It Li "client_flags" Ta "" Ta "List of client flags"
|
||||
.It Li "client_height" Ta "" Ta "Height of client"
|
||||
.It Li "client_key_mode" Ta "" Ta "Extended key reporting mode for this client"
|
||||
.It Li "client_key_table" Ta "" Ta "Current key table"
|
||||
.It Li "client_last_session" Ta "" Ta "Name of the client's last session"
|
||||
.It Li "client_name" Ta "" Ta "Name of client"
|
||||
|
||||
117
tmux.h
117
tmux.h
@@ -142,8 +142,6 @@ struct winlink;
|
||||
#define VISUAL_BOTH 2
|
||||
|
||||
/* Key modifier bits. */
|
||||
#define KEYC_SUPER 0x00010000000000ULL
|
||||
#define KEYC_HYPER 0x00020000000000ULL
|
||||
#define KEYC_META 0x00100000000000ULL
|
||||
#define KEYC_CTRL 0x00200000000000ULL
|
||||
#define KEYC_SHIFT 0x00400000000000ULL
|
||||
@@ -376,29 +374,6 @@ enum {
|
||||
KEYC_F10,
|
||||
KEYC_F11,
|
||||
KEYC_F12,
|
||||
KEYC_F13,
|
||||
KEYC_F14,
|
||||
KEYC_F15,
|
||||
KEYC_F16,
|
||||
KEYC_F17,
|
||||
KEYC_F18,
|
||||
KEYC_F19,
|
||||
KEYC_F20,
|
||||
KEYC_F21,
|
||||
KEYC_F22,
|
||||
KEYC_F23,
|
||||
KEYC_F24,
|
||||
KEYC_F25,
|
||||
KEYC_F26,
|
||||
KEYC_F27,
|
||||
KEYC_F28,
|
||||
KEYC_F29,
|
||||
KEYC_F30,
|
||||
KEYC_F31,
|
||||
KEYC_F32,
|
||||
KEYC_F33,
|
||||
KEYC_F34,
|
||||
KEYC_F35,
|
||||
KEYC_IC,
|
||||
KEYC_DC,
|
||||
KEYC_HOME,
|
||||
@@ -430,54 +405,6 @@ enum {
|
||||
KEYC_KP_ENTER,
|
||||
KEYC_KP_ZERO,
|
||||
KEYC_KP_PERIOD,
|
||||
KEYC_KP_EQUAL,
|
||||
KEYC_KP_SEPARATOR,
|
||||
KEYC_KP_LEFT,
|
||||
KEYC_KP_RIGHT,
|
||||
KEYC_KP_UP,
|
||||
KEYC_KP_DOWN,
|
||||
KEYC_KP_PPAGE,
|
||||
KEYC_KP_NPAGE,
|
||||
KEYC_KP_HOME,
|
||||
KEYC_KP_END,
|
||||
KEYC_KP_IC,
|
||||
KEYC_KP_DC,
|
||||
KEYC_KP_BEGIN,
|
||||
|
||||
/* Other function keys. */
|
||||
KEYC_CAPSLOCK,
|
||||
KEYC_SCROLLLOCK,
|
||||
KEYC_NUMLOCK,
|
||||
KEYC_PRINTSCREEN,
|
||||
KEYC_PAUSE,
|
||||
KEYC_MENU,
|
||||
KEYC_MEDIA_PLAY,
|
||||
KEYC_MEDIA_PAUSE,
|
||||
KEYC_MEDIA_PLAYPAUSE,
|
||||
KEYC_MEDIA_REVERSE,
|
||||
KEYC_MEDIA_STOP,
|
||||
KEYC_MEDIA_FASTFORWARD,
|
||||
KEYC_MEDIA_REWIND,
|
||||
KEYC_MEDIA_NEXT,
|
||||
KEYC_MEDIA_PREVIOUS,
|
||||
KEYC_MEDIA_RECORD,
|
||||
KEYC_VOLUME_DOWN,
|
||||
KEYC_VOLUME_UP,
|
||||
KEYC_VOLUME_MUTE,
|
||||
KEYC_LEFT_SHIFT,
|
||||
KEYC_LEFT_CTRL,
|
||||
KEYC_LEFT_ALT,
|
||||
KEYC_LEFT_SUPER,
|
||||
KEYC_LEFT_HYPER,
|
||||
KEYC_LEFT_META,
|
||||
KEYC_RIGHT_SHIFT,
|
||||
KEYC_RIGHT_CTRL,
|
||||
KEYC_RIGHT_ALT,
|
||||
KEYC_RIGHT_SUPER,
|
||||
KEYC_RIGHT_HYPER,
|
||||
KEYC_RIGHT_META,
|
||||
KEYC_ISO_LEVEL3_SHIFT,
|
||||
KEYC_ISO_LEVEL5_SHIFT,
|
||||
|
||||
/* Theme reporting. */
|
||||
KEYC_REPORT_DARK_THEME,
|
||||
@@ -775,16 +702,6 @@ enum tty_code_code {
|
||||
#define CURSOR_MODES (MODE_CURSOR|MODE_CURSOR_BLINKING|MODE_CURSOR_VERY_VISIBLE)
|
||||
#define EXTENDED_KEY_MODES (MODE_KEYS_EXTENDED|MODE_KEYS_EXTENDED_2)
|
||||
|
||||
/* Extended key output formats. */
|
||||
#define EXTENDED_KEYS_CSI_U 0
|
||||
#define EXTENDED_KEYS_XTERM 1
|
||||
#define EXTENDED_KEYS_KITTY 2
|
||||
|
||||
/* Supported Kitty keyboard protocol flags. */
|
||||
#define KITTY_KEY_DISAMBIGUATE 0x1
|
||||
#define KITTY_KEY_REPORT_ALL 0x8
|
||||
#define KITTY_KEY_SUPPORTED (KITTY_KEY_DISAMBIGUATE|KITTY_KEY_REPORT_ALL)
|
||||
|
||||
/* Mouse protocol constants. */
|
||||
#define MOUSE_PARAM_MAX 0xff
|
||||
#define MOUSE_PARAM_UTF8_MAX 0x7ff
|
||||
@@ -899,6 +816,7 @@ struct colour_palette {
|
||||
#define GRID_LINE_START_OUTPUT 0x40
|
||||
#define GRID_LINE_END_OUTPUT 0x80
|
||||
#define GRID_LINE_HYPERLINK 0x100
|
||||
#define GRID_LINE_END_OUTPUT_STATUS 0x200
|
||||
|
||||
/* All OSC 133 flags. */
|
||||
#define GRID_LINE_OSC133_FLAGS \
|
||||
@@ -906,7 +824,8 @@ struct colour_palette {
|
||||
GRID_LINE_SECOND_PROMPT| \
|
||||
GRID_LINE_START_COMMAND| \
|
||||
GRID_LINE_START_OUTPUT| \
|
||||
GRID_LINE_END_OUTPUT)
|
||||
GRID_LINE_END_OUTPUT| \
|
||||
GRID_LINE_END_OUTPUT_STATUS)
|
||||
|
||||
/* Grid string flags. */
|
||||
#define GRID_STRING_WITH_SEQUENCES 0x1
|
||||
@@ -1151,11 +1070,6 @@ struct progress_bar {
|
||||
/* Virtual screen. */
|
||||
struct screen_sel;
|
||||
struct screen_titles;
|
||||
struct kitty_key_state {
|
||||
u_int flags;
|
||||
u_int saved_flags;
|
||||
int have_saved;
|
||||
};
|
||||
struct screen {
|
||||
char *title;
|
||||
char *path;
|
||||
@@ -1177,8 +1091,6 @@ struct screen {
|
||||
|
||||
int mode;
|
||||
int default_mode;
|
||||
struct kitty_key_state kitty_keys;
|
||||
struct kitty_key_state saved_kitty_keys;
|
||||
|
||||
u_int saved_cx;
|
||||
u_int saved_cy;
|
||||
@@ -1829,7 +1741,6 @@ struct tty_term {
|
||||
#define TERM_VT100LIKE 0x20
|
||||
#define TERM_SIXEL 0x40
|
||||
#define TERM_INVALIDMS 0x80
|
||||
#define TERM_KITTYKEYS 0x100
|
||||
int flags;
|
||||
|
||||
LIST_ENTRY(tty_term) entry;
|
||||
@@ -1910,12 +1821,9 @@ struct tty {
|
||||
#define TTY_WAITBG 0x4000
|
||||
#define TTY_BRACKETPASTE 0x8000
|
||||
#define TTY_HAVESYNC 0x10000
|
||||
#define TTY_HAVEKKB 0x20000
|
||||
#define TTY_KKBPUSHED 0x40000
|
||||
#define TTY_ALL_REQUEST_FLAGS \
|
||||
(TTY_HAVEDA|TTY_HAVEDA2|TTY_HAVEXDA|TTY_HAVESYNC|TTY_HAVEKKB)
|
||||
(TTY_HAVEDA|TTY_HAVEDA2|TTY_HAVEXDA|TTY_HAVESYNC)
|
||||
int flags;
|
||||
u_int kitty_keys;
|
||||
|
||||
struct tty_term *term;
|
||||
|
||||
@@ -3068,7 +2976,6 @@ int tty_open(struct tty *, char **);
|
||||
void tty_close(struct tty *);
|
||||
void tty_free(struct tty *);
|
||||
void tty_update_features(struct tty *);
|
||||
void tty_update_kitty(struct tty *, struct screen *);
|
||||
void tty_set_selection(struct tty *, const char *, const char *, size_t);
|
||||
void tty_write(void (*)(struct tty *, const struct tty_ctx *),
|
||||
struct tty_ctx *);
|
||||
@@ -3550,20 +3457,6 @@ int input_key(struct screen *, struct bufferevent *, key_code);
|
||||
int input_key_get_mouse(struct screen *, struct mouse_event *, u_int,
|
||||
u_int, const char **, size_t *);
|
||||
|
||||
/* input-kitty.c */
|
||||
void input_kitty_reset(struct screen *);
|
||||
void input_kitty_alternate_on(struct screen *);
|
||||
void input_kitty_alternate_off(struct screen *);
|
||||
void input_kitty_set(struct screen *, u_int, int);
|
||||
void input_kitty_push(struct screen *, u_int);
|
||||
void input_kitty_pop(struct screen *, u_int);
|
||||
int input_key_kitty(struct screen *, struct bufferevent *, key_code);
|
||||
|
||||
/* tty-kitty.c */
|
||||
int tty_keys_kitty(struct tty *, const char *, size_t, size_t *,
|
||||
key_code *);
|
||||
int tty_keys_kitty_query(struct tty *, const char *, size_t, size_t *);
|
||||
|
||||
/* colour.c */
|
||||
int colour_find_rgb(u_char, u_char, u_char);
|
||||
int colour_join_rgb(u_char, u_char, u_char);
|
||||
@@ -4336,7 +4229,7 @@ struct winlink *spawn_window(struct spawn_context *, char **);
|
||||
struct window_pane *spawn_pane(struct spawn_context *, char **);
|
||||
typedef void (*spawn_finish_edit_cb)(char *, size_t, void *);
|
||||
struct spawn_editor_state *spawn_editor(struct client *, const char *, size_t,
|
||||
spawn_finish_edit_cb, void *);
|
||||
const char *, spawn_finish_edit_cb, void *);
|
||||
void spawn_cancel_editor(struct spawn_editor_state *);
|
||||
pid_t spawn_get_editor_pid(struct spawn_editor_state *);
|
||||
void spawn_editor_finish(struct window_pane *);
|
||||
|
||||
@@ -235,13 +235,6 @@ static const struct tty_feature tty_feature_sync = {
|
||||
0
|
||||
};
|
||||
|
||||
/* Terminal supports the Kitty keyboard protocol. */
|
||||
static const struct tty_feature tty_feature_kittykeys = {
|
||||
"kittykeys",
|
||||
NULL,
|
||||
TERM_KITTYKEYS
|
||||
};
|
||||
|
||||
/* Terminal supports extended keys. */
|
||||
static const char *const tty_feature_extkeys_capabilities[] = {
|
||||
"Eneks=\\E[>4;2m",
|
||||
@@ -393,7 +386,6 @@ static const struct tty_feature *const tty_features[] = {
|
||||
&tty_feature_extkeys,
|
||||
&tty_feature_focus,
|
||||
&tty_feature_ignorefkeys,
|
||||
&tty_feature_kittykeys,
|
||||
&tty_feature_margins,
|
||||
&tty_feature_mouse,
|
||||
&tty_feature_osc7,
|
||||
|
||||
27
tty-keys.c
27
tty-keys.c
@@ -772,17 +772,6 @@ tty_keys_next(struct tty *tty)
|
||||
goto partial_key;
|
||||
}
|
||||
|
||||
/* Is this a Kitty keyboard protocol response? */
|
||||
switch (tty_keys_kitty_query(tty, buf, len, &size)) {
|
||||
case 0: /* yes */
|
||||
key = KEYC_UNKNOWN;
|
||||
goto complete_key;
|
||||
case -1: /* no, or not valid */
|
||||
break;
|
||||
case 1: /* partial */
|
||||
goto partial_key;
|
||||
}
|
||||
|
||||
/* Is this a synchronized update mode response? */
|
||||
switch (tty_keys_sync(tty, buf, len, &size)) {
|
||||
case 0: /* yes */
|
||||
@@ -869,18 +858,6 @@ tty_keys_next(struct tty *tty)
|
||||
goto partial_key;
|
||||
}
|
||||
|
||||
/* Is this an extended key press? */
|
||||
switch (tty_keys_kitty(tty, buf, len, &size, &key)) {
|
||||
case 0: /* yes */
|
||||
goto complete_key;
|
||||
case -1: /* no, or not valid */
|
||||
break;
|
||||
case -2: /* yes, but not representable by tmux */
|
||||
goto discard_key;
|
||||
case 1: /* partial */
|
||||
goto partial_key;
|
||||
}
|
||||
|
||||
/* Is this an extended key press? */
|
||||
switch (tty_keys_extended_key(tty, buf, len, &size, &key)) {
|
||||
case 0: /* yes */
|
||||
@@ -1112,8 +1089,6 @@ tty_keys_extended_key(struct tty *tty, const char *buf, size_t len,
|
||||
utf8_char uc;
|
||||
|
||||
*size = 0;
|
||||
if (tty->flags & TTY_KKBPUSHED)
|
||||
return (-1);
|
||||
|
||||
/* First two bytes are always \033[. */
|
||||
if (buf[0] != '\033')
|
||||
@@ -1552,8 +1527,6 @@ tty_keys_device_attributes(struct tty *tty, const char *buf, size_t len,
|
||||
}
|
||||
log_debug("%s: received primary DA %.*s", c->name, (int)*size, buf);
|
||||
|
||||
/* A DA response without a preceding keyboard response means no support. */
|
||||
tty->flags |= TTY_HAVEKKB;
|
||||
tty_update_features(tty);
|
||||
tty->flags |= TTY_HAVEDA;
|
||||
|
||||
|
||||
430
tty-kitty.c
430
tty-kitty.c
@@ -1,430 +0,0 @@
|
||||
/* $OpenBSD$ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2026 Michael Grant <mgrant@grant.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
/* Detect support in the outside terminal and decode its key sequences. */
|
||||
|
||||
struct tty_kitty_key {
|
||||
u_int number;
|
||||
key_code key;
|
||||
};
|
||||
|
||||
static const struct tty_kitty_key tty_kitty_keys[] = {
|
||||
{ 57358, KEYC_CAPSLOCK },
|
||||
{ 57359, KEYC_SCROLLLOCK },
|
||||
{ 57360, KEYC_NUMLOCK },
|
||||
{ 57361, KEYC_PRINTSCREEN },
|
||||
{ 57362, KEYC_PAUSE },
|
||||
{ 57363, KEYC_MENU },
|
||||
{ 57376, KEYC_F13 },
|
||||
{ 57377, KEYC_F14 },
|
||||
{ 57378, KEYC_F15 },
|
||||
{ 57379, KEYC_F16 },
|
||||
{ 57380, KEYC_F17 },
|
||||
{ 57381, KEYC_F18 },
|
||||
{ 57382, KEYC_F19 },
|
||||
{ 57383, KEYC_F20 },
|
||||
{ 57384, KEYC_F21 },
|
||||
{ 57385, KEYC_F22 },
|
||||
{ 57386, KEYC_F23 },
|
||||
{ 57387, KEYC_F24 },
|
||||
{ 57388, KEYC_F25 },
|
||||
{ 57389, KEYC_F26 },
|
||||
{ 57390, KEYC_F27 },
|
||||
{ 57391, KEYC_F28 },
|
||||
{ 57392, KEYC_F29 },
|
||||
{ 57393, KEYC_F30 },
|
||||
{ 57394, KEYC_F31 },
|
||||
{ 57395, KEYC_F32 },
|
||||
{ 57396, KEYC_F33 },
|
||||
{ 57397, KEYC_F34 },
|
||||
{ 57398, KEYC_F35 },
|
||||
{ 57399, KEYC_KP_ZERO|KEYC_KEYPAD },
|
||||
{ 57400, KEYC_KP_ONE|KEYC_KEYPAD },
|
||||
{ 57401, KEYC_KP_TWO|KEYC_KEYPAD },
|
||||
{ 57402, KEYC_KP_THREE|KEYC_KEYPAD },
|
||||
{ 57403, KEYC_KP_FOUR|KEYC_KEYPAD },
|
||||
{ 57404, KEYC_KP_FIVE|KEYC_KEYPAD },
|
||||
{ 57405, KEYC_KP_SIX|KEYC_KEYPAD },
|
||||
{ 57406, KEYC_KP_SEVEN|KEYC_KEYPAD },
|
||||
{ 57407, KEYC_KP_EIGHT|KEYC_KEYPAD },
|
||||
{ 57408, KEYC_KP_NINE|KEYC_KEYPAD },
|
||||
{ 57409, KEYC_KP_PERIOD|KEYC_KEYPAD },
|
||||
{ 57410, KEYC_KP_SLASH|KEYC_KEYPAD },
|
||||
{ 57411, KEYC_KP_STAR|KEYC_KEYPAD },
|
||||
{ 57412, KEYC_KP_MINUS|KEYC_KEYPAD },
|
||||
{ 57413, KEYC_KP_PLUS|KEYC_KEYPAD },
|
||||
{ 57414, KEYC_KP_ENTER|KEYC_KEYPAD },
|
||||
{ 57415, KEYC_KP_EQUAL|KEYC_KEYPAD },
|
||||
{ 57416, KEYC_KP_SEPARATOR|KEYC_KEYPAD },
|
||||
{ 57417, KEYC_KP_LEFT|KEYC_KEYPAD },
|
||||
{ 57418, KEYC_KP_RIGHT|KEYC_KEYPAD },
|
||||
{ 57419, KEYC_KP_UP|KEYC_KEYPAD },
|
||||
{ 57420, KEYC_KP_DOWN|KEYC_KEYPAD },
|
||||
{ 57421, KEYC_KP_PPAGE|KEYC_KEYPAD },
|
||||
{ 57422, KEYC_KP_NPAGE|KEYC_KEYPAD },
|
||||
{ 57423, KEYC_KP_HOME|KEYC_KEYPAD },
|
||||
{ 57424, KEYC_KP_END|KEYC_KEYPAD },
|
||||
{ 57425, KEYC_KP_IC|KEYC_KEYPAD },
|
||||
{ 57426, KEYC_KP_DC|KEYC_KEYPAD },
|
||||
{ 57427, KEYC_KP_BEGIN|KEYC_KEYPAD },
|
||||
{ 57428, KEYC_MEDIA_PLAY },
|
||||
{ 57429, KEYC_MEDIA_PAUSE },
|
||||
{ 57430, KEYC_MEDIA_PLAYPAUSE },
|
||||
{ 57431, KEYC_MEDIA_REVERSE },
|
||||
{ 57432, KEYC_MEDIA_STOP },
|
||||
{ 57433, KEYC_MEDIA_FASTFORWARD },
|
||||
{ 57434, KEYC_MEDIA_REWIND },
|
||||
{ 57435, KEYC_MEDIA_NEXT },
|
||||
{ 57436, KEYC_MEDIA_PREVIOUS },
|
||||
{ 57437, KEYC_MEDIA_RECORD },
|
||||
{ 57438, KEYC_VOLUME_DOWN },
|
||||
{ 57439, KEYC_VOLUME_UP },
|
||||
{ 57440, KEYC_VOLUME_MUTE },
|
||||
{ 57441, KEYC_LEFT_SHIFT },
|
||||
{ 57442, KEYC_LEFT_CTRL },
|
||||
{ 57443, KEYC_LEFT_ALT },
|
||||
{ 57444, KEYC_LEFT_SUPER },
|
||||
{ 57445, KEYC_LEFT_HYPER },
|
||||
{ 57446, KEYC_LEFT_META },
|
||||
{ 57447, KEYC_RIGHT_SHIFT },
|
||||
{ 57448, KEYC_RIGHT_CTRL },
|
||||
{ 57449, KEYC_RIGHT_ALT },
|
||||
{ 57450, KEYC_RIGHT_SUPER },
|
||||
{ 57451, KEYC_RIGHT_HYPER },
|
||||
{ 57452, KEYC_RIGHT_META },
|
||||
{ 57453, KEYC_ISO_LEVEL3_SHIFT },
|
||||
{ 57454, KEYC_ISO_LEVEL5_SHIFT }
|
||||
};
|
||||
|
||||
static int
|
||||
tty_kitty_parse_number(const char *s, u_int *value, int empty)
|
||||
{
|
||||
char *end;
|
||||
unsigned long number;
|
||||
|
||||
if (*s == '\0') {
|
||||
if (!empty)
|
||||
return (-1);
|
||||
return (0);
|
||||
}
|
||||
if (!isdigit((u_char)*s))
|
||||
return (-1);
|
||||
number = strtoul(s, &end, 10);
|
||||
if (*end != '\0' || number > UINT_MAX)
|
||||
return (-1);
|
||||
*value = number;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
tty_kitty_parse_list(char *s, u_int *first, u_int *second, int empty,
|
||||
u_int maximum)
|
||||
{
|
||||
char *copy, *item;
|
||||
u_int n = 0, value;
|
||||
int result = 0;
|
||||
|
||||
copy = s;
|
||||
while ((item = strsep(©, ":")) != NULL) {
|
||||
if (maximum != 0 && n == maximum)
|
||||
return (-1);
|
||||
value = 0;
|
||||
if (tty_kitty_parse_number(item, &value, empty) != 0) {
|
||||
result = -1;
|
||||
break;
|
||||
}
|
||||
if (n == 0 && *item != '\0')
|
||||
*first = value;
|
||||
else if (n == 1 && *item != '\0')
|
||||
*second = value;
|
||||
n++;
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
static int
|
||||
tty_kitty_find_end(const char *buf, size_t len, size_t *end)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 2; i < len; i++) {
|
||||
if (buf[i] == 'u' || buf[i] == '~' || buf[i] == 'A' ||
|
||||
buf[i] == 'B' || buf[i] == 'C' || buf[i] == 'D' ||
|
||||
buf[i] == 'E' || buf[i] == 'F' || buf[i] == 'H' ||
|
||||
buf[i] == 'P' || buf[i] == 'Q' || buf[i] == 'S') {
|
||||
*end = i;
|
||||
return (0);
|
||||
}
|
||||
if (!isdigit((u_char)buf[i]) && buf[i] != ';' && buf[i] != ':')
|
||||
return (-1);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
static key_code
|
||||
tty_kitty_function(u_int number, char final)
|
||||
{
|
||||
u_int i;
|
||||
|
||||
if (final == 'u') {
|
||||
switch (number) {
|
||||
case 9:
|
||||
return (C0_HT);
|
||||
case 13:
|
||||
return (C0_CR);
|
||||
case 27:
|
||||
return (C0_ESC);
|
||||
case 127:
|
||||
return (KEYC_BSPACE);
|
||||
}
|
||||
for (i = 0; i < nitems(tty_kitty_keys); i++) {
|
||||
if (tty_kitty_keys[i].number == number)
|
||||
return (tty_kitty_keys[i].key);
|
||||
}
|
||||
return (KEYC_NONE);
|
||||
}
|
||||
|
||||
if (final == '~') {
|
||||
switch (number) {
|
||||
case 2: return (KEYC_IC);
|
||||
case 3: return (KEYC_DC);
|
||||
case 5: return (KEYC_PPAGE);
|
||||
case 6: return (KEYC_NPAGE);
|
||||
case 7: return (KEYC_HOME);
|
||||
case 8: return (KEYC_END);
|
||||
case 11: return (KEYC_F1);
|
||||
case 12: return (KEYC_F2);
|
||||
case 13: return (KEYC_F3);
|
||||
case 14: return (KEYC_F4);
|
||||
case 15: return (KEYC_F5);
|
||||
case 17: return (KEYC_F6);
|
||||
case 18: return (KEYC_F7);
|
||||
case 19: return (KEYC_F8);
|
||||
case 20: return (KEYC_F9);
|
||||
case 21: return (KEYC_F10);
|
||||
case 23: return (KEYC_F11);
|
||||
case 24: return (KEYC_F12);
|
||||
case 29: return (KEYC_MENU);
|
||||
case 57427: return (KEYC_KP_BEGIN|KEYC_KEYPAD);
|
||||
}
|
||||
return (KEYC_UNKNOWN);
|
||||
}
|
||||
if (number != 1)
|
||||
return (KEYC_UNKNOWN);
|
||||
switch (final) {
|
||||
case 'A': return (KEYC_UP|KEYC_CURSOR);
|
||||
case 'B': return (KEYC_DOWN|KEYC_CURSOR);
|
||||
case 'C': return (KEYC_RIGHT|KEYC_CURSOR);
|
||||
case 'D': return (KEYC_LEFT|KEYC_CURSOR);
|
||||
case 'E': return (KEYC_KP_BEGIN|KEYC_KEYPAD);
|
||||
case 'F': return (KEYC_END);
|
||||
case 'H': return (KEYC_HOME);
|
||||
case 'P': return (KEYC_F1);
|
||||
case 'Q': return (KEYC_F2);
|
||||
case 'S': return (KEYC_F4);
|
||||
}
|
||||
return (KEYC_UNKNOWN);
|
||||
}
|
||||
|
||||
int
|
||||
tty_keys_kitty_query(struct tty *tty, const char *buf, size_t len,
|
||||
size_t *size)
|
||||
{
|
||||
struct client *c = tty->client;
|
||||
size_t i;
|
||||
u_int flags = 0;
|
||||
|
||||
*size = 0;
|
||||
if (tty->flags & TTY_HAVEKKB)
|
||||
return (-1);
|
||||
|
||||
if (buf[0] != '\033')
|
||||
return (-1);
|
||||
if (len == 1)
|
||||
return (1);
|
||||
if (buf[1] != '[')
|
||||
return (-1);
|
||||
if (len == 2)
|
||||
return (1);
|
||||
if (buf[2] != '?')
|
||||
return (-1);
|
||||
if (len == 3)
|
||||
return (1);
|
||||
|
||||
for (i = 3; i < len && isdigit((u_char)buf[i]); i++) {
|
||||
if (flags > (UINT_MAX - (buf[i] - '0')) / 10)
|
||||
return (-1);
|
||||
flags = (flags * 10) + (buf[i] - '0');
|
||||
}
|
||||
if (i == len)
|
||||
return (1);
|
||||
if (i == 3 || buf[i] != 'u')
|
||||
return (-1);
|
||||
|
||||
*size = i + 1;
|
||||
tty->kitty_keys = flags;
|
||||
tty->flags |= TTY_HAVEKKB;
|
||||
log_debug("%s: received Kitty keyboard flags %u", c->name, flags);
|
||||
tty_parse_client_features(c, "kittykeys", ",");
|
||||
tty_update_features(tty);
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
tty_update_kitty(struct tty *tty, struct screen *s)
|
||||
{
|
||||
u_int flags;
|
||||
char buf[32];
|
||||
|
||||
if (options_get_number(global_options, "extended-keys") == 0 ||
|
||||
(~tty->term->flags & TERM_KITTYKEYS)) {
|
||||
if (tty->flags & TTY_KKBPUSHED) {
|
||||
tty_puts(tty, "\033[<u");
|
||||
tty->flags &= ~TTY_KKBPUSHED;
|
||||
}
|
||||
return;
|
||||
}
|
||||
flags = KITTY_KEY_DISAMBIGUATE;
|
||||
if (s != NULL && (s->kitty_keys.flags & KITTY_KEY_SUPPORTED) != 0)
|
||||
flags = s->kitty_keys.flags & KITTY_KEY_SUPPORTED;
|
||||
if ((tty->flags & TTY_KKBPUSHED) == 0) {
|
||||
xsnprintf(buf, sizeof buf, "\033[>%uu", flags);
|
||||
tty_puts(tty, buf);
|
||||
tty->flags |= TTY_KKBPUSHED;
|
||||
} else if (tty->kitty_keys != flags) {
|
||||
xsnprintf(buf, sizeof buf, "\033[=%uu", flags);
|
||||
tty_puts(tty, buf);
|
||||
}
|
||||
tty->kitty_keys = flags;
|
||||
}
|
||||
|
||||
int
|
||||
tty_keys_kitty(struct tty *tty, const char *buf, size_t len, size_t *size,
|
||||
key_code *key)
|
||||
{
|
||||
struct client *c = tty->client;
|
||||
struct utf8_data ud;
|
||||
utf8_char uc;
|
||||
size_t end;
|
||||
char tmp[128], *copy, *field, final;
|
||||
u_int number = 0, modifiers = 1, event = 1, value;
|
||||
u_int fields = 0;
|
||||
key_code nkey, onlykey;
|
||||
int result;
|
||||
|
||||
*size = 0;
|
||||
if ((tty->flags & TTY_KKBPUSHED) == 0)
|
||||
return (-1);
|
||||
if (len == 0 || buf[0] != '\033')
|
||||
return (-1);
|
||||
if (len == 1)
|
||||
return (1);
|
||||
if (buf[1] != '[')
|
||||
return (-1);
|
||||
if (len == 2)
|
||||
return (1);
|
||||
if (buf[2] == '?')
|
||||
return (-1);
|
||||
|
||||
result = tty_kitty_find_end(buf, len, &end);
|
||||
if (result != 0)
|
||||
return (result);
|
||||
if (end - 2 >= sizeof tmp)
|
||||
return (-1);
|
||||
memcpy(tmp, buf + 2, end - 2);
|
||||
tmp[end - 2] = '\0';
|
||||
final = buf[end];
|
||||
*size = end + 1;
|
||||
|
||||
copy = tmp;
|
||||
while ((field = strsep(©, ";")) != NULL) {
|
||||
if (fields == 3)
|
||||
return (-1);
|
||||
value = 0;
|
||||
if (fields == 0) {
|
||||
if (*field == '\0') {
|
||||
if (final == 'u')
|
||||
return (-1);
|
||||
number = 1;
|
||||
} else if (tty_kitty_parse_list(field, &number, &value,
|
||||
1, 3) != 0)
|
||||
return (-1);
|
||||
} else if (fields == 1) {
|
||||
if (tty_kitty_parse_list(field, &modifiers, &event, 1,
|
||||
2) != 0)
|
||||
return (-1);
|
||||
} else if (tty_kitty_parse_list(field, &value, &value, 1, 0) != 0)
|
||||
return (-1);
|
||||
fields++;
|
||||
}
|
||||
if (fields == 0 || number == 0 || modifiers == 0)
|
||||
return (-1);
|
||||
if (event == 0 || event == 3 || event > 3)
|
||||
return (-2);
|
||||
|
||||
modifiers--;
|
||||
if (modifiers & 32)
|
||||
return (-2);
|
||||
nkey = tty_kitty_function(number, final);
|
||||
if (nkey == KEYC_NONE) {
|
||||
if (final != 'u')
|
||||
return (-1);
|
||||
if (number >= 57344 && number <= 63743)
|
||||
return (-2);
|
||||
if (number <= 0x7f)
|
||||
nkey = number;
|
||||
else if (utf8_fromwc(number, &ud) != UTF8_DONE ||
|
||||
utf8_from_data(&ud, &uc) != UTF8_DONE)
|
||||
return (-2);
|
||||
else
|
||||
nkey = uc;
|
||||
} else if (nkey == KEYC_UNKNOWN)
|
||||
return (-1);
|
||||
|
||||
if (modifiers & 1)
|
||||
nkey |= KEYC_SHIFT;
|
||||
if (modifiers & 2)
|
||||
nkey |= KEYC_META|KEYC_IMPLIED_META;
|
||||
if (modifiers & 4)
|
||||
nkey |= KEYC_CTRL;
|
||||
if (modifiers & 8)
|
||||
nkey |= KEYC_SUPER;
|
||||
if (modifiers & 16)
|
||||
nkey |= KEYC_HYPER;
|
||||
|
||||
/* Shift-Tab has a dedicated tmux key code. */
|
||||
onlykey = nkey & KEYC_MASK_KEY;
|
||||
if (onlykey == C0_HT && (nkey & KEYC_SHIFT))
|
||||
nkey = KEYC_BTAB|(nkey & ~KEYC_MASK_KEY & ~KEYC_SHIFT);
|
||||
|
||||
if (log_get_level() != 0) {
|
||||
log_debug("%s: Kitty key %.*s is %llx (%s)", c->name,
|
||||
(int)*size, buf, nkey, key_string_lookup_key(nkey, 1));
|
||||
}
|
||||
*key = nkey;
|
||||
return (0);
|
||||
}
|
||||
12
tty.c
12
tty.c
@@ -409,8 +409,6 @@ tty_send_requests(struct tty *tty)
|
||||
return;
|
||||
|
||||
if (tty->term->flags & TERM_VT100LIKE) {
|
||||
if (~tty->flags & TTY_HAVEKKB)
|
||||
tty_puts(tty, "\033[?u");
|
||||
if (~tty->flags & TTY_HAVEDA)
|
||||
tty_puts(tty, "\033[c");
|
||||
if (~tty->flags & TTY_HAVEDA2)
|
||||
@@ -509,10 +507,6 @@ tty_stop_tty(struct tty *tty)
|
||||
tty_raw(tty, "\033[?7727l");
|
||||
tty_raw(tty, tty_term_string(tty->term, TTYC_DSFCS));
|
||||
tty_raw(tty, tty_term_string(tty->term, TTYC_DSEKS));
|
||||
if (tty->flags & TTY_KKBPUSHED) {
|
||||
tty_raw(tty, "\033[<u");
|
||||
tty->flags &= ~TTY_KKBPUSHED;
|
||||
}
|
||||
|
||||
if (tty_use_margin(tty))
|
||||
tty_raw(tty, tty_term_string(tty->term, TTYC_DSMG));
|
||||
@@ -565,12 +559,8 @@ tty_update_features(struct tty *tty)
|
||||
|
||||
if (tty_use_margin(tty))
|
||||
tty_putcode(tty, TTYC_ENMG);
|
||||
if (options_get_number(global_options, "extended-keys") == 0 ||
|
||||
(tty->term->flags & TERM_KITTYKEYS))
|
||||
tty_puts(tty, tty_term_string(tty->term, TTYC_DSEKS));
|
||||
else
|
||||
if (options_get_number(global_options, "extended-keys"))
|
||||
tty_puts(tty, tty_term_string(tty->term, TTYC_ENEKS));
|
||||
tty_update_kitty(tty, NULL);
|
||||
if (options_get_number(global_options, "focus-events"))
|
||||
tty_puts(tty, tty_term_string(tty->term, TTYC_ENFCS));
|
||||
if (tty->term->flags & TERM_VT100LIKE)
|
||||
|
||||
@@ -606,7 +606,8 @@ window_buffer_start_edit(struct window_buffer_modedata *data,
|
||||
ed->name = xstrdup(paste_buffer_name(pb));
|
||||
ed->pb = pb;
|
||||
|
||||
ed->editor = spawn_editor(c, buf, len, window_buffer_edit_close_cb, ed);
|
||||
ed->editor = spawn_editor(c, buf, len, NULL, window_buffer_edit_close_cb,
|
||||
ed);
|
||||
if (ed->editor == NULL)
|
||||
window_buffer_finish_edit(ed);
|
||||
else {
|
||||
|
||||
1597
window-copy.c
1597
window-copy.c
File diff suppressed because it is too large
Load Diff
@@ -2104,8 +2104,8 @@ window_customize_start_edit(struct window_customize_modedata *data,
|
||||
buf = "\n";
|
||||
len = 1;
|
||||
}
|
||||
ed->editor = spawn_editor(c, buf, len, window_customize_edit_close_cb,
|
||||
ed);
|
||||
ed->editor = spawn_editor(c, buf, len, NULL,
|
||||
window_customize_edit_close_cb, ed);
|
||||
free(value);
|
||||
if (ed->editor == NULL)
|
||||
window_customize_finish_edit(ed);
|
||||
|
||||
Reference in New Issue
Block a user