tmux  3.2a
About: tmux is a terminal multiplexer that lets you switch easily between several programs in one terminal.
  Fossies Dox: tmux-3.2a.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

key-string.c
Go to the documentation of this file.
1 /* $OpenBSD$ */
2 
3 /*
4  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
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 <stdlib.h>
22 #include <string.h>
23 #include <wchar.h>
24 
25 #include "tmux.h"
26 
27 static key_code key_string_search_table(const char *);
28 static key_code key_string_get_modifiers(const char **);
29 
30 static const struct {
31  const char *string;
33 } key_string_table[] = {
34  /* Function keys. */
35  { "F1", KEYC_F1|KEYC_IMPLIED_META },
36  { "F2", KEYC_F2|KEYC_IMPLIED_META },
37  { "F3", KEYC_F3|KEYC_IMPLIED_META },
38  { "F4", KEYC_F4|KEYC_IMPLIED_META },
39  { "F5", KEYC_F5|KEYC_IMPLIED_META },
40  { "F6", KEYC_F6|KEYC_IMPLIED_META },
41  { "F7", KEYC_F7|KEYC_IMPLIED_META },
42  { "F8", KEYC_F8|KEYC_IMPLIED_META },
43  { "F9", KEYC_F9|KEYC_IMPLIED_META },
44  { "F10", KEYC_F10|KEYC_IMPLIED_META },
45  { "F11", KEYC_F11|KEYC_IMPLIED_META },
46  { "F12", KEYC_F12|KEYC_IMPLIED_META },
47  { "IC", KEYC_IC|KEYC_IMPLIED_META },
48  { "Insert", KEYC_IC|KEYC_IMPLIED_META },
49  { "DC", KEYC_DC|KEYC_IMPLIED_META },
50  { "Delete", KEYC_DC|KEYC_IMPLIED_META },
51  { "Home", KEYC_HOME|KEYC_IMPLIED_META },
52  { "End", KEYC_END|KEYC_IMPLIED_META },
53  { "NPage", KEYC_NPAGE|KEYC_IMPLIED_META },
54  { "PageDown", KEYC_NPAGE|KEYC_IMPLIED_META },
55  { "PgDn", KEYC_NPAGE|KEYC_IMPLIED_META },
56  { "PPage", KEYC_PPAGE|KEYC_IMPLIED_META },
57  { "PageUp", KEYC_PPAGE|KEYC_IMPLIED_META },
58  { "PgUp", KEYC_PPAGE|KEYC_IMPLIED_META },
59  { "Tab", '\011' },
60  { "BTab", KEYC_BTAB },
61  { "Space", ' ' },
62  { "BSpace", KEYC_BSPACE },
63  { "Enter", '\r' },
64  { "Escape", '\033' },
65 
66  /* Arrow keys. */
71 
72  /* Numeric keypad. */
73  { "KP/", KEYC_KP_SLASH|KEYC_KEYPAD },
74  { "KP*", KEYC_KP_STAR|KEYC_KEYPAD },
75  { "KP-", KEYC_KP_MINUS|KEYC_KEYPAD },
76  { "KP7", KEYC_KP_SEVEN|KEYC_KEYPAD },
77  { "KP8", KEYC_KP_EIGHT|KEYC_KEYPAD },
78  { "KP9", KEYC_KP_NINE|KEYC_KEYPAD },
79  { "KP+", KEYC_KP_PLUS|KEYC_KEYPAD },
80  { "KP4", KEYC_KP_FOUR|KEYC_KEYPAD },
81  { "KP5", KEYC_KP_FIVE|KEYC_KEYPAD },
82  { "KP6", KEYC_KP_SIX|KEYC_KEYPAD },
83  { "KP1", KEYC_KP_ONE|KEYC_KEYPAD },
84  { "KP2", KEYC_KP_TWO|KEYC_KEYPAD },
85  { "KP3", KEYC_KP_THREE|KEYC_KEYPAD },
86  { "KPEnter", KEYC_KP_ENTER|KEYC_KEYPAD },
87  { "KP0", KEYC_KP_ZERO|KEYC_KEYPAD },
88  { "KP.", KEYC_KP_PERIOD|KEYC_KEYPAD },
89 
90  /* Mouse keys. */
91  KEYC_MOUSE_STRING(MOUSEDOWN1, MouseDown1),
92  KEYC_MOUSE_STRING(MOUSEDOWN2, MouseDown2),
93  KEYC_MOUSE_STRING(MOUSEDOWN3, MouseDown3),
94  KEYC_MOUSE_STRING(MOUSEUP1, MouseUp1),
95  KEYC_MOUSE_STRING(MOUSEUP2, MouseUp2),
96  KEYC_MOUSE_STRING(MOUSEUP3, MouseUp3),
97  KEYC_MOUSE_STRING(MOUSEDRAG1, MouseDrag1),
98  KEYC_MOUSE_STRING(MOUSEDRAG2, MouseDrag2),
99  KEYC_MOUSE_STRING(MOUSEDRAG3, MouseDrag3),
100  KEYC_MOUSE_STRING(MOUSEDRAGEND1, MouseDragEnd1),
101  KEYC_MOUSE_STRING(MOUSEDRAGEND2, MouseDragEnd2),
102  KEYC_MOUSE_STRING(MOUSEDRAGEND3, MouseDragEnd3),
103  KEYC_MOUSE_STRING(WHEELUP, WheelUp),
104  KEYC_MOUSE_STRING(WHEELDOWN, WheelDown),
105  KEYC_MOUSE_STRING(SECONDCLICK1, SecondClick1),
106  KEYC_MOUSE_STRING(SECONDCLICK2, SecondClick2),
107  KEYC_MOUSE_STRING(SECONDCLICK3, SecondClick3),
108  KEYC_MOUSE_STRING(DOUBLECLICK1, DoubleClick1),
109  KEYC_MOUSE_STRING(DOUBLECLICK2, DoubleClick2),
110  KEYC_MOUSE_STRING(DOUBLECLICK3, DoubleClick3),
111  KEYC_MOUSE_STRING(TRIPLECLICK1, TripleClick1),
112  KEYC_MOUSE_STRING(TRIPLECLICK2, TripleClick2),
113  KEYC_MOUSE_STRING(TRIPLECLICK3, TripleClick3),
114 };
115 
116 /* Find key string in table. */
117 static key_code
118 key_string_search_table(const char *string)
119 {
120  u_int i, user;
121 
122  for (i = 0; i < nitems(key_string_table); i++) {
123  if (strcasecmp(string, key_string_table[i].string) == 0)
124  return (key_string_table[i].key);
125  }
126 
127  if (sscanf(string, "User%u", &user) == 1 && user < KEYC_NUSER)
128  return (KEYC_USER + user);
129 
130  return (KEYC_UNKNOWN);
131 }
132 
133 /* Find modifiers. */
134 static key_code
135 key_string_get_modifiers(const char **string)
136 {
137  key_code modifiers;
138 
139  modifiers = 0;
140  while (((*string)[0] != '\0') && (*string)[1] == '-') {
141  switch ((*string)[0]) {
142  case 'C':
143  case 'c':
144  modifiers |= KEYC_CTRL;
145  break;
146  case 'M':
147  case 'm':
148  modifiers |= KEYC_META;
149  break;
150  case 'S':
151  case 's':
152  modifiers |= KEYC_SHIFT;
153  break;
154  default:
155  *string = NULL;
156  return (0);
157  }
158  *string += 2;
159  }
160  return (modifiers);
161 }
162 
163 /* Lookup a string and convert to a key value. */
164 key_code
165 key_string_lookup_string(const char *string)
166 {
167  static const char *other = "!#()+,-.0123456789:;<=>'\r\t\177`/";
168  key_code key, modifiers;
169  u_int u, i;
170  struct utf8_data ud, *udp;
171  enum utf8_state more;
172  utf8_char uc;
173  char m[MB_LEN_MAX + 1];
174  int mlen;
175 
176  /* Is this no key or any key? */
177  if (strcasecmp(string, "None") == 0)
178  return (KEYC_NONE);
179  if (strcasecmp(string, "Any") == 0)
180  return (KEYC_ANY);
181 
182  /* Is this a hexadecimal value? */
183  if (string[0] == '0' && string[1] == 'x') {
184  if (sscanf(string + 2, "%x", &u) != 1)
185  return (KEYC_UNKNOWN);
186  mlen = wctomb(m, u);
187  if (mlen <= 0 || mlen > MB_LEN_MAX)
188  return (KEYC_UNKNOWN);
189  m[mlen] = '\0';
190 
191  udp = utf8_fromcstr(m);
192  if (udp == NULL ||
193  udp[0].size == 0 ||
194  udp[1].size != 0 ||
195  utf8_from_data(&udp[0], &uc) != UTF8_DONE) {
196  free(udp);
197  return (KEYC_UNKNOWN);
198  }
199  free(udp);
200  return (uc);
201  }
202 
203  /* Check for modifiers. */
204  modifiers = 0;
205  if (string[0] == '^' && string[1] != '\0') {
206  modifiers |= KEYC_CTRL;
207  string++;
208  }
209  modifiers |= key_string_get_modifiers(&string);
210  if (string == NULL || string[0] == '\0')
211  return (KEYC_UNKNOWN);
212 
213  /* Is this a standard ASCII key? */
214  if (string[1] == '\0' && (u_char)string[0] <= 127) {
215  key = (u_char)string[0];
216  if (key < 32)
217  return (KEYC_UNKNOWN);
218  } else {
219  /* Try as a UTF-8 key. */
220  if ((more = utf8_open(&ud, (u_char)*string)) == UTF8_MORE) {
221  if (strlen(string) != ud.size)
222  return (KEYC_UNKNOWN);
223  for (i = 1; i < ud.size; i++)
224  more = utf8_append(&ud, (u_char)string[i]);
225  if (more != UTF8_DONE)
226  return (KEYC_UNKNOWN);
227  if (utf8_from_data(&ud, &uc) != UTF8_DONE)
228  return (KEYC_UNKNOWN);
229  return (uc|modifiers);
230  }
231 
232  /* Otherwise look the key up in the table. */
233  key = key_string_search_table(string);
234  if (key == KEYC_UNKNOWN)
235  return (KEYC_UNKNOWN);
236  if (~modifiers & KEYC_META)
237  key &= ~~KEYC_IMPLIED_META;
238  }
239 
240  /* Convert the standard control keys. */
241  if (key <= 127 &&
242  (modifiers & KEYC_CTRL) &&
243  strchr(other, key) == NULL &&
244  key != 9 &&
245  key != 13 &&
246  key != 27) {
247  if (key >= 97 && key <= 122)
248  key -= 96;
249  else if (key >= 64 && key <= 95)
250  key -= 64;
251  else if (key == 32)
252  key = 0;
253  else if (key == 63)
254  key = 127;
255  else
256  return (KEYC_UNKNOWN);
257  modifiers &= ~~KEYC_CTRL;
258  }
259 
260  return (key|modifiers);
261 }
262 
263 /* Convert a key code into string format, with prefix if necessary. */
264 const char *
266 {
267  key_code saved = key;
268  static char out[64];
269  char tmp[8];
270  const char *s;
271  u_int i;
272  struct utf8_data ud;
273  size_t off;
274 
275  *out = '\0';
276 
277  /* Literal keys are themselves. */
278  if (key & KEYC_LITERAL) {
279  snprintf(out, sizeof out, "%c", (int)(key & 0xff));
280  goto out;
281  }
282 
283  /* Display C-@ as C-Space. */
284  if ((key & (KEYC_MASK_KEY|KEYC_MASK_MODIFIERS)) == 0)
285  key = ' '|KEYC_CTRL;
286 
287  /* Fill in the modifiers. */
288  if (key & KEYC_CTRL)
289  strlcat(out, "C-", sizeof out);
290  if (key & KEYC_META)
291  strlcat(out, "M-", sizeof out);
292  if (key & KEYC_SHIFT)
293  strlcat(out, "S-", sizeof out);
294  key &= KEYC_MASK_KEY;
295 
296  /* Handle no key. */
297  if (key == KEYC_NONE) {
298  s = "None";
299  goto append;
300  }
301 
302  /* Handle special keys. */
303  if (key == KEYC_UNKNOWN) {
304  s = "Unknown";
305  goto append;
306  }
307  if (key == KEYC_ANY) {
308  s = "Any";
309  goto append;
310  }
311  if (key == KEYC_FOCUS_IN) {
312  s = "FocusIn";
313  goto append;
314  }
315  if (key == KEYC_FOCUS_OUT) {
316  s = "FocusOut";
317  goto append;
318  }
319  if (key == KEYC_PASTE_START) {
320  s = "PasteStart";
321  goto append;
322  }
323  if (key == KEYC_PASTE_END) {
324  s = "PasteEnd";
325  goto append;
326  }
327  if (key == KEYC_MOUSE) {
328  s = "Mouse";
329  goto append;
330  }
331  if (key == KEYC_DRAGGING) {
332  s = "Dragging";
333  goto append;
334  }
335  if (key == KEYC_MOUSEMOVE_PANE) {
336  s = "MouseMovePane";
337  goto append;
338  }
339  if (key == KEYC_MOUSEMOVE_STATUS) {
340  s = "MouseMoveStatus";
341  goto append;
342  }
344  s = "MouseMoveStatusLeft";
345  goto append;
346  }
348  s = "MouseMoveStatusRight";
349  goto append;
350  }
351  if (key == KEYC_MOUSEMOVE_BORDER) {
352  s = "MouseMoveBorder";
353  goto append;
354  }
355  if (key >= KEYC_USER && key < KEYC_USER + KEYC_NUSER) {
356  snprintf(tmp, sizeof tmp, "User%u", (u_int)(key - KEYC_USER));
357  strlcat(out, tmp, sizeof out);
358  goto out;
359  }
360 
361  /* Try the key against the string table. */
362  for (i = 0; i < nitems(key_string_table); i++) {
363  if (key == (key_string_table[i].key & KEYC_MASK_KEY))
364  break;
365  }
366  if (i != nitems(key_string_table)) {
367  strlcat(out, key_string_table[i].string, sizeof out);
368  goto out;
369  }
370 
371  /* Is this a Unicode key? */
372  if (KEYC_IS_UNICODE(key)) {
373  utf8_to_data(key, &ud);
374  off = strlen(out);
375  memcpy(out + off, ud.data, ud.size);
376  out[off + ud.size] = '\0';
377  goto out;
378  }
379 
380  /* Invalid keys are errors. */
381  if (key > 255) {
382  snprintf(out, sizeof out, "Invalid#%llx", saved);
383  goto out;
384  }
385 
386  /* Check for standard or control key. */
387  if (key <= 32) {
388  if (key == 0 || key > 26)
389  xsnprintf(tmp, sizeof tmp, "C-%c", (int)(64 + key));
390  else
391  xsnprintf(tmp, sizeof tmp, "C-%c", (int)(96 + key));
392  } else if (key >= 32 && key <= 126) {
393  tmp[0] = key;
394  tmp[1] = '\0';
395  } else if (key == 127)
396  xsnprintf(tmp, sizeof tmp, "C-?");
397  else if (key >= 128)
398  xsnprintf(tmp, sizeof tmp, "\\%llo", key);
399 
400  strlcat(out, tmp, sizeof out);
401  goto out;
402 
403 append:
404  strlcat(out, s, sizeof out);
405 
406 out:
407  if (with_flags && (saved & KEYC_MASK_FLAGS) != 0) {
408  strlcat(out, "[", sizeof out);
409  if (saved & KEYC_LITERAL)
410  strlcat(out, "L", sizeof out);
411  if (saved & KEYC_KEYPAD)
412  strlcat(out, "K", sizeof out);
413  if (saved & KEYC_CURSOR)
414  strlcat(out, "C", sizeof out);
415  if (saved & KEYC_IMPLIED_META)
416  strlcat(out, "I", sizeof out);
417  if (saved & KEYC_BUILD_MODIFIERS)
418  strlcat(out, "B", sizeof out);
419  strlcat(out, "]", sizeof out);
420  }
421  return (out);
422 }
size_t strlcat(char *, const char *, size_t)
static key_code key_string_search_table(const char *)
Definition: key-string.c:118
key_code key_string_lookup_string(const char *string)
Definition: key-string.c:165
key_code key
Definition: key-string.c:32
static key_code key_string_get_modifiers(const char **)
Definition: key-string.c:135
const char * string
Definition: key-string.c:31
static const struct @8 key_string_table[]
const char * key_string_lookup_key(key_code key, int with_flags)
Definition: key-string.c:265
#define nitems(_a)
u_char data[21]
Definition: tmux.h:629
u_char size
Definition: tmux.h:632
#define KEYC_UNKNOWN
Definition: tmux.h:114
#define KEYC_MOUSE_STRING(name, s)
Definition: tmux.h:165
#define KEYC_META
Definition: tmux.h:124
#define KEYC_SHIFT
Definition: tmux.h:126
u_int utf8_char
Definition: tmux.h:620
#define KEYC_CTRL
Definition: tmux.h:125
enum utf8_state utf8_from_data(const struct utf8_data *, utf8_char *)
Definition: utf8.c:127
struct utf8_data * utf8_fromcstr(const char *)
Definition: utf8.c:472
#define KEYC_CURSOR
Definition: tmux.h:131
#define KEYC_BUILD_MODIFIERS
Definition: tmux.h:133
enum utf8_state utf8_open(struct utf8_data *, u_char)
Definition: utf8.c:266
#define KEYC_LITERAL
Definition: tmux.h:129
unsigned long long key_code
Definition: tmux.h:177
#define KEYC_NONE
Definition: tmux.h:113
void utf8_to_data(utf8_char, struct utf8_data *)
Definition: utf8.c:159
#define KEYC_KEYPAD
Definition: tmux.h:130
#define KEYC_MASK_FLAGS
Definition: tmux.h:137
#define KEYC_USER
Definition: tmux.h:121
#define KEYC_NUSER
Definition: tmux.h:141
utf8_state
Definition: tmux.h:636
@ UTF8_DONE
Definition: tmux.h:638
@ UTF8_MORE
Definition: tmux.h:637
@ KEYC_F6
Definition: tmux.h:230
@ KEYC_KP_FOUR
Definition: tmux.h:259
@ KEYC_HOME
Definition: tmux.h:239
@ KEYC_F5
Definition: tmux.h:229
@ KEYC_MOUSEMOVE_BORDER
Definition: tmux.h:196
@ KEYC_F7
Definition: tmux.h:231
@ KEYC_MOUSEMOVE_STATUS_RIGHT
Definition: tmux.h:196
@ KEYC_MOUSEMOVE_STATUS
Definition: tmux.h:196
@ KEYC_ANY
Definition: tmux.h:186
@ KEYC_UP
Definition: tmux.h:246
@ KEYC_MOUSE
Definition: tmux.h:193
@ KEYC_F11
Definition: tmux.h:235
@ KEYC_F12
Definition: tmux.h:236
@ KEYC_BTAB
Definition: tmux.h:243
@ KEYC_F2
Definition: tmux.h:226
@ KEYC_F9
Definition: tmux.h:233
@ KEYC_KP_PERIOD
Definition: tmux.h:267
@ KEYC_IC
Definition: tmux.h:237
@ KEYC_END
Definition: tmux.h:240
@ KEYC_KP_FIVE
Definition: tmux.h:260
@ KEYC_F4
Definition: tmux.h:228
@ KEYC_F1
Definition: tmux.h:225
@ KEYC_LEFT
Definition: tmux.h:248
@ KEYC_PPAGE
Definition: tmux.h:242
@ KEYC_KP_ZERO
Definition: tmux.h:266
@ KEYC_KP_STAR
Definition: tmux.h:253
@ KEYC_KP_THREE
Definition: tmux.h:264
@ KEYC_FOCUS_OUT
Definition: tmux.h:183
@ KEYC_DOWN
Definition: tmux.h:247
@ KEYC_F3
Definition: tmux.h:227
@ KEYC_KP_EIGHT
Definition: tmux.h:256
@ KEYC_KP_TWO
Definition: tmux.h:263
@ KEYC_KP_MINUS
Definition: tmux.h:254
@ KEYC_KP_PLUS
Definition: tmux.h:258
@ KEYC_KP_SIX
Definition: tmux.h:261
@ KEYC_PASTE_START
Definition: tmux.h:189
@ KEYC_F8
Definition: tmux.h:232
@ KEYC_BSPACE
Definition: tmux.h:222
@ KEYC_NPAGE
Definition: tmux.h:241
@ KEYC_KP_SEVEN
Definition: tmux.h:255
@ KEYC_DC
Definition: tmux.h:238
@ KEYC_DRAGGING
Definition: tmux.h:194
@ KEYC_KP_ENTER
Definition: tmux.h:265
@ KEYC_KP_SLASH
Definition: tmux.h:252
@ KEYC_PASTE_END
Definition: tmux.h:190
@ KEYC_KP_ONE
Definition: tmux.h:262
@ KEYC_MOUSEMOVE_STATUS_LEFT
Definition: tmux.h:196
@ KEYC_F10
Definition: tmux.h:234
@ KEYC_RIGHT
Definition: tmux.h:249
@ KEYC_FOCUS_IN
Definition: tmux.h:182
@ KEYC_MOUSEMOVE_PANE
Definition: tmux.h:196
@ KEYC_KP_NINE
Definition: tmux.h:257
#define KEYC_MASK_MODIFIERS
Definition: tmux.h:136
#define KEYC_IS_UNICODE(key)
Definition: tmux.h:149
#define KEYC_MASK_KEY
Definition: tmux.h:138
enum utf8_state utf8_append(struct utf8_data *, u_char)
Definition: utf8.c:283
#define KEYC_IMPLIED_META
Definition: tmux.h:132
int xsnprintf(char *str, size_t len, const char *fmt,...)
Definition: xmalloc.c:135