Annotation of embedaddon/tmux/key-string.c, revision 1.1
1.1 ! misho 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 <string.h>
! 22:
! 23: #include "tmux.h"
! 24:
! 25: static key_code key_string_search_table(const char *);
! 26: static key_code key_string_get_modifiers(const char **);
! 27:
! 28: static const struct {
! 29: const char *string;
! 30: key_code key;
! 31: } key_string_table[] = {
! 32: /* Function keys. */
! 33: { "F1", KEYC_F1 },
! 34: { "F2", KEYC_F2 },
! 35: { "F3", KEYC_F3 },
! 36: { "F4", KEYC_F4 },
! 37: { "F5", KEYC_F5 },
! 38: { "F6", KEYC_F6 },
! 39: { "F7", KEYC_F7 },
! 40: { "F8", KEYC_F8 },
! 41: { "F9", KEYC_F9 },
! 42: { "F10", KEYC_F10 },
! 43: { "F11", KEYC_F11 },
! 44: { "F12", KEYC_F12 },
! 45: { "IC", KEYC_IC },
! 46: { "DC", KEYC_DC },
! 47: { "Home", KEYC_HOME },
! 48: { "End", KEYC_END },
! 49: { "NPage", KEYC_NPAGE },
! 50: { "PageDown", KEYC_NPAGE },
! 51: { "PgDn", KEYC_NPAGE },
! 52: { "PPage", KEYC_PPAGE },
! 53: { "PageUp", KEYC_PPAGE },
! 54: { "PgUp", KEYC_PPAGE },
! 55: { "Tab", '\011' },
! 56: { "BTab", KEYC_BTAB },
! 57: { "Space", ' ' },
! 58: { "BSpace", KEYC_BSPACE },
! 59: { "Enter", '\r' },
! 60: { "Escape", '\033' },
! 61:
! 62: /* Arrow keys. */
! 63: { "Up", KEYC_UP },
! 64: { "Down", KEYC_DOWN },
! 65: { "Left", KEYC_LEFT },
! 66: { "Right", KEYC_RIGHT },
! 67:
! 68: /* Numeric keypad. */
! 69: { "KP/", KEYC_KP_SLASH },
! 70: { "KP*", KEYC_KP_STAR },
! 71: { "KP-", KEYC_KP_MINUS },
! 72: { "KP7", KEYC_KP_SEVEN },
! 73: { "KP8", KEYC_KP_EIGHT },
! 74: { "KP9", KEYC_KP_NINE },
! 75: { "KP+", KEYC_KP_PLUS },
! 76: { "KP4", KEYC_KP_FOUR },
! 77: { "KP5", KEYC_KP_FIVE },
! 78: { "KP6", KEYC_KP_SIX },
! 79: { "KP1", KEYC_KP_ONE },
! 80: { "KP2", KEYC_KP_TWO },
! 81: { "KP3", KEYC_KP_THREE },
! 82: { "KPEnter", KEYC_KP_ENTER },
! 83: { "KP0", KEYC_KP_ZERO },
! 84: { "KP.", KEYC_KP_PERIOD },
! 85:
! 86: /* Mouse keys. */
! 87: KEYC_MOUSE_STRING(MOUSEDOWN1, MouseDown1),
! 88: KEYC_MOUSE_STRING(MOUSEDOWN2, MouseDown2),
! 89: KEYC_MOUSE_STRING(MOUSEDOWN3, MouseDown3),
! 90: KEYC_MOUSE_STRING(MOUSEUP1, MouseUp1),
! 91: KEYC_MOUSE_STRING(MOUSEUP2, MouseUp2),
! 92: KEYC_MOUSE_STRING(MOUSEUP3, MouseUp3),
! 93: KEYC_MOUSE_STRING(MOUSEDRAG1, MouseDrag1),
! 94: KEYC_MOUSE_STRING(MOUSEDRAG2, MouseDrag2),
! 95: KEYC_MOUSE_STRING(MOUSEDRAG3, MouseDrag3),
! 96: KEYC_MOUSE_STRING(MOUSEDRAGEND1, MouseDragEnd1),
! 97: KEYC_MOUSE_STRING(MOUSEDRAGEND2, MouseDragEnd2),
! 98: KEYC_MOUSE_STRING(MOUSEDRAGEND3, MouseDragEnd3),
! 99: KEYC_MOUSE_STRING(WHEELUP, WheelUp),
! 100: KEYC_MOUSE_STRING(WHEELDOWN, WheelDown),
! 101: KEYC_MOUSE_STRING(DOUBLECLICK1, DoubleClick1),
! 102: KEYC_MOUSE_STRING(DOUBLECLICK2, DoubleClick2),
! 103: KEYC_MOUSE_STRING(DOUBLECLICK3, DoubleClick3),
! 104: KEYC_MOUSE_STRING(TRIPLECLICK1, TripleClick1),
! 105: KEYC_MOUSE_STRING(TRIPLECLICK2, TripleClick2),
! 106: KEYC_MOUSE_STRING(TRIPLECLICK3, TripleClick3),
! 107: };
! 108:
! 109: /* Find key string in table. */
! 110: static key_code
! 111: key_string_search_table(const char *string)
! 112: {
! 113: u_int i;
! 114:
! 115: for (i = 0; i < nitems(key_string_table); i++) {
! 116: if (strcasecmp(string, key_string_table[i].string) == 0)
! 117: return (key_string_table[i].key);
! 118: }
! 119: return (KEYC_UNKNOWN);
! 120: }
! 121:
! 122: /* Find modifiers. */
! 123: static key_code
! 124: key_string_get_modifiers(const char **string)
! 125: {
! 126: key_code modifiers;
! 127:
! 128: modifiers = 0;
! 129: while (((*string)[0] != '\0') && (*string)[1] == '-') {
! 130: switch ((*string)[0]) {
! 131: case 'C':
! 132: case 'c':
! 133: modifiers |= KEYC_CTRL;
! 134: break;
! 135: case 'M':
! 136: case 'm':
! 137: modifiers |= KEYC_ESCAPE;
! 138: break;
! 139: case 'S':
! 140: case 's':
! 141: modifiers |= KEYC_SHIFT;
! 142: break;
! 143: default:
! 144: *string = NULL;
! 145: return (0);
! 146: }
! 147: *string += 2;
! 148: }
! 149: return (modifiers);
! 150: }
! 151:
! 152: /* Lookup a string and convert to a key value. */
! 153: key_code
! 154: key_string_lookup_string(const char *string)
! 155: {
! 156: static const char *other = "!#()+,-.0123456789:;<=>?'\r\t";
! 157: key_code key;
! 158: u_int u;
! 159: key_code modifiers;
! 160: struct utf8_data ud;
! 161: u_int i;
! 162: enum utf8_state more;
! 163: wchar_t wc;
! 164:
! 165: /* Is this no key? */
! 166: if (strcasecmp(string, "None") == 0)
! 167: return (KEYC_NONE);
! 168:
! 169: /* Is this a hexadecimal value? */
! 170: if (string[0] == '0' && string[1] == 'x') {
! 171: if (sscanf(string + 2, "%x", &u) != 1)
! 172: return (KEYC_UNKNOWN);
! 173: if (u > 0x1fffff)
! 174: return (KEYC_UNKNOWN);
! 175: return (u);
! 176: }
! 177:
! 178: /* Check for modifiers. */
! 179: modifiers = 0;
! 180: if (string[0] == '^' && string[1] != '\0') {
! 181: modifiers |= KEYC_CTRL;
! 182: string++;
! 183: }
! 184: modifiers |= key_string_get_modifiers(&string);
! 185: if (string == NULL || string[0] == '\0')
! 186: return (KEYC_UNKNOWN);
! 187:
! 188: /* Is this a standard ASCII key? */
! 189: if (string[1] == '\0' && (u_char)string[0] <= 127) {
! 190: key = (u_char)string[0];
! 191: if (key < 32 || key == 127)
! 192: return (KEYC_UNKNOWN);
! 193: } else {
! 194: /* Try as a UTF-8 key. */
! 195: if ((more = utf8_open(&ud, (u_char)*string)) == UTF8_MORE) {
! 196: if (strlen(string) != ud.size)
! 197: return (KEYC_UNKNOWN);
! 198: for (i = 1; i < ud.size; i++)
! 199: more = utf8_append(&ud, (u_char)string[i]);
! 200: if (more != UTF8_DONE)
! 201: return (KEYC_UNKNOWN);
! 202: if (utf8_combine(&ud, &wc) != UTF8_DONE)
! 203: return (KEYC_UNKNOWN);
! 204: return (wc | modifiers);
! 205: }
! 206:
! 207: /* Otherwise look the key up in the table. */
! 208: key = key_string_search_table(string);
! 209: if (key == KEYC_UNKNOWN)
! 210: return (KEYC_UNKNOWN);
! 211: }
! 212:
! 213: /* Convert the standard control keys. */
! 214: if (key < KEYC_BASE && (modifiers & KEYC_CTRL) && !strchr(other, key)) {
! 215: if (key >= 97 && key <= 122)
! 216: key -= 96;
! 217: else if (key >= 64 && key <= 95)
! 218: key -= 64;
! 219: else if (key == 32)
! 220: key = 0;
! 221: else if (key == 63)
! 222: key = KEYC_BSPACE;
! 223: else
! 224: return (KEYC_UNKNOWN);
! 225: modifiers &= ~KEYC_CTRL;
! 226: }
! 227:
! 228: return (key | modifiers);
! 229: }
! 230:
! 231: /* Convert a key code into string format, with prefix if necessary. */
! 232: const char *
! 233: key_string_lookup_key(key_code key)
! 234: {
! 235: static char out[32];
! 236: char tmp[8];
! 237: u_int i;
! 238: struct utf8_data ud;
! 239: size_t off;
! 240:
! 241: *out = '\0';
! 242:
! 243: /* Handle no key. */
! 244: if (key == KEYC_NONE)
! 245: return ("None");
! 246:
! 247: /* Handle special keys. */
! 248: if (key == KEYC_UNKNOWN)
! 249: return ("Unknown");
! 250: if (key == KEYC_FOCUS_IN)
! 251: return ("FocusIn");
! 252: if (key == KEYC_FOCUS_OUT)
! 253: return ("FocusOut");
! 254: if (key == KEYC_MOUSE)
! 255: return ("Mouse");
! 256: if (key == KEYC_DRAGGING)
! 257: return ("Dragging");
! 258: if (key == KEYC_MOUSEMOVE_PANE)
! 259: return ("MouseMovePane");
! 260: if (key == KEYC_MOUSEMOVE_STATUS)
! 261: return ("MouseMoveStatus");
! 262: if (key == KEYC_MOUSEMOVE_BORDER)
! 263: return ("MouseMoveBorder");
! 264:
! 265: /*
! 266: * Special case: display C-@ as C-Space. Could do this below in
! 267: * the (key >= 0 && key <= 32), but this way we let it be found
! 268: * in key_string_table, for the unlikely chance that we might
! 269: * change its name.
! 270: */
! 271: if ((key & KEYC_MASK_KEY) == 0)
! 272: key = ' ' | KEYC_CTRL | (key & KEYC_MASK_MOD);
! 273:
! 274: /* Fill in the modifiers. */
! 275: if (key & KEYC_CTRL)
! 276: strlcat(out, "C-", sizeof out);
! 277: if (key & KEYC_ESCAPE)
! 278: strlcat(out, "M-", sizeof out);
! 279: if (key & KEYC_SHIFT)
! 280: strlcat(out, "S-", sizeof out);
! 281: key &= KEYC_MASK_KEY;
! 282:
! 283: /* Try the key against the string table. */
! 284: for (i = 0; i < nitems(key_string_table); i++) {
! 285: if (key == key_string_table[i].key)
! 286: break;
! 287: }
! 288: if (i != nitems(key_string_table)) {
! 289: strlcat(out, key_string_table[i].string, sizeof out);
! 290: return (out);
! 291: }
! 292:
! 293: /* Is this a UTF-8 key? */
! 294: if (key > 127 && key < KEYC_BASE) {
! 295: if (utf8_split(key, &ud) == UTF8_DONE) {
! 296: off = strlen(out);
! 297: memcpy(out + off, ud.data, ud.size);
! 298: out[off + ud.size] = '\0';
! 299: return (out);
! 300: }
! 301: }
! 302:
! 303: /* Invalid keys are errors. */
! 304: if (key == 127 || key > 255) {
! 305: snprintf(out, sizeof out, "Invalid#%llx", key);
! 306: return (out);
! 307: }
! 308:
! 309: /* Check for standard or control key. */
! 310: if (key <= 32) {
! 311: if (key == 0 || key > 26)
! 312: xsnprintf(tmp, sizeof tmp, "C-%c", (int)(64 + key));
! 313: else
! 314: xsnprintf(tmp, sizeof tmp, "C-%c", (int)(96 + key));
! 315: } else if (key >= 32 && key <= 126) {
! 316: tmp[0] = key;
! 317: tmp[1] = '\0';
! 318: } else if (key >= 128)
! 319: xsnprintf(tmp, sizeof tmp, "\\%llo", key);
! 320:
! 321: strlcat(out, tmp, sizeof out);
! 322: return (out);
! 323: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>