tmux/input-keys.c
nicm 17bab32794 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.
2024-10-01 06:15:47 +00:00

799 lines
19 KiB
C

/* $OpenBSD$ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* 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 <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
* This file is rather misleadingly named, it contains the code which takes a
* key code and translates it into something suitable to be sent to the
* application running in a pane (similar to input.c does in the other
* direction with output).
*/
static void input_key_mouse(struct window_pane *, struct mouse_event *);
/* Entry in the key tree. */
struct input_key_entry {
key_code key;
const char *data;
RB_ENTRY(input_key_entry) entry;
};
RB_HEAD(input_key_tree, input_key_entry);
/* Tree of input keys. */
static int input_key_cmp(struct input_key_entry *,
struct input_key_entry *);
RB_GENERATE_STATIC(input_key_tree, input_key_entry, entry, input_key_cmp);
struct input_key_tree input_key_tree = RB_INITIALIZER(&input_key_tree);
/* List of default keys, the tree is built from this. */
static struct input_key_entry input_key_defaults[] = {
/* Paste keys. */
{ .key = KEYC_PASTE_START,
.data = "\033[200~"
},
{ .key = KEYC_PASTE_END,
.data = "\033[201~"
},
/* Function keys. */
{ .key = KEYC_F1,
.data = "\033OP"
},
{ .key = KEYC_F2,
.data = "\033OQ"
},
{ .key = KEYC_F3,
.data = "\033OR"
},
{ .key = KEYC_F4,
.data = "\033OS"
},
{ .key = KEYC_F5,
.data = "\033[15~"
},
{ .key = KEYC_F6,
.data = "\033[17~"
},
{ .key = KEYC_F7,
.data = "\033[18~"
},
{ .key = KEYC_F8,
.data = "\033[19~"
},
{ .key = KEYC_F9,
.data = "\033[20~"
},
{ .key = KEYC_F10,
.data = "\033[21~"
},
{ .key = KEYC_F11,
.data = "\033[23~"
},
{ .key = KEYC_F12,
.data = "\033[24~"
},
{ .key = KEYC_IC,
.data = "\033[2~"
},
{ .key = KEYC_DC,
.data = "\033[3~"
},
{ .key = KEYC_HOME,
.data = "\033[1~"
},
{ .key = KEYC_END,
.data = "\033[4~"
},
{ .key = KEYC_NPAGE,
.data = "\033[6~"
},
{ .key = KEYC_PPAGE,
.data = "\033[5~"
},
{ .key = KEYC_BTAB,
.data = "\033[Z"
},
/* Arrow keys. */
{ .key = KEYC_UP|KEYC_CURSOR,
.data = "\033OA"
},
{ .key = KEYC_DOWN|KEYC_CURSOR,
.data = "\033OB"
},
{ .key = KEYC_RIGHT|KEYC_CURSOR,
.data = "\033OC"
},
{ .key = KEYC_LEFT|KEYC_CURSOR,
.data = "\033OD"
},
{ .key = KEYC_UP,
.data = "\033[A"
},
{ .key = KEYC_DOWN,
.data = "\033[B"
},
{ .key = KEYC_RIGHT,
.data = "\033[C"
},
{ .key = KEYC_LEFT,
.data = "\033[D"
},
/* Keypad keys. */
{ .key = KEYC_KP_SLASH|KEYC_KEYPAD,
.data = "\033Oo"
},
{ .key = KEYC_KP_STAR|KEYC_KEYPAD,
.data = "\033Oj"
},
{ .key = KEYC_KP_MINUS|KEYC_KEYPAD,
.data = "\033Om"
},
{ .key = KEYC_KP_SEVEN|KEYC_KEYPAD,
.data = "\033Ow"
},
{ .key = KEYC_KP_EIGHT|KEYC_KEYPAD,
.data = "\033Ox"
},
{ .key = KEYC_KP_NINE|KEYC_KEYPAD,
.data = "\033Oy"
},
{ .key = KEYC_KP_PLUS|KEYC_KEYPAD,
.data = "\033Ok"
},
{ .key = KEYC_KP_FOUR|KEYC_KEYPAD,
.data = "\033Ot"
},
{ .key = KEYC_KP_FIVE|KEYC_KEYPAD,
.data = "\033Ou"
},
{ .key = KEYC_KP_SIX|KEYC_KEYPAD,
.data = "\033Ov"
},
{ .key = KEYC_KP_ONE|KEYC_KEYPAD,
.data = "\033Oq"
},
{ .key = KEYC_KP_TWO|KEYC_KEYPAD,
.data = "\033Or"
},
{ .key = KEYC_KP_THREE|KEYC_KEYPAD,
.data = "\033Os"
},
{ .key = KEYC_KP_ENTER|KEYC_KEYPAD,
.data = "\033OM"
},
{ .key = KEYC_KP_ZERO|KEYC_KEYPAD,
.data = "\033Op"
},
{ .key = KEYC_KP_PERIOD|KEYC_KEYPAD,
.data = "\033On"
},
{ .key = KEYC_KP_SLASH,
.data = "/"
},
{ .key = KEYC_KP_STAR,
.data = "*"
},
{ .key = KEYC_KP_MINUS,
.data = "-"
},
{ .key = KEYC_KP_SEVEN,
.data = "7"
},
{ .key = KEYC_KP_EIGHT,
.data = "8"
},
{ .key = KEYC_KP_NINE,
.data = "9"
},
{ .key = KEYC_KP_PLUS,
.data = "+"
},
{ .key = KEYC_KP_FOUR,
.data = "4"
},
{ .key = KEYC_KP_FIVE,
.data = "5"
},
{ .key = KEYC_KP_SIX,
.data = "6"
},
{ .key = KEYC_KP_ONE,
.data = "1"
},
{ .key = KEYC_KP_TWO,
.data = "2"
},
{ .key = KEYC_KP_THREE,
.data = "3"
},
{ .key = KEYC_KP_ENTER,
.data = "\n"
},
{ .key = KEYC_KP_ZERO,
.data = "0"
},
{ .key = KEYC_KP_PERIOD,
.data = "."
},
/* Keys with an embedded modifier. */
{ .key = KEYC_F1|KEYC_BUILD_MODIFIERS,
.data = "\033[1;_P"
},
{ .key = KEYC_F2|KEYC_BUILD_MODIFIERS,
.data = "\033[1;_Q"
},
{ .key = KEYC_F3|KEYC_BUILD_MODIFIERS,
.data = "\033[1;_R"
},
{ .key = KEYC_F4|KEYC_BUILD_MODIFIERS,
.data = "\033[1;_S"
},
{ .key = KEYC_F5|KEYC_BUILD_MODIFIERS,
.data = "\033[15;_~"
},
{ .key = KEYC_F6|KEYC_BUILD_MODIFIERS,
.data = "\033[17;_~"
},
{ .key = KEYC_F7|KEYC_BUILD_MODIFIERS,
.data = "\033[18;_~"
},
{ .key = KEYC_F8|KEYC_BUILD_MODIFIERS,
.data = "\033[19;_~"
},
{ .key = KEYC_F9|KEYC_BUILD_MODIFIERS,
.data = "\033[20;_~"
},
{ .key = KEYC_F10|KEYC_BUILD_MODIFIERS,
.data = "\033[21;_~"
},
{ .key = KEYC_F11|KEYC_BUILD_MODIFIERS,
.data = "\033[23;_~"
},
{ .key = KEYC_F12|KEYC_BUILD_MODIFIERS,
.data = "\033[24;_~"
},
{ .key = KEYC_UP|KEYC_BUILD_MODIFIERS,
.data = "\033[1;_A"
},
{ .key = KEYC_DOWN|KEYC_BUILD_MODIFIERS,
.data = "\033[1;_B"
},
{ .key = KEYC_RIGHT|KEYC_BUILD_MODIFIERS,
.data = "\033[1;_C"
},
{ .key = KEYC_LEFT|KEYC_BUILD_MODIFIERS,
.data = "\033[1;_D"
},
{ .key = KEYC_HOME|KEYC_BUILD_MODIFIERS,
.data = "\033[1;_H"
},
{ .key = KEYC_END|KEYC_BUILD_MODIFIERS,
.data = "\033[1;_F"
},
{ .key = KEYC_PPAGE|KEYC_BUILD_MODIFIERS,
.data = "\033[5;_~"
},
{ .key = KEYC_NPAGE|KEYC_BUILD_MODIFIERS,
.data = "\033[6;_~"
},
{ .key = KEYC_IC|KEYC_BUILD_MODIFIERS,
.data = "\033[2;_~"
},
{ .key = KEYC_DC|KEYC_BUILD_MODIFIERS,
.data = "\033[3;_~"
},
};
static const key_code input_key_modifiers[] = {
0,
0,
KEYC_SHIFT,
KEYC_META|KEYC_IMPLIED_META,
KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META,
KEYC_CTRL,
KEYC_SHIFT|KEYC_CTRL,
KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL,
KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL
};
/* Input key comparison function. */
static int
input_key_cmp(struct input_key_entry *ike1, struct input_key_entry *ike2)
{
if (ike1->key < ike2->key)
return (-1);
if (ike1->key > ike2->key)
return (1);
return (0);
}
/* Look for key in tree. */
static struct input_key_entry *
input_key_get(key_code key)
{
struct input_key_entry entry = { .key = key };
return (RB_FIND(input_key_tree, &input_key_tree, &entry));
}
/* Split a character into two UTF-8 bytes. */
static size_t
input_key_split2(u_int c, u_char *dst)
{
if (c > 0x7f) {
dst[0] = (c >> 6) | 0xc0;
dst[1] = (c & 0x3f) | 0x80;
return (2);
}
dst[0] = c;
return (1);
}
/* Build input key tree. */
void
input_key_build(void)
{
struct input_key_entry *ike, *new;
u_int i, j;
char *data;
key_code key;
for (i = 0; i < nitems(input_key_defaults); i++) {
ike = &input_key_defaults[i];
if (~ike->key & KEYC_BUILD_MODIFIERS) {
RB_INSERT(input_key_tree, &input_key_tree, ike);
continue;
}
for (j = 2; j < nitems(input_key_modifiers); j++) {
key = (ike->key & ~KEYC_BUILD_MODIFIERS);
data = xstrdup(ike->data);
data[strcspn(data, "_")] = '0' + j;
new = xcalloc(1, sizeof *new);
new->key = key|input_key_modifiers[j];
new->data = data;
RB_INSERT(input_key_tree, &input_key_tree, new);
}
}
RB_FOREACH(ike, input_key_tree, &input_key_tree) {
log_debug("%s: 0x%llx (%s) is %s", __func__, ike->key,
key_string_lookup_key(ike->key, 1), ike->data);
}
}
/* Translate a key code into an output key sequence for a pane. */
int
input_key_pane(struct window_pane *wp, key_code key, struct mouse_event *m)
{
if (log_get_level() != 0) {
log_debug("writing key 0x%llx (%s) to %%%u", key,
key_string_lookup_key(key, 1), wp->id);
}
if (KEYC_IS_MOUSE(key)) {
if (m != NULL && m->wp != -1 && (u_int)m->wp == wp->id)
input_key_mouse(wp, m);
return (0);
}
return (input_key(wp->screen, wp->event, key));
}
static void
input_key_write(const char *from, struct bufferevent *bev, const char *data,
size_t size)
{
log_debug("%s: %.*s", from, (int)size, data);
bufferevent_write(bev, data, size);
}
/*
* Encode and write an extended key escape sequence in one of the two
* possible formats, depending on the configured output mode.
*/
static int
input_key_extended(struct bufferevent *bev, key_code key)
{
char tmp[64], modifier;
struct utf8_data ud;
wchar_t wc;
switch (key & KEYC_MASK_MODIFIERS) {
case KEYC_SHIFT:
modifier = '2';
break;
case KEYC_META:
modifier = '3';
break;
case KEYC_SHIFT|KEYC_META:
modifier = '4';
break;
case KEYC_CTRL:
modifier = '5';
break;
case KEYC_SHIFT|KEYC_CTRL:
modifier = '6';
break;
case KEYC_META|KEYC_CTRL:
modifier = '7';
break;
case KEYC_SHIFT|KEYC_META|KEYC_CTRL:
modifier = '8';
break;
default:
return (-1);
}
if (KEYC_IS_UNICODE(key)) {
utf8_to_data(key & KEYC_MASK_KEY, &ud);
if (utf8_towc(&ud, &wc) == UTF8_DONE)
key = wc;
else
return (-1);
} else
key &= KEYC_MASK_KEY;
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);
input_key_write(__func__, bev, tmp, strlen(tmp));
return (0);
}
/*
* Outputs the key in the "standard" mode. This is by far the most
* complicated output mode, with a lot of remapping in order to
* emulate quirks of terminals that today can be only found in museums.
*/
static int
input_key_vt10x(struct bufferevent *bev, key_code key)
{
struct utf8_data ud;
key_code onlykey;
char *p;
static const char *standard_map[2] = {
"1!9(0)=+;:'\",<.>/-8? 2",
"119900=+;;'',,..\x1f\x1f\x7f\x7f\0\0",
};
log_debug("%s: key in %llx", __func__, key);
if (key & KEYC_META)
input_key_write(__func__, bev, "\033", 1);
/*
* There's no way to report modifiers for unicode keys in standard mode
* so lose the modifiers.
*/
if (KEYC_IS_UNICODE(key)) {
utf8_to_data(key, &ud);
input_key_write(__func__, bev, ud.data, ud.size);
return (0);
}
/*
* Prevent TAB, CR and LF from being swallowed by the C0 remapping
* logic.
*/
onlykey = key & KEYC_MASK_KEY;
if (onlykey == '\r' || onlykey == '\n' || onlykey == '\t')
key &= ~KEYC_CTRL;
/*
* Convert keys with Ctrl modifier into corresponding C0 control codes,
* with the exception of *some* keys, which are remapped into printable
* ASCII characters.
*
* There is no special handling for Shift modifier, which is pretty
* much redundant anyway, as no terminal will send <base key>|SHIFT,
* but only <shifted key>|SHIFT.
*/
if (key & KEYC_CTRL) {
p = strchr(standard_map[0], onlykey);
if (p != NULL)
key = standard_map[1][p - standard_map[0]];
else if (onlykey >= '3' && onlykey <= '7')
key = onlykey - '\030';
else if (onlykey >= '@' && onlykey <= '~')
key = onlykey & 0x1f;
else
return (-1);
}
log_debug("%s: key out %llx", __func__, key);
ud.data[0] = key & 0x7f;
input_key_write(__func__, bev, &ud.data[0], 1);
return (0);
}
/* Pick keys that are reported as vt10x keys in modifyOtherKeys=1 mode. */
static int
input_key_mode1(struct bufferevent *bev, key_code key)
{
key_code onlykey;
log_debug("%s: key in %llx", __func__, key);
/*
* As per
* https://invisible-island.net/xterm/modified-keys-us-pc105.html.
*/
onlykey = key & KEYC_MASK_KEY;
if ((key & (KEYC_META | KEYC_CTRL)) == KEYC_CTRL &&
(onlykey == ' ' ||
onlykey == '/' ||
onlykey == '@' ||
onlykey == '^' ||
(onlykey >= '2' && onlykey <= '8') ||
(onlykey >= '@' && onlykey <= '~')))
return (input_key_vt10x(bev, key));
/*
* A regular key + Meta. In the absence of a standard to back this, we
* mimic what iTerm 2 does.
*/
if ((key & (KEYC_CTRL | KEYC_META)) == KEYC_META)
return (input_key_vt10x(bev, key));
return (-1);
}
/* Translate a key code into an output key sequence. */
int
input_key(struct screen *s, struct bufferevent *bev, key_code key)
{
struct input_key_entry *ike = NULL;
key_code newkey;
struct utf8_data ud;
/* Mouse keys need a pane. */
if (KEYC_IS_MOUSE(key))
return (0);
/* Literal keys go as themselves (can't be more than eight bits). */
if (key & KEYC_LITERAL) {
ud.data[0] = (u_char)key;
input_key_write(__func__, bev, &ud.data[0], 1);
return (0);
}
/* Is this backspace? */
if ((key & KEYC_MASK_KEY) == KEYC_BSPACE) {
newkey = options_get_number(global_options, "backspace");
if (newkey >= 0x7f)
newkey = '\177';
key = newkey|(key & (KEYC_MASK_MODIFIERS|KEYC_MASK_FLAGS));
}
/* Is this backtab? */
if ((key & KEYC_MASK_KEY) == KEYC_BTAB) {
if ((s->mode & EXTENDED_KEY_MODES) != 0) {
/* When in xterm extended mode, remap into S-Tab. */
key = '\011' | (key & ~KEYC_MASK_KEY) | KEYC_SHIFT;
} else {
/* Otherwise clear modifiers. */
key &= ~KEYC_MASK_MODIFIERS;
}
}
/*
* A trivial case, that is a 7-bit key, excluding C0 control characters
* that can't be entered from the keyboard, and no modifiers; or a UTF-8
* key and no modifiers.
*/
if (!(key & ~KEYC_MASK_KEY)) {
if (key == C0_HT ||
key == C0_CR ||
key == C0_ESC ||
(key >= 0x20 && key <= 0x7f)) {
ud.data[0] = key;
input_key_write(__func__, bev, &ud.data[0], 1);
return (0);
}
if (KEYC_IS_UNICODE(key)) {
utf8_to_data(key, &ud);
input_key_write(__func__, bev, ud.data, ud.size);
return (0);
}
}
/*
* Look up the standard VT10x keys in the tree. If not in application
* keypad or cursor mode, remove the respective flags from the key.
*/
if (~s->mode & MODE_KKEYPAD)
key &= ~KEYC_KEYPAD;
if (~s->mode & MODE_KCURSOR)
key &= ~KEYC_CURSOR;
if (ike == NULL)
ike = input_key_get(key);
if (ike == NULL && (key & KEYC_META) && (~key & KEYC_IMPLIED_META))
ike = input_key_get(key & ~KEYC_META);
if (ike == NULL && (key & KEYC_CURSOR))
ike = input_key_get(key & ~KEYC_CURSOR);
if (ike == NULL && (key & KEYC_KEYPAD))
ike = input_key_get(key & ~KEYC_KEYPAD);
if (ike != NULL) {
log_debug("%s: found key 0x%llx: \"%s\"", __func__, key,
ike->data);
if ((key == KEYC_PASTE_START || key == KEYC_PASTE_END) &&
(~s->mode & MODE_BRACKETPASTE))
return (0);
if ((key & KEYC_META) && (~key & KEYC_IMPLIED_META))
input_key_write(__func__, bev, "\033", 1);
input_key_write(__func__, bev, ike->data, strlen(ike->data));
return (0);
}
/* Ignore internal function key codes. */
if ((key >= KEYC_BASE && key < KEYC_BASE_END) ||
(key >= KEYC_USER && key < KEYC_USER_END)) {
log_debug("%s: ignoring key 0x%llx", __func__, key);
return (0);
}
/*
* No builtin key sequence; construct an extended key sequence
* depending on the client mode.
*
* If something invalid reaches here, an invalid output may be
* produced. For example Ctrl-Shift-2 is invalid (as there's
* no way to enter it). The correct form is Ctrl-Shift-@, at
* least in US English keyboard layout.
*/
switch (s->mode & EXTENDED_KEY_MODES) {
case MODE_KEYS_EXTENDED_2:
/*
* The simplest mode to handle - *all* modified keys are
* reported in the extended form.
*/
return (input_key_extended(bev, key));
case MODE_KEYS_EXTENDED:
/*
* Some keys are still reported in standard mode, to maintain
* compatibility with applications unaware of extended keys.
*/
if (input_key_mode1(bev, key) == -1)
return (input_key_extended(bev, key));
return (0);
default:
/* The standard mode. */
return (input_key_vt10x(bev, key));
}
}
/* Get mouse event string. */
int
input_key_get_mouse(struct screen *s, struct mouse_event *m, u_int x, u_int y,
const char **rbuf, size_t *rlen)
{
static char buf[40];
size_t len;
*rbuf = NULL;
*rlen = 0;
/* If this pane is not in button or all mode, discard motion events. */
if (MOUSE_DRAG(m->b) && (s->mode & MOTION_MOUSE_MODES) == 0)
return (0);
if ((s->mode & ALL_MOUSE_MODES) == 0)
return (0);
/*
* If this event is a release event and not in all mode, discard it.
* In SGR mode we can tell absolutely because a release is normally
* shown by the last character. Without SGR, we check if the last
* buttons was also a release.
*/
if (m->sgr_type != ' ') {
if (MOUSE_DRAG(m->sgr_b) &&
MOUSE_RELEASE(m->sgr_b) &&
(~s->mode & MODE_MOUSE_ALL))
return (0);
} else {
if (MOUSE_DRAG(m->b) &&
MOUSE_RELEASE(m->b) &&
MOUSE_RELEASE(m->lb) &&
(~s->mode & MODE_MOUSE_ALL))
return (0);
}
/*
* Use the SGR (1006) extension only if the application requested it
* and the underlying terminal also sent the event in this format (this
* is because an old style mouse release event cannot be converted into
* the new SGR format, since the released button is unknown). Otherwise
* pretend that tmux doesn't speak this extension, and fall back to the
* UTF-8 (1005) extension if the application requested, or to the
* legacy format.
*/
if (m->sgr_type != ' ' && (s->mode & MODE_MOUSE_SGR)) {
len = xsnprintf(buf, sizeof buf, "\033[<%u;%u;%u%c",
m->sgr_b, x + 1, y + 1, m->sgr_type);
} else if (s->mode & MODE_MOUSE_UTF8) {
if (m->b > MOUSE_PARAM_UTF8_MAX - MOUSE_PARAM_BTN_OFF ||
x > MOUSE_PARAM_UTF8_MAX - MOUSE_PARAM_POS_OFF ||
y > MOUSE_PARAM_UTF8_MAX - MOUSE_PARAM_POS_OFF)
return (0);
len = xsnprintf(buf, sizeof buf, "\033[M");
len += input_key_split2(m->b + MOUSE_PARAM_BTN_OFF, &buf[len]);
len += input_key_split2(x + MOUSE_PARAM_POS_OFF, &buf[len]);
len += input_key_split2(y + MOUSE_PARAM_POS_OFF, &buf[len]);
} else {
if (m->b + MOUSE_PARAM_BTN_OFF > MOUSE_PARAM_MAX)
return (0);
len = xsnprintf(buf, sizeof buf, "\033[M");
buf[len++] = m->b + MOUSE_PARAM_BTN_OFF;
/*
* The incoming x and y may be out of the range which can be
* supported by the "normal" mouse protocol. Clamp the
* coordinates to the supported range.
*/
if (x + MOUSE_PARAM_POS_OFF > MOUSE_PARAM_MAX)
buf[len++] = MOUSE_PARAM_MAX;
else
buf[len++] = x + MOUSE_PARAM_POS_OFF;
if (y + MOUSE_PARAM_POS_OFF > MOUSE_PARAM_MAX)
buf[len++] = MOUSE_PARAM_MAX;
else
buf[len++] = y + MOUSE_PARAM_POS_OFF;
}
*rbuf = buf;
*rlen = len;
return (1);
}
/* Translate mouse and output. */
static void
input_key_mouse(struct window_pane *wp, struct mouse_event *m)
{
struct screen *s = wp->screen;
u_int x, y;
const char *buf;
size_t len;
/* Ignore events if no mouse mode or the pane is not visible. */
if (m->ignore || (s->mode & ALL_MOUSE_MODES) == 0)
return;
if (cmd_mouse_at(wp, m, &x, &y, 0) != 0)
return;
if (!window_pane_visible(wp))
return;
if (!input_key_get_mouse(s, m, x, y, &buf, &len))
return;
log_debug("writing mouse %.*s to %%%u", (int)len, buf, wp->id);
input_key_write(__func__, wp->event, buf, len);
}