| /* $Id$ */ |
| |
| /* |
| * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> |
| * |
| * Permission to use, copy, modify, and distribute this software for any |
| * purpose with or without fee is hereby granted, provided that the above |
| * copyright notice and this permission notice appear in all copies. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER |
| * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING |
| * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| */ |
| |
| #include <sys/types.h> |
| |
| #include <string.h> |
| |
| #include "tmux.h" |
| |
| int key_string_search_table(const char *); |
| int key_string_get_modifiers(const char **); |
| |
| const struct { |
| const char *string; |
| int key; |
| } key_string_table[] = { |
| /* Function keys. */ |
| { "F1", KEYC_F1 }, |
| { "F2", KEYC_F2 }, |
| { "F3", KEYC_F3 }, |
| { "F4", KEYC_F4 }, |
| { "F5", KEYC_F5 }, |
| { "F6", KEYC_F6 }, |
| { "F7", KEYC_F7 }, |
| { "F8", KEYC_F8 }, |
| { "F9", KEYC_F9 }, |
| { "F10", KEYC_F10 }, |
| { "F11", KEYC_F11 }, |
| { "F12", KEYC_F12 }, |
| { "F13", KEYC_F13 }, |
| { "F14", KEYC_F14 }, |
| { "F15", KEYC_F15 }, |
| { "F16", KEYC_F16 }, |
| { "F17", KEYC_F17 }, |
| { "F18", KEYC_F18 }, |
| { "F19", KEYC_F19 }, |
| { "F20", KEYC_F20 }, |
| { "IC", KEYC_IC }, |
| { "DC", KEYC_DC }, |
| { "Home", KEYC_HOME }, |
| { "End", KEYC_END }, |
| { "NPage", KEYC_NPAGE }, |
| { "PageDown", KEYC_NPAGE }, |
| { "PgDn", KEYC_NPAGE }, |
| { "PPage", KEYC_PPAGE }, |
| { "PageUp", KEYC_PPAGE }, |
| { "PgUp", KEYC_PPAGE }, |
| { "Tab", '\011' }, |
| { "BTab", KEYC_BTAB }, |
| { "Space", ' ' }, |
| { "BSpace", KEYC_BSPACE }, |
| { "Enter", '\r' }, |
| { "Escape", '\033' }, |
| |
| /* Arrow keys. */ |
| { "Up", KEYC_UP }, |
| { "Down", KEYC_DOWN }, |
| { "Left", KEYC_LEFT }, |
| { "Right", KEYC_RIGHT }, |
| |
| /* Numeric keypad. */ |
| { "KP/", KEYC_KP_SLASH }, |
| { "KP*", KEYC_KP_STAR }, |
| { "KP-", KEYC_KP_MINUS }, |
| { "KP7", KEYC_KP_SEVEN }, |
| { "KP8", KEYC_KP_EIGHT }, |
| { "KP9", KEYC_KP_NINE }, |
| { "KP+", KEYC_KP_PLUS }, |
| { "KP4", KEYC_KP_FOUR }, |
| { "KP5", KEYC_KP_FIVE }, |
| { "KP6", KEYC_KP_SIX }, |
| { "KP1", KEYC_KP_ONE }, |
| { "KP2", KEYC_KP_TWO }, |
| { "KP3", KEYC_KP_THREE }, |
| { "KPEnter", KEYC_KP_ENTER }, |
| { "KP0", KEYC_KP_ZERO }, |
| { "KP.", KEYC_KP_PERIOD }, |
| }; |
| |
| /* Find key string in table. */ |
| int |
| key_string_search_table(const char *string) |
| { |
| u_int i; |
| |
| for (i = 0; i < nitems(key_string_table); i++) { |
| if (strcasecmp(string, key_string_table[i].string) == 0) |
| return (key_string_table[i].key); |
| } |
| return (KEYC_NONE); |
| } |
| |
| /* Find modifiers. */ |
| int |
| key_string_get_modifiers(const char **string) |
| { |
| int modifiers; |
| |
| modifiers = 0; |
| while (((*string)[0] != '\0') && (*string)[1] == '-') { |
| switch ((*string)[0]) { |
| case 'C': |
| case 'c': |
| modifiers |= KEYC_CTRL; |
| break; |
| case 'M': |
| case 'm': |
| modifiers |= KEYC_ESCAPE; |
| break; |
| case 'S': |
| case 's': |
| modifiers |= KEYC_SHIFT; |
| break; |
| } |
| *string += 2; |
| } |
| return (modifiers); |
| } |
| |
| /* Lookup a string and convert to a key value. */ |
| int |
| key_string_lookup_string(const char *string) |
| { |
| int key, modifiers; |
| u_short u; |
| int size; |
| |
| /* Is this a hexadecimal value? */ |
| if (string[0] == '0' && string[1] == 'x') { |
| if (sscanf(string + 2, "%hx%n", &u, &size) != 1 || size > 4) |
| return (KEYC_NONE); |
| return (u); |
| } |
| |
| /* Check for modifiers. */ |
| modifiers = 0; |
| if (string[0] == '^' && string[1] != '\0') { |
| modifiers |= KEYC_CTRL; |
| string++; |
| } |
| modifiers |= key_string_get_modifiers(&string); |
| if (string[0] == '\0') |
| return (KEYC_NONE); |
| |
| /* Is this a standard ASCII key? */ |
| if (string[1] == '\0') { |
| key = (u_char) string[0]; |
| if (key < 32 || key == 127 || key > 255) |
| return (KEYC_NONE); |
| } else { |
| /* Otherwise look the key up in the table. */ |
| key = key_string_search_table(string); |
| if (key == KEYC_NONE) |
| return (KEYC_NONE); |
| } |
| |
| /* Convert the standard control keys. */ |
| if (key < KEYC_BASE && (modifiers & KEYC_CTRL)) { |
| if (key >= 97 && key <= 122) |
| key -= 96; |
| else if (key >= 64 && key <= 95) |
| key -= 64; |
| else if (key == 32) |
| key = 0; |
| else if (key == 63) |
| key = KEYC_BSPACE; |
| else |
| return (KEYC_NONE); |
| modifiers &= ~KEYC_CTRL; |
| } |
| |
| return (key | modifiers); |
| } |
| |
| /* Convert a key code into string format, with prefix if necessary. */ |
| const char * |
| key_string_lookup_key(int key) |
| { |
| static char out[24]; |
| char tmp[8]; |
| u_int i; |
| |
| *out = '\0'; |
| |
| /* Handle no key. */ |
| if (key == KEYC_NONE) |
| return ("none"); |
| |
| /* |
| * Special case: display C-@ as C-Space. Could do this below in |
| * the (key >= 0 && key <= 32), but this way we let it be found |
| * in key_string_table, for the unlikely chance that we might |
| * change its name. |
| */ |
| if ((key & KEYC_MASK_KEY) == 0) |
| key = ' ' | KEYC_CTRL | (key & KEYC_MASK_MOD); |
| |
| /* Fill in the modifiers. */ |
| if (key & KEYC_CTRL) |
| strlcat(out, "C-", sizeof out); |
| if (key & KEYC_ESCAPE) |
| strlcat(out, "M-", sizeof out); |
| if (key & KEYC_SHIFT) |
| strlcat(out, "S-", sizeof out); |
| key &= KEYC_MASK_KEY; |
| |
| /* Try the key against the string table. */ |
| for (i = 0; i < nitems(key_string_table); i++) { |
| if (key == key_string_table[i].key) |
| break; |
| } |
| if (i != nitems(key_string_table)) { |
| strlcat(out, key_string_table[i].string, sizeof out); |
| return (out); |
| } |
| |
| /* Invalid keys are errors. */ |
| if (key == 127 || key > 255) |
| return (NULL); |
| |
| /* Check for standard or control key. */ |
| if (key >= 0 && key <= 32) { |
| if (key == 0 || key > 26) |
| xsnprintf(tmp, sizeof tmp, "C-%c", 64 + key); |
| else |
| xsnprintf(tmp, sizeof tmp, "C-%c", 96 + key); |
| } else if (key >= 32 && key <= 126) { |
| tmp[0] = key; |
| tmp[1] = '\0'; |
| } else if (key >= 128) |
| xsnprintf(tmp, sizeof tmp, "\\%o", key); |
| |
| strlcat(out, tmp, sizeof out); |
| return (out); |
| } |