File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / tmux / key-string.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 14 12:22:44 2017 UTC (6 years, 11 months ago) by misho
Branches: tmux, MAIN
CVS tags: v2_4p0, v2_4, HEAD
tmux 2.4

    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>