key-string.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. /* $OpenBSD$ */
  2. /*
  3. * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
  14. * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
  15. * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. #include <sys/types.h>
  18. #include <string.h>
  19. #include "tmux.h"
  20. static key_code key_string_search_table(const char *);
  21. static key_code key_string_get_modifiers(const char **);
  22. const struct {
  23. const char *string;
  24. key_code key;
  25. } key_string_table[] = {
  26. /* Function keys. */
  27. { "F1", KEYC_F1 },
  28. { "F2", KEYC_F2 },
  29. { "F3", KEYC_F3 },
  30. { "F4", KEYC_F4 },
  31. { "F5", KEYC_F5 },
  32. { "F6", KEYC_F6 },
  33. { "F7", KEYC_F7 },
  34. { "F8", KEYC_F8 },
  35. { "F9", KEYC_F9 },
  36. { "F10", KEYC_F10 },
  37. { "F11", KEYC_F11 },
  38. { "F12", KEYC_F12 },
  39. { "IC", KEYC_IC },
  40. { "DC", KEYC_DC },
  41. { "Home", KEYC_HOME },
  42. { "End", KEYC_END },
  43. { "NPage", KEYC_NPAGE },
  44. { "PageDown", KEYC_NPAGE },
  45. { "PgDn", KEYC_NPAGE },
  46. { "PPage", KEYC_PPAGE },
  47. { "PageUp", KEYC_PPAGE },
  48. { "PgUp", KEYC_PPAGE },
  49. { "Tab", '\011' },
  50. { "BTab", KEYC_BTAB },
  51. { "Space", ' ' },
  52. { "BSpace", KEYC_BSPACE },
  53. { "Enter", '\r' },
  54. { "Escape", '\033' },
  55. /* Arrow keys. */
  56. { "Up", KEYC_UP },
  57. { "Down", KEYC_DOWN },
  58. { "Left", KEYC_LEFT },
  59. { "Right", KEYC_RIGHT },
  60. /* Numeric keypad. */
  61. { "KP/", KEYC_KP_SLASH },
  62. { "KP*", KEYC_KP_STAR },
  63. { "KP-", KEYC_KP_MINUS },
  64. { "KP7", KEYC_KP_SEVEN },
  65. { "KP8", KEYC_KP_EIGHT },
  66. { "KP9", KEYC_KP_NINE },
  67. { "KP+", KEYC_KP_PLUS },
  68. { "KP4", KEYC_KP_FOUR },
  69. { "KP5", KEYC_KP_FIVE },
  70. { "KP6", KEYC_KP_SIX },
  71. { "KP1", KEYC_KP_ONE },
  72. { "KP2", KEYC_KP_TWO },
  73. { "KP3", KEYC_KP_THREE },
  74. { "KPEnter", KEYC_KP_ENTER },
  75. { "KP0", KEYC_KP_ZERO },
  76. { "KP.", KEYC_KP_PERIOD },
  77. /* Mouse keys. */
  78. KEYC_MOUSE_STRING(MOUSEDOWN1, MouseDown1),
  79. KEYC_MOUSE_STRING(MOUSEDOWN2, MouseDown2),
  80. KEYC_MOUSE_STRING(MOUSEDOWN3, MouseDown3),
  81. KEYC_MOUSE_STRING(MOUSEUP1, MouseUp1),
  82. KEYC_MOUSE_STRING(MOUSEUP2, MouseUp2),
  83. KEYC_MOUSE_STRING(MOUSEUP3, MouseUp3),
  84. KEYC_MOUSE_STRING(MOUSEDRAG1, MouseDrag1),
  85. KEYC_MOUSE_STRING(MOUSEDRAG2, MouseDrag2),
  86. KEYC_MOUSE_STRING(MOUSEDRAG3, MouseDrag3),
  87. KEYC_MOUSE_STRING(MOUSEDRAGEND1, MouseDragEnd1),
  88. KEYC_MOUSE_STRING(MOUSEDRAGEND2, MouseDragEnd2),
  89. KEYC_MOUSE_STRING(MOUSEDRAGEND3, MouseDragEnd3),
  90. KEYC_MOUSE_STRING(WHEELUP, WheelUp),
  91. KEYC_MOUSE_STRING(WHEELDOWN, WheelDown),
  92. };
  93. /* Find key string in table. */
  94. static key_code
  95. key_string_search_table(const char *string)
  96. {
  97. u_int i;
  98. for (i = 0; i < nitems(key_string_table); i++) {
  99. if (strcasecmp(string, key_string_table[i].string) == 0)
  100. return (key_string_table[i].key);
  101. }
  102. return (KEYC_UNKNOWN);
  103. }
  104. /* Find modifiers. */
  105. static key_code
  106. key_string_get_modifiers(const char **string)
  107. {
  108. key_code modifiers;
  109. modifiers = 0;
  110. while (((*string)[0] != '\0') && (*string)[1] == '-') {
  111. switch ((*string)[0]) {
  112. case 'C':
  113. case 'c':
  114. modifiers |= KEYC_CTRL;
  115. break;
  116. case 'M':
  117. case 'm':
  118. modifiers |= KEYC_ESCAPE;
  119. break;
  120. case 'S':
  121. case 's':
  122. modifiers |= KEYC_SHIFT;
  123. break;
  124. }
  125. *string += 2;
  126. }
  127. return (modifiers);
  128. }
  129. /* Lookup a string and convert to a key value. */
  130. key_code
  131. key_string_lookup_string(const char *string)
  132. {
  133. static const char *other = "!#()+,-.0123456789:;<=>?'\r\t";
  134. key_code key;
  135. u_short u;
  136. int size;
  137. key_code modifiers;
  138. struct utf8_data ud;
  139. u_int i;
  140. enum utf8_state more;
  141. wchar_t wc;
  142. /* Is this no key? */
  143. if (strcasecmp(string, "None") == 0)
  144. return (KEYC_NONE);
  145. /* Is this a hexadecimal value? */
  146. if (string[0] == '0' && string[1] == 'x') {
  147. if (sscanf(string + 2, "%hx%n", &u, &size) != 1 || size > 4)
  148. return (KEYC_UNKNOWN);
  149. return (u);
  150. }
  151. /* Check for modifiers. */
  152. modifiers = 0;
  153. if (string[0] == '^' && string[1] != '\0') {
  154. modifiers |= KEYC_CTRL;
  155. string++;
  156. }
  157. modifiers |= key_string_get_modifiers(&string);
  158. if (string[0] == '\0')
  159. return (KEYC_UNKNOWN);
  160. /* Is this a standard ASCII key? */
  161. if (string[1] == '\0' && (u_char)string[0] <= 127) {
  162. key = (u_char)string[0];
  163. if (key < 32 || key == 127)
  164. return (KEYC_UNKNOWN);
  165. } else {
  166. /* Try as a UTF-8 key. */
  167. if ((more = utf8_open(&ud, (u_char)*string)) == UTF8_MORE) {
  168. if (strlen(string) != ud.size)
  169. return (KEYC_UNKNOWN);
  170. for (i = 1; i < ud.size; i++)
  171. more = utf8_append(&ud, (u_char)string[i]);
  172. if (more != UTF8_DONE)
  173. return (KEYC_UNKNOWN);
  174. if (utf8_combine(&ud, &wc) != UTF8_DONE)
  175. return (KEYC_UNKNOWN);
  176. return (wc | modifiers);
  177. }
  178. /* Otherwise look the key up in the table. */
  179. key = key_string_search_table(string);
  180. if (key == KEYC_UNKNOWN)
  181. return (KEYC_UNKNOWN);
  182. }
  183. /* Convert the standard control keys. */
  184. if (key < KEYC_BASE && (modifiers & KEYC_CTRL) && !strchr(other, key)) {
  185. if (key >= 97 && key <= 122)
  186. key -= 96;
  187. else if (key >= 64 && key <= 95)
  188. key -= 64;
  189. else if (key == 32)
  190. key = 0;
  191. else if (key == 63)
  192. key = KEYC_BSPACE;
  193. else
  194. return (KEYC_UNKNOWN);
  195. modifiers &= ~KEYC_CTRL;
  196. }
  197. return (key | modifiers);
  198. }
  199. /* Convert a key code into string format, with prefix if necessary. */
  200. const char *
  201. key_string_lookup_key(key_code key)
  202. {
  203. static char out[24];
  204. char tmp[8];
  205. u_int i;
  206. struct utf8_data ud;
  207. *out = '\0';
  208. /* Handle no key. */
  209. if (key == KEYC_NONE)
  210. return ("None");
  211. /* Handle special keys. */
  212. if (key == KEYC_UNKNOWN)
  213. return ("Unknown");
  214. if (key == KEYC_MOUSE)
  215. return ("Mouse");
  216. /*
  217. * Special case: display C-@ as C-Space. Could do this below in
  218. * the (key >= 0 && key <= 32), but this way we let it be found
  219. * in key_string_table, for the unlikely chance that we might
  220. * change its name.
  221. */
  222. if ((key & KEYC_MASK_KEY) == 0)
  223. key = ' ' | KEYC_CTRL | (key & KEYC_MASK_MOD);
  224. /* Fill in the modifiers. */
  225. if (key & KEYC_CTRL)
  226. strlcat(out, "C-", sizeof out);
  227. if (key & KEYC_ESCAPE)
  228. strlcat(out, "M-", sizeof out);
  229. if (key & KEYC_SHIFT)
  230. strlcat(out, "S-", sizeof out);
  231. key &= KEYC_MASK_KEY;
  232. /* Try the key against the string table. */
  233. for (i = 0; i < nitems(key_string_table); i++) {
  234. if (key == key_string_table[i].key)
  235. break;
  236. }
  237. if (i != nitems(key_string_table)) {
  238. strlcat(out, key_string_table[i].string, sizeof out);
  239. return (out);
  240. }
  241. /* Is this a UTF-8 key? */
  242. if (key > 127 && key < KEYC_BASE) {
  243. if (utf8_split(key, &ud) == UTF8_DONE) {
  244. memcpy(out, ud.data, ud.size);
  245. out[ud.size] = '\0';
  246. return (out);
  247. }
  248. }
  249. /* Invalid keys are errors. */
  250. if (key == 127 || key > 255) {
  251. snprintf(out, sizeof out, "Invalid#%llx", key);
  252. return (out);
  253. }
  254. /* Check for standard or control key. */
  255. if (key <= 32) {
  256. if (key == 0 || key > 26)
  257. xsnprintf(tmp, sizeof tmp, "C-%c", (int)(64 + key));
  258. else
  259. xsnprintf(tmp, sizeof tmp, "C-%c", (int)(96 + key));
  260. } else if (key >= 32 && key <= 126) {
  261. tmp[0] = key;
  262. tmp[1] = '\0';
  263. } else if (key >= 128)
  264. xsnprintf(tmp, sizeof tmp, "\\%llo", key);
  265. strlcat(out, tmp, sizeof out);
  266. return (out);
  267. }