xref: /minix3/external/bsd/tmux/dist/tty-keys.c (revision eda6f5931d42c77e1480347b1fc3eef2f8d33806)
1*eda6f593SDavid van Moolenbroek /* $Id: tty-keys.c,v 1.4 2011/08/17 19:28:36 jmmv Exp $ */
2*eda6f593SDavid van Moolenbroek 
3*eda6f593SDavid van Moolenbroek /*
4*eda6f593SDavid van Moolenbroek  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
5*eda6f593SDavid van Moolenbroek  *
6*eda6f593SDavid van Moolenbroek  * Permission to use, copy, modify, and distribute this software for any
7*eda6f593SDavid van Moolenbroek  * purpose with or without fee is hereby granted, provided that the above
8*eda6f593SDavid van Moolenbroek  * copyright notice and this permission notice appear in all copies.
9*eda6f593SDavid van Moolenbroek  *
10*eda6f593SDavid van Moolenbroek  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11*eda6f593SDavid van Moolenbroek  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12*eda6f593SDavid van Moolenbroek  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13*eda6f593SDavid van Moolenbroek  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14*eda6f593SDavid van Moolenbroek  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15*eda6f593SDavid van Moolenbroek  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16*eda6f593SDavid van Moolenbroek  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*eda6f593SDavid van Moolenbroek  */
18*eda6f593SDavid van Moolenbroek 
19*eda6f593SDavid van Moolenbroek #include <sys/types.h>
20*eda6f593SDavid van Moolenbroek #include <sys/time.h>
21*eda6f593SDavid van Moolenbroek 
22*eda6f593SDavid van Moolenbroek #include <string.h>
23*eda6f593SDavid van Moolenbroek #include <termios.h>
24*eda6f593SDavid van Moolenbroek #include <unistd.h>
25*eda6f593SDavid van Moolenbroek 
26*eda6f593SDavid van Moolenbroek #include "tmux.h"
27*eda6f593SDavid van Moolenbroek 
28*eda6f593SDavid van Moolenbroek /*
29*eda6f593SDavid van Moolenbroek  * Handle keys input from the outside terminal. tty_keys[] is a base table of
30*eda6f593SDavid van Moolenbroek  * supported keys which are looked up in terminfo(5) and translated into a
31*eda6f593SDavid van Moolenbroek  * ternary tree (a binary tree of binary trees).
32*eda6f593SDavid van Moolenbroek  */
33*eda6f593SDavid van Moolenbroek 
34*eda6f593SDavid van Moolenbroek void		tty_keys_add1(struct tty_key **, const char *, int);
35*eda6f593SDavid van Moolenbroek void		tty_keys_add(struct tty *, const char *, int);
36*eda6f593SDavid van Moolenbroek void		tty_keys_free1(struct tty_key *);
37*eda6f593SDavid van Moolenbroek struct tty_key *tty_keys_find1(
38*eda6f593SDavid van Moolenbroek 		    struct tty_key *, const char *, size_t, size_t *);
39*eda6f593SDavid van Moolenbroek struct tty_key *tty_keys_find(struct tty *, const char *, size_t, size_t *);
40*eda6f593SDavid van Moolenbroek void		tty_keys_callback(int, short, void *);
41*eda6f593SDavid van Moolenbroek int		tty_keys_mouse(struct tty *,
42*eda6f593SDavid van Moolenbroek 		    const char *, size_t, size_t *, struct mouse_event *);
43*eda6f593SDavid van Moolenbroek 
44*eda6f593SDavid van Moolenbroek struct tty_key_ent {
45*eda6f593SDavid van Moolenbroek 	enum tty_code_code	code;
46*eda6f593SDavid van Moolenbroek 	const char	       *string;
47*eda6f593SDavid van Moolenbroek 
48*eda6f593SDavid van Moolenbroek 	int	 	 	key;
49*eda6f593SDavid van Moolenbroek 	int		 	flags;
50*eda6f593SDavid van Moolenbroek #define TTYKEY_RAW 0x1
51*eda6f593SDavid van Moolenbroek };
52*eda6f593SDavid van Moolenbroek 
53*eda6f593SDavid van Moolenbroek /*
54*eda6f593SDavid van Moolenbroek  * Default key tables. Those flagged with TTYKEY_RAW are inserted directly,
55*eda6f593SDavid van Moolenbroek  * otherwise they are looked up in terminfo(5).
56*eda6f593SDavid van Moolenbroek  */
57*eda6f593SDavid van Moolenbroek const struct tty_key_ent tty_keys[] = {
58*eda6f593SDavid van Moolenbroek 	/*
59*eda6f593SDavid van Moolenbroek 	 * Numeric keypad. Just use the vt100 escape sequences here and always
60*eda6f593SDavid van Moolenbroek 	 * put the terminal into keypad_xmit mode. Translation of numbers
61*eda6f593SDavid van Moolenbroek 	 * mode/applications mode is done in input-keys.c.
62*eda6f593SDavid van Moolenbroek 	 */
63*eda6f593SDavid van Moolenbroek 	{ 0,	"\033Oo",	KEYC_KP_SLASH,		TTYKEY_RAW },
64*eda6f593SDavid van Moolenbroek 	{ 0,	"\033Oj",	KEYC_KP_STAR,		TTYKEY_RAW },
65*eda6f593SDavid van Moolenbroek 	{ 0,	"\033Om",	KEYC_KP_MINUS,		TTYKEY_RAW },
66*eda6f593SDavid van Moolenbroek 	{ 0,	"\033Ow",	KEYC_KP_SEVEN,		TTYKEY_RAW },
67*eda6f593SDavid van Moolenbroek 	{ 0,	"\033Ox",	KEYC_KP_EIGHT,		TTYKEY_RAW },
68*eda6f593SDavid van Moolenbroek 	{ 0,	"\033Oy",	KEYC_KP_NINE,		TTYKEY_RAW },
69*eda6f593SDavid van Moolenbroek 	{ 0,	"\033Ok",	KEYC_KP_PLUS,		TTYKEY_RAW },
70*eda6f593SDavid van Moolenbroek 	{ 0,	"\033Ot",	KEYC_KP_FOUR,		TTYKEY_RAW },
71*eda6f593SDavid van Moolenbroek 	{ 0,	"\033Ou",	KEYC_KP_FIVE,		TTYKEY_RAW },
72*eda6f593SDavid van Moolenbroek 	{ 0,	"\033Ov",	KEYC_KP_SIX,		TTYKEY_RAW },
73*eda6f593SDavid van Moolenbroek 	{ 0,	"\033Oq",	KEYC_KP_ONE,		TTYKEY_RAW },
74*eda6f593SDavid van Moolenbroek 	{ 0,	"\033Or",	KEYC_KP_TWO,		TTYKEY_RAW },
75*eda6f593SDavid van Moolenbroek 	{ 0,	"\033Os",	KEYC_KP_THREE,		TTYKEY_RAW },
76*eda6f593SDavid van Moolenbroek 	{ 0,	"\033OM",	KEYC_KP_ENTER,		TTYKEY_RAW },
77*eda6f593SDavid van Moolenbroek 	{ 0,	"\033Op",	KEYC_KP_ZERO,		TTYKEY_RAW },
78*eda6f593SDavid van Moolenbroek 	{ 0,	"\033On",	KEYC_KP_PERIOD,		TTYKEY_RAW },
79*eda6f593SDavid van Moolenbroek 
80*eda6f593SDavid van Moolenbroek 	/* Arrow keys. */
81*eda6f593SDavid van Moolenbroek 	{ 0,	"\033OA",	KEYC_UP,		TTYKEY_RAW },
82*eda6f593SDavid van Moolenbroek 	{ 0,	"\033OB",	KEYC_DOWN,		TTYKEY_RAW },
83*eda6f593SDavid van Moolenbroek 	{ 0,	"\033OC",	KEYC_RIGHT,		TTYKEY_RAW },
84*eda6f593SDavid van Moolenbroek 	{ 0,	"\033OD",	KEYC_LEFT,		TTYKEY_RAW },
85*eda6f593SDavid van Moolenbroek 
86*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[A",	KEYC_UP,		TTYKEY_RAW },
87*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[B",	KEYC_DOWN,		TTYKEY_RAW },
88*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[C",	KEYC_RIGHT,		TTYKEY_RAW },
89*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[D",	KEYC_LEFT,		TTYKEY_RAW },
90*eda6f593SDavid van Moolenbroek 
91*eda6f593SDavid van Moolenbroek 	/* rxvt-style arrow + modifier keys. */
92*eda6f593SDavid van Moolenbroek 	{ 0,	"\033Oa",	KEYC_UP|KEYC_CTRL,	TTYKEY_RAW },
93*eda6f593SDavid van Moolenbroek 	{ 0,	"\033Ob",	KEYC_DOWN|KEYC_CTRL,	TTYKEY_RAW },
94*eda6f593SDavid van Moolenbroek 	{ 0,	"\033Oc",	KEYC_RIGHT|KEYC_CTRL,	TTYKEY_RAW },
95*eda6f593SDavid van Moolenbroek 	{ 0,	"\033Od",	KEYC_LEFT|KEYC_CTRL,	TTYKEY_RAW },
96*eda6f593SDavid van Moolenbroek 
97*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[a",	KEYC_UP|KEYC_SHIFT,	TTYKEY_RAW },
98*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[b",	KEYC_DOWN|KEYC_SHIFT,	TTYKEY_RAW },
99*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[c",	KEYC_RIGHT|KEYC_SHIFT,	TTYKEY_RAW },
100*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[d",	KEYC_LEFT|KEYC_SHIFT,	TTYKEY_RAW },
101*eda6f593SDavid van Moolenbroek 
102*eda6f593SDavid van Moolenbroek 	/*
103*eda6f593SDavid van Moolenbroek 	 * rxvt-style function + modifier keys:
104*eda6f593SDavid van Moolenbroek 	 *		Ctrl = ^, Shift = $, Ctrl+Shift = @
105*eda6f593SDavid van Moolenbroek 	 */
106*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[11^",	KEYC_F1|KEYC_CTRL,	TTYKEY_RAW },
107*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[12^",	KEYC_F2|KEYC_CTRL,	TTYKEY_RAW },
108*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[13^",	KEYC_F3|KEYC_CTRL,	TTYKEY_RAW },
109*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[14^",	KEYC_F4|KEYC_CTRL,	TTYKEY_RAW },
110*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[15^",	KEYC_F5|KEYC_CTRL,	TTYKEY_RAW },
111*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[17^",	KEYC_F6|KEYC_CTRL,	TTYKEY_RAW },
112*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[18^",	KEYC_F7|KEYC_CTRL,	TTYKEY_RAW },
113*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[19^",	KEYC_F8|KEYC_CTRL,	TTYKEY_RAW },
114*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[20^",	KEYC_F9|KEYC_CTRL,	TTYKEY_RAW },
115*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[21^",	KEYC_F10|KEYC_CTRL,	TTYKEY_RAW },
116*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[23^",	KEYC_F11|KEYC_CTRL,	TTYKEY_RAW },
117*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[24^",	KEYC_F12|KEYC_CTRL,	TTYKEY_RAW },
118*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[25^",	KEYC_F13|KEYC_CTRL,	TTYKEY_RAW },
119*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[26^",	KEYC_F14|KEYC_CTRL,	TTYKEY_RAW },
120*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[28^",	KEYC_F15|KEYC_CTRL,	TTYKEY_RAW },
121*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[29^",	KEYC_F16|KEYC_CTRL,	TTYKEY_RAW },
122*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[31^",	KEYC_F17|KEYC_CTRL,	TTYKEY_RAW },
123*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[32^",	KEYC_F18|KEYC_CTRL,	TTYKEY_RAW },
124*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[33^",	KEYC_F19|KEYC_CTRL,	TTYKEY_RAW },
125*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[34^",	KEYC_F20|KEYC_CTRL,	TTYKEY_RAW },
126*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[2^",	KEYC_IC|KEYC_CTRL,	TTYKEY_RAW },
127*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[3^",	KEYC_DC|KEYC_CTRL,	TTYKEY_RAW },
128*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[7^",	KEYC_HOME|KEYC_CTRL,	TTYKEY_RAW },
129*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[8^",	KEYC_END|KEYC_CTRL,	TTYKEY_RAW },
130*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[6^",	KEYC_NPAGE|KEYC_CTRL,	TTYKEY_RAW },
131*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[5^",	KEYC_PPAGE|KEYC_CTRL,	TTYKEY_RAW },
132*eda6f593SDavid van Moolenbroek 
133*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[11$",	KEYC_F1|KEYC_SHIFT,	TTYKEY_RAW },
134*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[12$",	KEYC_F2|KEYC_SHIFT,	TTYKEY_RAW },
135*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[13$",	KEYC_F3|KEYC_SHIFT,	TTYKEY_RAW },
136*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[14$",	KEYC_F4|KEYC_SHIFT,	TTYKEY_RAW },
137*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[15$",	KEYC_F5|KEYC_SHIFT,	TTYKEY_RAW },
138*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[17$",	KEYC_F6|KEYC_SHIFT,	TTYKEY_RAW },
139*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[18$",	KEYC_F7|KEYC_SHIFT,	TTYKEY_RAW },
140*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[19$",	KEYC_F8|KEYC_SHIFT,	TTYKEY_RAW },
141*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[20$",	KEYC_F9|KEYC_SHIFT,	TTYKEY_RAW },
142*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[21$",	KEYC_F10|KEYC_SHIFT,	TTYKEY_RAW },
143*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[23$",	KEYC_F11|KEYC_SHIFT,	TTYKEY_RAW },
144*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[24$",	KEYC_F12|KEYC_SHIFT,	TTYKEY_RAW },
145*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[25$",	KEYC_F13|KEYC_SHIFT,	TTYKEY_RAW },
146*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[26$",	KEYC_F14|KEYC_SHIFT,	TTYKEY_RAW },
147*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[28$",	KEYC_F15|KEYC_SHIFT,	TTYKEY_RAW },
148*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[29$",	KEYC_F16|KEYC_SHIFT,	TTYKEY_RAW },
149*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[31$",	KEYC_F17|KEYC_SHIFT,	TTYKEY_RAW },
150*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[32$",	KEYC_F18|KEYC_SHIFT,	TTYKEY_RAW },
151*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[33$",	KEYC_F19|KEYC_SHIFT,	TTYKEY_RAW },
152*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[34$",	KEYC_F20|KEYC_SHIFT,	TTYKEY_RAW },
153*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[2$",	KEYC_IC|KEYC_SHIFT,	TTYKEY_RAW },
154*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[3$",	KEYC_DC|KEYC_SHIFT,	TTYKEY_RAW },
155*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[7$",	KEYC_HOME|KEYC_SHIFT,	TTYKEY_RAW },
156*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[8$",	KEYC_END|KEYC_SHIFT,	TTYKEY_RAW },
157*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[6$",	KEYC_NPAGE|KEYC_SHIFT,	TTYKEY_RAW },
158*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[5$",	KEYC_PPAGE|KEYC_SHIFT,	TTYKEY_RAW },
159*eda6f593SDavid van Moolenbroek 
160*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[11@",	KEYC_F1|KEYC_CTRL|KEYC_SHIFT,	TTYKEY_RAW },
161*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[12@",	KEYC_F2|KEYC_CTRL|KEYC_SHIFT,	TTYKEY_RAW },
162*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[13@",	KEYC_F3|KEYC_CTRL|KEYC_SHIFT,	TTYKEY_RAW },
163*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[14@",	KEYC_F4|KEYC_CTRL|KEYC_SHIFT,	TTYKEY_RAW },
164*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[15@",	KEYC_F5|KEYC_CTRL|KEYC_SHIFT,	TTYKEY_RAW },
165*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[17@",	KEYC_F6|KEYC_CTRL|KEYC_SHIFT,	TTYKEY_RAW },
166*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[18@",	KEYC_F7|KEYC_CTRL|KEYC_SHIFT,	TTYKEY_RAW },
167*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[19@",	KEYC_F8|KEYC_CTRL|KEYC_SHIFT,	TTYKEY_RAW },
168*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[20@",	KEYC_F9|KEYC_CTRL|KEYC_SHIFT,	TTYKEY_RAW },
169*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[21@",	KEYC_F10|KEYC_CTRL|KEYC_SHIFT,	TTYKEY_RAW },
170*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[23@",	KEYC_F11|KEYC_CTRL|KEYC_SHIFT,	TTYKEY_RAW },
171*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[24@",	KEYC_F12|KEYC_CTRL|KEYC_SHIFT,	TTYKEY_RAW },
172*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[25@",	KEYC_F13|KEYC_CTRL|KEYC_SHIFT,	TTYKEY_RAW },
173*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[26@",	KEYC_F14|KEYC_CTRL|KEYC_SHIFT,	TTYKEY_RAW },
174*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[28@",	KEYC_F15|KEYC_CTRL|KEYC_SHIFT,	TTYKEY_RAW },
175*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[29@",	KEYC_F16|KEYC_CTRL|KEYC_SHIFT,	TTYKEY_RAW },
176*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[31@",	KEYC_F17|KEYC_CTRL|KEYC_SHIFT,	TTYKEY_RAW },
177*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[32@",	KEYC_F18|KEYC_CTRL|KEYC_SHIFT,	TTYKEY_RAW },
178*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[33@",	KEYC_F19|KEYC_CTRL|KEYC_SHIFT,	TTYKEY_RAW },
179*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[34@",	KEYC_F20|KEYC_CTRL|KEYC_SHIFT,	TTYKEY_RAW },
180*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[2@",	KEYC_IC|KEYC_CTRL|KEYC_SHIFT,	TTYKEY_RAW },
181*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[3@",	KEYC_DC|KEYC_CTRL|KEYC_SHIFT,	TTYKEY_RAW },
182*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[7@",	KEYC_HOME|KEYC_CTRL|KEYC_SHIFT,	TTYKEY_RAW },
183*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[8@",	KEYC_END|KEYC_CTRL|KEYC_SHIFT,	TTYKEY_RAW },
184*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[6@",	KEYC_NPAGE|KEYC_CTRL|KEYC_SHIFT,TTYKEY_RAW },
185*eda6f593SDavid van Moolenbroek 	{ 0,	"\033[5@",	KEYC_PPAGE|KEYC_CTRL|KEYC_SHIFT,TTYKEY_RAW },
186*eda6f593SDavid van Moolenbroek 
187*eda6f593SDavid van Moolenbroek 	/* terminfo lookups below this line so they can override raw keys. */
188*eda6f593SDavid van Moolenbroek 
189*eda6f593SDavid van Moolenbroek 	/* Function keys. */
190*eda6f593SDavid van Moolenbroek 	{ TTYC_KF1,	NULL,		KEYC_F1,		0 },
191*eda6f593SDavid van Moolenbroek 	{ TTYC_KF2,	NULL,		KEYC_F2,		0 },
192*eda6f593SDavid van Moolenbroek 	{ TTYC_KF3,	NULL,		KEYC_F3,		0 },
193*eda6f593SDavid van Moolenbroek 	{ TTYC_KF4,	NULL,		KEYC_F4,		0 },
194*eda6f593SDavid van Moolenbroek 	{ TTYC_KF5,	NULL,		KEYC_F5,		0 },
195*eda6f593SDavid van Moolenbroek 	{ TTYC_KF6,	NULL,		KEYC_F6,		0 },
196*eda6f593SDavid van Moolenbroek 	{ TTYC_KF7,	NULL,		KEYC_F7,		0 },
197*eda6f593SDavid van Moolenbroek 	{ TTYC_KF8,	NULL,		KEYC_F8,		0 },
198*eda6f593SDavid van Moolenbroek 	{ TTYC_KF9,	NULL,		KEYC_F9,		0 },
199*eda6f593SDavid van Moolenbroek 	{ TTYC_KF10,	NULL,		KEYC_F10,		0 },
200*eda6f593SDavid van Moolenbroek 	{ TTYC_KF11,	NULL,		KEYC_F11,		0 },
201*eda6f593SDavid van Moolenbroek 	{ TTYC_KF12,	NULL,		KEYC_F12,		0 },
202*eda6f593SDavid van Moolenbroek 	{ TTYC_KF13,	NULL,		KEYC_F13,		0 },
203*eda6f593SDavid van Moolenbroek 	{ TTYC_KF14,	NULL,		KEYC_F14,		0 },
204*eda6f593SDavid van Moolenbroek 	{ TTYC_KF15,	NULL,		KEYC_F15,		0 },
205*eda6f593SDavid van Moolenbroek 	{ TTYC_KF16,	NULL,		KEYC_F16,		0 },
206*eda6f593SDavid van Moolenbroek 	{ TTYC_KF17,	NULL,		KEYC_F17,		0 },
207*eda6f593SDavid van Moolenbroek 	{ TTYC_KF18,	NULL,		KEYC_F18,		0 },
208*eda6f593SDavid van Moolenbroek 	{ TTYC_KF19,	NULL,		KEYC_F19,		0 },
209*eda6f593SDavid van Moolenbroek 	{ TTYC_KF20,	NULL,		KEYC_F20,		0 },
210*eda6f593SDavid van Moolenbroek 	{ TTYC_KICH1,	NULL,		KEYC_IC,		0 },
211*eda6f593SDavid van Moolenbroek 	{ TTYC_KDCH1,	NULL,		KEYC_DC,		0 },
212*eda6f593SDavid van Moolenbroek 	{ TTYC_KHOME,	NULL,		KEYC_HOME,		0 },
213*eda6f593SDavid van Moolenbroek 	{ TTYC_KEND,	NULL,		KEYC_END,		0 },
214*eda6f593SDavid van Moolenbroek 	{ TTYC_KNP,	NULL,		KEYC_NPAGE,		0 },
215*eda6f593SDavid van Moolenbroek 	{ TTYC_KPP,	NULL,		KEYC_PPAGE,		0 },
216*eda6f593SDavid van Moolenbroek 	{ TTYC_KCBT,	NULL,		KEYC_BTAB,		0 },
217*eda6f593SDavid van Moolenbroek 
218*eda6f593SDavid van Moolenbroek 	/* Arrow keys from terminfo. */
219*eda6f593SDavid van Moolenbroek 	{ TTYC_KCUU1,	NULL,		KEYC_UP,		0 },
220*eda6f593SDavid van Moolenbroek 	{ TTYC_KCUD1,	NULL,		KEYC_DOWN,		0 },
221*eda6f593SDavid van Moolenbroek 	{ TTYC_KCUB1,	NULL,		KEYC_LEFT,		0 },
222*eda6f593SDavid van Moolenbroek 	{ TTYC_KCUF1,	NULL,		KEYC_RIGHT,		0 },
223*eda6f593SDavid van Moolenbroek 
224*eda6f593SDavid van Moolenbroek 	/* Key and modifier capabilities. */
225*eda6f593SDavid van Moolenbroek 	{ TTYC_KDC2,	NULL,		KEYC_DC|KEYC_SHIFT,	0 },
226*eda6f593SDavid van Moolenbroek 	{ TTYC_KDC3,	NULL,		KEYC_DC|KEYC_ESCAPE,	0 },
227*eda6f593SDavid van Moolenbroek 	{ TTYC_KDC4,	NULL,		KEYC_DC|KEYC_SHIFT|KEYC_ESCAPE, 0 },
228*eda6f593SDavid van Moolenbroek 	{ TTYC_KDC5,	NULL,		KEYC_DC|KEYC_CTRL,	0 },
229*eda6f593SDavid van Moolenbroek 	{ TTYC_KDC6,	NULL,		KEYC_DC|KEYC_SHIFT|KEYC_CTRL, 0 },
230*eda6f593SDavid van Moolenbroek 	{ TTYC_KDC7,	NULL,		KEYC_DC|KEYC_ESCAPE|KEYC_CTRL, 0 },
231*eda6f593SDavid van Moolenbroek 	{ TTYC_KDN2,	NULL,		KEYC_DOWN|KEYC_SHIFT,	0 },
232*eda6f593SDavid van Moolenbroek 	{ TTYC_KDN3,	NULL,		KEYC_DOWN|KEYC_ESCAPE,	0 },
233*eda6f593SDavid van Moolenbroek 	{ TTYC_KDN4,	NULL,		KEYC_DOWN|KEYC_SHIFT|KEYC_ESCAPE, 0 },
234*eda6f593SDavid van Moolenbroek 	{ TTYC_KDN5,	NULL,		KEYC_DOWN|KEYC_CTRL,	0 },
235*eda6f593SDavid van Moolenbroek 	{ TTYC_KDN6,	NULL,		KEYC_DOWN|KEYC_SHIFT|KEYC_CTRL, 0 },
236*eda6f593SDavid van Moolenbroek 	{ TTYC_KDN7,	NULL,		KEYC_DOWN|KEYC_ESCAPE|KEYC_CTRL, 0 },
237*eda6f593SDavid van Moolenbroek 	{ TTYC_KEND2,	NULL,		KEYC_END|KEYC_SHIFT,	0 },
238*eda6f593SDavid van Moolenbroek 	{ TTYC_KEND3,	NULL,		KEYC_END|KEYC_ESCAPE,	0 },
239*eda6f593SDavid van Moolenbroek 	{ TTYC_KEND4,	NULL,		KEYC_END|KEYC_SHIFT|KEYC_ESCAPE, 0 },
240*eda6f593SDavid van Moolenbroek 	{ TTYC_KEND5,	NULL,		KEYC_END|KEYC_CTRL,	0 },
241*eda6f593SDavid van Moolenbroek 	{ TTYC_KEND6,	NULL,		KEYC_END|KEYC_SHIFT|KEYC_CTRL, 0 },
242*eda6f593SDavid van Moolenbroek 	{ TTYC_KEND7,	NULL,		KEYC_END|KEYC_ESCAPE|KEYC_CTRL, 0 },
243*eda6f593SDavid van Moolenbroek 	{ TTYC_KHOM2,	NULL,		KEYC_HOME|KEYC_SHIFT,	0 },
244*eda6f593SDavid van Moolenbroek 	{ TTYC_KHOM3,	NULL,		KEYC_HOME|KEYC_ESCAPE,	0 },
245*eda6f593SDavid van Moolenbroek 	{ TTYC_KHOM4,	NULL,		KEYC_HOME|KEYC_SHIFT|KEYC_ESCAPE, 0 },
246*eda6f593SDavid van Moolenbroek 	{ TTYC_KHOM5,	NULL,		KEYC_HOME|KEYC_CTRL,	0 },
247*eda6f593SDavid van Moolenbroek 	{ TTYC_KHOM6,	NULL,		KEYC_HOME|KEYC_SHIFT|KEYC_CTRL, 0 },
248*eda6f593SDavid van Moolenbroek 	{ TTYC_KHOM7,	NULL,		KEYC_HOME|KEYC_ESCAPE|KEYC_CTRL, 0 },
249*eda6f593SDavid van Moolenbroek 	{ TTYC_KIC2,	NULL,		KEYC_IC|KEYC_SHIFT,	0 },
250*eda6f593SDavid van Moolenbroek 	{ TTYC_KIC3,	NULL,		KEYC_IC|KEYC_ESCAPE,	0 },
251*eda6f593SDavid van Moolenbroek 	{ TTYC_KIC4,	NULL,		KEYC_IC|KEYC_SHIFT|KEYC_ESCAPE,	0 },
252*eda6f593SDavid van Moolenbroek 	{ TTYC_KIC5,	NULL,		KEYC_IC|KEYC_CTRL,	0 },
253*eda6f593SDavid van Moolenbroek 	{ TTYC_KIC6,	NULL,		KEYC_IC|KEYC_SHIFT|KEYC_CTRL, 0 },
254*eda6f593SDavid van Moolenbroek 	{ TTYC_KIC7,	NULL,		KEYC_IC|KEYC_ESCAPE|KEYC_CTRL, 0 },
255*eda6f593SDavid van Moolenbroek 	{ TTYC_KLFT2,	NULL,		KEYC_LEFT|KEYC_SHIFT,	0 },
256*eda6f593SDavid van Moolenbroek 	{ TTYC_KLFT3,	NULL,		KEYC_LEFT|KEYC_ESCAPE,	0 },
257*eda6f593SDavid van Moolenbroek 	{ TTYC_KLFT4,	NULL,		KEYC_LEFT|KEYC_SHIFT|KEYC_ESCAPE, 0 },
258*eda6f593SDavid van Moolenbroek 	{ TTYC_KLFT5,	NULL,		KEYC_LEFT|KEYC_CTRL,	0 },
259*eda6f593SDavid van Moolenbroek 	{ TTYC_KLFT6,	NULL,		KEYC_LEFT|KEYC_SHIFT|KEYC_CTRL, 0 },
260*eda6f593SDavid van Moolenbroek 	{ TTYC_KLFT7,	NULL,		KEYC_LEFT|KEYC_ESCAPE|KEYC_CTRL, 0 },
261*eda6f593SDavid van Moolenbroek 	{ TTYC_KNXT2,	NULL,		KEYC_NPAGE|KEYC_SHIFT,	0 },
262*eda6f593SDavid van Moolenbroek 	{ TTYC_KNXT3,	NULL,		KEYC_NPAGE|KEYC_ESCAPE,	0 },
263*eda6f593SDavid van Moolenbroek 	{ TTYC_KNXT4,	NULL,		KEYC_NPAGE|KEYC_SHIFT|KEYC_ESCAPE, 0 },
264*eda6f593SDavid van Moolenbroek 	{ TTYC_KNXT5,	NULL,		KEYC_NPAGE|KEYC_CTRL,	0 },
265*eda6f593SDavid van Moolenbroek 	{ TTYC_KNXT6,	NULL,		KEYC_NPAGE|KEYC_SHIFT|KEYC_CTRL, 0 },
266*eda6f593SDavid van Moolenbroek 	{ TTYC_KNXT7,	NULL,		KEYC_NPAGE|KEYC_ESCAPE|KEYC_CTRL, 0 },
267*eda6f593SDavid van Moolenbroek 	{ TTYC_KPRV2,	NULL,		KEYC_PPAGE|KEYC_SHIFT,	0 },
268*eda6f593SDavid van Moolenbroek 	{ TTYC_KPRV3,	NULL,		KEYC_PPAGE|KEYC_ESCAPE,	0 },
269*eda6f593SDavid van Moolenbroek 	{ TTYC_KPRV4,	NULL,		KEYC_PPAGE|KEYC_SHIFT|KEYC_ESCAPE, 0 },
270*eda6f593SDavid van Moolenbroek 	{ TTYC_KPRV5,	NULL,		KEYC_PPAGE|KEYC_CTRL,	0 },
271*eda6f593SDavid van Moolenbroek 	{ TTYC_KPRV6,	NULL,		KEYC_PPAGE|KEYC_SHIFT|KEYC_CTRL, 0 },
272*eda6f593SDavid van Moolenbroek 	{ TTYC_KPRV7,	NULL,		KEYC_PPAGE|KEYC_ESCAPE|KEYC_CTRL, 0 },
273*eda6f593SDavid van Moolenbroek 	{ TTYC_KRIT2,	NULL,		KEYC_RIGHT|KEYC_SHIFT,	0 },
274*eda6f593SDavid van Moolenbroek 	{ TTYC_KRIT3,	NULL,		KEYC_RIGHT|KEYC_ESCAPE,	0 },
275*eda6f593SDavid van Moolenbroek 	{ TTYC_KRIT4,	NULL,		KEYC_RIGHT|KEYC_SHIFT|KEYC_ESCAPE, 0 },
276*eda6f593SDavid van Moolenbroek 	{ TTYC_KRIT5,	NULL,		KEYC_RIGHT|KEYC_CTRL,	0 },
277*eda6f593SDavid van Moolenbroek 	{ TTYC_KRIT6,	NULL,		KEYC_RIGHT|KEYC_SHIFT|KEYC_CTRL, 0 },
278*eda6f593SDavid van Moolenbroek 	{ TTYC_KRIT7,	NULL,		KEYC_RIGHT|KEYC_ESCAPE|KEYC_CTRL, 0 },
279*eda6f593SDavid van Moolenbroek 	{ TTYC_KUP2,	NULL,		KEYC_UP|KEYC_SHIFT,	0 },
280*eda6f593SDavid van Moolenbroek 	{ TTYC_KUP3,	NULL,		KEYC_UP|KEYC_ESCAPE,	0 },
281*eda6f593SDavid van Moolenbroek 	{ TTYC_KUP4,	NULL,		KEYC_UP|KEYC_SHIFT|KEYC_ESCAPE,	0 },
282*eda6f593SDavid van Moolenbroek 	{ TTYC_KUP5,	NULL,		KEYC_UP|KEYC_CTRL,	0 },
283*eda6f593SDavid van Moolenbroek 	{ TTYC_KUP6,	NULL,		KEYC_UP|KEYC_SHIFT|KEYC_CTRL, 0 },
284*eda6f593SDavid van Moolenbroek 	{ TTYC_KUP7,	NULL,		KEYC_UP|KEYC_ESCAPE|KEYC_CTRL, 0 },
285*eda6f593SDavid van Moolenbroek };
286*eda6f593SDavid van Moolenbroek 
287*eda6f593SDavid van Moolenbroek void
288*eda6f593SDavid van Moolenbroek tty_keys_add(struct tty *tty, const char *s, int key)
289*eda6f593SDavid van Moolenbroek {
290*eda6f593SDavid van Moolenbroek 	struct tty_key	*tk;
291*eda6f593SDavid van Moolenbroek 	size_t		 size;
292*eda6f593SDavid van Moolenbroek 	const char     	*keystr;
293*eda6f593SDavid van Moolenbroek 
294*eda6f593SDavid van Moolenbroek 	keystr = key_string_lookup_key(key);
295*eda6f593SDavid van Moolenbroek 	if ((tk = tty_keys_find(tty, s, strlen(s), &size)) == NULL) {
296*eda6f593SDavid van Moolenbroek 		log_debug("new key %s: 0x%x (%s)", s, key, keystr);
297*eda6f593SDavid van Moolenbroek 		tty_keys_add1(&tty->key_tree, s, key);
298*eda6f593SDavid van Moolenbroek 	} else {
299*eda6f593SDavid van Moolenbroek 		log_debug("replacing key %s: 0x%x (%s)", s, key, keystr);
300*eda6f593SDavid van Moolenbroek 		tk->key = key;
301*eda6f593SDavid van Moolenbroek 	}
302*eda6f593SDavid van Moolenbroek }
303*eda6f593SDavid van Moolenbroek 
304*eda6f593SDavid van Moolenbroek /* Add next node to the tree. */
305*eda6f593SDavid van Moolenbroek void
306*eda6f593SDavid van Moolenbroek tty_keys_add1(struct tty_key **tkp, const char *s, int key)
307*eda6f593SDavid van Moolenbroek {
308*eda6f593SDavid van Moolenbroek 	struct tty_key	*tk;
309*eda6f593SDavid van Moolenbroek 
310*eda6f593SDavid van Moolenbroek 	/* Allocate a tree entry if there isn't one already. */
311*eda6f593SDavid van Moolenbroek 	tk = *tkp;
312*eda6f593SDavid van Moolenbroek 	if (tk == NULL) {
313*eda6f593SDavid van Moolenbroek 		tk = *tkp = xcalloc(1, sizeof *tk);
314*eda6f593SDavid van Moolenbroek 		tk->ch = *s;
315*eda6f593SDavid van Moolenbroek 		tk->key = KEYC_NONE;
316*eda6f593SDavid van Moolenbroek 	}
317*eda6f593SDavid van Moolenbroek 
318*eda6f593SDavid van Moolenbroek 	/* Find the next entry. */
319*eda6f593SDavid van Moolenbroek 	if (*s == tk->ch) {
320*eda6f593SDavid van Moolenbroek 		/* Move forward in string. */
321*eda6f593SDavid van Moolenbroek 		s++;
322*eda6f593SDavid van Moolenbroek 
323*eda6f593SDavid van Moolenbroek 		/* If this is the end of the string, no more is necessary. */
324*eda6f593SDavid van Moolenbroek 		if (*s == '\0') {
325*eda6f593SDavid van Moolenbroek 			tk->key = key;
326*eda6f593SDavid van Moolenbroek 			return;
327*eda6f593SDavid van Moolenbroek 		}
328*eda6f593SDavid van Moolenbroek 
329*eda6f593SDavid van Moolenbroek 		/* Use the child tree for the next character. */
330*eda6f593SDavid van Moolenbroek 		tkp = &tk->next;
331*eda6f593SDavid van Moolenbroek 	} else {
332*eda6f593SDavid van Moolenbroek 		if (*s < tk->ch)
333*eda6f593SDavid van Moolenbroek 			tkp = &tk->left;
334*eda6f593SDavid van Moolenbroek 		else if (*s > tk->ch)
335*eda6f593SDavid van Moolenbroek 			tkp = &tk->right;
336*eda6f593SDavid van Moolenbroek 	}
337*eda6f593SDavid van Moolenbroek 
338*eda6f593SDavid van Moolenbroek 	/* And recurse to add it. */
339*eda6f593SDavid van Moolenbroek 	tty_keys_add1(tkp, s, key);
340*eda6f593SDavid van Moolenbroek }
341*eda6f593SDavid van Moolenbroek 
342*eda6f593SDavid van Moolenbroek /* Initialise a key tree from the table. */
343*eda6f593SDavid van Moolenbroek void
344*eda6f593SDavid van Moolenbroek tty_keys_init(struct tty *tty)
345*eda6f593SDavid van Moolenbroek {
346*eda6f593SDavid van Moolenbroek 	const struct tty_key_ent	*tke;
347*eda6f593SDavid van Moolenbroek 	u_int		 		 i;
348*eda6f593SDavid van Moolenbroek 	const char			*s;
349*eda6f593SDavid van Moolenbroek 
350*eda6f593SDavid van Moolenbroek 	tty->key_tree = NULL;
351*eda6f593SDavid van Moolenbroek 	for (i = 0; i < nitems(tty_keys); i++) {
352*eda6f593SDavid van Moolenbroek 		tke = &tty_keys[i];
353*eda6f593SDavid van Moolenbroek 
354*eda6f593SDavid van Moolenbroek 		if (tke->flags & TTYKEY_RAW)
355*eda6f593SDavid van Moolenbroek 			s = tke->string;
356*eda6f593SDavid van Moolenbroek 		else {
357*eda6f593SDavid van Moolenbroek 			if (!tty_term_has(tty->term, tke->code))
358*eda6f593SDavid van Moolenbroek 				continue;
359*eda6f593SDavid van Moolenbroek 			s = tty_term_string(tty->term, tke->code);
360*eda6f593SDavid van Moolenbroek 		}
361*eda6f593SDavid van Moolenbroek 		if (s[0] != '\033' || s[1] == '\0')
362*eda6f593SDavid van Moolenbroek 			continue;
363*eda6f593SDavid van Moolenbroek 
364*eda6f593SDavid van Moolenbroek 		tty_keys_add(tty, s + 1, tke->key);
365*eda6f593SDavid van Moolenbroek 	}
366*eda6f593SDavid van Moolenbroek }
367*eda6f593SDavid van Moolenbroek 
368*eda6f593SDavid van Moolenbroek /* Free the entire key tree. */
369*eda6f593SDavid van Moolenbroek void
370*eda6f593SDavid van Moolenbroek tty_keys_free(struct tty *tty)
371*eda6f593SDavid van Moolenbroek {
372*eda6f593SDavid van Moolenbroek 	tty_keys_free1(tty->key_tree);
373*eda6f593SDavid van Moolenbroek }
374*eda6f593SDavid van Moolenbroek 
375*eda6f593SDavid van Moolenbroek /* Free a single key. */
376*eda6f593SDavid van Moolenbroek void
377*eda6f593SDavid van Moolenbroek tty_keys_free1(struct tty_key *tk)
378*eda6f593SDavid van Moolenbroek {
379*eda6f593SDavid van Moolenbroek 	if (tk->next != NULL)
380*eda6f593SDavid van Moolenbroek 		tty_keys_free1(tk->next);
381*eda6f593SDavid van Moolenbroek 	if (tk->left != NULL)
382*eda6f593SDavid van Moolenbroek 		tty_keys_free1(tk->left);
383*eda6f593SDavid van Moolenbroek 	if (tk->right != NULL)
384*eda6f593SDavid van Moolenbroek 		tty_keys_free1(tk->right);
385*eda6f593SDavid van Moolenbroek 	xfree(tk);
386*eda6f593SDavid van Moolenbroek }
387*eda6f593SDavid van Moolenbroek 
388*eda6f593SDavid van Moolenbroek /* Lookup a key in the tree. */
389*eda6f593SDavid van Moolenbroek struct tty_key *
390*eda6f593SDavid van Moolenbroek tty_keys_find(struct tty *tty, const char *buf, size_t len, size_t *size)
391*eda6f593SDavid van Moolenbroek {
392*eda6f593SDavid van Moolenbroek 	*size = 0;
393*eda6f593SDavid van Moolenbroek 	return (tty_keys_find1(tty->key_tree, buf, len, size));
394*eda6f593SDavid van Moolenbroek }
395*eda6f593SDavid van Moolenbroek 
396*eda6f593SDavid van Moolenbroek /* Find the next node. */
397*eda6f593SDavid van Moolenbroek struct tty_key *
398*eda6f593SDavid van Moolenbroek tty_keys_find1(struct tty_key *tk, const char *buf, size_t len, size_t *size)
399*eda6f593SDavid van Moolenbroek {
400*eda6f593SDavid van Moolenbroek 	/* If the node is NULL, this is the end of the tree. No match. */
401*eda6f593SDavid van Moolenbroek 	if (tk == NULL)
402*eda6f593SDavid van Moolenbroek 		return (NULL);
403*eda6f593SDavid van Moolenbroek 
404*eda6f593SDavid van Moolenbroek 	/* Pick the next in the sequence. */
405*eda6f593SDavid van Moolenbroek 	if (tk->ch == *buf) {
406*eda6f593SDavid van Moolenbroek 		/* Move forward in the string. */
407*eda6f593SDavid van Moolenbroek 		buf++; len--;
408*eda6f593SDavid van Moolenbroek 		(*size)++;
409*eda6f593SDavid van Moolenbroek 
410*eda6f593SDavid van Moolenbroek 		/* At the end of the string, return the current node. */
411*eda6f593SDavid van Moolenbroek 		if (len == 0 || (tk->next == NULL && tk->key != KEYC_NONE))
412*eda6f593SDavid van Moolenbroek 			return (tk);
413*eda6f593SDavid van Moolenbroek 
414*eda6f593SDavid van Moolenbroek 		/* Move into the next tree for the following character. */
415*eda6f593SDavid van Moolenbroek 		tk = tk->next;
416*eda6f593SDavid van Moolenbroek 	} else {
417*eda6f593SDavid van Moolenbroek 		if (*buf < tk->ch)
418*eda6f593SDavid van Moolenbroek 			tk = tk->left;
419*eda6f593SDavid van Moolenbroek 		else if (*buf > tk->ch)
420*eda6f593SDavid van Moolenbroek 			tk = tk->right;
421*eda6f593SDavid van Moolenbroek 	}
422*eda6f593SDavid van Moolenbroek 
423*eda6f593SDavid van Moolenbroek 	/* Move to the next in the tree. */
424*eda6f593SDavid van Moolenbroek 	return (tty_keys_find1(tk, buf, len, size));
425*eda6f593SDavid van Moolenbroek }
426*eda6f593SDavid van Moolenbroek 
427*eda6f593SDavid van Moolenbroek /*
428*eda6f593SDavid van Moolenbroek  * Process at least one key in the buffer and invoke tty->key_callback. Return
429*eda6f593SDavid van Moolenbroek  * 0 if there are no further keys, or 1 if there could be more in the buffer.
430*eda6f593SDavid van Moolenbroek  */
431*eda6f593SDavid van Moolenbroek int
432*eda6f593SDavid van Moolenbroek tty_keys_next(struct tty *tty)
433*eda6f593SDavid van Moolenbroek {
434*eda6f593SDavid van Moolenbroek 	struct tty_key		*tk;
435*eda6f593SDavid van Moolenbroek 	struct timeval		 tv;
436*eda6f593SDavid van Moolenbroek 	struct mouse_event	 mouse;
437*eda6f593SDavid van Moolenbroek 	const u_char		*buf;
438*eda6f593SDavid van Moolenbroek 	size_t			 len, size;
439*eda6f593SDavid van Moolenbroek 	cc_t			 bspace;
440*eda6f593SDavid van Moolenbroek 	int			 key, delay;
441*eda6f593SDavid van Moolenbroek 
442*eda6f593SDavid van Moolenbroek 	buf = EVBUFFER_DATA(tty->event->input);
443*eda6f593SDavid van Moolenbroek 	len = EVBUFFER_LENGTH(tty->event->input);
444*eda6f593SDavid van Moolenbroek 	if (len == 0)
445*eda6f593SDavid van Moolenbroek 		return (0);
446*eda6f593SDavid van Moolenbroek 	log_debug("keys are %zu (%.*s)", len, (int) len, buf);
447*eda6f593SDavid van Moolenbroek 
448*eda6f593SDavid van Moolenbroek 	/* If a normal key, return it. */
449*eda6f593SDavid van Moolenbroek 	if (*buf != '\033') {
450*eda6f593SDavid van Moolenbroek 		key = *buf;
451*eda6f593SDavid van Moolenbroek 		evbuffer_drain(tty->event->input, 1);
452*eda6f593SDavid van Moolenbroek 
453*eda6f593SDavid van Moolenbroek 		/*
454*eda6f593SDavid van Moolenbroek 		 * Check for backspace key using termios VERASE - the terminfo
455*eda6f593SDavid van Moolenbroek 		 * kbs entry is extremely unreliable, so cannot be safely
456*eda6f593SDavid van Moolenbroek 		 * used. termios should have a better idea.
457*eda6f593SDavid van Moolenbroek 		 */
458*eda6f593SDavid van Moolenbroek 		bspace = tty->tio.c_cc[VERASE];
459*eda6f593SDavid van Moolenbroek 		if (bspace != _POSIX_VDISABLE && key == bspace)
460*eda6f593SDavid van Moolenbroek 			key = KEYC_BSPACE;
461*eda6f593SDavid van Moolenbroek 		goto handle_key;
462*eda6f593SDavid van Moolenbroek 	}
463*eda6f593SDavid van Moolenbroek 
464*eda6f593SDavid van Moolenbroek 	/* Is this a mouse key press? */
465*eda6f593SDavid van Moolenbroek 	switch (tty_keys_mouse(tty, (const char *)buf, len, &size, &mouse)) {
466*eda6f593SDavid van Moolenbroek 	case 0:		/* yes */
467*eda6f593SDavid van Moolenbroek 		evbuffer_drain(tty->event->input, size);
468*eda6f593SDavid van Moolenbroek 		key = KEYC_MOUSE;
469*eda6f593SDavid van Moolenbroek 		goto handle_key;
470*eda6f593SDavid van Moolenbroek 	case -1:	/* no, or not valid */
471*eda6f593SDavid van Moolenbroek 		break;
472*eda6f593SDavid van Moolenbroek 	case 1:		/* partial */
473*eda6f593SDavid van Moolenbroek 		goto partial_key;
474*eda6f593SDavid van Moolenbroek 	}
475*eda6f593SDavid van Moolenbroek 
476*eda6f593SDavid van Moolenbroek 	/* Try to parse a key with an xterm-style modifier. */
477*eda6f593SDavid van Moolenbroek 	switch (xterm_keys_find((const char *)buf, len, &size, &key)) {
478*eda6f593SDavid van Moolenbroek 	case 0:		/* found */
479*eda6f593SDavid van Moolenbroek 		evbuffer_drain(tty->event->input, size);
480*eda6f593SDavid van Moolenbroek 		goto handle_key;
481*eda6f593SDavid van Moolenbroek 	case -1:	/* not found */
482*eda6f593SDavid van Moolenbroek 		break;
483*eda6f593SDavid van Moolenbroek 	case 1:
484*eda6f593SDavid van Moolenbroek 		goto partial_key;
485*eda6f593SDavid van Moolenbroek 	}
486*eda6f593SDavid van Moolenbroek 
487*eda6f593SDavid van Moolenbroek 	/* Look for matching key string and return if found. */
488*eda6f593SDavid van Moolenbroek 	tk = tty_keys_find(tty, (const char *)buf + 1, len - 1, &size);
489*eda6f593SDavid van Moolenbroek 	if (tk != NULL) {
490*eda6f593SDavid van Moolenbroek 		key = tk->key;
491*eda6f593SDavid van Moolenbroek 		goto found_key;
492*eda6f593SDavid van Moolenbroek 	}
493*eda6f593SDavid van Moolenbroek 
494*eda6f593SDavid van Moolenbroek 	/* Skip the escape. */
495*eda6f593SDavid van Moolenbroek 	buf++;
496*eda6f593SDavid van Moolenbroek 	len--;
497*eda6f593SDavid van Moolenbroek 
498*eda6f593SDavid van Moolenbroek 	/* Is there a normal key following? */
499*eda6f593SDavid van Moolenbroek 	if (len != 0 && *buf != '\033') {
500*eda6f593SDavid van Moolenbroek 		key = *buf | KEYC_ESCAPE;
501*eda6f593SDavid van Moolenbroek 		evbuffer_drain(tty->event->input, 2);
502*eda6f593SDavid van Moolenbroek 		goto handle_key;
503*eda6f593SDavid van Moolenbroek 	}
504*eda6f593SDavid van Moolenbroek 
505*eda6f593SDavid van Moolenbroek 	/* Or a key string? */
506*eda6f593SDavid van Moolenbroek 	if (len > 1) {
507*eda6f593SDavid van Moolenbroek 		tk = tty_keys_find(tty, (const char *)buf + 1, len - 1, &size);
508*eda6f593SDavid van Moolenbroek 		if (tk != NULL) {
509*eda6f593SDavid van Moolenbroek 			key = tk->key | KEYC_ESCAPE;
510*eda6f593SDavid van Moolenbroek 			size++;	/* include escape */
511*eda6f593SDavid van Moolenbroek 			goto found_key;
512*eda6f593SDavid van Moolenbroek 		}
513*eda6f593SDavid van Moolenbroek 	}
514*eda6f593SDavid van Moolenbroek 
515*eda6f593SDavid van Moolenbroek 	/* Escape and then nothing useful - fall through. */
516*eda6f593SDavid van Moolenbroek 
517*eda6f593SDavid van Moolenbroek partial_key:
518*eda6f593SDavid van Moolenbroek 	/*
519*eda6f593SDavid van Moolenbroek 	 * Escape but no key string. If have already seen an escape, then the
520*eda6f593SDavid van Moolenbroek 	 * timer must have expired, so give up waiting and send the escape.
521*eda6f593SDavid van Moolenbroek 	 */
522*eda6f593SDavid van Moolenbroek 	if (tty->flags & TTY_ESCAPE) {
523*eda6f593SDavid van Moolenbroek 		evbuffer_drain(tty->event->input, 1);
524*eda6f593SDavid van Moolenbroek 		key = '\033';
525*eda6f593SDavid van Moolenbroek 		goto handle_key;
526*eda6f593SDavid van Moolenbroek 	}
527*eda6f593SDavid van Moolenbroek 
528*eda6f593SDavid van Moolenbroek 	/* Fall through to start the timer. */
529*eda6f593SDavid van Moolenbroek 
530*eda6f593SDavid van Moolenbroek start_timer:
531*eda6f593SDavid van Moolenbroek 	/* Start the timer and wait for expiry or more data. */
532*eda6f593SDavid van Moolenbroek 	delay = options_get_number(&global_options, "escape-time");
533*eda6f593SDavid van Moolenbroek 	tv.tv_sec = delay / 1000;
534*eda6f593SDavid van Moolenbroek 	tv.tv_usec = (delay % 1000) * 1000L;
535*eda6f593SDavid van Moolenbroek 
536*eda6f593SDavid van Moolenbroek 	evtimer_del(&tty->key_timer);
537*eda6f593SDavid van Moolenbroek 	evtimer_set(&tty->key_timer, tty_keys_callback, tty);
538*eda6f593SDavid van Moolenbroek 	evtimer_add(&tty->key_timer, &tv);
539*eda6f593SDavid van Moolenbroek 
540*eda6f593SDavid van Moolenbroek 	tty->flags |= TTY_ESCAPE;
541*eda6f593SDavid van Moolenbroek 	return (0);
542*eda6f593SDavid van Moolenbroek 
543*eda6f593SDavid van Moolenbroek found_key:
544*eda6f593SDavid van Moolenbroek 	if (tk->next != NULL) {
545*eda6f593SDavid van Moolenbroek 		/* Partial key. Start the timer if not already expired. */
546*eda6f593SDavid van Moolenbroek 		if (!(tty->flags & TTY_ESCAPE))
547*eda6f593SDavid van Moolenbroek 			goto start_timer;
548*eda6f593SDavid van Moolenbroek 
549*eda6f593SDavid van Moolenbroek 		/* Otherwise, if no key, send the escape alone. */
550*eda6f593SDavid van Moolenbroek 		if (tk->key == KEYC_NONE)
551*eda6f593SDavid van Moolenbroek 			goto partial_key;
552*eda6f593SDavid van Moolenbroek 
553*eda6f593SDavid van Moolenbroek 		/* Or fall through to send the partial key found. */
554*eda6f593SDavid van Moolenbroek 	}
555*eda6f593SDavid van Moolenbroek 	evbuffer_drain(tty->event->input, size + 1);
556*eda6f593SDavid van Moolenbroek 
557*eda6f593SDavid van Moolenbroek 	goto handle_key;
558*eda6f593SDavid van Moolenbroek 
559*eda6f593SDavid van Moolenbroek handle_key:
560*eda6f593SDavid van Moolenbroek 	evtimer_del(&tty->key_timer);
561*eda6f593SDavid van Moolenbroek 
562*eda6f593SDavid van Moolenbroek 	tty->key_callback(key, &mouse, tty->key_data);
563*eda6f593SDavid van Moolenbroek 
564*eda6f593SDavid van Moolenbroek 	tty->flags &= ~TTY_ESCAPE;
565*eda6f593SDavid van Moolenbroek 	return (1);
566*eda6f593SDavid van Moolenbroek }
567*eda6f593SDavid van Moolenbroek 
568*eda6f593SDavid van Moolenbroek /* Key timer callback. */
569*eda6f593SDavid van Moolenbroek /* ARGSUSED */
570*eda6f593SDavid van Moolenbroek void
571*eda6f593SDavid van Moolenbroek tty_keys_callback(unused int fd, unused short events, void *data)
572*eda6f593SDavid van Moolenbroek {
573*eda6f593SDavid van Moolenbroek 	struct tty	*tty = data;
574*eda6f593SDavid van Moolenbroek 
575*eda6f593SDavid van Moolenbroek 	if (!(tty->flags & TTY_ESCAPE))
576*eda6f593SDavid van Moolenbroek 		return;
577*eda6f593SDavid van Moolenbroek 
578*eda6f593SDavid van Moolenbroek 	while (tty_keys_next(tty))
579*eda6f593SDavid van Moolenbroek 		;
580*eda6f593SDavid van Moolenbroek }
581*eda6f593SDavid van Moolenbroek 
582*eda6f593SDavid van Moolenbroek /*
583*eda6f593SDavid van Moolenbroek  * Handle mouse key input. Returns 0 for success, -1 for failure, 1 for partial
584*eda6f593SDavid van Moolenbroek  * (probably a mouse sequence but need more data).
585*eda6f593SDavid van Moolenbroek  */
586*eda6f593SDavid van Moolenbroek int
587*eda6f593SDavid van Moolenbroek tty_keys_mouse(struct tty *tty,
588*eda6f593SDavid van Moolenbroek     const char *buf, size_t len, size_t *size, struct mouse_event *m)
589*eda6f593SDavid van Moolenbroek {
590*eda6f593SDavid van Moolenbroek 	struct utf8_data	utf8data;
591*eda6f593SDavid van Moolenbroek 	u_int			i, value;
592*eda6f593SDavid van Moolenbroek 
593*eda6f593SDavid van Moolenbroek 	/*
594*eda6f593SDavid van Moolenbroek 	 * Standard mouse sequences are \033[M followed by three characters
595*eda6f593SDavid van Moolenbroek 	 * indicating buttons, X and Y, all based at 32 with 1,1 top-left.
596*eda6f593SDavid van Moolenbroek 	 *
597*eda6f593SDavid van Moolenbroek 	 * UTF-8 mouse sequences are similar but the three are expressed as
598*eda6f593SDavid van Moolenbroek 	 * UTF-8 characters.
599*eda6f593SDavid van Moolenbroek 	 */
600*eda6f593SDavid van Moolenbroek 
601*eda6f593SDavid van Moolenbroek 	*size = 0;
602*eda6f593SDavid van Moolenbroek 
603*eda6f593SDavid van Moolenbroek 	/* First three bytes are always \033[M. */
604*eda6f593SDavid van Moolenbroek 	if (buf[0] != '\033')
605*eda6f593SDavid van Moolenbroek 		return (-1);
606*eda6f593SDavid van Moolenbroek 	if (len == 1)
607*eda6f593SDavid van Moolenbroek 		return (1);
608*eda6f593SDavid van Moolenbroek 	if (buf[1] != '[')
609*eda6f593SDavid van Moolenbroek 		return (-1);
610*eda6f593SDavid van Moolenbroek 	if (len == 2)
611*eda6f593SDavid van Moolenbroek 		return (1);
612*eda6f593SDavid van Moolenbroek 	if (buf[2] != 'M')
613*eda6f593SDavid van Moolenbroek 		return (-1);
614*eda6f593SDavid van Moolenbroek 	if (len == 3)
615*eda6f593SDavid van Moolenbroek 		return (1);
616*eda6f593SDavid van Moolenbroek 
617*eda6f593SDavid van Moolenbroek 	/* Read the three inputs. */
618*eda6f593SDavid van Moolenbroek 	*size = 3;
619*eda6f593SDavid van Moolenbroek 	for (i = 0; i < 3; i++) {
620*eda6f593SDavid van Moolenbroek 		if (len < *size)
621*eda6f593SDavid van Moolenbroek 			return (1);
622*eda6f593SDavid van Moolenbroek 
623*eda6f593SDavid van Moolenbroek 		if (tty->mode & MODE_MOUSE_UTF8) {
624*eda6f593SDavid van Moolenbroek 			if (utf8_open(&utf8data, buf[*size])) {
625*eda6f593SDavid van Moolenbroek 				if (utf8data.size != 2)
626*eda6f593SDavid van Moolenbroek 					return (-1);
627*eda6f593SDavid van Moolenbroek 				(*size)++;
628*eda6f593SDavid van Moolenbroek 				if (len < *size)
629*eda6f593SDavid van Moolenbroek 					return (1);
630*eda6f593SDavid van Moolenbroek 				utf8_append(&utf8data, buf[*size]);
631*eda6f593SDavid van Moolenbroek 				value = utf8_combine(&utf8data);
632*eda6f593SDavid van Moolenbroek 			} else
633*eda6f593SDavid van Moolenbroek 				value = (unsigned char)buf[*size];
634*eda6f593SDavid van Moolenbroek 			(*size)++;
635*eda6f593SDavid van Moolenbroek 		} else {
636*eda6f593SDavid van Moolenbroek 			value = (unsigned char)buf[*size];
637*eda6f593SDavid van Moolenbroek 			(*size)++;
638*eda6f593SDavid van Moolenbroek 		}
639*eda6f593SDavid van Moolenbroek 
640*eda6f593SDavid van Moolenbroek 		if (i == 0)
641*eda6f593SDavid van Moolenbroek 			m->b = value;
642*eda6f593SDavid van Moolenbroek 		else if (i == 1)
643*eda6f593SDavid van Moolenbroek 			m->x = value;
644*eda6f593SDavid van Moolenbroek 		else
645*eda6f593SDavid van Moolenbroek 			m->y = value;
646*eda6f593SDavid van Moolenbroek 	}
647*eda6f593SDavid van Moolenbroek 	log_debug("mouse input: %.*s", (int) *size, buf);
648*eda6f593SDavid van Moolenbroek 
649*eda6f593SDavid van Moolenbroek 	/* Check and return the mouse input. */
650*eda6f593SDavid van Moolenbroek 	if (m->b < 32 || m->x < 33 || m->y < 33)
651*eda6f593SDavid van Moolenbroek 		return (-1);
652*eda6f593SDavid van Moolenbroek 	m->b -= 32;
653*eda6f593SDavid van Moolenbroek 	m->x -= 33;
654*eda6f593SDavid van Moolenbroek 	m->y -= 33;
655*eda6f593SDavid van Moolenbroek 	log_debug("mouse position: x=%u y=%u b=%u", m->x, m->y, m->b);
656*eda6f593SDavid van Moolenbroek 	return (0);
657*eda6f593SDavid van Moolenbroek }
658