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