1 /* $Id: xterm-keys.c,v 1.1.1.2 2011/08/17 18:40:05 jmmv Exp $ */ 2 3 /* 4 * Copyright (c) 2009 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 <string.h> 22 23 #include "tmux.h" 24 25 /* 26 * xterm-style function keys append one of the following values before the last 27 * character: 28 * 29 * 2 Shift 30 * 3 Alt 31 * 4 Shift + Alt 32 * 5 Ctrl 33 * 6 Shift + Ctrl 34 * 7 Alt + Ctrl 35 * 8 Shift + Alt + Ctrl 36 * 37 * Rather than parsing them, just match against a table. 38 * 39 * There are three forms for F1-F4 (\\033O_P and \\033O1;_P and \\033[1;_P). 40 * We accept any but always output the latter (it comes first in the table). 41 */ 42 43 int xterm_keys_match(const char *, const char *, size_t); 44 int xterm_keys_modifiers(const char *, const char *, size_t); 45 46 struct xterm_keys_entry { 47 int key; 48 const char *template; 49 }; 50 51 const struct xterm_keys_entry xterm_keys_table[] = { 52 { KEYC_F1, "\033[1;_P" }, 53 { KEYC_F1, "\033O1;_P" }, 54 { KEYC_F1, "\033O_P" }, 55 { KEYC_F2, "\033[1;_Q" }, 56 { KEYC_F2, "\033O1;_Q" }, 57 { KEYC_F2, "\033O_Q" }, 58 { KEYC_F3, "\033[1;_R" }, 59 { KEYC_F3, "\033O1;_R" }, 60 { KEYC_F3, "\033O_R" }, 61 { KEYC_F4, "\033[1;_S" }, 62 { KEYC_F4, "\033O1;_S" }, 63 { KEYC_F4, "\033O_S" }, 64 { KEYC_F5, "\033[15;_~" }, 65 { KEYC_F6, "\033[17;_~" }, 66 { KEYC_F7, "\033[18;_~" }, 67 { KEYC_F8, "\033[19;_~" }, 68 { KEYC_F9, "\033[20;_~" }, 69 { KEYC_F10, "\033[21;_~" }, 70 { KEYC_F11, "\033[23;_~" }, 71 { KEYC_F12, "\033[24;_~" }, 72 { KEYC_F13, "\033[25;_~" }, 73 { KEYC_F14, "\033[26;_~" }, 74 { KEYC_F15, "\033[28;_~" }, 75 { KEYC_F16, "\033[29;_~" }, 76 { KEYC_F17, "\033[31;_~" }, 77 { KEYC_F18, "\033[32;_~" }, 78 { KEYC_F19, "\033[33;_~" }, 79 { KEYC_F20, "\033[34;_~" }, 80 { KEYC_UP, "\033[1;_A" }, 81 { KEYC_DOWN, "\033[1;_B" }, 82 { KEYC_RIGHT, "\033[1;_C" }, 83 { KEYC_LEFT, "\033[1;_D" }, 84 { KEYC_HOME, "\033[1;_H" }, 85 { KEYC_END, "\033[1;_F" }, 86 { KEYC_PPAGE, "\033[5;_~" }, 87 { KEYC_NPAGE, "\033[6;_~" }, 88 { KEYC_IC, "\033[2;_~" }, 89 { KEYC_DC, "\033[3;_~" }, 90 }; 91 92 /* 93 * Match key against buffer, treating _ as a wildcard. Return -1 for no match, 94 * 0 for match, 1 if the end of the buffer is reached (need more data). 95 */ 96 int 97 xterm_keys_match(const char *template, const char *buf, size_t len) 98 { 99 size_t pos; 100 101 if (len == 0) 102 return (0); 103 104 pos = 0; 105 do { 106 if (*template != '_' && buf[pos] != *template) 107 return (-1); 108 } while (pos++ != len && *++template != '\0'); 109 110 if (*template != '\0') /* partial */ 111 return (1); 112 113 return (0); 114 } 115 116 /* Find modifiers based on template. */ 117 int 118 xterm_keys_modifiers(const char *template, const char *buf, size_t len) 119 { 120 size_t idx; 121 int param, modifiers; 122 123 idx = strcspn(template, "_"); 124 if (idx >= len) 125 return (0); 126 param = buf[idx] - '1'; 127 128 modifiers = 0; 129 if (param & 1) 130 modifiers |= KEYC_SHIFT; 131 if (param & 2) 132 modifiers |= KEYC_ESCAPE; 133 if (param & 4) 134 modifiers |= KEYC_CTRL; 135 if (param & 8) 136 modifiers |= KEYC_ESCAPE; 137 return (modifiers); 138 } 139 140 /* 141 * Lookup key from a buffer against the table. Returns 0 for found (and the 142 * key), -1 for not found, 1 for partial match. 143 */ 144 int 145 xterm_keys_find(const char *buf, size_t len, size_t *size, int *key) 146 { 147 const struct xterm_keys_entry *entry; 148 u_int i; 149 150 for (i = 0; i < nitems(xterm_keys_table); i++) { 151 entry = &xterm_keys_table[i]; 152 switch (xterm_keys_match(entry->template, buf, len)) { 153 case 0: 154 *size = strlen(entry->template); 155 *key = entry->key; 156 *key |= xterm_keys_modifiers(entry->template, buf, len); 157 return (0); 158 case 1: 159 return (1); 160 } 161 } 162 return (-1); 163 } 164 165 /* Lookup a key number from the table. */ 166 char * 167 xterm_keys_lookup(int key) 168 { 169 const struct xterm_keys_entry *entry; 170 u_int i; 171 int modifiers; 172 char *out; 173 174 modifiers = 1; 175 if (key & KEYC_SHIFT) 176 modifiers += 1; 177 if (key & KEYC_ESCAPE) 178 modifiers += 2; 179 if (key & KEYC_CTRL) 180 modifiers += 4; 181 182 /* 183 * If the key has no modifiers, return NULL and let it fall through to 184 * the normal lookup. 185 */ 186 if (modifiers == 1) 187 return (NULL); 188 189 /* Otherwise, find the key in the table. */ 190 key &= ~(KEYC_SHIFT|KEYC_ESCAPE|KEYC_CTRL); 191 for (i = 0; i < nitems(xterm_keys_table); i++) { 192 entry = &xterm_keys_table[i]; 193 if (key == entry->key) 194 break; 195 } 196 if (i == nitems(xterm_keys_table)) 197 return (NULL); 198 199 /* Copy the template and replace the modifier. */ 200 out = xstrdup(entry->template); 201 out[strcspn(out, "_")] = '0' + modifiers; 202 return (out); 203 } 204