xref: /openbsd-src/usr.bin/tmux/key-string.c (revision 5054e3e78af0749a9bb00ba9a024b3ee2d90290f)
1 /* $OpenBSD: key-string.c,v 1.10 2009/11/10 17:24:43 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 <string.h>
22 
23 #include "tmux.h"
24 
25 int	key_string_search_table(const char *);
26 
27 struct {
28 	const char *string;
29 	int	 key;
30 } key_string_table[] = {
31 	/* Function keys. */
32 	{ "F1",		KEYC_F1 },
33 	{ "F2",		KEYC_F2 },
34 	{ "F3",		KEYC_F3 },
35 	{ "F4",		KEYC_F4 },
36 	{ "F5",		KEYC_F5 },
37 	{ "F6",		KEYC_F6 },
38 	{ "F7",		KEYC_F7 },
39 	{ "F8",		KEYC_F8 },
40 	{ "F9",		KEYC_F9 },
41 	{ "F10",	KEYC_F10 },
42 	{ "F11",	KEYC_F11 },
43 	{ "F12",	KEYC_F12 },
44 	{ "F13",	KEYC_F13 },
45 	{ "F14",	KEYC_F14 },
46 	{ "F15",	KEYC_F15 },
47 	{ "F16",	KEYC_F16 },
48 	{ "F17",	KEYC_F17 },
49 	{ "F18",	KEYC_F18 },
50 	{ "F19",	KEYC_F19 },
51 	{ "F20",	KEYC_F20 },
52 	{ "IC",		KEYC_IC },
53 	{ "DC",		KEYC_DC },
54 	{ "Home",	KEYC_HOME },
55 	{ "End",	KEYC_END },
56 	{ "NPage",	KEYC_NPAGE },
57 	{ "PPage",	KEYC_PPAGE },
58 	{ "Tab",	'\011' },
59 	{ "BTab",	KEYC_BTAB },
60 	{ "Space",	' ' },
61 	{ "BSpace",	KEYC_BSPACE },
62 	{ "Enter",	'\r' },
63 	{ "Escape",	'\033' },
64 
65 	/* Arrow keys. */
66 	{ "Up",		KEYC_UP },
67 	{ "Down",	KEYC_DOWN },
68 	{ "Left",	KEYC_LEFT },
69 	{ "Right",	KEYC_RIGHT },
70 
71 	/* Numeric keypad. */
72 	{ "KP/", 	KEYC_KP_SLASH },
73 	{ "KP*",	KEYC_KP_STAR },
74 	{ "KP-",	KEYC_KP_MINUS },
75 	{ "KP7",	KEYC_KP_SEVEN },
76 	{ "KP8",	KEYC_KP_EIGHT },
77 	{ "KP9",	KEYC_KP_NINE },
78 	{ "KP+",	KEYC_KP_PLUS },
79 	{ "KP4",	KEYC_KP_FOUR },
80 	{ "KP5",	KEYC_KP_FIVE },
81 	{ "KP6",	KEYC_KP_SIX },
82 	{ "KP1",	KEYC_KP_ONE },
83 	{ "KP2",	KEYC_KP_TWO },
84 	{ "KP3",	KEYC_KP_THREE },
85 	{ "KPEnter",	KEYC_KP_ENTER },
86 	{ "KP0",	KEYC_KP_ZERO },
87 	{ "KP.",	KEYC_KP_PERIOD },
88 };
89 
90 /* Find key string in table. */
91 int
92 key_string_search_table(const char *string)
93 {
94 	u_int	i;
95 
96 	for (i = 0; i < nitems(key_string_table); i++) {
97 		if (strcasecmp(string, key_string_table[i].string) == 0)
98 			return (key_string_table[i].key);
99 	}
100 	return (KEYC_NONE);
101 }
102 
103 /* Lookup a string and convert to a key value, handling C-/M-/S- prefix. */
104 int
105 key_string_lookup_string(const char *string)
106 {
107 	int	      	 key;
108 	const u_char	*ptr;
109 
110 	if (string[0] == '\0')
111 		return (KEYC_NONE);
112 	if (string[1] == '\0')
113 		return (string[0]);
114 
115 	ptr = NULL;
116 	if ((string[0] == 'C' || string[0] == 'c') && string[1] == '-')
117 		ptr = string + 2;
118 	else if (string[0] == '^')
119 		ptr = string + 1;
120 	if (ptr != NULL) {
121 		if (ptr[0] == '\0')
122 			return (KEYC_NONE);
123 		/*
124 		 * Lookup as a named key. If a function key (>= KEYC_BASE),
125 		 * return it with the ctrl modifier, otherwise fallthrough with
126 		 * the key value from the table (eg for C-Space). If not a
127 		 * named key, check for single character keys and try that.
128 		 */
129 		key = key_string_search_table(ptr);
130 		if (key != KEYC_NONE) {
131 			if (key >= KEYC_BASE)
132 				return (key | KEYC_CTRL);
133 		} else {
134 			if (ptr[1] != '\0')
135 				return (KEYC_NONE);
136 			key = ptr[0];
137 		}
138 
139 		/*
140 		 * Figure out if the single character in key is a valid ctrl
141 		 * key.
142 		 */
143 		if (key == 32)
144 			return (0);
145 		if (key == 63)
146 			return (KEYC_BSPACE);
147 		if (key >= 64 && key <= 95)
148 			return (key - 64);
149 		if (key >= 97 && key <= 122)
150 			return (key - 96);
151 		return (KEYC_NONE);
152 	}
153 
154 	if ((string[0] == 'M' || string[0] == 'm') && string[1] == '-') {
155 		ptr = string + 2;
156 		if (ptr[0] == '\0')
157 			return (KEYC_NONE);
158 		key = key_string_lookup_string(ptr);
159 		if (key != KEYC_NONE) {
160 			if (key >= KEYC_BASE)
161 				return (key | KEYC_ESCAPE);
162 		} else {
163 			if (ptr[1] == '\0')
164 				return (KEYC_NONE);
165 			key = ptr[0];
166 		}
167 
168 		if (key >= 32 && key <= 127)
169 			return (key | KEYC_ESCAPE);
170 		return (KEYC_NONE);
171 	}
172 
173 	return (key_string_search_table(string));
174 }
175 
176 /* Convert a key code into string format, with prefix if necessary. */
177 const char *
178 key_string_lookup_key(int key)
179 {
180 	static char tmp[24], tmp2[24];
181 	const char *s;
182 	u_int	    i;
183 
184 	if (key == 127)
185 		return (NULL);
186 
187 	if (key & KEYC_ESCAPE) {
188 		if ((s = key_string_lookup_key(key & ~KEYC_ESCAPE)) == NULL)
189 			return (NULL);
190 		xsnprintf(tmp2, sizeof tmp2, "M-%s", s);
191 		return (tmp2);
192 	}
193 	if (key & KEYC_CTRL) {
194 		if ((s = key_string_lookup_key(key & ~KEYC_CTRL)) == NULL)
195 			return (NULL);
196 		xsnprintf(tmp2, sizeof tmp2, "C-%s", s);
197 		return (tmp2);
198 	}
199 	if (key & KEYC_SHIFT) {
200 		if ((s = key_string_lookup_key(key & ~KEYC_SHIFT)) == NULL)
201 			return (NULL);
202 		xsnprintf(tmp2, sizeof tmp2, "S-%s", s);
203 		return (tmp2);
204 	}
205 
206 	for (i = 0; i < nitems(key_string_table); i++) {
207 		if (key == key_string_table[i].key)
208 			return (key_string_table[i].string);
209 	}
210 
211 	if (key >= 32 && key <= 255) {
212 		tmp[0] = key;
213 		tmp[1] = '\0';
214 		return (tmp);
215 	}
216 
217 	if (key >= 0 && key <= 32) {
218 		if (key == 0 || key > 26)
219 			xsnprintf(tmp, sizeof tmp, "C-%c", 64 + key);
220 		else
221 			xsnprintf(tmp, sizeof tmp, "C-%c", 96 + key);
222 		return (tmp);
223 	}
224 
225 	return (NULL);
226 }
227