File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / tmux / input-keys.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 14 12:22:44 2017 UTC (7 years, 9 months ago) by misho
Branches: tmux, MAIN
CVS tags: v2_4p0, v2_4, HEAD
tmux 2.4

    1: /* $OpenBSD$ */
    2: 
    3: /*
    4:  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
    5:  *
    6:  * Permission to use, copy, modify, and distribute this software for any
    7:  * purpose with or without fee is hereby granted, provided that the above
    8:  * copyright notice and this permission notice appear in all copies.
    9:  *
   10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   14:  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
   15:  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
   16:  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   17:  */
   18: 
   19: #include <sys/types.h>
   20: 
   21: #include <stdlib.h>
   22: #include <string.h>
   23: 
   24: #include "tmux.h"
   25: 
   26: /*
   27:  * This file is rather misleadingly named, it contains the code which takes a
   28:  * key code and translates it into something suitable to be sent to the
   29:  * application running in a pane (similar to input.c does in the other
   30:  * direction with output).
   31:  */
   32: 
   33: static void	 input_key_mouse(struct window_pane *, struct mouse_event *);
   34: 
   35: struct input_key_ent {
   36: 	key_code	 key;
   37: 	const char	*data;
   38: 
   39: 	int		 flags;
   40: #define INPUTKEY_KEYPAD 0x1	/* keypad key */
   41: #define INPUTKEY_CURSOR 0x2	/* cursor key */
   42: };
   43: 
   44: static const struct input_key_ent input_keys[] = {
   45: 	/* Backspace key. */
   46: 	{ KEYC_BSPACE,		"\177",		0 },
   47: 
   48: 	/* Function keys. */
   49: 	{ KEYC_F1,		"\033OP",	0 },
   50: 	{ KEYC_F2,		"\033OQ",	0 },
   51: 	{ KEYC_F3,		"\033OR",	0 },
   52: 	{ KEYC_F4,		"\033OS",	0 },
   53: 	{ KEYC_F5,		"\033[15~",	0 },
   54: 	{ KEYC_F6,		"\033[17~",	0 },
   55: 	{ KEYC_F7,		"\033[18~",	0 },
   56: 	{ KEYC_F8,		"\033[19~",	0 },
   57: 	{ KEYC_F9,		"\033[20~",	0 },
   58: 	{ KEYC_F10,		"\033[21~",	0 },
   59: 	{ KEYC_F11,		"\033[23~",	0 },
   60: 	{ KEYC_F12,		"\033[24~",	0 },
   61: 	{ KEYC_F1|KEYC_SHIFT,	"\033[25~",	0 },
   62: 	{ KEYC_F2|KEYC_SHIFT,	"\033[26~",	0 },
   63: 	{ KEYC_F3|KEYC_SHIFT,	"\033[28~",	0 },
   64: 	{ KEYC_F4|KEYC_SHIFT,	"\033[29~",	0 },
   65: 	{ KEYC_F5|KEYC_SHIFT,	"\033[31~",	0 },
   66: 	{ KEYC_F6|KEYC_SHIFT,	"\033[32~",	0 },
   67: 	{ KEYC_F7|KEYC_SHIFT,	"\033[33~",	0 },
   68: 	{ KEYC_F8|KEYC_SHIFT,	"\033[34~",	0 },
   69: 	{ KEYC_IC,		"\033[2~",	0 },
   70: 	{ KEYC_DC,		"\033[3~",	0 },
   71: 	{ KEYC_HOME,		"\033[1~",	0 },
   72: 	{ KEYC_END,		"\033[4~",	0 },
   73: 	{ KEYC_NPAGE,		"\033[6~",	0 },
   74: 	{ KEYC_PPAGE,		"\033[5~",	0 },
   75: 	{ KEYC_BTAB,		"\033[Z",	0 },
   76: 
   77: 	/*
   78: 	 * Arrow keys. Cursor versions must come first. The codes are toggled
   79: 	 * between CSI and SS3 versions when ctrl is pressed.
   80: 	 */
   81: 	{ KEYC_UP|KEYC_CTRL,	"\033[A",	INPUTKEY_CURSOR },
   82: 	{ KEYC_DOWN|KEYC_CTRL,	"\033[B",	INPUTKEY_CURSOR },
   83: 	{ KEYC_RIGHT|KEYC_CTRL,	"\033[C",	INPUTKEY_CURSOR },
   84: 	{ KEYC_LEFT|KEYC_CTRL,	"\033[D",	INPUTKEY_CURSOR },
   85: 
   86: 	{ KEYC_UP,		"\033OA",	INPUTKEY_CURSOR },
   87: 	{ KEYC_DOWN,		"\033OB",	INPUTKEY_CURSOR },
   88: 	{ KEYC_RIGHT,		"\033OC",	INPUTKEY_CURSOR },
   89: 	{ KEYC_LEFT,		"\033OD",	INPUTKEY_CURSOR },
   90: 
   91: 	{ KEYC_UP|KEYC_CTRL,	"\033OA",	0 },
   92: 	{ KEYC_DOWN|KEYC_CTRL,	"\033OB",	0 },
   93: 	{ KEYC_RIGHT|KEYC_CTRL,	"\033OC",	0 },
   94: 	{ KEYC_LEFT|KEYC_CTRL,	"\033OD",	0 },
   95: 
   96: 	{ KEYC_UP,		"\033[A",	0 },
   97: 	{ KEYC_DOWN,		"\033[B",	0 },
   98: 	{ KEYC_RIGHT,		"\033[C",	0 },
   99: 	{ KEYC_LEFT,		"\033[D",	0 },
  100: 
  101: 	/* Keypad keys. Keypad versions must come first. */
  102: 	{ KEYC_KP_SLASH,	"\033Oo",	INPUTKEY_KEYPAD },
  103: 	{ KEYC_KP_STAR,		"\033Oj",	INPUTKEY_KEYPAD },
  104: 	{ KEYC_KP_MINUS,	"\033Om",	INPUTKEY_KEYPAD },
  105: 	{ KEYC_KP_SEVEN,	"\033Ow",	INPUTKEY_KEYPAD },
  106: 	{ KEYC_KP_EIGHT,	"\033Ox",	INPUTKEY_KEYPAD },
  107: 	{ KEYC_KP_NINE,		"\033Oy",	INPUTKEY_KEYPAD },
  108: 	{ KEYC_KP_PLUS,		"\033Ok",	INPUTKEY_KEYPAD },
  109: 	{ KEYC_KP_FOUR,		"\033Ot",	INPUTKEY_KEYPAD },
  110: 	{ KEYC_KP_FIVE,		"\033Ou",	INPUTKEY_KEYPAD },
  111: 	{ KEYC_KP_SIX,		"\033Ov",	INPUTKEY_KEYPAD },
  112: 	{ KEYC_KP_ONE,		"\033Oq",	INPUTKEY_KEYPAD },
  113: 	{ KEYC_KP_TWO,		"\033Or",	INPUTKEY_KEYPAD },
  114: 	{ KEYC_KP_THREE,	"\033Os",	INPUTKEY_KEYPAD },
  115: 	{ KEYC_KP_ENTER,	"\033OM",	INPUTKEY_KEYPAD },
  116: 	{ KEYC_KP_ZERO,		"\033Op",	INPUTKEY_KEYPAD },
  117: 	{ KEYC_KP_PERIOD,	"\033On",	INPUTKEY_KEYPAD },
  118: 
  119: 	{ KEYC_KP_SLASH,	"/",		0 },
  120: 	{ KEYC_KP_STAR,		"*",		0 },
  121: 	{ KEYC_KP_MINUS,	"-",		0 },
  122: 	{ KEYC_KP_SEVEN,	"7",		0 },
  123: 	{ KEYC_KP_EIGHT,	"8",		0 },
  124: 	{ KEYC_KP_NINE,		"9",		0 },
  125: 	{ KEYC_KP_PLUS,		"+",		0 },
  126: 	{ KEYC_KP_FOUR,		"4",		0 },
  127: 	{ KEYC_KP_FIVE,		"5",		0 },
  128: 	{ KEYC_KP_SIX,		"6",		0 },
  129: 	{ KEYC_KP_ONE,		"1",		0 },
  130: 	{ KEYC_KP_TWO,		"2",		0 },
  131: 	{ KEYC_KP_THREE,	"3",		0 },
  132: 	{ KEYC_KP_ENTER,	"\n",		0 },
  133: 	{ KEYC_KP_ZERO,		"0",		0 },
  134: 	{ KEYC_KP_PERIOD,	".",		0 },
  135: };
  136: 
  137: /* Split a character into two UTF-8 bytes. */
  138: static size_t
  139: input_split2(u_int c, u_char *dst)
  140: {
  141: 	if (c > 0x7f) {
  142: 		dst[0] = (c >> 6) | 0xc0;
  143: 		dst[1] = (c & 0x3f) | 0x80;
  144: 		return (2);
  145: 	}
  146: 	dst[0] = c;
  147: 	return (1);
  148: }
  149: 
  150: /* Translate a key code into an output key sequence. */
  151: void
  152: input_key(struct window_pane *wp, key_code key, struct mouse_event *m)
  153: {
  154: 	const struct input_key_ent	*ike;
  155: 	u_int				 i;
  156: 	size_t				 dlen;
  157: 	char				*out;
  158: 	key_code			 justkey;
  159: 	struct utf8_data		 ud;
  160: 
  161: 	log_debug("writing key 0x%llx (%s) to %%%u", key,
  162: 	    key_string_lookup_key(key), wp->id);
  163: 
  164: 	/* If this is a mouse key, pass off to mouse function. */
  165: 	if (KEYC_IS_MOUSE(key)) {
  166: 		if (m != NULL && m->wp != -1 && (u_int)m->wp == wp->id)
  167: 			input_key_mouse(wp, m);
  168: 		return;
  169: 	}
  170: 
  171: 	/*
  172: 	 * If this is a normal 7-bit key, just send it, with a leading escape
  173: 	 * if necessary. If it is a UTF-8 key, split it and send it.
  174: 	 */
  175: 	justkey = (key & ~KEYC_ESCAPE);
  176: 	if (justkey <= 0x7f) {
  177: 		if (key & KEYC_ESCAPE)
  178: 			bufferevent_write(wp->event, "\033", 1);
  179: 		ud.data[0] = justkey;
  180: 		bufferevent_write(wp->event, &ud.data[0], 1);
  181: 		return;
  182: 	}
  183: 	if (justkey > 0x7f && justkey < KEYC_BASE) {
  184: 		if (utf8_split(justkey, &ud) != UTF8_DONE)
  185: 			return;
  186: 		if (key & KEYC_ESCAPE)
  187: 			bufferevent_write(wp->event, "\033", 1);
  188: 		bufferevent_write(wp->event, ud.data, ud.size);
  189: 		return;
  190: 	}
  191: 
  192: 	/*
  193: 	 * Then try to look this up as an xterm key, if the flag to output them
  194: 	 * is set.
  195: 	 */
  196: 	if (options_get_number(wp->window->options, "xterm-keys")) {
  197: 		if ((out = xterm_keys_lookup(key)) != NULL) {
  198: 			bufferevent_write(wp->event, out, strlen(out));
  199: 			free(out);
  200: 			return;
  201: 		}
  202: 	}
  203: 
  204: 	/* Otherwise look the key up in the table. */
  205: 	for (i = 0; i < nitems(input_keys); i++) {
  206: 		ike = &input_keys[i];
  207: 
  208: 		if ((ike->flags & INPUTKEY_KEYPAD) &&
  209: 		    !(wp->screen->mode & MODE_KKEYPAD))
  210: 			continue;
  211: 		if ((ike->flags & INPUTKEY_CURSOR) &&
  212: 		    !(wp->screen->mode & MODE_KCURSOR))
  213: 			continue;
  214: 
  215: 		if ((key & KEYC_ESCAPE) && (ike->key | KEYC_ESCAPE) == key)
  216: 			break;
  217: 		if (ike->key == key)
  218: 			break;
  219: 	}
  220: 	if (i == nitems(input_keys)) {
  221: 		log_debug("key 0x%llx missing", key);
  222: 		return;
  223: 	}
  224: 	dlen = strlen(ike->data);
  225: 	log_debug("found key 0x%llx: \"%s\"", key, ike->data);
  226: 
  227: 	/* Prefix a \033 for escape. */
  228: 	if (key & KEYC_ESCAPE)
  229: 		bufferevent_write(wp->event, "\033", 1);
  230: 	bufferevent_write(wp->event, ike->data, dlen);
  231: }
  232: 
  233: /* Translate mouse and output. */
  234: static void
  235: input_key_mouse(struct window_pane *wp, struct mouse_event *m)
  236: {
  237: 	struct screen	*s = wp->screen;
  238: 	int		 mode = s->mode;
  239: 	char		 buf[40];
  240: 	size_t		 len;
  241: 	u_int		 x, y;
  242: 
  243: 	if ((mode & ALL_MOUSE_MODES) == 0)
  244: 		return;
  245: 	if (!window_pane_visible(wp))
  246: 		return;
  247: 	if (cmd_mouse_at(wp, m, &x, &y, 0) != 0)
  248: 		return;
  249: 
  250: 	/* If this pane is not in button or all mode, discard motion events. */
  251: 	if (MOUSE_DRAG(m->b) &&
  252: 	    (mode & (MODE_MOUSE_BUTTON|MODE_MOUSE_ALL)) == 0)
  253: 	    return;
  254: 
  255: 	/*
  256: 	 * If this event is a release event and not in all mode, discard it.
  257: 	 * In SGR mode we can tell absolutely because a release is normally
  258: 	 * shown by the last character. Without SGR, we check if the last
  259: 	 * buttons was also a release.
  260: 	 */
  261: 	if (m->sgr_type != ' ') {
  262: 		if (MOUSE_DRAG(m->sgr_b) &&
  263: 		    MOUSE_BUTTONS(m->sgr_b) == 3 &&
  264: 		    (~mode & MODE_MOUSE_ALL))
  265: 			return;
  266: 	} else {
  267: 		if (MOUSE_DRAG(m->b) &&
  268: 		    MOUSE_BUTTONS(m->b) == 3 &&
  269: 		    MOUSE_BUTTONS(m->lb) == 3 &&
  270: 		    (~mode & MODE_MOUSE_ALL))
  271: 			return;
  272: 	}
  273: 
  274: 	/*
  275: 	 * Use the SGR (1006) extension only if the application requested it
  276: 	 * and the underlying terminal also sent the event in this format (this
  277: 	 * is because an old style mouse release event cannot be converted into
  278: 	 * the new SGR format, since the released button is unknown). Otherwise
  279: 	 * pretend that tmux doesn't speak this extension, and fall back to the
  280: 	 * UTF-8 (1005) extension if the application requested, or to the
  281: 	 * legacy format.
  282: 	 */
  283: 	if (m->sgr_type != ' ' && (s->mode & MODE_MOUSE_SGR)) {
  284: 		len = xsnprintf(buf, sizeof buf, "\033[<%u;%u;%u%c",
  285: 		    m->sgr_b, x + 1, y + 1, m->sgr_type);
  286: 	} else if (s->mode & MODE_MOUSE_UTF8) {
  287: 		if (m->b > 0x7ff - 32 || x > 0x7ff - 33 || y > 0x7ff - 33)
  288: 			return;
  289: 		len = xsnprintf(buf, sizeof buf, "\033[M");
  290: 		len += input_split2(m->b + 32, &buf[len]);
  291: 		len += input_split2(x + 33, &buf[len]);
  292: 		len += input_split2(y + 33, &buf[len]);
  293: 	} else {
  294: 		if (m->b > 223)
  295: 			return;
  296: 		len = xsnprintf(buf, sizeof buf, "\033[M");
  297: 		buf[len++] = m->b + 32;
  298: 		buf[len++] = x + 33;
  299: 		buf[len++] = y + 33;
  300: 	}
  301: 	log_debug("writing mouse %.*s to %%%u", (int)len, buf, wp->id);
  302: 	bufferevent_write(wp->event, buf, len);
  303: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>