mirror of
https://github.com/tmux/tmux.git
synced 2024-12-04 19:58:48 +00:00
Change pasting to bypass the output key processing entirely and write
what was originally received. Fixes problems with pasted text being interpreted as extended keys reported by Mark Kelly.
This commit is contained in:
parent
89adec0ca5
commit
17bab32794
@ -73,11 +73,13 @@ cmd_send_keys_inject_key(struct cmdq_item *item, struct cmdq_item *after,
|
|||||||
if (args_has(args, 'K')) {
|
if (args_has(args, 'K')) {
|
||||||
if (tc == NULL)
|
if (tc == NULL)
|
||||||
return (item);
|
return (item);
|
||||||
event = xmalloc(sizeof *event);
|
event = xcalloc(1, sizeof *event);
|
||||||
event->key = key|KEYC_SENT;
|
event->key = key|KEYC_SENT;
|
||||||
memset(&event->m, 0, sizeof event->m);
|
memset(&event->m, 0, sizeof event->m);
|
||||||
if (server_client_handle_key(tc, event) == 0)
|
if (server_client_handle_key(tc, event) == 0) {
|
||||||
|
free(event->buf);
|
||||||
free(event);
|
free(event);
|
||||||
|
}
|
||||||
return (item);
|
return (item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -499,9 +499,12 @@ input_key_vt10x(struct bufferevent *bev, key_code key)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Prevent TAB and RET from being swallowed by C0 remapping logic. */
|
/*
|
||||||
|
* Prevent TAB, CR and LF from being swallowed by the C0 remapping
|
||||||
|
* logic.
|
||||||
|
*/
|
||||||
onlykey = key & KEYC_MASK_KEY;
|
onlykey = key & KEYC_MASK_KEY;
|
||||||
if (onlykey == '\r' || onlykey == '\t')
|
if (onlykey == '\r' || onlykey == '\n' || onlykey == '\t')
|
||||||
key &= ~KEYC_CTRL;
|
key &= ~KEYC_CTRL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -46,8 +46,6 @@ static void server_client_check_modes(struct client *);
|
|||||||
static void server_client_set_title(struct client *);
|
static void server_client_set_title(struct client *);
|
||||||
static void server_client_set_path(struct client *);
|
static void server_client_set_path(struct client *);
|
||||||
static void server_client_reset_state(struct client *);
|
static void server_client_reset_state(struct client *);
|
||||||
static int server_client_is_bracket_pasting(struct client *, key_code);
|
|
||||||
static int server_client_assume_paste(struct session *);
|
|
||||||
static void server_client_update_latest(struct client *);
|
static void server_client_update_latest(struct client *);
|
||||||
|
|
||||||
static void server_client_dispatch(struct imsg *, void *);
|
static void server_client_dispatch(struct imsg *, void *);
|
||||||
@ -1801,18 +1799,18 @@ out:
|
|||||||
|
|
||||||
/* Is this a bracket paste key? */
|
/* Is this a bracket paste key? */
|
||||||
static int
|
static int
|
||||||
server_client_is_bracket_pasting(struct client *c, key_code key)
|
server_client_is_bracket_paste(struct client *c, key_code key)
|
||||||
{
|
{
|
||||||
if (key == KEYC_PASTE_START) {
|
if (key == KEYC_PASTE_START) {
|
||||||
c->flags |= CLIENT_BRACKETPASTING;
|
c->flags |= CLIENT_BRACKETPASTING;
|
||||||
log_debug("%s: bracket paste on", c->name);
|
log_debug("%s: bracket paste on", c->name);
|
||||||
return (1);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key == KEYC_PASTE_END) {
|
if (key == KEYC_PASTE_END) {
|
||||||
c->flags &= ~CLIENT_BRACKETPASTING;
|
c->flags &= ~CLIENT_BRACKETPASTING;
|
||||||
log_debug("%s: bracket paste off", c->name);
|
log_debug("%s: bracket paste off", c->name);
|
||||||
return (1);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return !!(c->flags & CLIENT_BRACKETPASTING);
|
return !!(c->flags & CLIENT_BRACKETPASTING);
|
||||||
@ -1820,25 +1818,29 @@ server_client_is_bracket_pasting(struct client *c, key_code key)
|
|||||||
|
|
||||||
/* Is this fast enough to probably be a paste? */
|
/* Is this fast enough to probably be a paste? */
|
||||||
static int
|
static int
|
||||||
server_client_assume_paste(struct session *s)
|
server_client_is_assume_paste(struct client *c)
|
||||||
{
|
{
|
||||||
struct timeval tv;
|
struct session *s = c->session;
|
||||||
int t;
|
struct timeval tv;
|
||||||
|
int t;
|
||||||
|
|
||||||
|
if (c->flags & CLIENT_BRACKETPASTING)
|
||||||
|
return (0);
|
||||||
if ((t = options_get_number(s->options, "assume-paste-time")) == 0)
|
if ((t = options_get_number(s->options, "assume-paste-time")) == 0)
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
timersub(&s->activity_time, &s->last_activity_time, &tv);
|
timersub(&c->activity_time, &c->last_activity_time, &tv);
|
||||||
if (tv.tv_sec == 0 && tv.tv_usec < t * 1000) {
|
if (tv.tv_sec == 0 && tv.tv_usec < t * 1000) {
|
||||||
log_debug("session %s pasting (flag %d)", s->name,
|
if (c->flags & CLIENT_ASSUMEPASTING)
|
||||||
!!(s->flags & SESSION_PASTING));
|
|
||||||
if (s->flags & SESSION_PASTING)
|
|
||||||
return (1);
|
return (1);
|
||||||
s->flags |= SESSION_PASTING;
|
c->flags |= CLIENT_ASSUMEPASTING;
|
||||||
|
log_debug("%s: assume paste on", c->name);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
log_debug("session %s not pasting", s->name);
|
if (c->flags & CLIENT_ASSUMEPASTING) {
|
||||||
s->flags &= ~SESSION_PASTING;
|
c->flags &= ~CLIENT_ASSUMEPASTING;
|
||||||
|
log_debug("%s: assume paste off", c->name);
|
||||||
|
}
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1891,6 +1893,8 @@ server_client_key_callback(struct cmdq_item *item, void *data)
|
|||||||
wl = s->curw;
|
wl = s->curw;
|
||||||
|
|
||||||
/* Update the activity timer. */
|
/* Update the activity timer. */
|
||||||
|
memcpy(&c->last_activity_time, &c->activity_time,
|
||||||
|
sizeof c->last_activity_time);
|
||||||
if (gettimeofday(&c->activity_time, NULL) != 0)
|
if (gettimeofday(&c->activity_time, NULL) != 0)
|
||||||
fatal("gettimeofday failed");
|
fatal("gettimeofday failed");
|
||||||
session_update_activity(s, &c->activity_time);
|
session_update_activity(s, &c->activity_time);
|
||||||
@ -1928,14 +1932,16 @@ server_client_key_callback(struct cmdq_item *item, void *data)
|
|||||||
goto forward_key;
|
goto forward_key;
|
||||||
|
|
||||||
/* Forward if bracket pasting. */
|
/* Forward if bracket pasting. */
|
||||||
if (server_client_is_bracket_pasting(c, key))
|
if (server_client_is_bracket_paste (c, key))
|
||||||
goto forward_key;
|
goto paste_key;
|
||||||
|
|
||||||
/* Treat everything as a regular key when pasting is detected. */
|
/* Treat everything as a regular key when pasting is detected. */
|
||||||
if (!KEYC_IS_MOUSE(key) &&
|
if (!KEYC_IS_MOUSE(key) &&
|
||||||
|
key != KEYC_FOCUS_IN &&
|
||||||
|
key != KEYC_FOCUS_OUT &&
|
||||||
(~key & KEYC_SENT) &&
|
(~key & KEYC_SENT) &&
|
||||||
server_client_assume_paste(s))
|
server_client_is_assume_paste(c))
|
||||||
goto forward_key;
|
goto paste_key;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Work out the current key table. If the pane is in a mode, use
|
* Work out the current key table. If the pane is in a mode, use
|
||||||
@ -2104,10 +2110,20 @@ forward_key:
|
|||||||
goto out;
|
goto out;
|
||||||
if (wp != NULL)
|
if (wp != NULL)
|
||||||
window_pane_key(wp, c, s, wl, key, m);
|
window_pane_key(wp, c, s, wl, key, m);
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
paste_key:
|
||||||
|
if (c->flags & CLIENT_READONLY)
|
||||||
|
goto out;
|
||||||
|
if (event->buf != NULL)
|
||||||
|
window_pane_paste(wp, event->buf, event->len);
|
||||||
|
key = KEYC_NONE;
|
||||||
|
goto out;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (s != NULL && key != KEYC_FOCUS_OUT)
|
if (s != NULL && key != KEYC_FOCUS_OUT)
|
||||||
server_client_update_latest(c);
|
server_client_update_latest(c);
|
||||||
|
free(event->buf);
|
||||||
free(event);
|
free(event);
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
@ -2521,11 +2537,13 @@ server_client_click_timer(__unused int fd, __unused short events, void *data)
|
|||||||
* Waiting for a third click that hasn't happened, so this must
|
* Waiting for a third click that hasn't happened, so this must
|
||||||
* have been a double click.
|
* have been a double click.
|
||||||
*/
|
*/
|
||||||
event = xmalloc(sizeof *event);
|
event = xcalloc(1, sizeof *event);
|
||||||
event->key = KEYC_DOUBLECLICK;
|
event->key = KEYC_DOUBLECLICK;
|
||||||
memcpy(&event->m, &c->click_event, sizeof event->m);
|
memcpy(&event->m, &c->click_event, sizeof event->m);
|
||||||
if (!server_client_handle_key(c, event))
|
if (!server_client_handle_key(c, event)) {
|
||||||
|
free(event->buf);
|
||||||
free(event);
|
free(event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
c->flags &= ~(CLIENT_DOUBLECLICK|CLIENT_TRIPLECLICK);
|
c->flags &= ~(CLIENT_DOUBLECLICK|CLIENT_TRIPLECLICK);
|
||||||
}
|
}
|
||||||
|
@ -272,19 +272,16 @@ session_lock_timer(__unused int fd, __unused short events, void *arg)
|
|||||||
void
|
void
|
||||||
session_update_activity(struct session *s, struct timeval *from)
|
session_update_activity(struct session *s, struct timeval *from)
|
||||||
{
|
{
|
||||||
struct timeval *last = &s->last_activity_time;
|
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
|
|
||||||
memcpy(last, &s->activity_time, sizeof *last);
|
|
||||||
if (from == NULL)
|
if (from == NULL)
|
||||||
gettimeofday(&s->activity_time, NULL);
|
gettimeofday(&s->activity_time, NULL);
|
||||||
else
|
else
|
||||||
memcpy(&s->activity_time, from, sizeof s->activity_time);
|
memcpy(&s->activity_time, from, sizeof s->activity_time);
|
||||||
|
|
||||||
log_debug("session $%u %s activity %lld.%06d (last %lld.%06d)", s->id,
|
log_debug("session $%u %s activity %lld.%06d", s->id,
|
||||||
s->name, (long long)s->activity_time.tv_sec,
|
s->name, (long long)s->activity_time.tv_sec,
|
||||||
(int)s->activity_time.tv_usec, (long long)last->tv_sec,
|
(int)s->activity_time.tv_usec);
|
||||||
(int)last->tv_usec);
|
|
||||||
|
|
||||||
if (evtimer_initialized(&s->lock_timer))
|
if (evtimer_initialized(&s->lock_timer))
|
||||||
evtimer_del(&s->lock_timer);
|
evtimer_del(&s->lock_timer);
|
||||||
|
13
tmux.h
13
tmux.h
@ -1311,8 +1311,7 @@ struct session {
|
|||||||
|
|
||||||
struct options *options;
|
struct options *options;
|
||||||
|
|
||||||
#define SESSION_PASTING 0x1
|
#define SESSION_ALERTED 0x1
|
||||||
#define SESSION_ALERTED 0x2
|
|
||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
u_int attached;
|
u_int attached;
|
||||||
@ -1390,8 +1389,11 @@ struct mouse_event {
|
|||||||
|
|
||||||
/* Key event. */
|
/* Key event. */
|
||||||
struct key_event {
|
struct key_event {
|
||||||
key_code key;
|
key_code key;
|
||||||
struct mouse_event m;
|
struct mouse_event m;
|
||||||
|
|
||||||
|
char *buf;
|
||||||
|
size_t len;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Terminal definition. */
|
/* Terminal definition. */
|
||||||
@ -1806,6 +1808,7 @@ struct client {
|
|||||||
|
|
||||||
struct timeval creation_time;
|
struct timeval creation_time;
|
||||||
struct timeval activity_time;
|
struct timeval activity_time;
|
||||||
|
struct timeval last_activity_time;
|
||||||
|
|
||||||
struct environ *environ;
|
struct environ *environ;
|
||||||
struct format_job_tree *jobs;
|
struct format_job_tree *jobs;
|
||||||
@ -1872,6 +1875,7 @@ struct client {
|
|||||||
#define CLIENT_WINDOWSIZECHANGED 0x400000000ULL
|
#define CLIENT_WINDOWSIZECHANGED 0x400000000ULL
|
||||||
#define CLIENT_CLIPBOARDBUFFER 0x800000000ULL
|
#define CLIENT_CLIPBOARDBUFFER 0x800000000ULL
|
||||||
#define CLIENT_BRACKETPASTING 0x1000000000ULL
|
#define CLIENT_BRACKETPASTING 0x1000000000ULL
|
||||||
|
#define CLIENT_ASSUMEPASTING 0x2000000000ULL
|
||||||
#define CLIENT_ALLREDRAWFLAGS \
|
#define CLIENT_ALLREDRAWFLAGS \
|
||||||
(CLIENT_REDRAWWINDOW| \
|
(CLIENT_REDRAWWINDOW| \
|
||||||
CLIENT_REDRAWSTATUS| \
|
CLIENT_REDRAWSTATUS| \
|
||||||
@ -3097,6 +3101,7 @@ void window_pane_reset_mode_all(struct window_pane *);
|
|||||||
int window_pane_key(struct window_pane *, struct client *,
|
int window_pane_key(struct window_pane *, struct client *,
|
||||||
struct session *, struct winlink *, key_code,
|
struct session *, struct winlink *, key_code,
|
||||||
struct mouse_event *);
|
struct mouse_event *);
|
||||||
|
void window_pane_paste(struct window_pane *, char *, size_t);
|
||||||
int window_pane_visible(struct window_pane *);
|
int window_pane_visible(struct window_pane *);
|
||||||
int window_pane_exited(struct window_pane *);
|
int window_pane_exited(struct window_pane *);
|
||||||
u_int window_pane_search(struct window_pane *, const char *, int,
|
u_int window_pane_search(struct window_pane *, const char *, int,
|
||||||
|
17
tty-keys.c
17
tty-keys.c
@ -944,9 +944,6 @@ complete_key:
|
|||||||
if (bspace != _POSIX_VDISABLE && (key & KEYC_MASK_KEY) == bspace)
|
if (bspace != _POSIX_VDISABLE && (key & KEYC_MASK_KEY) == bspace)
|
||||||
key = (key & KEYC_MASK_MODIFIERS)|KEYC_BSPACE;
|
key = (key & KEYC_MASK_MODIFIERS)|KEYC_BSPACE;
|
||||||
|
|
||||||
/* Remove data from buffer. */
|
|
||||||
evbuffer_drain(tty->in, size);
|
|
||||||
|
|
||||||
/* Remove key timer. */
|
/* Remove key timer. */
|
||||||
if (event_initialized(&tty->key_timer))
|
if (event_initialized(&tty->key_timer))
|
||||||
evtimer_del(&tty->key_timer);
|
evtimer_del(&tty->key_timer);
|
||||||
@ -965,13 +962,23 @@ complete_key:
|
|||||||
|
|
||||||
/* Fire the key. */
|
/* Fire the key. */
|
||||||
if (key != KEYC_UNKNOWN) {
|
if (key != KEYC_UNKNOWN) {
|
||||||
event = xmalloc(sizeof *event);
|
event = xcalloc(1, sizeof *event);
|
||||||
event->key = key;
|
event->key = key;
|
||||||
memcpy(&event->m, &m, sizeof event->m);
|
memcpy(&event->m, &m, sizeof event->m);
|
||||||
if (!server_client_handle_key(c, event))
|
|
||||||
|
event->buf = xmalloc(size);
|
||||||
|
event->len = size;
|
||||||
|
memcpy (event->buf, buf, event->len);
|
||||||
|
|
||||||
|
if (!server_client_handle_key(c, event)) {
|
||||||
|
free(event->buf);
|
||||||
free(event);
|
free(event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Remove data from buffer. */
|
||||||
|
evbuffer_drain(tty->in, size);
|
||||||
|
|
||||||
return (1);
|
return (1);
|
||||||
|
|
||||||
discard_key:
|
discard_key:
|
||||||
|
34
window.c
34
window.c
@ -1154,6 +1154,24 @@ window_pane_reset_mode_all(struct window_pane *wp)
|
|||||||
window_pane_reset_mode(wp);
|
window_pane_reset_mode(wp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
window_pane_copy_paste(struct window_pane *wp, char *buf, size_t len)
|
||||||
|
{
|
||||||
|
struct window_pane *loop;
|
||||||
|
|
||||||
|
TAILQ_FOREACH(loop, &wp->window->panes, entry) {
|
||||||
|
if (loop != wp &&
|
||||||
|
TAILQ_EMPTY(&loop->modes) &&
|
||||||
|
loop->fd != -1 &&
|
||||||
|
(~loop->flags & PANE_INPUTOFF) &&
|
||||||
|
window_pane_visible(loop) &&
|
||||||
|
options_get_number(loop->options, "synchronize-panes")) {
|
||||||
|
log_debug("%s: %.*s", __func__, (int)len, buf);
|
||||||
|
bufferevent_write(loop->event, buf, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
window_pane_copy_key(struct window_pane *wp, key_code key)
|
window_pane_copy_key(struct window_pane *wp, key_code key)
|
||||||
{
|
{
|
||||||
@ -1170,6 +1188,22 @@ window_pane_copy_key(struct window_pane *wp, key_code key)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
window_pane_paste(struct window_pane *wp, char *buf, size_t len)
|
||||||
|
{
|
||||||
|
if (!TAILQ_EMPTY(&wp->modes))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (wp->fd == -1 || wp->flags & PANE_INPUTOFF)
|
||||||
|
return;
|
||||||
|
|
||||||
|
log_debug("%s: %.*s", __func__, (int)len, buf);
|
||||||
|
bufferevent_write(wp->event, buf, len);
|
||||||
|
|
||||||
|
if (options_get_number(wp->options, "synchronize-panes"))
|
||||||
|
window_pane_copy_paste(wp, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
window_pane_key(struct window_pane *wp, struct client *c, struct session *s,
|
window_pane_key(struct window_pane *wp, struct client *c, struct session *s,
|
||||||
struct winlink *wl, key_code key, struct mouse_event *m)
|
struct winlink *wl, key_code key, struct mouse_event *m)
|
||||||
|
Loading…
Reference in New Issue
Block a user