key-string.c revision 1.10
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
25int	key_string_search_table(const char *);
26
27struct {
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. */
91int
92key_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. */
104int
105key_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. */
177const char *
178key_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