mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-04 00:56:10 +00:00 
			
		
		
		
	xterm-keys has been on by default for 5 years and all other modern terminals
use these key sequences by default. Merge the code into the main tty and input tree processing (convering the latter to use a tree rather than a table at the same time) and make the option a no-op.
This commit is contained in:
		@@ -184,8 +184,7 @@ dist_tmux_SOURCES = \
 | 
			
		||||
	window-tree.c \
 | 
			
		||||
	window.c \
 | 
			
		||||
	xmalloc.c \
 | 
			
		||||
	xmalloc.h \
 | 
			
		||||
	xterm-keys.c
 | 
			
		||||
	xmalloc.h
 | 
			
		||||
nodist_tmux_SOURCES = osdep-@PLATFORM@.c
 | 
			
		||||
 | 
			
		||||
# Add compat file for forkpty.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										490
									
								
								input-keys.c
									
									
									
									
									
								
							
							
						
						
									
										490
									
								
								input-keys.c
									
									
									
									
									
								
							@@ -32,112 +32,331 @@
 | 
			
		||||
 | 
			
		||||
static void	 input_key_mouse(struct window_pane *, struct mouse_event *);
 | 
			
		||||
 | 
			
		||||
struct input_key_ent {
 | 
			
		||||
/* Entry in the key tree. */
 | 
			
		||||
struct input_key_entry {
 | 
			
		||||
	key_code			 key;
 | 
			
		||||
	const char			*data;
 | 
			
		||||
 | 
			
		||||
	int		 flags;
 | 
			
		||||
#define INPUTKEY_KEYPAD 0x1	/* keypad key */
 | 
			
		||||
#define INPUTKEY_CURSOR 0x2	/* cursor key */
 | 
			
		||||
	RB_ENTRY(input_key_entry)	 entry;
 | 
			
		||||
};
 | 
			
		||||
RB_HEAD(input_key_tree, input_key_entry);
 | 
			
		||||
 | 
			
		||||
static const struct input_key_ent input_keys[] = {
 | 
			
		||||
/* Tree of input keys. */
 | 
			
		||||
static int	input_key_cmp(struct input_key_entry *,
 | 
			
		||||
		    struct input_key_entry *);
 | 
			
		||||
RB_GENERATE_STATIC(input_key_tree, input_key_entry, entry, input_key_cmp);
 | 
			
		||||
struct input_key_tree input_key_tree = RB_INITIALIZER(&input_key_tree);
 | 
			
		||||
 | 
			
		||||
/* List of default keys, the tree is built from this. */
 | 
			
		||||
static struct input_key_entry input_key_defaults[] = {
 | 
			
		||||
	/* Paste keys. */
 | 
			
		||||
	{ KEYC_PASTE_START,	"\033[200~",	0 },
 | 
			
		||||
	{ KEYC_PASTE_END,	"\033[201~",	0 },
 | 
			
		||||
	{ .key = KEYC_PASTE_START,
 | 
			
		||||
	  .data = "\033[200~"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_PASTE_END,
 | 
			
		||||
	  .data = "\033[201~"
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	/* Function keys. */
 | 
			
		||||
	{ KEYC_F1,		"\033OP",	0 },
 | 
			
		||||
	{ KEYC_F2,		"\033OQ",	0 },
 | 
			
		||||
	{ KEYC_F3,		"\033OR",	0 },
 | 
			
		||||
	{ KEYC_F4,		"\033OS",	0 },
 | 
			
		||||
	{ KEYC_F5,		"\033[15~",	0 },
 | 
			
		||||
	{ KEYC_F6,		"\033[17~",	0 },
 | 
			
		||||
	{ KEYC_F7,		"\033[18~",	0 },
 | 
			
		||||
	{ KEYC_F8,		"\033[19~",	0 },
 | 
			
		||||
	{ KEYC_F9,		"\033[20~",	0 },
 | 
			
		||||
	{ KEYC_F10,		"\033[21~",	0 },
 | 
			
		||||
	{ KEYC_F11,		"\033[23~",	0 },
 | 
			
		||||
	{ KEYC_F12,		"\033[24~",	0 },
 | 
			
		||||
	{ KEYC_F1|KEYC_SHIFT,	"\033[25~",	0 },
 | 
			
		||||
	{ KEYC_F2|KEYC_SHIFT,	"\033[26~",	0 },
 | 
			
		||||
	{ KEYC_F3|KEYC_SHIFT,	"\033[28~",	0 },
 | 
			
		||||
	{ KEYC_F4|KEYC_SHIFT,	"\033[29~",	0 },
 | 
			
		||||
	{ KEYC_F5|KEYC_SHIFT,	"\033[31~",	0 },
 | 
			
		||||
	{ KEYC_F6|KEYC_SHIFT,	"\033[32~",	0 },
 | 
			
		||||
	{ KEYC_F7|KEYC_SHIFT,	"\033[33~",	0 },
 | 
			
		||||
	{ KEYC_F8|KEYC_SHIFT,	"\033[34~",	0 },
 | 
			
		||||
	{ KEYC_IC,		"\033[2~",	0 },
 | 
			
		||||
	{ KEYC_DC,		"\033[3~",	0 },
 | 
			
		||||
	{ KEYC_HOME,		"\033[1~",	0 },
 | 
			
		||||
	{ KEYC_END,		"\033[4~",	0 },
 | 
			
		||||
	{ KEYC_NPAGE,		"\033[6~",	0 },
 | 
			
		||||
	{ KEYC_PPAGE,		"\033[5~",	0 },
 | 
			
		||||
	{ KEYC_BTAB,		"\033[Z",	0 },
 | 
			
		||||
	{ .key = KEYC_F1,
 | 
			
		||||
	  .data = "\033OP"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_F2,
 | 
			
		||||
	  .data = "\033OQ"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_F3,
 | 
			
		||||
	  .data = "\033OR"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_F4,
 | 
			
		||||
	  .data = "\033OS"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_F5,
 | 
			
		||||
	  .data = "\033[15~"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_F6,
 | 
			
		||||
	  .data = "\033[17~"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_F7,
 | 
			
		||||
	  .data = "\033[18~"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_F8,
 | 
			
		||||
	  .data = "\033[19~"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_F9,
 | 
			
		||||
	  .data = "\033[20~"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_F10,
 | 
			
		||||
	  .data = "\033[21~"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_F11,
 | 
			
		||||
	  .data = "\033[23~"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_F12,
 | 
			
		||||
	  .data = "\033[24~"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_F1|KEYC_SHIFT,
 | 
			
		||||
	  .data = "\033[25~"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_F2|KEYC_SHIFT,
 | 
			
		||||
	  .data = "\033[26~"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_F3|KEYC_SHIFT,
 | 
			
		||||
	  .data = "\033[28~"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_F4|KEYC_SHIFT,
 | 
			
		||||
	  .data = "\033[29~"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_F5|KEYC_SHIFT,
 | 
			
		||||
	  .data = "\033[31~"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_F6|KEYC_SHIFT,
 | 
			
		||||
	  .data = "\033[32~"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_F7|KEYC_SHIFT,
 | 
			
		||||
	  .data = "\033[33~"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_F8|KEYC_SHIFT,
 | 
			
		||||
	  .data = "\033[34~"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_IC,
 | 
			
		||||
	  .data = "\033[2~"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_DC,
 | 
			
		||||
	  .data = "\033[3~"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_HOME,
 | 
			
		||||
	  .data = "\033[1~"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_END,
 | 
			
		||||
	  .data = "\033[4~"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_NPAGE,
 | 
			
		||||
	  .data = "\033[6~"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_PPAGE,
 | 
			
		||||
	  .data = "\033[5~"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_BTAB,
 | 
			
		||||
	  .data = "\033[Z"
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Arrow keys. Cursor versions must come first. The codes are toggled
 | 
			
		||||
	 * between CSI and SS3 versions when ctrl is pressed.
 | 
			
		||||
	 */
 | 
			
		||||
	{ KEYC_UP|KEYC_CTRL,	"\033[A",	INPUTKEY_CURSOR },
 | 
			
		||||
	{ KEYC_DOWN|KEYC_CTRL,	"\033[B",	INPUTKEY_CURSOR },
 | 
			
		||||
	{ KEYC_RIGHT|KEYC_CTRL,	"\033[C",	INPUTKEY_CURSOR },
 | 
			
		||||
	{ KEYC_LEFT|KEYC_CTRL,	"\033[D",	INPUTKEY_CURSOR },
 | 
			
		||||
	/* Arrow keys. */
 | 
			
		||||
	{ .key = KEYC_UP|KEYC_CURSOR,
 | 
			
		||||
	  .data = "\033OA"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_DOWN|KEYC_CURSOR,
 | 
			
		||||
	  .data = "\033OB"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_RIGHT|KEYC_CURSOR,
 | 
			
		||||
	  .data = "\033OC"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_LEFT|KEYC_CURSOR,
 | 
			
		||||
	  .data = "\033OD"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_UP,
 | 
			
		||||
	  .data = "\033[A"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_DOWN,
 | 
			
		||||
	  .data = "\033[B"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_RIGHT,
 | 
			
		||||
	  .data = "\033[C"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_LEFT,
 | 
			
		||||
	  .data = "\033[D"
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	{ KEYC_UP,		"\033OA",	INPUTKEY_CURSOR },
 | 
			
		||||
	{ KEYC_DOWN,		"\033OB",	INPUTKEY_CURSOR },
 | 
			
		||||
	{ KEYC_RIGHT,		"\033OC",	INPUTKEY_CURSOR },
 | 
			
		||||
	{ KEYC_LEFT,		"\033OD",	INPUTKEY_CURSOR },
 | 
			
		||||
	/* Keypad keys. */
 | 
			
		||||
	{ .key = KEYC_KP_SLASH|KEYC_KEYPAD,
 | 
			
		||||
	  .data = "\033Oo"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_KP_STAR|KEYC_KEYPAD,
 | 
			
		||||
	  .data = "\033Oj"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_KP_MINUS|KEYC_KEYPAD,
 | 
			
		||||
	  .data = "\033Om"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_KP_SEVEN|KEYC_KEYPAD,
 | 
			
		||||
	  .data = "\033Ow"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_KP_EIGHT|KEYC_KEYPAD,
 | 
			
		||||
	  .data = "\033Ox"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_KP_NINE|KEYC_KEYPAD,
 | 
			
		||||
	  .data = "\033Oy"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_KP_PLUS|KEYC_KEYPAD,
 | 
			
		||||
	  .data = "\033Ok"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_KP_FOUR|KEYC_KEYPAD,
 | 
			
		||||
	  .data = "\033Ot"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_KP_FIVE|KEYC_KEYPAD,
 | 
			
		||||
	  .data = "\033Ou"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_KP_SIX|KEYC_KEYPAD,
 | 
			
		||||
	  .data = "\033Ov"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_KP_ONE|KEYC_KEYPAD,
 | 
			
		||||
	  .data = "\033Oq"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_KP_TWO|KEYC_KEYPAD,
 | 
			
		||||
	  .data = "\033Or"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_KP_THREE|KEYC_KEYPAD,
 | 
			
		||||
	  .data = "\033Os"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_KP_ENTER|KEYC_KEYPAD,
 | 
			
		||||
	  .data = "\033OM"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_KP_ZERO|KEYC_KEYPAD,
 | 
			
		||||
	  .data = "\033Op"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_KP_PERIOD|KEYC_KEYPAD,
 | 
			
		||||
	  .data = "\033On"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_KP_SLASH,
 | 
			
		||||
	  .data = "/"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_KP_STAR,
 | 
			
		||||
	  .data = "*"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_KP_MINUS,
 | 
			
		||||
	  .data = "-"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_KP_SEVEN,
 | 
			
		||||
	  .data = "7"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_KP_EIGHT,
 | 
			
		||||
	  .data = "8"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_KP_NINE,
 | 
			
		||||
	  .data = "9"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_KP_PLUS,
 | 
			
		||||
	  .data = "+"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_KP_FOUR,
 | 
			
		||||
	  .data = "4"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_KP_FIVE,
 | 
			
		||||
	  .data = "5"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_KP_SIX,
 | 
			
		||||
	  .data = "6"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_KP_ONE,
 | 
			
		||||
	  .data = "1"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_KP_TWO,
 | 
			
		||||
	  .data = "2"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_KP_THREE,
 | 
			
		||||
	  .data = "3"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_KP_ENTER,
 | 
			
		||||
	  .data = "\n"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_KP_ZERO,
 | 
			
		||||
	  .data = "0"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_KP_PERIOD,
 | 
			
		||||
	  .data = "."
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	{ KEYC_UP|KEYC_CTRL,	"\033OA",	0 },
 | 
			
		||||
	{ KEYC_DOWN|KEYC_CTRL,	"\033OB",	0 },
 | 
			
		||||
	{ KEYC_RIGHT|KEYC_CTRL,	"\033OC",	0 },
 | 
			
		||||
	{ KEYC_LEFT|KEYC_CTRL,	"\033OD",	0 },
 | 
			
		||||
 | 
			
		||||
	{ KEYC_UP,		"\033[A",	0 },
 | 
			
		||||
	{ KEYC_DOWN,		"\033[B",	0 },
 | 
			
		||||
	{ KEYC_RIGHT,		"\033[C",	0 },
 | 
			
		||||
	{ KEYC_LEFT,		"\033[D",	0 },
 | 
			
		||||
 | 
			
		||||
	/* Keypad keys. Keypad versions must come first. */
 | 
			
		||||
	{ KEYC_KP_SLASH,	"\033Oo",	INPUTKEY_KEYPAD },
 | 
			
		||||
	{ KEYC_KP_STAR,		"\033Oj",	INPUTKEY_KEYPAD },
 | 
			
		||||
	{ KEYC_KP_MINUS,	"\033Om",	INPUTKEY_KEYPAD },
 | 
			
		||||
	{ KEYC_KP_SEVEN,	"\033Ow",	INPUTKEY_KEYPAD },
 | 
			
		||||
	{ KEYC_KP_EIGHT,	"\033Ox",	INPUTKEY_KEYPAD },
 | 
			
		||||
	{ KEYC_KP_NINE,		"\033Oy",	INPUTKEY_KEYPAD },
 | 
			
		||||
	{ KEYC_KP_PLUS,		"\033Ok",	INPUTKEY_KEYPAD },
 | 
			
		||||
	{ KEYC_KP_FOUR,		"\033Ot",	INPUTKEY_KEYPAD },
 | 
			
		||||
	{ KEYC_KP_FIVE,		"\033Ou",	INPUTKEY_KEYPAD },
 | 
			
		||||
	{ KEYC_KP_SIX,		"\033Ov",	INPUTKEY_KEYPAD },
 | 
			
		||||
	{ KEYC_KP_ONE,		"\033Oq",	INPUTKEY_KEYPAD },
 | 
			
		||||
	{ KEYC_KP_TWO,		"\033Or",	INPUTKEY_KEYPAD },
 | 
			
		||||
	{ KEYC_KP_THREE,	"\033Os",	INPUTKEY_KEYPAD },
 | 
			
		||||
	{ KEYC_KP_ENTER,	"\033OM",	INPUTKEY_KEYPAD },
 | 
			
		||||
	{ KEYC_KP_ZERO,		"\033Op",	INPUTKEY_KEYPAD },
 | 
			
		||||
	{ KEYC_KP_PERIOD,	"\033On",	INPUTKEY_KEYPAD },
 | 
			
		||||
 | 
			
		||||
	{ KEYC_KP_SLASH,	"/",		0 },
 | 
			
		||||
	{ KEYC_KP_STAR,		"*",		0 },
 | 
			
		||||
	{ KEYC_KP_MINUS,	"-",		0 },
 | 
			
		||||
	{ KEYC_KP_SEVEN,	"7",		0 },
 | 
			
		||||
	{ KEYC_KP_EIGHT,	"8",		0 },
 | 
			
		||||
	{ KEYC_KP_NINE,		"9",		0 },
 | 
			
		||||
	{ KEYC_KP_PLUS,		"+",		0 },
 | 
			
		||||
	{ KEYC_KP_FOUR,		"4",		0 },
 | 
			
		||||
	{ KEYC_KP_FIVE,		"5",		0 },
 | 
			
		||||
	{ KEYC_KP_SIX,		"6",		0 },
 | 
			
		||||
	{ KEYC_KP_ONE,		"1",		0 },
 | 
			
		||||
	{ KEYC_KP_TWO,		"2",		0 },
 | 
			
		||||
	{ KEYC_KP_THREE,	"3",		0 },
 | 
			
		||||
	{ KEYC_KP_ENTER,	"\n",		0 },
 | 
			
		||||
	{ KEYC_KP_ZERO,		"0",		0 },
 | 
			
		||||
	{ KEYC_KP_PERIOD,	".",		0 },
 | 
			
		||||
	/* Keys with an embedded modifier. */
 | 
			
		||||
	{ .key = KEYC_F1|KEYC_XTERM,
 | 
			
		||||
	  .data = "\033[1;_P"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_F2|KEYC_XTERM,
 | 
			
		||||
	  .data = "\033[1;_Q"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_F3|KEYC_XTERM,
 | 
			
		||||
	  .data = "\033[1;_R"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_F4|KEYC_XTERM,
 | 
			
		||||
	  .data = "\033[1;_S"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_F5|KEYC_XTERM,
 | 
			
		||||
	  .data = "\033[15;_~"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_F6|KEYC_XTERM,
 | 
			
		||||
	  .data = "\033[17;_~"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_F7|KEYC_XTERM,
 | 
			
		||||
	  .data = "\033[18;_~"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_F8|KEYC_XTERM,
 | 
			
		||||
	  .data = "\033[19;_~"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_F9|KEYC_XTERM,
 | 
			
		||||
	  .data = "\033[20;_~"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_F10|KEYC_XTERM,
 | 
			
		||||
	  .data = "\033[21;_~"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_F11|KEYC_XTERM,
 | 
			
		||||
	  .data = "\033[23;_~"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_F12|KEYC_XTERM,
 | 
			
		||||
	  .data = "\033[24;_~"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_UP|KEYC_XTERM,
 | 
			
		||||
	  .data = "\033[1;_A"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_DOWN|KEYC_XTERM,
 | 
			
		||||
	  .data = "\033[1;_B"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_RIGHT|KEYC_XTERM,
 | 
			
		||||
	  .data = "\033[1;_C"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_LEFT|KEYC_XTERM,
 | 
			
		||||
	  .data = "\033[1;_D"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_HOME|KEYC_XTERM,
 | 
			
		||||
	  .data = "\033[1;_H"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_END|KEYC_XTERM,
 | 
			
		||||
	  .data = "\033[1;_F"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_PPAGE|KEYC_XTERM,
 | 
			
		||||
	  .data = "\033[5;_~"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_NPAGE|KEYC_XTERM,
 | 
			
		||||
	  .data = "\033[6;_~"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_IC|KEYC_XTERM,
 | 
			
		||||
	  .data = "\033[2;_~"
 | 
			
		||||
	},
 | 
			
		||||
	{ .key = KEYC_DC|KEYC_XTERM,
 | 
			
		||||
	  .data = "\033[3;_~" }
 | 
			
		||||
};
 | 
			
		||||
static const key_code input_key_modifiers[] = {
 | 
			
		||||
	0,
 | 
			
		||||
	0,
 | 
			
		||||
	KEYC_SHIFT|KEYC_XTERM,
 | 
			
		||||
	KEYC_ESCAPE|KEYC_XTERM,
 | 
			
		||||
	KEYC_SHIFT|KEYC_ESCAPE|KEYC_XTERM,
 | 
			
		||||
	KEYC_CTRL|KEYC_XTERM,
 | 
			
		||||
	KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM,
 | 
			
		||||
	KEYC_ESCAPE|KEYC_CTRL|KEYC_XTERM,
 | 
			
		||||
	KEYC_SHIFT|KEYC_ESCAPE|KEYC_CTRL|KEYC_XTERM
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Input key comparison function. */
 | 
			
		||||
static int
 | 
			
		||||
input_key_cmp(struct input_key_entry *ike1, struct input_key_entry *ike2)
 | 
			
		||||
{
 | 
			
		||||
	if (ike1->key < ike2->key)
 | 
			
		||||
		return (-1);
 | 
			
		||||
	if (ike1->key > ike2->key)
 | 
			
		||||
		return (1);
 | 
			
		||||
	return (0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Split a character into two UTF-8 bytes. */
 | 
			
		||||
static size_t
 | 
			
		||||
input_split2(u_int c, u_char *dst)
 | 
			
		||||
input_key_split2(u_int c, u_char *dst)
 | 
			
		||||
{
 | 
			
		||||
	if (c > 0x7f) {
 | 
			
		||||
		dst[0] = (c >> 6) | 0xc0;
 | 
			
		||||
@@ -148,30 +367,61 @@ input_split2(u_int c, u_char *dst)
 | 
			
		||||
	return (1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Build input key tree. */
 | 
			
		||||
void
 | 
			
		||||
input_key_build(void)
 | 
			
		||||
{
 | 
			
		||||
	struct input_key_entry	*ike, *new;
 | 
			
		||||
	u_int			 i, j;
 | 
			
		||||
	char			*data;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < nitems(input_key_defaults); i++) {
 | 
			
		||||
		ike = &input_key_defaults[i];
 | 
			
		||||
		if (~ike->key & KEYC_XTERM) {
 | 
			
		||||
			RB_INSERT(input_key_tree, &input_key_tree, ike);
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for (j = 2; j < nitems(input_key_modifiers); j++) {
 | 
			
		||||
			data = xstrdup(ike->data);
 | 
			
		||||
			data[strcspn(data, "_")] = '0' + j;
 | 
			
		||||
 | 
			
		||||
			new = xcalloc(1, sizeof *new);
 | 
			
		||||
			new->key = ike->key|input_key_modifiers[j];
 | 
			
		||||
			new->data = data;
 | 
			
		||||
			RB_INSERT(input_key_tree, &input_key_tree, new);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	RB_FOREACH(ike, input_key_tree, &input_key_tree) {
 | 
			
		||||
		log_debug("%s: 0x%llx (%s) is %s", __func__, ike->key,
 | 
			
		||||
		    key_string_lookup_key(ike->key), ike->data);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Translate a key code into an output key sequence for a pane. */
 | 
			
		||||
int
 | 
			
		||||
input_key_pane(struct window_pane *wp, key_code key, struct mouse_event *m)
 | 
			
		||||
{
 | 
			
		||||
	if (log_get_level() != 0) {
 | 
			
		||||
		log_debug("writing key 0x%llx (%s) to %%%u", key,
 | 
			
		||||
		    key_string_lookup_key(key), wp->id);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (KEYC_IS_MOUSE(key)) {
 | 
			
		||||
		if (m != NULL && m->wp != -1 && (u_int)m->wp == wp->id)
 | 
			
		||||
			input_key_mouse(wp, m);
 | 
			
		||||
		return (0);
 | 
			
		||||
	}
 | 
			
		||||
	return (input_key(wp, wp->screen, wp->event, key));
 | 
			
		||||
	return (input_key(wp->screen, wp->event, key));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Translate a key code into an output key sequence. */
 | 
			
		||||
int
 | 
			
		||||
input_key(struct window_pane *wp, struct screen *s, struct bufferevent *bev,
 | 
			
		||||
    key_code key)
 | 
			
		||||
input_key(struct screen *s, struct bufferevent *bev, key_code key)
 | 
			
		||||
{
 | 
			
		||||
	const struct input_key_ent	*ike;
 | 
			
		||||
	u_int				 i;
 | 
			
		||||
	size_t				 dlen;
 | 
			
		||||
	char				*out;
 | 
			
		||||
	struct input_key_entry	*ike, entry;
 | 
			
		||||
	size_t			 datalen;
 | 
			
		||||
	key_code		 justkey, newkey;
 | 
			
		||||
	struct utf8_data	 ud;
 | 
			
		||||
 | 
			
		||||
@@ -216,43 +466,25 @@ input_key(struct window_pane *wp, struct screen *s, struct bufferevent *bev,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Then try to look this up as an xterm key, if the flag to output them
 | 
			
		||||
	 * is set.
 | 
			
		||||
	 * Look up in the tree. If not in application keypad or cursor mode,
 | 
			
		||||
	 * remove the flags from the key.
 | 
			
		||||
	 */
 | 
			
		||||
	if (wp == NULL || options_get_number(wp->window->options, "xterm-keys")) {
 | 
			
		||||
		if ((out = xterm_keys_lookup(key)) != NULL) {
 | 
			
		||||
			bufferevent_write(bev, out, strlen(out));
 | 
			
		||||
			free(out);
 | 
			
		||||
			return (0);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	key &= ~KEYC_XTERM;
 | 
			
		||||
 | 
			
		||||
	/* Otherwise look the key up in the table. */
 | 
			
		||||
	for (i = 0; i < nitems(input_keys); i++) {
 | 
			
		||||
		ike = &input_keys[i];
 | 
			
		||||
 | 
			
		||||
		if ((ike->flags & INPUTKEY_KEYPAD) && (~s->mode & MODE_KKEYPAD))
 | 
			
		||||
			continue;
 | 
			
		||||
		if ((ike->flags & INPUTKEY_CURSOR) && (~s->mode & MODE_KCURSOR))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if ((key & KEYC_ESCAPE) && (ike->key | KEYC_ESCAPE) == key)
 | 
			
		||||
			break;
 | 
			
		||||
		if (ike->key == key)
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
	if (i == nitems(input_keys)) {
 | 
			
		||||
	if (~s->mode & MODE_KKEYPAD)
 | 
			
		||||
		key &= ~KEYC_KEYPAD;
 | 
			
		||||
	if (~s->mode & MODE_KCURSOR)
 | 
			
		||||
		key &= ~KEYC_CURSOR;
 | 
			
		||||
	entry.key = key;
 | 
			
		||||
	if ((ike = RB_FIND(input_key_tree, &input_key_tree, &entry)) == NULL) {
 | 
			
		||||
		log_debug("key 0x%llx missing", key);
 | 
			
		||||
		return (-1);
 | 
			
		||||
	}
 | 
			
		||||
	dlen = strlen(ike->data);
 | 
			
		||||
	datalen = strlen(ike->data);
 | 
			
		||||
	log_debug("found key 0x%llx: \"%s\"", key, ike->data);
 | 
			
		||||
 | 
			
		||||
	/* Prefix a \033 for escape. */
 | 
			
		||||
	if (key & KEYC_ESCAPE)
 | 
			
		||||
		bufferevent_write(bev, "\033", 1);
 | 
			
		||||
	bufferevent_write(bev, ike->data, dlen);
 | 
			
		||||
	bufferevent_write(bev, ike->data, datalen);
 | 
			
		||||
	return (0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -308,9 +540,9 @@ input_key_get_mouse(struct screen *s, struct mouse_event *m, u_int x, u_int y,
 | 
			
		||||
		if (m->b > 0x7ff - 32 || x > 0x7ff - 33 || y > 0x7ff - 33)
 | 
			
		||||
			return (0);
 | 
			
		||||
		len = xsnprintf(buf, sizeof buf, "\033[M");
 | 
			
		||||
		len += input_split2(m->b + 32, &buf[len]);
 | 
			
		||||
		len += input_split2(x + 33, &buf[len]);
 | 
			
		||||
		len += input_split2(y + 33, &buf[len]);
 | 
			
		||||
		len += input_key_split2(m->b + 32, &buf[len]);
 | 
			
		||||
		len += input_key_split2(x + 33, &buf[len]);
 | 
			
		||||
		len += input_key_split2(y + 33, &buf[len]);
 | 
			
		||||
	} else {
 | 
			
		||||
		if (m->b > 223)
 | 
			
		||||
			return (0);
 | 
			
		||||
 
 | 
			
		||||
@@ -1052,11 +1052,12 @@ const struct options_table_entry options_table[] = {
 | 
			
		||||
		  "bottom."
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	{ .name = "xterm-keys",
 | 
			
		||||
	{ .name = "xterm-keys", /* no longer used */
 | 
			
		||||
	  .type = OPTIONS_TABLE_FLAG,
 | 
			
		||||
	  .scope = OPTIONS_TABLE_WINDOW,
 | 
			
		||||
	  .default_num = 1,
 | 
			
		||||
	  .text = "Whether xterm-style function key sequences should be sent."
 | 
			
		||||
	  .text = "Whether xterm-style function key sequences should be sent. "
 | 
			
		||||
	          "This option is no longer used."
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	/* Hook options. */
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								popup.c
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								popup.c
									
									
									
									
									
								
							@@ -328,7 +328,7 @@ popup_key_cb(struct client *c, struct key_event *event)
 | 
			
		||||
			bufferevent_write(job_get_event(pd->job), buf, len);
 | 
			
		||||
			return (0);
 | 
			
		||||
		}
 | 
			
		||||
		input_key(NULL, &pd->s, job_get_event(pd->job), event->key);
 | 
			
		||||
		input_key(&pd->s, job_get_event(pd->job), event->key);
 | 
			
		||||
		return (0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								server.c
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								server.c
									
									
									
									
									
								
							@@ -198,6 +198,7 @@ server_start(struct tmuxproc *client, int flags, struct event_base *base,
 | 
			
		||||
	    "tty ps", NULL) != 0)
 | 
			
		||||
		fatal("pledge failed");
 | 
			
		||||
 | 
			
		||||
	input_key_build();
 | 
			
		||||
	RB_INIT(&windows);
 | 
			
		||||
	RB_INIT(&all_window_panes);
 | 
			
		||||
	TAILQ_INIT(&clients);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								tmux.1
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								tmux.1
									
									
									
									
									
								
							@@ -4054,16 +4054,6 @@ option.
 | 
			
		||||
.Xc
 | 
			
		||||
If this option is set, searches will wrap around the end of the pane contents.
 | 
			
		||||
The default is on.
 | 
			
		||||
.Pp
 | 
			
		||||
.It Xo Ic xterm-keys
 | 
			
		||||
.Op Ic on | off
 | 
			
		||||
.Xc
 | 
			
		||||
If this option is set,
 | 
			
		||||
.Nm
 | 
			
		||||
will generate
 | 
			
		||||
.Xr xterm 1 -style
 | 
			
		||||
function key sequences; these have a number included to indicate modifiers such
 | 
			
		||||
as Shift, Alt or Ctrl.
 | 
			
		||||
.El
 | 
			
		||||
.Pp
 | 
			
		||||
Available pane options are:
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								tmux.h
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								tmux.h
									
									
									
									
									
								
							@@ -125,6 +125,8 @@ struct winlink;
 | 
			
		||||
#define KEYC_SHIFT   0x0400000000000ULL
 | 
			
		||||
#define KEYC_XTERM   0x0800000000000ULL
 | 
			
		||||
#define KEYC_LITERAL 0x1000000000000ULL
 | 
			
		||||
#define KEYC_KEYPAD  0x2000000000000ULL
 | 
			
		||||
#define KEYC_CURSOR  0x4000000000000ULL
 | 
			
		||||
 | 
			
		||||
/* Available user keys. */
 | 
			
		||||
#define KEYC_NUSER 1000
 | 
			
		||||
@@ -2417,16 +2419,12 @@ void	 input_parse_screen(struct input_ctx *, struct screen *,
 | 
			
		||||
	     screen_write_init_ctx_cb, void *, u_char *, size_t);
 | 
			
		||||
 | 
			
		||||
/* input-key.c */
 | 
			
		||||
void	 input_key_build(void);
 | 
			
		||||
int	 input_key_pane(struct window_pane *, key_code, struct mouse_event *);
 | 
			
		||||
int	 input_key(struct window_pane *, struct screen *, struct bufferevent *,
 | 
			
		||||
	     key_code);
 | 
			
		||||
int	 input_key(struct screen *, struct bufferevent *, key_code);
 | 
			
		||||
int	 input_key_get_mouse(struct screen *, struct mouse_event *, u_int,
 | 
			
		||||
	     u_int, const char **, size_t *);
 | 
			
		||||
 | 
			
		||||
/* xterm-keys.c */
 | 
			
		||||
char	*xterm_keys_lookup(key_code);
 | 
			
		||||
int	 xterm_keys_find(const char *, size_t, size_t *, key_code *);
 | 
			
		||||
 | 
			
		||||
/* colour.c */
 | 
			
		||||
int	 colour_find_rgb(u_char, u_char, u_char);
 | 
			
		||||
int	 colour_join_rgb(u_char, u_char, u_char);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										135
									
								
								tty-keys.c
									
									
									
									
									
								
							
							
						
						
									
										135
									
								
								tty-keys.c
									
									
									
									
									
								
							@@ -69,33 +69,33 @@ static const struct tty_default_key_raw tty_default_raw_keys[] = {
 | 
			
		||||
	 * put the terminal into keypad_xmit mode. Translation of numbers
 | 
			
		||||
	 * mode/applications mode is done in input-keys.c.
 | 
			
		||||
	 */
 | 
			
		||||
	{ "\033Oo", KEYC_KP_SLASH },
 | 
			
		||||
	{ "\033Oj", KEYC_KP_STAR },
 | 
			
		||||
	{ "\033Om", KEYC_KP_MINUS },
 | 
			
		||||
	{ "\033Ow", KEYC_KP_SEVEN },
 | 
			
		||||
	{ "\033Ox", KEYC_KP_EIGHT },
 | 
			
		||||
	{ "\033Oy", KEYC_KP_NINE },
 | 
			
		||||
	{ "\033Ok", KEYC_KP_PLUS },
 | 
			
		||||
	{ "\033Ot", KEYC_KP_FOUR },
 | 
			
		||||
	{ "\033Ou", KEYC_KP_FIVE },
 | 
			
		||||
	{ "\033Ov", KEYC_KP_SIX },
 | 
			
		||||
	{ "\033Oq", KEYC_KP_ONE },
 | 
			
		||||
	{ "\033Or", KEYC_KP_TWO },
 | 
			
		||||
	{ "\033Os", KEYC_KP_THREE },
 | 
			
		||||
	{ "\033OM", KEYC_KP_ENTER },
 | 
			
		||||
	{ "\033Op", KEYC_KP_ZERO },
 | 
			
		||||
	{ "\033On", KEYC_KP_PERIOD },
 | 
			
		||||
	{ "\033Oo", KEYC_KP_SLASH|KEYC_KEYPAD },
 | 
			
		||||
	{ "\033Oj", KEYC_KP_STAR|KEYC_KEYPAD },
 | 
			
		||||
	{ "\033Om", KEYC_KP_MINUS|KEYC_KEYPAD },
 | 
			
		||||
	{ "\033Ow", KEYC_KP_SEVEN|KEYC_KEYPAD },
 | 
			
		||||
	{ "\033Ox", KEYC_KP_EIGHT|KEYC_KEYPAD },
 | 
			
		||||
	{ "\033Oy", KEYC_KP_NINE|KEYC_KEYPAD },
 | 
			
		||||
	{ "\033Ok", KEYC_KP_PLUS|KEYC_KEYPAD },
 | 
			
		||||
	{ "\033Ot", KEYC_KP_FOUR|KEYC_KEYPAD },
 | 
			
		||||
	{ "\033Ou", KEYC_KP_FIVE|KEYC_KEYPAD },
 | 
			
		||||
	{ "\033Ov", KEYC_KP_SIX|KEYC_KEYPAD },
 | 
			
		||||
	{ "\033Oq", KEYC_KP_ONE|KEYC_KEYPAD },
 | 
			
		||||
	{ "\033Or", KEYC_KP_TWO|KEYC_KEYPAD },
 | 
			
		||||
	{ "\033Os", KEYC_KP_THREE|KEYC_KEYPAD },
 | 
			
		||||
	{ "\033OM", KEYC_KP_ENTER|KEYC_KEYPAD },
 | 
			
		||||
	{ "\033Op", KEYC_KP_ZERO|KEYC_KEYPAD },
 | 
			
		||||
	{ "\033On", KEYC_KP_PERIOD|KEYC_KEYPAD },
 | 
			
		||||
 | 
			
		||||
	/* Arrow keys. */
 | 
			
		||||
	{ "\033OA", KEYC_UP },
 | 
			
		||||
	{ "\033OB", KEYC_DOWN },
 | 
			
		||||
	{ "\033OC", KEYC_RIGHT },
 | 
			
		||||
	{ "\033OD", KEYC_LEFT },
 | 
			
		||||
	{ "\033OA", KEYC_UP|KEYC_CURSOR },
 | 
			
		||||
	{ "\033OB", KEYC_DOWN|KEYC_CURSOR },
 | 
			
		||||
	{ "\033OC", KEYC_RIGHT|KEYC_CURSOR },
 | 
			
		||||
	{ "\033OD", KEYC_LEFT|KEYC_CURSOR },
 | 
			
		||||
 | 
			
		||||
	{ "\033[A", KEYC_UP },
 | 
			
		||||
	{ "\033[B", KEYC_DOWN },
 | 
			
		||||
	{ "\033[C", KEYC_RIGHT },
 | 
			
		||||
	{ "\033[D", KEYC_LEFT },
 | 
			
		||||
	{ "\033[A", KEYC_UP|KEYC_CURSOR },
 | 
			
		||||
	{ "\033[B", KEYC_DOWN|KEYC_CURSOR },
 | 
			
		||||
	{ "\033[C", KEYC_RIGHT|KEYC_CURSOR },
 | 
			
		||||
	{ "\033[D", KEYC_LEFT|KEYC_CURSOR },
 | 
			
		||||
 | 
			
		||||
	/* Other (xterm) "cursor" keys. */
 | 
			
		||||
	{ "\033OH", KEYC_HOME },
 | 
			
		||||
@@ -182,11 +182,59 @@ static const struct tty_default_key_raw tty_default_raw_keys[] = {
 | 
			
		||||
	{ "\033[201~", KEYC_PASTE_END },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Default xterm keys. */
 | 
			
		||||
struct tty_default_key_xterm {
 | 
			
		||||
	const char	*template;
 | 
			
		||||
	key_code	 key;
 | 
			
		||||
};
 | 
			
		||||
static const struct tty_default_key_xterm tty_default_xterm_keys[] = {
 | 
			
		||||
	{ "\033[1;_P", KEYC_F1 },
 | 
			
		||||
	{ "\033O1;_P", KEYC_F1 },
 | 
			
		||||
	{ "\033O_P", KEYC_F1 },
 | 
			
		||||
	{ "\033[1;_Q", KEYC_F2 },
 | 
			
		||||
	{ "\033O1;_Q", KEYC_F2 },
 | 
			
		||||
	{ "\033O_Q", KEYC_F2 },
 | 
			
		||||
	{ "\033[1;_R", KEYC_F3 },
 | 
			
		||||
	{ "\033O1;_R", KEYC_F3 },
 | 
			
		||||
	{ "\033O_R", KEYC_F3 },
 | 
			
		||||
	{ "\033[1;_S", KEYC_F4 },
 | 
			
		||||
	{ "\033O1;_S", KEYC_F4 },
 | 
			
		||||
	{ "\033O_S", KEYC_F4 },
 | 
			
		||||
	{ "\033[15;_~", KEYC_F5 },
 | 
			
		||||
	{ "\033[17;_~", KEYC_F6 },
 | 
			
		||||
	{ "\033[18;_~", KEYC_F7 },
 | 
			
		||||
	{ "\033[19;_~", KEYC_F8 },
 | 
			
		||||
	{ "\033[20;_~", KEYC_F9 },
 | 
			
		||||
	{ "\033[21;_~", KEYC_F10 },
 | 
			
		||||
	{ "\033[23;_~", KEYC_F11 },
 | 
			
		||||
	{ "\033[24;_~", KEYC_F12 },
 | 
			
		||||
	{ "\033[1;_A", KEYC_UP },
 | 
			
		||||
	{ "\033[1;_B", KEYC_DOWN },
 | 
			
		||||
	{ "\033[1;_C", KEYC_RIGHT },
 | 
			
		||||
	{ "\033[1;_D", KEYC_LEFT },
 | 
			
		||||
	{ "\033[1;_H", KEYC_HOME },
 | 
			
		||||
	{ "\033[1;_F", KEYC_END },
 | 
			
		||||
	{ "\033[5;_~", KEYC_PPAGE },
 | 
			
		||||
	{ "\033[6;_~", KEYC_NPAGE },
 | 
			
		||||
	{ "\033[2;_~", KEYC_IC },
 | 
			
		||||
	{ "\033[3;_~", KEYC_DC },
 | 
			
		||||
};
 | 
			
		||||
static const key_code tty_default_xterm_modifiers[] = {
 | 
			
		||||
	0,
 | 
			
		||||
	0,
 | 
			
		||||
	KEYC_SHIFT|KEYC_XTERM,
 | 
			
		||||
	KEYC_ESCAPE|KEYC_XTERM,
 | 
			
		||||
	KEYC_SHIFT|KEYC_ESCAPE|KEYC_XTERM,
 | 
			
		||||
	KEYC_CTRL|KEYC_XTERM,
 | 
			
		||||
	KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM,
 | 
			
		||||
	KEYC_ESCAPE|KEYC_CTRL|KEYC_XTERM,
 | 
			
		||||
	KEYC_SHIFT|KEYC_ESCAPE|KEYC_CTRL|KEYC_XTERM
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Default terminfo(5) keys. Any keys that have builtin modifiers
 | 
			
		||||
 * (that is, where the key itself contains the modifiers) has the
 | 
			
		||||
 * KEYC_XTERM flag set so a leading escape is not treated as meta (and
 | 
			
		||||
 * probably removed).
 | 
			
		||||
 * Default terminfo(5) keys. Any keys that have builtin modifiers (that is,
 | 
			
		||||
 * where the key itself contains the modifiers) has the KEYC_XTERM flag set so
 | 
			
		||||
 * a leading escape is not treated as meta (and probably removed).
 | 
			
		||||
 */
 | 
			
		||||
struct tty_default_key_code {
 | 
			
		||||
	enum tty_code_code	code;
 | 
			
		||||
@@ -272,10 +320,10 @@ static const struct tty_default_key_code tty_default_code_keys[] = {
 | 
			
		||||
	{ TTYC_KCBT, KEYC_BTAB },
 | 
			
		||||
 | 
			
		||||
	/* Arrow keys from terminfo. */
 | 
			
		||||
	{ TTYC_KCUU1, KEYC_UP },
 | 
			
		||||
	{ TTYC_KCUD1, KEYC_DOWN },
 | 
			
		||||
	{ TTYC_KCUB1, KEYC_LEFT },
 | 
			
		||||
	{ TTYC_KCUF1, KEYC_RIGHT },
 | 
			
		||||
	{ TTYC_KCUU1, KEYC_UP|KEYC_CURSOR },
 | 
			
		||||
	{ TTYC_KCUD1, KEYC_DOWN|KEYC_CURSOR },
 | 
			
		||||
	{ TTYC_KCUB1, KEYC_LEFT|KEYC_CURSOR },
 | 
			
		||||
	{ TTYC_KCUF1, KEYC_RIGHT|KEYC_CURSOR },
 | 
			
		||||
 | 
			
		||||
	/* Key and modifier capabilities. */
 | 
			
		||||
	{ TTYC_KDC2, KEYC_DC|KEYC_SHIFT|KEYC_XTERM },
 | 
			
		||||
@@ -403,17 +451,30 @@ void
 | 
			
		||||
tty_keys_build(struct tty *tty)
 | 
			
		||||
{
 | 
			
		||||
	const struct tty_default_key_raw	*tdkr;
 | 
			
		||||
	const struct tty_default_key_xterm	*tdkx;
 | 
			
		||||
	const struct tty_default_key_code	*tdkc;
 | 
			
		||||
	u_int		 			 i;
 | 
			
		||||
	u_int		 			 i, j;
 | 
			
		||||
	const char				*s;
 | 
			
		||||
	struct options_entry			*o;
 | 
			
		||||
	struct options_array_item		*a;
 | 
			
		||||
	union options_value			*ov;
 | 
			
		||||
	char					 copy[16];
 | 
			
		||||
	key_code				 key;
 | 
			
		||||
 | 
			
		||||
	if (tty->key_tree != NULL)
 | 
			
		||||
		tty_keys_free(tty);
 | 
			
		||||
	tty->key_tree = NULL;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < nitems(tty_default_xterm_keys); i++) {
 | 
			
		||||
		tdkx = &tty_default_xterm_keys[i];
 | 
			
		||||
		for (j = 2; j < nitems(tty_default_xterm_modifiers); j++) {
 | 
			
		||||
			strlcpy(copy, tdkx->template, sizeof copy);
 | 
			
		||||
			copy[strcspn(copy, "_")] = '0' + j;
 | 
			
		||||
 | 
			
		||||
			key = tdkx->key|tty_default_xterm_modifiers[j];
 | 
			
		||||
			tty_keys_add(tty, copy, key);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for (i = 0; i < nitems(tty_default_raw_keys); i++) {
 | 
			
		||||
		tdkr = &tty_default_raw_keys[i];
 | 
			
		||||
 | 
			
		||||
@@ -516,7 +577,6 @@ tty_keys_next1(struct tty *tty, const char *buf, size_t len, key_code *key,
 | 
			
		||||
	enum utf8_state		 more;
 | 
			
		||||
	u_int			 i;
 | 
			
		||||
	wchar_t			 wc;
 | 
			
		||||
	int			 n;
 | 
			
		||||
 | 
			
		||||
	log_debug("%s: next key is %zu (%.*s) (expired=%d)", c->name, len,
 | 
			
		||||
	    (int)len, buf, expired);
 | 
			
		||||
@@ -534,13 +594,6 @@ tty_keys_next1(struct tty *tty, const char *buf, size_t len, key_code *key,
 | 
			
		||||
		return (0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Is this an an xterm(1) key? */
 | 
			
		||||
	n = xterm_keys_find(buf, len, size, key);
 | 
			
		||||
	if (n == 0)
 | 
			
		||||
		return (0);
 | 
			
		||||
	if (n == 1 && !expired)
 | 
			
		||||
		return (1);
 | 
			
		||||
 | 
			
		||||
	/* Is this valid UTF-8? */
 | 
			
		||||
	more = utf8_open(&ud, (u_char)*buf);
 | 
			
		||||
	if (more == UTF8_MORE) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										252
									
								
								xterm-keys.c
									
									
									
									
									
								
							
							
						
						
									
										252
									
								
								xterm-keys.c
									
									
									
									
									
								
							@@ -1,252 +0,0 @@
 | 
			
		||||
/* $OpenBSD$ */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
 | 
			
		||||
 *
 | 
			
		||||
 * 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"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * xterm-style function keys append one of the following values before the last
 | 
			
		||||
 * character:
 | 
			
		||||
 *
 | 
			
		||||
 * 2 Shift
 | 
			
		||||
 * 3 Alt
 | 
			
		||||
 * 4 Shift + Alt
 | 
			
		||||
 * 5 Ctrl
 | 
			
		||||
 * 6 Shift + Ctrl
 | 
			
		||||
 * 7 Alt + Ctrl
 | 
			
		||||
 * 8 Shift + Alt + Ctrl
 | 
			
		||||
 *
 | 
			
		||||
 * Rather than parsing them, just match against a table.
 | 
			
		||||
 *
 | 
			
		||||
 * There are three forms for F1-F4 (\\033O_P and \\033O1;_P and \\033[1;_P).
 | 
			
		||||
 * We accept any but always output the latter (it comes first in the table).
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static int	xterm_keys_match(const char *, const char *, size_t, size_t *,
 | 
			
		||||
		    key_code *);
 | 
			
		||||
static int	xterm_keys_modifiers(const char *, size_t, size_t *,
 | 
			
		||||
		    key_code *);
 | 
			
		||||
 | 
			
		||||
struct xterm_keys_entry {
 | 
			
		||||
	key_code	 key;
 | 
			
		||||
	const char	*template;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct xterm_keys_entry xterm_keys_table[] = {
 | 
			
		||||
	{ KEYC_F1,	"\033[1;_P" },
 | 
			
		||||
	{ KEYC_F1,	"\033O1;_P" },
 | 
			
		||||
	{ KEYC_F1,	"\033O_P" },
 | 
			
		||||
	{ KEYC_F2,	"\033[1;_Q" },
 | 
			
		||||
	{ KEYC_F2,	"\033O1;_Q" },
 | 
			
		||||
	{ KEYC_F2,	"\033O_Q" },
 | 
			
		||||
	{ KEYC_F3,	"\033[1;_R" },
 | 
			
		||||
	{ KEYC_F3,	"\033O1;_R" },
 | 
			
		||||
	{ KEYC_F3,	"\033O_R" },
 | 
			
		||||
	{ KEYC_F4,	"\033[1;_S" },
 | 
			
		||||
	{ KEYC_F4,	"\033O1;_S" },
 | 
			
		||||
	{ KEYC_F4,	"\033O_S" },
 | 
			
		||||
	{ KEYC_F5,	"\033[15;_~" },
 | 
			
		||||
	{ KEYC_F6,	"\033[17;_~" },
 | 
			
		||||
	{ KEYC_F7,	"\033[18;_~" },
 | 
			
		||||
	{ KEYC_F8,	"\033[19;_~" },
 | 
			
		||||
	{ KEYC_F9,	"\033[20;_~" },
 | 
			
		||||
	{ KEYC_F10,	"\033[21;_~" },
 | 
			
		||||
	{ KEYC_F11,	"\033[23;_~" },
 | 
			
		||||
	{ KEYC_F12,	"\033[24;_~" },
 | 
			
		||||
	{ KEYC_UP,	"\033[1;_A" },
 | 
			
		||||
	{ KEYC_DOWN,	"\033[1;_B" },
 | 
			
		||||
	{ KEYC_RIGHT,	"\033[1;_C" },
 | 
			
		||||
	{ KEYC_LEFT,	"\033[1;_D" },
 | 
			
		||||
	{ KEYC_HOME,	"\033[1;_H" },
 | 
			
		||||
	{ KEYC_END,	"\033[1;_F" },
 | 
			
		||||
	{ KEYC_PPAGE,	"\033[5;_~" },
 | 
			
		||||
	{ KEYC_NPAGE,	"\033[6;_~" },
 | 
			
		||||
	{ KEYC_IC,	"\033[2;_~" },
 | 
			
		||||
	{ KEYC_DC,	"\033[3;_~" },
 | 
			
		||||
 | 
			
		||||
	{ '!',          "\033[27;_;33~" },
 | 
			
		||||
	{ '#',		"\033[27;_;35~" },
 | 
			
		||||
	{ '(',		"\033[27;_;40~" },
 | 
			
		||||
	{ ')',		"\033[27;_;41~" },
 | 
			
		||||
	{ '+',		"\033[27;_;43~" },
 | 
			
		||||
	{ ',',		"\033[27;_;44~" },
 | 
			
		||||
	{ '-',		"\033[27;_;45~" },
 | 
			
		||||
	{ '.',		"\033[27;_;46~" },
 | 
			
		||||
	{ '0',		"\033[27;_;48~" },
 | 
			
		||||
	{ '1',		"\033[27;_;49~" },
 | 
			
		||||
	{ '2',		"\033[27;_;50~" },
 | 
			
		||||
	{ '3',		"\033[27;_;51~" },
 | 
			
		||||
	{ '4',		"\033[27;_;52~" },
 | 
			
		||||
	{ '5',		"\033[27;_;53~" },
 | 
			
		||||
	{ '6',		"\033[27;_;54~" },
 | 
			
		||||
	{ '7',		"\033[27;_;55~" },
 | 
			
		||||
	{ '8',		"\033[27;_;56~" },
 | 
			
		||||
	{ '9',		"\033[27;_;57~" },
 | 
			
		||||
	{ ':',		"\033[27;_;58~" },
 | 
			
		||||
	{ ';',		"\033[27;_;59~" },
 | 
			
		||||
	{ '<',		"\033[27;_;60~" },
 | 
			
		||||
	{ '=',		"\033[27;_;61~" },
 | 
			
		||||
	{ '>',		"\033[27;_;62~" },
 | 
			
		||||
	{ '?',		"\033[27;_;63~" },
 | 
			
		||||
	{ '\'',		"\033[27;_;39~" },
 | 
			
		||||
	{ '\r',		"\033[27;_;13~" },
 | 
			
		||||
	{ '\t',		"\033[27;_;9~" },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Match key against buffer, treating _ as a wildcard. Return -1 for no match,
 | 
			
		||||
 * 0 for match, 1 if the end of the buffer is reached (need more data).
 | 
			
		||||
 */
 | 
			
		||||
static int
 | 
			
		||||
xterm_keys_match(const char *template, const char *buf, size_t len,
 | 
			
		||||
    size_t *size, key_code *modifiers)
 | 
			
		||||
{
 | 
			
		||||
	size_t	pos;
 | 
			
		||||
	int	retval;
 | 
			
		||||
 | 
			
		||||
	*modifiers = 0;
 | 
			
		||||
 | 
			
		||||
	if (len == 0)
 | 
			
		||||
		return (0);
 | 
			
		||||
 | 
			
		||||
	pos = 0;
 | 
			
		||||
	do {
 | 
			
		||||
		if (*template == '_') {
 | 
			
		||||
			retval = xterm_keys_modifiers(buf, len, &pos,
 | 
			
		||||
			    modifiers);
 | 
			
		||||
			if (retval != 0)
 | 
			
		||||
				return (retval);
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		if (buf[pos] != *template)
 | 
			
		||||
			return (-1);
 | 
			
		||||
		pos++;
 | 
			
		||||
	} while (*++template != '\0' && pos != len);
 | 
			
		||||
 | 
			
		||||
	if (*template != '\0')	/* partial */
 | 
			
		||||
		return (1);
 | 
			
		||||
 | 
			
		||||
	*size = pos;
 | 
			
		||||
	return (0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Find modifiers from buffer. */
 | 
			
		||||
static int
 | 
			
		||||
xterm_keys_modifiers(const char *buf, size_t len, size_t *pos,
 | 
			
		||||
    key_code *modifiers)
 | 
			
		||||
{
 | 
			
		||||
	u_int	flags;
 | 
			
		||||
 | 
			
		||||
	if (len - *pos < 2)
 | 
			
		||||
		return (1);
 | 
			
		||||
 | 
			
		||||
	if (buf[*pos] < '0' || buf[*pos] > '9')
 | 
			
		||||
		return (-1);
 | 
			
		||||
	flags = buf[(*pos)++] - '0';
 | 
			
		||||
	if (buf[*pos] >= '0' && buf[*pos] <= '9')
 | 
			
		||||
		flags = (flags * 10) + (buf[(*pos)++] - '0');
 | 
			
		||||
	flags -= 1;
 | 
			
		||||
 | 
			
		||||
	*modifiers = 0;
 | 
			
		||||
	if (flags & 1)
 | 
			
		||||
		*modifiers |= KEYC_SHIFT;
 | 
			
		||||
	if (flags & 2)
 | 
			
		||||
		*modifiers |= KEYC_ESCAPE;
 | 
			
		||||
	if (flags & 4)
 | 
			
		||||
		*modifiers |= KEYC_CTRL;
 | 
			
		||||
	if (flags & 8)
 | 
			
		||||
		*modifiers |= KEYC_ESCAPE;
 | 
			
		||||
	return (0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Lookup key from a buffer against the table. Returns 0 for found (and the
 | 
			
		||||
 * key), -1 for not found, 1 for partial match.
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
xterm_keys_find(const char *buf, size_t len, size_t *size, key_code *key)
 | 
			
		||||
{
 | 
			
		||||
	const struct xterm_keys_entry	*entry;
 | 
			
		||||
	u_int				 i;
 | 
			
		||||
	int				 matched;
 | 
			
		||||
	key_code			 modifiers;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < nitems(xterm_keys_table); i++) {
 | 
			
		||||
		entry = &xterm_keys_table[i];
 | 
			
		||||
 | 
			
		||||
		matched = xterm_keys_match(entry->template, buf, len, size,
 | 
			
		||||
		    &modifiers);
 | 
			
		||||
		if (matched == -1)
 | 
			
		||||
			continue;
 | 
			
		||||
		if (matched == 0)
 | 
			
		||||
			*key = (entry->key|modifiers|KEYC_XTERM);
 | 
			
		||||
		return (matched);
 | 
			
		||||
	}
 | 
			
		||||
	return (-1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Lookup a key number from the table. */
 | 
			
		||||
char *
 | 
			
		||||
xterm_keys_lookup(key_code key)
 | 
			
		||||
{
 | 
			
		||||
	const struct xterm_keys_entry	*entry;
 | 
			
		||||
	u_int				 i;
 | 
			
		||||
	key_code			 modifiers;
 | 
			
		||||
	char				*out;
 | 
			
		||||
 | 
			
		||||
	modifiers = 1;
 | 
			
		||||
	if (key & KEYC_SHIFT)
 | 
			
		||||
		modifiers += 1;
 | 
			
		||||
	if (key & KEYC_ESCAPE)
 | 
			
		||||
		modifiers += 2;
 | 
			
		||||
	if (key & KEYC_CTRL)
 | 
			
		||||
		modifiers += 4;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * If the key has no modifiers, return NULL and let it fall through to
 | 
			
		||||
	 * the normal lookup.
 | 
			
		||||
	 */
 | 
			
		||||
	if (modifiers == 1)
 | 
			
		||||
		return (NULL);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * If this has the escape modifier, but was not originally an xterm
 | 
			
		||||
	 * key, it may be a genuine escape + key. So don't pass it through as
 | 
			
		||||
	 * an xterm key or programs like vi may be confused.
 | 
			
		||||
	 */
 | 
			
		||||
	if ((key & (KEYC_ESCAPE|KEYC_XTERM)) == KEYC_ESCAPE)
 | 
			
		||||
		return (NULL);
 | 
			
		||||
 | 
			
		||||
	/* Otherwise, find the key in the table. */
 | 
			
		||||
	key &= KEYC_MASK_KEY;
 | 
			
		||||
	for (i = 0; i < nitems(xterm_keys_table); i++) {
 | 
			
		||||
		entry = &xterm_keys_table[i];
 | 
			
		||||
		if (key == entry->key)
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
	if (i == nitems(xterm_keys_table))
 | 
			
		||||
		return (NULL);
 | 
			
		||||
 | 
			
		||||
	/* Copy the template and replace the modifier. */
 | 
			
		||||
	out = xstrdup(entry->template);
 | 
			
		||||
	out[strcspn(out, "_")] = '0' + modifiers;
 | 
			
		||||
	return (out);
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user