xref: /openbsd-src/usr.bin/tmux/input-keys.c (revision fdcac80ec23e3c4e3093c4268ef2f6e5e3d43f19)
1 /* $OpenBSD: input-keys.c,v 1.14 2009/11/04 22:43:11 nicm Exp $ */
2 
3 /*
4  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
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 <stdint.h>
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #include "tmux.h"
26 
27 /*
28  * This file is rather misleadingly named, it contains the code which takes a
29  * key code and translates it into something suitable to be sent to the
30  * application running in a pane (similar to input.c does in the other
31  * direction with output).
32  */
33 
34 struct input_key_ent {
35 	int		 key;
36 	const char	*data;
37 
38 	int		 flags;
39 #define INPUTKEY_KEYPAD 0x1	/* keypad key */
40 #define INPUTKEY_CURSOR 0x2	/* cursor key */
41 };
42 
43 struct input_key_ent input_keys[] = {
44 	/* Backspace key. */
45 	{ KEYC_BSPACE,		"\177",		0 },
46 
47 	/* Function keys. */
48 	{ KEYC_F1,		"\033OP",	0 },
49 	{ KEYC_F2,		"\033OQ",	0 },
50 	{ KEYC_F3,		"\033OR",	0 },
51 	{ KEYC_F4,		"\033OS",	0 },
52 	{ KEYC_F5,		"\033[15~",	0 },
53 	{ KEYC_F5|KEYC_CTRL,	"\033[15^",	0 },
54 	{ KEYC_F6,		"\033[17~",	0 },
55 	{ KEYC_F6|KEYC_CTRL,	"\033[17^",	0 },
56 	{ KEYC_F7,		"\033[18~",	0 },
57 	{ KEYC_F7|KEYC_CTRL,	"\033[18^",	0 },
58 	{ KEYC_F8,		"\033[19~",	0 },
59 	{ KEYC_F8|KEYC_CTRL,	"\033[19^",	0 },
60 	{ KEYC_F9,		"\033[20~",	0 },
61 	{ KEYC_F9|KEYC_CTRL,	"\033[20^",	0 },
62 	{ KEYC_F10,		"\033[21~",	0 },
63 	{ KEYC_F10|KEYC_CTRL,	"\033[21^",	0 },
64 	{ KEYC_F11,		"\033[23~",	0 },
65 	{ KEYC_F1|KEYC_CTRL,	"\033[23^",	0 },
66 	{ KEYC_F12,		"\033[24~",	0 },
67 	{ KEYC_F12|KEYC_CTRL,	"\033[24^",	0 },
68 	{ KEYC_F13,		"\033[25~",	0 },
69 	{ KEYC_F13|KEYC_CTRL,	"\033[25^",	0 },
70 	{ KEYC_F14,		"\033[26~",	0 },
71 	{ KEYC_F14|KEYC_CTRL,	"\033[26^",	0 },
72 	{ KEYC_F15,		"\033[28~",	0 },
73 	{ KEYC_F15|KEYC_CTRL,	"\033[28^",	0 },
74 	{ KEYC_F16,		"\033[29~",	0 },
75 	{ KEYC_F16|KEYC_CTRL,	"\033[29^",	0 },
76 	{ KEYC_F17,		"\033[31~",	0 },
77 	{ KEYC_F17|KEYC_CTRL,	"\033[31^",	0 },
78 	{ KEYC_F18,		"\033[32~",	0 },
79 	{ KEYC_F18|KEYC_CTRL,	"\033[32^",	0 },
80 	{ KEYC_F19,		"\033[33~",	0 },
81 	{ KEYC_F19|KEYC_CTRL,	"\033[33^",	0 },
82 	{ KEYC_F20,		"\033[34~",	0 },
83 	{ KEYC_F20|KEYC_CTRL,	"\033[34^",	0 },
84 	{ KEYC_IC,		"\033[2~",	0 },
85 	{ KEYC_IC|KEYC_CTRL,	"\033[2^",	0 },
86 	{ KEYC_DC,		"\033[3~",	0 },
87 	{ KEYC_DC|KEYC_CTRL,	"\033[3^",	0 },
88 	{ KEYC_HOME,		"\033[1~",	0 },
89 	{ KEYC_HOME|KEYC_CTRL,	"\033[1^",	0 },
90 	{ KEYC_END,		"\033[4~",	0 },
91 	{ KEYC_END|KEYC_CTRL,	"\033[4^",	0 },
92 	{ KEYC_NPAGE,		"\033[6~",	0 },
93 	{ KEYC_NPAGE|KEYC_CTRL,	"\033[6^",	0 },
94 	{ KEYC_PPAGE,		"\033[5~",	0 },
95 	{ KEYC_PPAGE|KEYC_CTRL,	"\033[5^",	0 },
96 	{ KEYC_BTAB,		"\033[Z",	0 },
97 
98 	/*
99 	 * Arrow keys. Cursor versions must come first. The codes are toggled
100 	 * between CSI and SS3 versions when ctrl is pressed.
101 	 */
102 	{ KEYC_UP|KEYC_CTRL,	"\033[A",	INPUTKEY_CURSOR },
103 	{ KEYC_DOWN|KEYC_CTRL,	"\033[B",	INPUTKEY_CURSOR },
104 	{ KEYC_RIGHT|KEYC_CTRL,	"\033[C",	INPUTKEY_CURSOR },
105 	{ KEYC_LEFT|KEYC_CTRL,	"\033[D",	INPUTKEY_CURSOR },
106 
107 	{ KEYC_UP,		"\033OA",	INPUTKEY_CURSOR },
108 	{ KEYC_DOWN,		"\033OB",	INPUTKEY_CURSOR },
109 	{ KEYC_RIGHT,		"\033OC",	INPUTKEY_CURSOR },
110 	{ KEYC_LEFT,		"\033OD",	INPUTKEY_CURSOR },
111 
112 	{ KEYC_UP|KEYC_CTRL,	"\033OA",	0 },
113 	{ KEYC_DOWN|KEYC_CTRL,	"\033OB",	0 },
114 	{ KEYC_RIGHT|KEYC_CTRL,	"\033OC",	0 },
115 	{ KEYC_LEFT|KEYC_CTRL,	"\033OD",	0 },
116 
117 	{ KEYC_UP,		"\033[A",	0 },
118 	{ KEYC_DOWN,		"\033[B",	0 },
119 	{ KEYC_RIGHT,		"\033[C",	0 },
120 	{ KEYC_LEFT,		"\033[D",	0 },
121 
122 	/* Keypad keys. Keypad versions must come first. */
123 	{ KEYC_KP_SLASH,	"/",		INPUTKEY_KEYPAD },
124 	{ KEYC_KP_STAR,		"*",		INPUTKEY_KEYPAD },
125 	{ KEYC_KP_MINUS,	"-",		INPUTKEY_KEYPAD },
126 	{ KEYC_KP_SEVEN,	"7",		INPUTKEY_KEYPAD },
127 	{ KEYC_KP_EIGHT,	"8",		INPUTKEY_KEYPAD },
128 	{ KEYC_KP_NINE,		"9",		INPUTKEY_KEYPAD },
129 	{ KEYC_KP_PLUS,		"+",		INPUTKEY_KEYPAD },
130 	{ KEYC_KP_FOUR,		"4",		INPUTKEY_KEYPAD },
131 	{ KEYC_KP_FIVE,		"5",		INPUTKEY_KEYPAD },
132 	{ KEYC_KP_SIX,		"6",		INPUTKEY_KEYPAD },
133 	{ KEYC_KP_ONE,		"1",		INPUTKEY_KEYPAD },
134 	{ KEYC_KP_TWO,		"2",		INPUTKEY_KEYPAD },
135 	{ KEYC_KP_THREE,	"3",		INPUTKEY_KEYPAD },
136 	{ KEYC_KP_ENTER,	"\n",		INPUTKEY_KEYPAD },
137 	{ KEYC_KP_ZERO,		"0",		INPUTKEY_KEYPAD },
138 	{ KEYC_KP_PERIOD,	".",		INPUTKEY_KEYPAD },
139 
140 	{ KEYC_KP_SLASH,	"\033Oo",	0 },
141 	{ KEYC_KP_STAR,		"\033Oj",	0 },
142 	{ KEYC_KP_MINUS,	"\033Om",	0 },
143 	{ KEYC_KP_SEVEN,	"\033Ow",	0 },
144 	{ KEYC_KP_EIGHT,	"\033Ox",	0 },
145 	{ KEYC_KP_NINE,		"\033Oy",	0 },
146 	{ KEYC_KP_PLUS,		"\033Ok",	0 },
147 	{ KEYC_KP_FOUR,		"\033Ot",	0 },
148 	{ KEYC_KP_FIVE,		"\033Ou",	0 },
149 	{ KEYC_KP_SIX,		"\033Ov",	0 },
150 	{ KEYC_KP_ONE,		"\033Oq",	0 },
151 	{ KEYC_KP_TWO,		"\033Or",	0 },
152 	{ KEYC_KP_THREE,	"\033Os",	0 },
153 	{ KEYC_KP_ENTER,	"\033OM",	0 },
154 	{ KEYC_KP_ZERO,		"\033Op",	0 },
155 	{ KEYC_KP_PERIOD,	"\033On",	0 },
156 };
157 
158 /* Translate a key code into an output key sequence. */
159 void
160 input_key(struct window_pane *wp, int key)
161 {
162 	struct input_key_ent   *ike;
163 	u_int			i;
164 	size_t			dlen;
165 	char		       *out;
166 	u_char			ch;
167 
168 	log_debug2("writing key 0x%x", key);
169 
170 	/*
171 	 * If this is a normal 7-bit key, just send it, with a leading escape
172 	 * if necessary.
173 	 */
174 	if (key != KEYC_NONE && (key & ~KEYC_ESCAPE) < 0x100) {
175 		if (key & KEYC_ESCAPE)
176 			ch = '\033';
177 		else
178 			ch = key & ~KEYC_ESCAPE;
179 		bufferevent_write(wp->event, &ch, 1);
180 		return;
181 	}
182 
183 	/*
184 	 * Then try to look this up as an xterm key, if the flag to output them
185 	 * is set.
186 	 */
187 	if (options_get_number(&wp->window->options, "xterm-keys")) {
188 		if ((out = xterm_keys_lookup(key)) != NULL) {
189 			bufferevent_write(wp->event, out, strlen(out));
190 			xfree(out);
191 			return;
192 		}
193 	}
194 
195 	/* Otherwise look the key up in the table. */
196 	for (i = 0; i < nitems(input_keys); i++) {
197 		ike = &input_keys[i];
198 
199 		if ((ike->flags & INPUTKEY_KEYPAD) &&
200 		    !(wp->screen->mode & MODE_KKEYPAD))
201 			continue;
202 		if ((ike->flags & INPUTKEY_CURSOR) &&
203 		    !(wp->screen->mode & MODE_KCURSOR))
204 			continue;
205 
206 		if ((key & KEYC_ESCAPE) && (ike->key | KEYC_ESCAPE) == key)
207 			break;
208 		if (ike->key == key)
209 			break;
210 	}
211 	if (i == nitems(input_keys)) {
212 		log_debug2("key 0x%x missing", key);
213 		return;
214 	}
215 	dlen = strlen(ike->data);
216 	log_debug2("found key 0x%x: \"%s\"", key, ike->data);
217 
218 	/* Prefix a \033 for escape. */
219 	if (key & KEYC_ESCAPE)
220 		bufferevent_write(wp->event, "\033", 1);
221 	bufferevent_write(wp->event, ike->data, dlen);
222 }
223 
224 /* Translate mouse and output. */
225 void
226 input_mouse(struct window_pane *wp, struct mouse_event *m)
227 {
228 	char	out[8];
229 
230 	if (wp->screen->mode & MODE_MOUSE) {
231 		xsnprintf(out, sizeof out,
232 		    "\033[M%c%c%c", m->b + 32, m->x + 33, m->y + 33);
233 		bufferevent_write(wp->event, out, strlen(out));
234 	}
235 }
236