Home | History | Annotate | Line # | Download | only in dist
key-string.c revision 1.1.1.16.2.1
      1       1.1.1.5  christos /* $OpenBSD$ */
      2           1.1      jmmv 
      3           1.1      jmmv /*
      4       1.1.1.6  christos  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott (at) gmail.com>
      5           1.1      jmmv  *
      6           1.1      jmmv  * Permission to use, copy, modify, and distribute this software for any
      7           1.1      jmmv  * purpose with or without fee is hereby granted, provided that the above
      8           1.1      jmmv  * copyright notice and this permission notice appear in all copies.
      9           1.1      jmmv  *
     10           1.1      jmmv  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     11           1.1      jmmv  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     12           1.1      jmmv  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     13           1.1      jmmv  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     14           1.1      jmmv  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
     15           1.1      jmmv  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
     16           1.1      jmmv  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     17           1.1      jmmv  */
     18           1.1      jmmv 
     19           1.1      jmmv #include <sys/types.h>
     20           1.1      jmmv 
     21  1.1.1.16.2.1  perseant #include <ctype.h>
     22      1.1.1.13  christos #include <stdlib.h>
     23           1.1      jmmv #include <string.h>
     24      1.1.1.13  christos #include <wchar.h>
     25           1.1      jmmv 
     26           1.1      jmmv #include "tmux.h"
     27           1.1      jmmv 
     28       1.1.1.6  christos static key_code	key_string_search_table(const char *);
     29       1.1.1.6  christos static key_code	key_string_get_modifiers(const char **);
     30           1.1      jmmv 
     31       1.1.1.7  christos static const struct {
     32           1.1      jmmv 	const char     *string;
     33       1.1.1.6  christos 	key_code	key;
     34           1.1      jmmv } key_string_table[] = {
     35           1.1      jmmv 	/* Function keys. */
     36      1.1.1.13  christos 	{ "F1",		KEYC_F1|KEYC_IMPLIED_META },
     37      1.1.1.13  christos 	{ "F2",		KEYC_F2|KEYC_IMPLIED_META },
     38      1.1.1.13  christos 	{ "F3",		KEYC_F3|KEYC_IMPLIED_META },
     39      1.1.1.13  christos 	{ "F4",		KEYC_F4|KEYC_IMPLIED_META },
     40      1.1.1.13  christos 	{ "F5",		KEYC_F5|KEYC_IMPLIED_META },
     41      1.1.1.13  christos 	{ "F6",		KEYC_F6|KEYC_IMPLIED_META },
     42      1.1.1.13  christos 	{ "F7",		KEYC_F7|KEYC_IMPLIED_META },
     43      1.1.1.13  christos 	{ "F8",		KEYC_F8|KEYC_IMPLIED_META },
     44      1.1.1.13  christos 	{ "F9",		KEYC_F9|KEYC_IMPLIED_META },
     45      1.1.1.13  christos 	{ "F10",	KEYC_F10|KEYC_IMPLIED_META },
     46      1.1.1.13  christos 	{ "F11",	KEYC_F11|KEYC_IMPLIED_META },
     47      1.1.1.13  christos 	{ "F12",	KEYC_F12|KEYC_IMPLIED_META },
     48      1.1.1.13  christos 	{ "IC",		KEYC_IC|KEYC_IMPLIED_META },
     49      1.1.1.13  christos 	{ "Insert",	KEYC_IC|KEYC_IMPLIED_META },
     50      1.1.1.13  christos 	{ "DC",		KEYC_DC|KEYC_IMPLIED_META },
     51      1.1.1.13  christos 	{ "Delete",	KEYC_DC|KEYC_IMPLIED_META },
     52      1.1.1.13  christos 	{ "Home",	KEYC_HOME|KEYC_IMPLIED_META },
     53      1.1.1.13  christos 	{ "End",	KEYC_END|KEYC_IMPLIED_META },
     54      1.1.1.13  christos 	{ "NPage",	KEYC_NPAGE|KEYC_IMPLIED_META },
     55      1.1.1.13  christos 	{ "PageDown",	KEYC_NPAGE|KEYC_IMPLIED_META },
     56      1.1.1.13  christos 	{ "PgDn",	KEYC_NPAGE|KEYC_IMPLIED_META },
     57      1.1.1.13  christos 	{ "PPage",	KEYC_PPAGE|KEYC_IMPLIED_META },
     58      1.1.1.13  christos 	{ "PageUp",	KEYC_PPAGE|KEYC_IMPLIED_META },
     59      1.1.1.13  christos 	{ "PgUp",	KEYC_PPAGE|KEYC_IMPLIED_META },
     60           1.1      jmmv 	{ "BTab",	KEYC_BTAB },
     61           1.1      jmmv 	{ "Space",	' ' },
     62           1.1      jmmv 	{ "BSpace",	KEYC_BSPACE },
     63  1.1.1.16.2.1  perseant 
     64  1.1.1.16.2.1  perseant 	/*
     65  1.1.1.16.2.1  perseant 	 * C0 control characters, with the exception of Tab, Enter,
     66  1.1.1.16.2.1  perseant 	 * and Esc, should never appear as keys. We still render them,
     67  1.1.1.16.2.1  perseant 	 * so to be able to spot them in logs in case of an abnormality.
     68  1.1.1.16.2.1  perseant 	 */
     69  1.1.1.16.2.1  perseant 	{ "[NUL]",	C0_NUL },
     70  1.1.1.16.2.1  perseant 	{ "[SOH]",	C0_SOH },
     71  1.1.1.16.2.1  perseant 	{ "[STX]",	C0_STX },
     72  1.1.1.16.2.1  perseant 	{ "[ETX]",	C0_ETX },
     73  1.1.1.16.2.1  perseant 	{ "[EOT]",	C0_EOT },
     74  1.1.1.16.2.1  perseant 	{ "[ENQ]",	C0_ENQ },
     75  1.1.1.16.2.1  perseant 	{ "[ASC]",	C0_ASC },
     76  1.1.1.16.2.1  perseant 	{ "[BEL]",	C0_BEL },
     77  1.1.1.16.2.1  perseant 	{ "[BS]",	C0_BS },
     78  1.1.1.16.2.1  perseant 	{ "Tab",	C0_HT },
     79  1.1.1.16.2.1  perseant 	{ "[LF]",	C0_LF },
     80  1.1.1.16.2.1  perseant 	{ "[VT]",	C0_VT },
     81  1.1.1.16.2.1  perseant 	{ "[FF]",	C0_FF },
     82  1.1.1.16.2.1  perseant 	{ "Enter",	C0_CR },
     83  1.1.1.16.2.1  perseant 	{ "[SO]",	C0_SO },
     84  1.1.1.16.2.1  perseant 	{ "[SI]",	C0_SI },
     85  1.1.1.16.2.1  perseant 	{ "[DLE]",	C0_DLE },
     86  1.1.1.16.2.1  perseant 	{ "[DC1]",	C0_DC1 },
     87  1.1.1.16.2.1  perseant 	{ "[DC2]",	C0_DC2 },
     88  1.1.1.16.2.1  perseant 	{ "[DC3]",	C0_DC3 },
     89  1.1.1.16.2.1  perseant 	{ "[DC4]",	C0_DC4 },
     90  1.1.1.16.2.1  perseant 	{ "[NAK]",	C0_NAK },
     91  1.1.1.16.2.1  perseant 	{ "[SYN]",	C0_SYN },
     92  1.1.1.16.2.1  perseant 	{ "[ETB]",	C0_ETB },
     93  1.1.1.16.2.1  perseant 	{ "[CAN]",	C0_CAN },
     94  1.1.1.16.2.1  perseant 	{ "[EM]",	C0_EM },
     95  1.1.1.16.2.1  perseant 	{ "[SUB]",	C0_SUB },
     96  1.1.1.16.2.1  perseant 	{ "Escape",	C0_ESC },
     97  1.1.1.16.2.1  perseant 	{ "[FS]",	C0_FS },
     98  1.1.1.16.2.1  perseant 	{ "[GS]",	C0_GS },
     99  1.1.1.16.2.1  perseant 	{ "[RS]",	C0_RS },
    100  1.1.1.16.2.1  perseant 	{ "[US]",	C0_US },
    101           1.1      jmmv 
    102           1.1      jmmv 	/* Arrow keys. */
    103      1.1.1.13  christos 	{ "Up",		KEYC_UP|KEYC_CURSOR|KEYC_IMPLIED_META },
    104      1.1.1.13  christos 	{ "Down",	KEYC_DOWN|KEYC_CURSOR|KEYC_IMPLIED_META },
    105      1.1.1.13  christos 	{ "Left",	KEYC_LEFT|KEYC_CURSOR|KEYC_IMPLIED_META },
    106      1.1.1.13  christos 	{ "Right",	KEYC_RIGHT|KEYC_CURSOR|KEYC_IMPLIED_META },
    107           1.1      jmmv 
    108           1.1      jmmv 	/* Numeric keypad. */
    109      1.1.1.13  christos 	{ "KP/",	KEYC_KP_SLASH|KEYC_KEYPAD },
    110      1.1.1.13  christos 	{ "KP*",	KEYC_KP_STAR|KEYC_KEYPAD },
    111      1.1.1.13  christos 	{ "KP-",	KEYC_KP_MINUS|KEYC_KEYPAD },
    112      1.1.1.13  christos 	{ "KP7",	KEYC_KP_SEVEN|KEYC_KEYPAD },
    113      1.1.1.13  christos 	{ "KP8",	KEYC_KP_EIGHT|KEYC_KEYPAD },
    114      1.1.1.13  christos 	{ "KP9",	KEYC_KP_NINE|KEYC_KEYPAD },
    115      1.1.1.13  christos 	{ "KP+",	KEYC_KP_PLUS|KEYC_KEYPAD },
    116      1.1.1.13  christos 	{ "KP4",	KEYC_KP_FOUR|KEYC_KEYPAD },
    117      1.1.1.13  christos 	{ "KP5",	KEYC_KP_FIVE|KEYC_KEYPAD },
    118      1.1.1.13  christos 	{ "KP6",	KEYC_KP_SIX|KEYC_KEYPAD },
    119      1.1.1.13  christos 	{ "KP1",	KEYC_KP_ONE|KEYC_KEYPAD },
    120      1.1.1.13  christos 	{ "KP2",	KEYC_KP_TWO|KEYC_KEYPAD },
    121      1.1.1.13  christos 	{ "KP3",	KEYC_KP_THREE|KEYC_KEYPAD },
    122      1.1.1.13  christos 	{ "KPEnter",	KEYC_KP_ENTER|KEYC_KEYPAD },
    123      1.1.1.13  christos 	{ "KP0",	KEYC_KP_ZERO|KEYC_KEYPAD },
    124      1.1.1.13  christos 	{ "KP.",	KEYC_KP_PERIOD|KEYC_KEYPAD },
    125       1.1.1.5  christos 
    126       1.1.1.5  christos 	/* Mouse keys. */
    127       1.1.1.5  christos 	KEYC_MOUSE_STRING(MOUSEDOWN1, MouseDown1),
    128       1.1.1.5  christos 	KEYC_MOUSE_STRING(MOUSEDOWN2, MouseDown2),
    129       1.1.1.5  christos 	KEYC_MOUSE_STRING(MOUSEDOWN3, MouseDown3),
    130      1.1.1.15       wiz 	KEYC_MOUSE_STRING(MOUSEDOWN6, MouseDown6),
    131      1.1.1.15       wiz 	KEYC_MOUSE_STRING(MOUSEDOWN7, MouseDown7),
    132      1.1.1.15       wiz 	KEYC_MOUSE_STRING(MOUSEDOWN8, MouseDown8),
    133      1.1.1.15       wiz 	KEYC_MOUSE_STRING(MOUSEDOWN9, MouseDown9),
    134      1.1.1.15       wiz 	KEYC_MOUSE_STRING(MOUSEDOWN10, MouseDown10),
    135      1.1.1.15       wiz 	KEYC_MOUSE_STRING(MOUSEDOWN11, MouseDown11),
    136       1.1.1.5  christos 	KEYC_MOUSE_STRING(MOUSEUP1, MouseUp1),
    137       1.1.1.5  christos 	KEYC_MOUSE_STRING(MOUSEUP2, MouseUp2),
    138       1.1.1.5  christos 	KEYC_MOUSE_STRING(MOUSEUP3, MouseUp3),
    139      1.1.1.15       wiz 	KEYC_MOUSE_STRING(MOUSEUP6, MouseUp6),
    140      1.1.1.15       wiz 	KEYC_MOUSE_STRING(MOUSEUP7, MouseUp7),
    141      1.1.1.15       wiz 	KEYC_MOUSE_STRING(MOUSEUP8, MouseUp8),
    142      1.1.1.15       wiz 	KEYC_MOUSE_STRING(MOUSEUP9, MouseUp9),
    143      1.1.1.15       wiz 	KEYC_MOUSE_STRING(MOUSEUP10, MouseUp10),
    144      1.1.1.15       wiz 	KEYC_MOUSE_STRING(MOUSEUP11, MouseUp11),
    145       1.1.1.5  christos 	KEYC_MOUSE_STRING(MOUSEDRAG1, MouseDrag1),
    146       1.1.1.5  christos 	KEYC_MOUSE_STRING(MOUSEDRAG2, MouseDrag2),
    147       1.1.1.5  christos 	KEYC_MOUSE_STRING(MOUSEDRAG3, MouseDrag3),
    148      1.1.1.15       wiz 	KEYC_MOUSE_STRING(MOUSEDRAG6, MouseDrag6),
    149      1.1.1.15       wiz 	KEYC_MOUSE_STRING(MOUSEDRAG7, MouseDrag7),
    150      1.1.1.15       wiz 	KEYC_MOUSE_STRING(MOUSEDRAG8, MouseDrag8),
    151      1.1.1.15       wiz 	KEYC_MOUSE_STRING(MOUSEDRAG9, MouseDrag9),
    152      1.1.1.15       wiz 	KEYC_MOUSE_STRING(MOUSEDRAG10, MouseDrag10),
    153      1.1.1.15       wiz 	KEYC_MOUSE_STRING(MOUSEDRAG11, MouseDrag11),
    154       1.1.1.6  christos 	KEYC_MOUSE_STRING(MOUSEDRAGEND1, MouseDragEnd1),
    155       1.1.1.6  christos 	KEYC_MOUSE_STRING(MOUSEDRAGEND2, MouseDragEnd2),
    156       1.1.1.6  christos 	KEYC_MOUSE_STRING(MOUSEDRAGEND3, MouseDragEnd3),
    157      1.1.1.15       wiz 	KEYC_MOUSE_STRING(MOUSEDRAGEND6, MouseDragEnd6),
    158      1.1.1.15       wiz 	KEYC_MOUSE_STRING(MOUSEDRAGEND7, MouseDragEnd7),
    159      1.1.1.15       wiz 	KEYC_MOUSE_STRING(MOUSEDRAGEND8, MouseDragEnd8),
    160      1.1.1.15       wiz 	KEYC_MOUSE_STRING(MOUSEDRAGEND9, MouseDragEnd9),
    161      1.1.1.15       wiz 	KEYC_MOUSE_STRING(MOUSEDRAGEND10, MouseDragEnd10),
    162      1.1.1.15       wiz 	KEYC_MOUSE_STRING(MOUSEDRAGEND11, MouseDragEnd11),
    163       1.1.1.5  christos 	KEYC_MOUSE_STRING(WHEELUP, WheelUp),
    164       1.1.1.5  christos 	KEYC_MOUSE_STRING(WHEELDOWN, WheelDown),
    165      1.1.1.13  christos 	KEYC_MOUSE_STRING(SECONDCLICK1, SecondClick1),
    166      1.1.1.13  christos 	KEYC_MOUSE_STRING(SECONDCLICK2, SecondClick2),
    167      1.1.1.13  christos 	KEYC_MOUSE_STRING(SECONDCLICK3, SecondClick3),
    168      1.1.1.15       wiz 	KEYC_MOUSE_STRING(SECONDCLICK6, SecondClick6),
    169      1.1.1.15       wiz 	KEYC_MOUSE_STRING(SECONDCLICK7, SecondClick7),
    170      1.1.1.15       wiz 	KEYC_MOUSE_STRING(SECONDCLICK8, SecondClick8),
    171      1.1.1.15       wiz 	KEYC_MOUSE_STRING(SECONDCLICK9, SecondClick9),
    172      1.1.1.15       wiz 	KEYC_MOUSE_STRING(SECONDCLICK10, SecondClick10),
    173      1.1.1.15       wiz 	KEYC_MOUSE_STRING(SECONDCLICK11, SecondClick11),
    174       1.1.1.7  christos 	KEYC_MOUSE_STRING(DOUBLECLICK1, DoubleClick1),
    175       1.1.1.7  christos 	KEYC_MOUSE_STRING(DOUBLECLICK2, DoubleClick2),
    176       1.1.1.7  christos 	KEYC_MOUSE_STRING(DOUBLECLICK3, DoubleClick3),
    177      1.1.1.15       wiz 	KEYC_MOUSE_STRING(DOUBLECLICK6, DoubleClick6),
    178      1.1.1.15       wiz 	KEYC_MOUSE_STRING(DOUBLECLICK7, DoubleClick7),
    179      1.1.1.15       wiz 	KEYC_MOUSE_STRING(DOUBLECLICK8, DoubleClick8),
    180      1.1.1.15       wiz 	KEYC_MOUSE_STRING(DOUBLECLICK9, DoubleClick9),
    181      1.1.1.15       wiz 	KEYC_MOUSE_STRING(DOUBLECLICK10, DoubleClick10),
    182      1.1.1.15       wiz 	KEYC_MOUSE_STRING(DOUBLECLICK11, DoubleClick11),
    183       1.1.1.7  christos 	KEYC_MOUSE_STRING(TRIPLECLICK1, TripleClick1),
    184       1.1.1.7  christos 	KEYC_MOUSE_STRING(TRIPLECLICK2, TripleClick2),
    185       1.1.1.7  christos 	KEYC_MOUSE_STRING(TRIPLECLICK3, TripleClick3),
    186      1.1.1.15       wiz 	KEYC_MOUSE_STRING(TRIPLECLICK6, TripleClick6),
    187      1.1.1.15       wiz 	KEYC_MOUSE_STRING(TRIPLECLICK7, TripleClick7),
    188      1.1.1.15       wiz 	KEYC_MOUSE_STRING(TRIPLECLICK8, TripleClick8),
    189      1.1.1.15       wiz 	KEYC_MOUSE_STRING(TRIPLECLICK9, TripleClick9),
    190      1.1.1.15       wiz 	KEYC_MOUSE_STRING(TRIPLECLICK10, TripleClick10),
    191      1.1.1.15       wiz 	KEYC_MOUSE_STRING(TRIPLECLICK11, TripleClick11)
    192           1.1      jmmv };
    193           1.1      jmmv 
    194           1.1      jmmv /* Find key string in table. */
    195       1.1.1.6  christos static key_code
    196           1.1      jmmv key_string_search_table(const char *string)
    197           1.1      jmmv {
    198       1.1.1.8  christos 	u_int	i, user;
    199           1.1      jmmv 
    200           1.1      jmmv 	for (i = 0; i < nitems(key_string_table); i++) {
    201           1.1      jmmv 		if (strcasecmp(string, key_string_table[i].string) == 0)
    202           1.1      jmmv 			return (key_string_table[i].key);
    203           1.1      jmmv 	}
    204       1.1.1.8  christos 
    205       1.1.1.8  christos 	if (sscanf(string, "User%u", &user) == 1 && user < KEYC_NUSER)
    206       1.1.1.8  christos 		return (KEYC_USER + user);
    207       1.1.1.8  christos 
    208       1.1.1.6  christos 	return (KEYC_UNKNOWN);
    209           1.1      jmmv }
    210           1.1      jmmv 
    211           1.1      jmmv /* Find modifiers. */
    212       1.1.1.6  christos static key_code
    213           1.1      jmmv key_string_get_modifiers(const char **string)
    214           1.1      jmmv {
    215       1.1.1.6  christos 	key_code	modifiers;
    216           1.1      jmmv 
    217           1.1      jmmv 	modifiers = 0;
    218           1.1      jmmv 	while (((*string)[0] != '\0') && (*string)[1] == '-') {
    219           1.1      jmmv 		switch ((*string)[0]) {
    220           1.1      jmmv 		case 'C':
    221           1.1      jmmv 		case 'c':
    222           1.1      jmmv 			modifiers |= KEYC_CTRL;
    223           1.1      jmmv 			break;
    224           1.1      jmmv 		case 'M':
    225           1.1      jmmv 		case 'm':
    226      1.1.1.13  christos 			modifiers |= KEYC_META;
    227           1.1      jmmv 			break;
    228           1.1      jmmv 		case 'S':
    229           1.1      jmmv 		case 's':
    230           1.1      jmmv 			modifiers |= KEYC_SHIFT;
    231           1.1      jmmv 			break;
    232       1.1.1.7  christos 		default:
    233       1.1.1.7  christos 			*string = NULL;
    234       1.1.1.7  christos 			return (0);
    235           1.1      jmmv 		}
    236           1.1      jmmv 		*string += 2;
    237           1.1      jmmv 	}
    238           1.1      jmmv 	return (modifiers);
    239           1.1      jmmv }
    240           1.1      jmmv 
    241           1.1      jmmv /* Lookup a string and convert to a key value. */
    242       1.1.1.6  christos key_code
    243           1.1      jmmv key_string_lookup_string(const char *string)
    244           1.1      jmmv {
    245  1.1.1.16.2.1  perseant 	key_code		 key, modifiers = 0;
    246      1.1.1.13  christos 	u_int			 u, i;
    247      1.1.1.13  christos 	struct utf8_data	 ud, *udp;
    248       1.1.1.6  christos 	enum utf8_state		 more;
    249      1.1.1.13  christos 	utf8_char		 uc;
    250      1.1.1.13  christos 	char			 m[MB_LEN_MAX + 1];
    251      1.1.1.13  christos 	int			 mlen;
    252       1.1.1.6  christos 
    253       1.1.1.9  christos 	/* Is this no key or any key? */
    254       1.1.1.6  christos 	if (strcasecmp(string, "None") == 0)
    255       1.1.1.6  christos 		return (KEYC_NONE);
    256       1.1.1.9  christos 	if (strcasecmp(string, "Any") == 0)
    257       1.1.1.9  christos 		return (KEYC_ANY);
    258       1.1.1.3  christos 
    259       1.1.1.3  christos 	/* Is this a hexadecimal value? */
    260       1.1.1.3  christos 	if (string[0] == '0' && string[1] == 'x') {
    261      1.1.1.13  christos 		if (sscanf(string + 2, "%x", &u) != 1)
    262      1.1.1.13  christos 			return (KEYC_UNKNOWN);
    263      1.1.1.15       wiz 		if (u < 32)
    264      1.1.1.15       wiz 			return (u);
    265      1.1.1.13  christos 		mlen = wctomb(m, u);
    266      1.1.1.13  christos 		if (mlen <= 0 || mlen > MB_LEN_MAX)
    267      1.1.1.13  christos 			return (KEYC_UNKNOWN);
    268      1.1.1.13  christos 		m[mlen] = '\0';
    269      1.1.1.13  christos 
    270      1.1.1.13  christos 		udp = utf8_fromcstr(m);
    271      1.1.1.13  christos 		if (udp == NULL ||
    272      1.1.1.13  christos 		    udp[0].size == 0 ||
    273      1.1.1.13  christos 		    udp[1].size != 0 ||
    274      1.1.1.13  christos 		    utf8_from_data(&udp[0], &uc) != UTF8_DONE) {
    275      1.1.1.13  christos 			free(udp);
    276      1.1.1.13  christos 			return (KEYC_UNKNOWN);
    277      1.1.1.13  christos 		}
    278      1.1.1.13  christos 		free(udp);
    279      1.1.1.13  christos 		return (uc);
    280       1.1.1.3  christos 	}
    281           1.1      jmmv 
    282  1.1.1.16.2.1  perseant 	/* Check for short Ctrl key. */
    283           1.1      jmmv 	if (string[0] == '^' && string[1] != '\0') {
    284  1.1.1.16.2.1  perseant 		if (string[2] == '\0')
    285  1.1.1.16.2.1  perseant 			return (tolower((u_char)string[1])|KEYC_CTRL);
    286           1.1      jmmv 		modifiers |= KEYC_CTRL;
    287           1.1      jmmv 		string++;
    288           1.1      jmmv 	}
    289  1.1.1.16.2.1  perseant 
    290  1.1.1.16.2.1  perseant 	/* Check for modifiers. */
    291           1.1      jmmv 	modifiers |= key_string_get_modifiers(&string);
    292       1.1.1.7  christos 	if (string == NULL || string[0] == '\0')
    293       1.1.1.6  christos 		return (KEYC_UNKNOWN);
    294           1.1      jmmv 
    295           1.1      jmmv 	/* Is this a standard ASCII key? */
    296       1.1.1.6  christos 	if (string[1] == '\0' && (u_char)string[0] <= 127) {
    297       1.1.1.6  christos 		key = (u_char)string[0];
    298      1.1.1.12  christos 		if (key < 32)
    299       1.1.1.6  christos 			return (KEYC_UNKNOWN);
    300           1.1      jmmv 	} else {
    301       1.1.1.6  christos 		/* Try as a UTF-8 key. */
    302       1.1.1.6  christos 		if ((more = utf8_open(&ud, (u_char)*string)) == UTF8_MORE) {
    303       1.1.1.6  christos 			if (strlen(string) != ud.size)
    304       1.1.1.6  christos 				return (KEYC_UNKNOWN);
    305       1.1.1.6  christos 			for (i = 1; i < ud.size; i++)
    306       1.1.1.6  christos 				more = utf8_append(&ud, (u_char)string[i]);
    307       1.1.1.6  christos 			if (more != UTF8_DONE)
    308       1.1.1.6  christos 				return (KEYC_UNKNOWN);
    309      1.1.1.13  christos 			if (utf8_from_data(&ud, &uc) != UTF8_DONE)
    310       1.1.1.6  christos 				return (KEYC_UNKNOWN);
    311      1.1.1.13  christos 			return (uc|modifiers);
    312       1.1.1.6  christos 		}
    313       1.1.1.6  christos 
    314           1.1      jmmv 		/* Otherwise look the key up in the table. */
    315           1.1      jmmv 		key = key_string_search_table(string);
    316       1.1.1.6  christos 		if (key == KEYC_UNKNOWN)
    317       1.1.1.6  christos 			return (KEYC_UNKNOWN);
    318      1.1.1.13  christos 		if (~modifiers & KEYC_META)
    319      1.1.1.13  christos 			key &= ~KEYC_IMPLIED_META;
    320           1.1      jmmv 	}
    321           1.1      jmmv 
    322      1.1.1.13  christos 	return (key|modifiers);
    323           1.1      jmmv }
    324           1.1      jmmv 
    325           1.1      jmmv /* Convert a key code into string format, with prefix if necessary. */
    326           1.1      jmmv const char *
    327      1.1.1.13  christos key_string_lookup_key(key_code key, int with_flags)
    328           1.1      jmmv {
    329      1.1.1.13  christos 	key_code		 saved = key;
    330      1.1.1.13  christos 	static char		 out[64];
    331      1.1.1.12  christos 	char			 tmp[8];
    332      1.1.1.12  christos 	const char		*s;
    333      1.1.1.12  christos 	u_int			 i;
    334      1.1.1.12  christos 	struct utf8_data	 ud;
    335      1.1.1.12  christos 	size_t			 off;
    336           1.1      jmmv 
    337           1.1      jmmv 	*out = '\0';
    338           1.1      jmmv 
    339      1.1.1.11  christos 	/* Literal keys are themselves. */
    340      1.1.1.11  christos 	if (key & KEYC_LITERAL) {
    341      1.1.1.11  christos 		snprintf(out, sizeof out, "%c", (int)(key & 0xff));
    342      1.1.1.13  christos 		goto out;
    343      1.1.1.11  christos 	}
    344      1.1.1.11  christos 
    345           1.1      jmmv 	/* Fill in the modifiers. */
    346           1.1      jmmv 	if (key & KEYC_CTRL)
    347           1.1      jmmv 		strlcat(out, "C-", sizeof out);
    348      1.1.1.13  christos 	if (key & KEYC_META)
    349           1.1      jmmv 		strlcat(out, "M-", sizeof out);
    350           1.1      jmmv 	if (key & KEYC_SHIFT)
    351           1.1      jmmv 		strlcat(out, "S-", sizeof out);
    352           1.1      jmmv 	key &= KEYC_MASK_KEY;
    353           1.1      jmmv 
    354      1.1.1.12  christos 	/* Handle no key. */
    355      1.1.1.13  christos 	if (key == KEYC_NONE) {
    356      1.1.1.13  christos 		s = "None";
    357      1.1.1.13  christos 		goto append;
    358      1.1.1.13  christos 	}
    359      1.1.1.12  christos 
    360      1.1.1.12  christos 	/* Handle special keys. */
    361      1.1.1.12  christos 	if (key == KEYC_UNKNOWN) {
    362      1.1.1.12  christos 		s = "Unknown";
    363      1.1.1.12  christos 		goto append;
    364      1.1.1.12  christos 	}
    365      1.1.1.12  christos 	if (key == KEYC_ANY) {
    366      1.1.1.12  christos 		s = "Any";
    367      1.1.1.12  christos 		goto append;
    368      1.1.1.12  christos 	}
    369      1.1.1.12  christos 	if (key == KEYC_FOCUS_IN) {
    370      1.1.1.12  christos 		s = "FocusIn";
    371      1.1.1.12  christos 		goto append;
    372      1.1.1.12  christos 	}
    373      1.1.1.12  christos 	if (key == KEYC_FOCUS_OUT) {
    374      1.1.1.12  christos 		s = "FocusOut";
    375      1.1.1.12  christos 		goto append;
    376      1.1.1.12  christos 	}
    377      1.1.1.12  christos 	if (key == KEYC_PASTE_START) {
    378      1.1.1.12  christos 		s = "PasteStart";
    379      1.1.1.12  christos 		goto append;
    380      1.1.1.12  christos 	}
    381      1.1.1.12  christos 	if (key == KEYC_PASTE_END) {
    382      1.1.1.12  christos 		s = "PasteEnd";
    383      1.1.1.12  christos 		goto append;
    384      1.1.1.12  christos 	}
    385      1.1.1.12  christos 	if (key == KEYC_MOUSE) {
    386      1.1.1.12  christos 		s = "Mouse";
    387      1.1.1.12  christos 		goto append;
    388      1.1.1.12  christos 	}
    389      1.1.1.12  christos 	if (key == KEYC_DRAGGING) {
    390      1.1.1.12  christos 		s = "Dragging";
    391      1.1.1.12  christos 		goto append;
    392      1.1.1.12  christos 	}
    393      1.1.1.12  christos 	if (key == KEYC_MOUSEMOVE_PANE) {
    394      1.1.1.12  christos 		s = "MouseMovePane";
    395      1.1.1.12  christos 		goto append;
    396      1.1.1.12  christos 	}
    397      1.1.1.12  christos 	if (key == KEYC_MOUSEMOVE_STATUS) {
    398      1.1.1.12  christos 		s = "MouseMoveStatus";
    399      1.1.1.12  christos 		goto append;
    400      1.1.1.12  christos 	}
    401      1.1.1.12  christos 	if (key == KEYC_MOUSEMOVE_STATUS_LEFT) {
    402      1.1.1.12  christos 		s = "MouseMoveStatusLeft";
    403      1.1.1.12  christos 		goto append;
    404      1.1.1.12  christos 	}
    405      1.1.1.12  christos 	if (key == KEYC_MOUSEMOVE_STATUS_RIGHT) {
    406      1.1.1.12  christos 		s = "MouseMoveStatusRight";
    407      1.1.1.12  christos 		goto append;
    408      1.1.1.12  christos 	}
    409      1.1.1.12  christos 	if (key == KEYC_MOUSEMOVE_BORDER) {
    410      1.1.1.12  christos 		s = "MouseMoveBorder";
    411      1.1.1.12  christos 		goto append;
    412      1.1.1.12  christos 	}
    413  1.1.1.16.2.1  perseant 	if (key >= KEYC_USER && key < KEYC_USER_END) {
    414      1.1.1.12  christos 		snprintf(tmp, sizeof tmp, "User%u", (u_int)(key - KEYC_USER));
    415      1.1.1.12  christos 		strlcat(out, tmp, sizeof out);
    416      1.1.1.13  christos 		goto out;
    417      1.1.1.12  christos 	}
    418      1.1.1.12  christos 
    419           1.1      jmmv 	/* Try the key against the string table. */
    420           1.1      jmmv 	for (i = 0; i < nitems(key_string_table); i++) {
    421      1.1.1.13  christos 		if (key == (key_string_table[i].key & KEYC_MASK_KEY))
    422           1.1      jmmv 			break;
    423           1.1      jmmv 	}
    424           1.1      jmmv 	if (i != nitems(key_string_table)) {
    425           1.1      jmmv 		strlcat(out, key_string_table[i].string, sizeof out);
    426      1.1.1.13  christos 		goto out;
    427           1.1      jmmv 	}
    428           1.1      jmmv 
    429      1.1.1.14  christos 	/* Is this a Unicode key? */
    430      1.1.1.14  christos 	if (KEYC_IS_UNICODE(key)) {
    431      1.1.1.13  christos 		utf8_to_data(key, &ud);
    432      1.1.1.13  christos 		off = strlen(out);
    433      1.1.1.13  christos 		memcpy(out + off, ud.data, ud.size);
    434      1.1.1.13  christos 		out[off + ud.size] = '\0';
    435      1.1.1.13  christos 		goto out;
    436       1.1.1.6  christos 	}
    437       1.1.1.6  christos 
    438           1.1      jmmv 	/* Invalid keys are errors. */
    439      1.1.1.12  christos 	if (key > 255) {
    440      1.1.1.13  christos 		snprintf(out, sizeof out, "Invalid#%llx", saved);
    441      1.1.1.13  christos 		goto out;
    442       1.1.1.6  christos 	}
    443           1.1      jmmv 
    444  1.1.1.16.2.1  perseant 	/* Printable ASCII keys. */
    445  1.1.1.16.2.1  perseant 	if (key > 32 && key <= 126) {
    446           1.1      jmmv 		tmp[0] = key;
    447           1.1      jmmv 		tmp[1] = '\0';
    448      1.1.1.12  christos 	} else if (key == 127)
    449      1.1.1.12  christos 		xsnprintf(tmp, sizeof tmp, "C-?");
    450      1.1.1.12  christos 	else if (key >= 128)
    451       1.1.1.6  christos 		xsnprintf(tmp, sizeof tmp, "\\%llo", key);
    452       1.1.1.2      jmmv 
    453           1.1      jmmv 	strlcat(out, tmp, sizeof out);
    454      1.1.1.13  christos 	goto out;
    455      1.1.1.12  christos 
    456      1.1.1.12  christos append:
    457      1.1.1.12  christos 	strlcat(out, s, sizeof out);
    458      1.1.1.13  christos 
    459      1.1.1.13  christos out:
    460      1.1.1.13  christos 	if (with_flags && (saved & KEYC_MASK_FLAGS) != 0) {
    461      1.1.1.13  christos 		strlcat(out, "[", sizeof out);
    462      1.1.1.13  christos 		if (saved & KEYC_LITERAL)
    463      1.1.1.13  christos 			strlcat(out, "L", sizeof out);
    464      1.1.1.13  christos 		if (saved & KEYC_KEYPAD)
    465      1.1.1.13  christos 			strlcat(out, "K", sizeof out);
    466      1.1.1.13  christos 		if (saved & KEYC_CURSOR)
    467      1.1.1.13  christos 			strlcat(out, "C", sizeof out);
    468      1.1.1.13  christos 		if (saved & KEYC_IMPLIED_META)
    469      1.1.1.13  christos 			strlcat(out, "I", sizeof out);
    470      1.1.1.13  christos 		if (saved & KEYC_BUILD_MODIFIERS)
    471      1.1.1.13  christos 			strlcat(out, "B", sizeof out);
    472      1.1.1.16       wiz 		if (saved & KEYC_SENT)
    473      1.1.1.16       wiz 			strlcat(out, "S", sizeof out);
    474      1.1.1.13  christos 		strlcat(out, "]", sizeof out);
    475      1.1.1.13  christos 	}
    476      1.1.1.12  christos 	return (out);
    477           1.1      jmmv }
    478