mirror of
				https://github.com/tmux/tmux.git
				synced 2025-10-26 12:27:15 +00:00 
			
		
		
		
	Merge branch 'obsd-master'
This commit is contained in:
		
							
								
								
									
										20
									
								
								format.c
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								format.c
									
									
									
									
									
								
							| @@ -1962,6 +1962,23 @@ format_cb_pane_unseen_changes(struct format_tree *ft) | ||||
| 	return (NULL); | ||||
| } | ||||
|  | ||||
| /* Callback for pane_key_mode. */ | ||||
| static void * | ||||
| format_cb_pane_key_mode(struct format_tree *ft) | ||||
| { | ||||
| 	if (ft->wp != NULL && ft->wp->screen != NULL) { | ||||
| 		switch (ft->wp->screen->mode & EXTENDED_KEY_MODES) { | ||||
| 		case MODE_KEYS_EXTENDED: | ||||
| 			return (xstrdup("Ext 1")); | ||||
| 		case MODE_KEYS_EXTENDED_2: | ||||
| 			return (xstrdup("Ext 2")); | ||||
| 		default: | ||||
| 			return (xstrdup("VT10x")); | ||||
| 		} | ||||
| 	} | ||||
| 	return (NULL); | ||||
| } | ||||
|  | ||||
| /* Callback for pane_last. */ | ||||
| static void * | ||||
| format_cb_pane_last(struct format_tree *ft) | ||||
| @@ -2997,6 +3014,9 @@ static const struct format_table_entry format_table[] = { | ||||
| 	{ "pane_input_off", FORMAT_TABLE_STRING, | ||||
| 	  format_cb_pane_input_off | ||||
| 	}, | ||||
| 	{ "pane_key_mode", FORMAT_TABLE_STRING, | ||||
| 	  format_cb_pane_key_mode | ||||
| 	}, | ||||
| 	{ "pane_last", FORMAT_TABLE_STRING, | ||||
| 	  format_cb_pane_last | ||||
| 	}, | ||||
|   | ||||
							
								
								
									
										373
									
								
								input-keys.c
									
									
									
									
									
								
							
							
						
						
									
										373
									
								
								input-keys.c
									
									
									
									
									
								
							| @@ -307,20 +307,6 @@ static struct input_key_entry input_key_defaults[] = { | ||||
| 	{ .key = KEYC_DC|KEYC_BUILD_MODIFIERS, | ||||
| 	  .data = "\033[3;_~" | ||||
| 	}, | ||||
|  | ||||
| 	/* Tab and modifiers. */ | ||||
| 	{ .key = '\011'|KEYC_CTRL, | ||||
| 	  .data = "\011" | ||||
| 	}, | ||||
| 	{ .key = '\011'|KEYC_CTRL|KEYC_EXTENDED, | ||||
| 	  .data = "\033[9;5u" | ||||
| 	}, | ||||
| 	{ .key = '\011'|KEYC_CTRL|KEYC_SHIFT, | ||||
| 	  .data = "\033[Z" | ||||
| 	}, | ||||
| 	{ .key = '\011'|KEYC_CTRL|KEYC_SHIFT|KEYC_EXTENDED, | ||||
| 	  .data = "\033[1;5Z" | ||||
| 	} | ||||
| }; | ||||
| static const key_code input_key_modifiers[] = { | ||||
| 	0, | ||||
| @@ -426,126 +412,18 @@ input_key_write(const char *from, struct bufferevent *bev, const char *data, | ||||
| 	bufferevent_write(bev, data, size); | ||||
| } | ||||
|  | ||||
| /* Translate a key code into an output key sequence. */ | ||||
| int | ||||
| input_key(struct screen *s, struct bufferevent *bev, key_code key) | ||||
| /* | ||||
|  * Encode and write an extended key escape sequence in one of the two | ||||
|  * possible formats, depending on the configured output mode. | ||||
|  */ | ||||
| static int | ||||
| input_key_extended(struct bufferevent *bev, key_code key) | ||||
| { | ||||
| 	struct input_key_entry	*ike = NULL; | ||||
| 	key_code		 justkey, newkey, outkey, modifiers; | ||||
| 	struct utf8_data	 ud; | ||||
| 	char			 tmp[64], modifier; | ||||
| 	char		 tmp[64], modifier; | ||||
| 	struct utf8_data ud; | ||||
| 	wchar_t		 wc; | ||||
|  | ||||
| 	/* Mouse keys need a pane. */ | ||||
| 	if (KEYC_IS_MOUSE(key)) | ||||
| 		return (0); | ||||
|  | ||||
| 	/* Literal keys go as themselves (can't be more than eight bits). */ | ||||
| 	if (key & KEYC_LITERAL) { | ||||
| 		ud.data[0] = (u_char)key; | ||||
| 		input_key_write(__func__, bev, &ud.data[0], 1); | ||||
| 		return (0); | ||||
| 	} | ||||
|  | ||||
| 	/* Is this backspace? */ | ||||
| 	if ((key & KEYC_MASK_KEY) == KEYC_BSPACE) { | ||||
| 		newkey = options_get_number(global_options, "backspace"); | ||||
| 		if (newkey >= 0x7f) | ||||
| 			newkey = '\177'; | ||||
| 		key = newkey|(key & (KEYC_MASK_MODIFIERS|KEYC_MASK_FLAGS)); | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * If this is a normal 7-bit key, just send it, with a leading escape | ||||
| 	 * if necessary. If it is a UTF-8 key, split it and send it. | ||||
| 	 */ | ||||
| 	justkey = (key & ~(KEYC_META|KEYC_IMPLIED_META)); | ||||
| 	if (justkey <= 0x7f) { | ||||
| 		if (key & KEYC_META) | ||||
| 			input_key_write(__func__, bev, "\033", 1); | ||||
| 		ud.data[0] = justkey; | ||||
| 		input_key_write(__func__, bev, &ud.data[0], 1); | ||||
| 		return (0); | ||||
| 	} | ||||
| 	if (KEYC_IS_UNICODE(justkey)) { | ||||
| 		if (key & KEYC_META) | ||||
| 			input_key_write(__func__, bev, "\033", 1); | ||||
| 		utf8_to_data(justkey, &ud); | ||||
| 		input_key_write(__func__, bev, ud.data, ud.size); | ||||
| 		return (0); | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Look up in the tree. If not in application keypad or cursor mode, | ||||
| 	 * remove the flags from the key. | ||||
| 	 */ | ||||
| 	if (~s->mode & MODE_KKEYPAD) | ||||
| 		key &= ~KEYC_KEYPAD; | ||||
| 	if (~s->mode & MODE_KCURSOR) | ||||
| 		key &= ~KEYC_CURSOR; | ||||
| 	if (s->mode & MODE_KEXTENDED) | ||||
| 		ike = input_key_get(key|KEYC_EXTENDED); | ||||
| 	if (ike == NULL) | ||||
| 		ike = input_key_get(key); | ||||
| 	if (ike == NULL && (key & KEYC_META) && (~key & KEYC_IMPLIED_META)) | ||||
| 		ike = input_key_get(key & ~KEYC_META); | ||||
| 	if (ike == NULL && (key & KEYC_CURSOR)) | ||||
| 		ike = input_key_get(key & ~KEYC_CURSOR); | ||||
| 	if (ike == NULL && (key & KEYC_KEYPAD)) | ||||
| 		ike = input_key_get(key & ~KEYC_KEYPAD); | ||||
| 	if (ike == NULL && (key & KEYC_EXTENDED)) | ||||
| 		ike = input_key_get(key & ~KEYC_EXTENDED); | ||||
| 	if (ike != NULL) { | ||||
| 		log_debug("found key 0x%llx: \"%s\"", key, ike->data); | ||||
| 		if ((key == KEYC_PASTE_START || key == KEYC_PASTE_END) && | ||||
| 		    (~s->mode & MODE_BRACKETPASTE)) | ||||
| 			return (0); | ||||
| 		if ((key & KEYC_META) && (~key & KEYC_IMPLIED_META)) | ||||
| 			input_key_write(__func__, bev, "\033", 1); | ||||
| 		input_key_write(__func__, bev, ike->data, strlen(ike->data)); | ||||
| 		return (0); | ||||
| 	} | ||||
|  | ||||
| 	/* No builtin key sequence; construct an extended key sequence. */ | ||||
| 	if (~s->mode & MODE_KEXTENDED) { | ||||
| 		if ((key & KEYC_MASK_MODIFIERS) != KEYC_CTRL) | ||||
| 			goto missing; | ||||
| 		justkey = (key & KEYC_MASK_KEY); | ||||
| 		switch (justkey) { | ||||
| 		case ' ': | ||||
| 		case '2': | ||||
| 			key = 0|(key & ~KEYC_MASK_KEY); | ||||
| 			break; | ||||
| 		case '|': | ||||
| 			key = 28|(key & ~KEYC_MASK_KEY); | ||||
| 			break; | ||||
| 		case '6': | ||||
| 			key = 30|(key & ~KEYC_MASK_KEY); | ||||
| 			break; | ||||
| 		case '-': | ||||
| 		case '/': | ||||
| 			key = 31|(key & ~KEYC_MASK_KEY); | ||||
| 			break; | ||||
| 		case '?': | ||||
| 			key = 127|(key & ~KEYC_MASK_KEY); | ||||
| 			break; | ||||
| 		default: | ||||
| 			if (justkey >= 'A' && justkey <= '_') | ||||
| 				key = (justkey - 'A')|(key & ~KEYC_MASK_KEY); | ||||
| 			else if (justkey >= 'a' && justkey <= '~') | ||||
| 				key = (justkey - 96)|(key & ~KEYC_MASK_KEY); | ||||
| 			else | ||||
| 				return (0); | ||||
| 			break; | ||||
| 		} | ||||
| 		return (input_key(s, bev, key & ~KEYC_CTRL)); | ||||
| 	} | ||||
| 	outkey = (key & KEYC_MASK_KEY); | ||||
| 	modifiers = (key & KEYC_MASK_MODIFIERS); | ||||
| 	if (outkey < 32 && outkey != 9 && outkey != 13 && outkey != 27) { | ||||
| 		outkey = 64 + outkey; | ||||
| 		modifiers |= KEYC_CTRL; | ||||
| 	} | ||||
| 	switch (modifiers) { | ||||
| 	switch (key & KEYC_MASK_MODIFIERS) { | ||||
| 	case KEYC_SHIFT: | ||||
| 		modifier = '2'; | ||||
| 		break; | ||||
| @@ -568,17 +446,240 @@ input_key(struct screen *s, struct bufferevent *bev, key_code key) | ||||
| 		modifier = '8'; | ||||
| 		break; | ||||
| 	default: | ||||
| 		goto missing; | ||||
| 		return (-1); | ||||
| 	} | ||||
| 	xsnprintf(tmp, sizeof tmp, "\033[%llu;%cu", outkey, modifier); | ||||
|  | ||||
| 	if (KEYC_IS_UNICODE(key)) { | ||||
| 		utf8_to_data(key & KEYC_MASK_KEY, &ud); | ||||
| 		if (utf8_towc(&ud, &wc) == UTF8_DONE) | ||||
| 			key = wc; | ||||
| 		else | ||||
| 			return (-1); | ||||
| 	} else | ||||
| 		key &= KEYC_MASK_KEY; | ||||
|  | ||||
| 	if (options_get_number(global_options, "extended-keys-format") == 1) | ||||
| 		xsnprintf(tmp, sizeof tmp, "\033[27;%c;%llu~", modifier, key); | ||||
| 	else | ||||
| 		xsnprintf(tmp, sizeof tmp, "\033[%llu;%cu", key, modifier); | ||||
|  | ||||
| 	input_key_write(__func__, bev, tmp, strlen(tmp)); | ||||
| 	return (0); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Outputs the key in the "standard" mode. This is by far the most | ||||
|  * complicated output mode, with a lot of remapping in order to | ||||
|  * emulate quirks of terminals that today can be only found in museums. | ||||
|  */ | ||||
| static int | ||||
| input_key_vt10x(struct bufferevent *bev, key_code key) | ||||
| { | ||||
| 	struct utf8_data	 ud; | ||||
| 	key_code		 onlykey; | ||||
| 	char			*p; | ||||
| 	static const char	*standard_map[2] = { | ||||
| 		"1!9(0)=+;:'\",<.>/-8? 2", | ||||
| 		"119900=+;;'',,..\x1f\x1f\x7f\x7f\0\0", | ||||
| 	}; | ||||
|  | ||||
| 	log_debug("%s: key in %llx", __func__, key); | ||||
|  | ||||
| 	if (key & KEYC_META) | ||||
| 		input_key_write(__func__, bev, "\033", 1); | ||||
|  | ||||
| 	/* | ||||
| 	 * There's no way to report modifiers for unicode keys in standard mode | ||||
| 	 * so lose the modifiers. | ||||
| 	 */ | ||||
| 	if (KEYC_IS_UNICODE(key)) { | ||||
| 		utf8_to_data(key, &ud); | ||||
|                 input_key_write(__func__, bev, ud.data, ud.size); | ||||
| 		return (0); | ||||
| 	} | ||||
|  | ||||
| 	onlykey = key & KEYC_MASK_KEY; | ||||
|  | ||||
| 	/* Prevent TAB and RET from being swallowed by C0 remapping logic. */ | ||||
| 	if (onlykey == '\r' || onlykey == '\t') | ||||
| 		key &= ~KEYC_CTRL; | ||||
|  | ||||
| 	/* | ||||
| 	 * Convert keys with Ctrl modifier into corresponding C0 control codes, | ||||
| 	 * with the exception of *some* keys, which are remapped into printable | ||||
| 	 * ASCII characters. | ||||
| 	 * | ||||
| 	 * There is no special handling for Shift modifier, which is pretty | ||||
| 	 * much redundant anyway, as no terminal will send <base key>|SHIFT, | ||||
| 	 * but only <shifted key>|SHIFT. | ||||
| 	 */ | ||||
| 	if (key & KEYC_CTRL) { | ||||
| 		p = strchr(standard_map[0], onlykey); | ||||
| 		if (p != NULL) | ||||
| 			key = standard_map[1][p - standard_map[0]]; | ||||
| 		else if (onlykey >= '3' && onlykey <= '7') | ||||
| 			key = onlykey - '\030'; | ||||
| 		else if (onlykey >= '@' && onlykey <= '~') | ||||
| 			key = onlykey & 0x1f; | ||||
| 		else | ||||
| 			return (-1); | ||||
| 	} | ||||
|  | ||||
| 	log_debug("%s: key out %llx", __func__, key); | ||||
|  | ||||
| 	ud.data[0] = key & 0x7f; | ||||
| 	input_key_write(__func__, bev, &ud.data[0], 1); | ||||
| 	return (0); | ||||
| } | ||||
|  | ||||
| /* Pick keys that are reported as vt10x keys in modifyOtherKeys=1 mode. */ | ||||
| static int | ||||
| input_key_mode1(struct bufferevent *bev, key_code key) | ||||
| { | ||||
| 	key_code	 onlykey; | ||||
|  | ||||
| 	log_debug("%s: key in %llx", __func__, key); | ||||
|  | ||||
| 	/* | ||||
| 	 * As per | ||||
| 	 * https://invisible-island.net/xterm/modified-keys-us-pc105.html. | ||||
| 	 */ | ||||
| 	onlykey = key & KEYC_MASK_KEY; | ||||
| 	if ((key & (KEYC_META | KEYC_CTRL)) == KEYC_CTRL && | ||||
| 	    (onlykey == ' ' || | ||||
| 	     onlykey == '/' || | ||||
| 	     onlykey == '@' || | ||||
| 	     onlykey == '^' || | ||||
| 	     (onlykey >= '2' && onlykey <= '8') || | ||||
| 	     (onlykey >= '@' && onlykey <= '~'))) | ||||
| 		return (input_key_vt10x(bev, key)); | ||||
|  | ||||
| 	/* | ||||
| 	 * A regular key + Meta. In the absence of a standard to back this, we | ||||
| 	 * mimic what iTerm 2 does. | ||||
| 	 */ | ||||
| 	if ((key & (KEYC_CTRL | KEYC_META)) == KEYC_META) | ||||
| 		return (input_key_vt10x(bev, key)); | ||||
|  | ||||
| missing: | ||||
| 	log_debug("key 0x%llx missing", key); | ||||
| 	return (-1); | ||||
| } | ||||
|  | ||||
| /* Translate a key code into an output key sequence. */ | ||||
| int | ||||
| input_key(struct screen *s, struct bufferevent *bev, key_code key) | ||||
| { | ||||
| 	struct input_key_entry	*ike = NULL; | ||||
| 	key_code		 newkey; | ||||
| 	struct utf8_data	 ud; | ||||
|  | ||||
| 	/* Mouse keys need a pane. */ | ||||
| 	if (KEYC_IS_MOUSE(key)) | ||||
| 		return (0); | ||||
|  | ||||
| 	/* Literal keys go as themselves (can't be more than eight bits). */ | ||||
| 	if (key & KEYC_LITERAL) { | ||||
| 		ud.data[0] = (u_char)key; | ||||
| 		input_key_write(__func__, bev, &ud.data[0], 1); | ||||
| 		return (0); | ||||
| 	} | ||||
|  | ||||
| 	/* Is this backspace? */ | ||||
| 	if ((key & KEYC_MASK_KEY) == KEYC_BSPACE) { | ||||
| 		newkey = options_get_number(global_options, "backspace"); | ||||
| 		if (newkey >= 0x7f) | ||||
| 			newkey = '\177'; | ||||
| 		key = newkey|(key & (KEYC_MASK_MODIFIERS|KEYC_MASK_FLAGS)); | ||||
| 	} | ||||
|  | ||||
| 	/* Is this backtab? */ | ||||
| 	if ((key & KEYC_MASK_KEY) == KEYC_BTAB) { | ||||
| 		if (s->mode & EXTENDED_KEY_MODES) { | ||||
| 			/* When in xterm extended mode, remap into S-Tab. */ | ||||
| 			key = '\011' | (key & ~KEYC_MASK_KEY) | KEYC_SHIFT; | ||||
| 		} else { | ||||
| 			/* Otherwise clear modifiers. */ | ||||
| 			key &= ~KEYC_MASK_MODIFIERS; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * A trivial case, that is a 7-bit key, excluding C0 control characters | ||||
| 	 * that can't be entered from the keyboard, and no modifiers; or a UTF-8 | ||||
| 	 * key and no modifiers. | ||||
| 	 */ | ||||
| 	if (!(key & ~KEYC_MASK_KEY)) { | ||||
| 		if (key == C0_BS || key == C0_HT || | ||||
| 		    key == C0_CR || key == C0_ESC || | ||||
| 		    (key >= 0x20 && key <= 0x7f)) { | ||||
| 			ud.data[0] = key; | ||||
| 			input_key_write(__func__, bev, &ud.data[0], 1); | ||||
| 			return (0); | ||||
| 		} | ||||
| 		if (KEYC_IS_UNICODE(key)) { | ||||
| 			utf8_to_data(key, &ud); | ||||
| 			input_key_write(__func__, bev, ud.data, ud.size); | ||||
| 			return (0); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Look up the standard VT10x keys in the tree. If not in application | ||||
| 	 * keypad or cursor mode, remove the respective flags from the key. | ||||
| 	 */ | ||||
| 	if (~s->mode & MODE_KKEYPAD) | ||||
| 		key &= ~KEYC_KEYPAD; | ||||
| 	if (~s->mode & MODE_KCURSOR) | ||||
| 		key &= ~KEYC_CURSOR; | ||||
| 	if (ike == NULL) | ||||
| 		ike = input_key_get(key); | ||||
| 	if (ike == NULL && (key & KEYC_META) && (~key & KEYC_IMPLIED_META)) | ||||
| 		ike = input_key_get(key & ~KEYC_META); | ||||
| 	if (ike == NULL && (key & KEYC_CURSOR)) | ||||
| 		ike = input_key_get(key & ~KEYC_CURSOR); | ||||
| 	if (ike == NULL && (key & KEYC_KEYPAD)) | ||||
| 		ike = input_key_get(key & ~KEYC_KEYPAD); | ||||
| 	if (ike != NULL) { | ||||
| 		log_debug("%s: found key 0x%llx: \"%s\"", __func__, key, | ||||
| 		    ike->data); | ||||
| 		if ((key == KEYC_PASTE_START || key == KEYC_PASTE_END) && | ||||
| 		    (~s->mode & MODE_BRACKETPASTE)) | ||||
| 			return (0); | ||||
| 		if ((key & KEYC_META) && (~key & KEYC_IMPLIED_META)) | ||||
| 			input_key_write(__func__, bev, "\033", 1); | ||||
| 		input_key_write(__func__, bev, ike->data, strlen(ike->data)); | ||||
| 		return (0); | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * No builtin key sequence; construct an extended key sequence | ||||
| 	 * depending on the client mode. | ||||
| 	 * | ||||
| 	 * If something invalid reaches here, an invalid output may be | ||||
| 	 * produced. For example Ctrl-Shift-2 is invalid (as there's | ||||
| 	 * no way to enter it). The correct form is Ctrl-Shift-@, at | ||||
| 	 * least in US English keyboard layout. | ||||
| 	 */ | ||||
| 	switch (s->mode & EXTENDED_KEY_MODES) { | ||||
| 	case MODE_KEYS_EXTENDED_2: | ||||
| 		/* | ||||
| 		 * The simplest mode to handle - *all* modified keys are | ||||
| 		 * reported in the extended form. | ||||
| 		 */ | ||||
| 		return (input_key_extended(bev, key)); | ||||
|         case MODE_KEYS_EXTENDED: | ||||
| 		/* | ||||
| 		 * Some keys are still reported in standard mode, to maintain | ||||
| 		 * compatibility with applications unaware of extended keys. | ||||
| 		 */ | ||||
| 		if (input_key_mode1(bev, key) == -1) | ||||
| 			return (input_key_extended(bev, key)); | ||||
| 		return (0); | ||||
| 	default: | ||||
| 		/* The standard mode. */ | ||||
| 		return (input_key_vt10x(bev, key)); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* Get mouse event string. */ | ||||
| int | ||||
| input_key_get_mouse(struct screen *s, struct mouse_event *m, u_int x, u_int y, | ||||
|   | ||||
							
								
								
									
										26
									
								
								input.c
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								input.c
									
									
									
									
									
								
							| @@ -1408,17 +1408,29 @@ input_csi_dispatch(struct input_ctx *ictx) | ||||
| 	case INPUT_CSI_MODSET: | ||||
| 		n = input_get(ictx, 0, 0, 0); | ||||
| 		m = input_get(ictx, 1, 0, 0); | ||||
| 		if (options_get_number(global_options, "extended-keys") == 2) | ||||
| 		/* | ||||
| 		 * Set the extended key reporting mode as per the client request, | ||||
| 		 * unless "extended-keys always" forces us into mode 1. | ||||
| 		 */ | ||||
| 		if (options_get_number(global_options, "extended-keys") != 1) | ||||
| 			break; | ||||
| 		if (n == 0 || (n == 4 && m == 0)) | ||||
| 			screen_write_mode_clear(sctx, MODE_KEXTENDED); | ||||
| 		else if (n == 4 && (m == 1 || m == 2)) | ||||
| 			screen_write_mode_set(sctx, MODE_KEXTENDED); | ||||
| 		screen_write_mode_clear(sctx, | ||||
| 		    MODE_KEYS_EXTENDED|MODE_KEYS_EXTENDED_2); | ||||
| 		if (n == 4 && m == 1) | ||||
| 			screen_write_mode_set(sctx, MODE_KEYS_EXTENDED); | ||||
| 		if (n == 4 && m == 2) | ||||
| 			screen_write_mode_set(sctx, MODE_KEYS_EXTENDED_2); | ||||
| 		break; | ||||
| 	case INPUT_CSI_MODOFF: | ||||
| 		n = input_get(ictx, 0, 0, 0); | ||||
| 		if (n == 4) | ||||
| 			screen_write_mode_clear(sctx, MODE_KEXTENDED); | ||||
| 		/* | ||||
| 		 * Clear the extended key reporting mode as per the client request, | ||||
| 		 * unless "extended-keys always" forces us into mode 1. | ||||
| 		 */ | ||||
| 		if (n == 4) { | ||||
| 			screen_write_mode_clear(sctx, | ||||
| 			    MODE_KEYS_EXTENDED|MODE_KEYS_EXTENDED_2); | ||||
| 		} | ||||
| 		break; | ||||
| 	case INPUT_CSI_WINOPS: | ||||
| 		input_csi_dispatch_winops(ictx); | ||||
|   | ||||
| @@ -413,6 +413,8 @@ key_bindings_init(void) | ||||
| 		"bind -N 'Set the main-horizontal layout' M-3 { select-layout main-horizontal }", | ||||
| 		"bind -N 'Set the main-vertical layout' M-4 { select-layout main-vertical }", | ||||
| 		"bind -N 'Select the tiled layout' M-5 { select-layout tiled }", | ||||
| 		"bind -N 'Set the main-horizontal-mirrored layout' M-6 { select-layout main-horizontal-mirrored }", | ||||
| 		"bind -N 'Set the main-vertical-mirrored layout' M-7 { select-layout main-vertical-mirrored }", | ||||
| 		"bind -N 'Select the next window with an alert' M-n { next-window -a }", | ||||
| 		"bind -N 'Rotate through the panes in reverse' M-o { rotate-window -D }", | ||||
| 		"bind -N 'Select the previous window with an alert' M-p { previous-window -a }", | ||||
|   | ||||
							
								
								
									
										77
									
								
								key-string.c
									
									
									
									
									
								
							
							
						
						
									
										77
									
								
								key-string.c
									
									
									
									
									
								
							| @@ -56,12 +56,47 @@ static const struct { | ||||
| 	{ "PPage",	KEYC_PPAGE|KEYC_IMPLIED_META }, | ||||
| 	{ "PageUp",	KEYC_PPAGE|KEYC_IMPLIED_META }, | ||||
| 	{ "PgUp",	KEYC_PPAGE|KEYC_IMPLIED_META }, | ||||
| 	{ "Tab",	'\011' }, | ||||
| 	{ "BTab",	KEYC_BTAB }, | ||||
| 	{ "Space",	' ' }, | ||||
| 	{ "BSpace",	KEYC_BSPACE }, | ||||
| 	{ "Enter",	'\r' }, | ||||
| 	{ "Escape",	'\033' }, | ||||
|  | ||||
| 	/* | ||||
| 	 * C0 control characters, with the exception of Tab, Enter, | ||||
| 	 * and Esc, should never appear as keys. We still render them, | ||||
| 	 * so to be able to spot them in logs in case of an abnormality. | ||||
| 	 */ | ||||
| 	{ "[NUL]",	C0_NUL }, | ||||
| 	{ "[SOH]",	C0_SOH }, | ||||
| 	{ "[STX]",	C0_STX }, | ||||
| 	{ "[ETX]",	C0_ETX }, | ||||
| 	{ "[EOT]",	C0_EOT }, | ||||
| 	{ "[ENQ]",	C0_ENQ }, | ||||
| 	{ "[ASC]",	C0_ASC }, | ||||
| 	{ "[BEL]",	C0_BEL }, | ||||
| 	{ "[BS]",	C0_BS }, | ||||
| 	{ "Tab",	C0_HT }, | ||||
| 	{ "[LF]",	C0_LF }, | ||||
| 	{ "[VT]",	C0_VT }, | ||||
| 	{ "[FF]",	C0_FF }, | ||||
| 	{ "Enter",	C0_CR }, | ||||
| 	{ "[SO]",	C0_SO }, | ||||
| 	{ "[SI]",	C0_SI }, | ||||
| 	{ "[DLE]",	C0_DLE }, | ||||
| 	{ "[DC1]",	C0_DC1 }, | ||||
| 	{ "[DC2]",	C0_DC2 }, | ||||
| 	{ "[DC3]",	C0_DC3 }, | ||||
| 	{ "[DC4]",	C0_DC4 }, | ||||
| 	{ "[NAK]",	C0_NAK }, | ||||
| 	{ "[SYN]",	C0_SYN }, | ||||
| 	{ "[ETB]",	C0_ETB }, | ||||
| 	{ "[CAN]",	C0_CAN }, | ||||
| 	{ "[EM]",	C0_EM }, | ||||
| 	{ "[SUB]",	C0_SUB }, | ||||
| 	{ "Escape",	C0_ESC }, | ||||
| 	{ "[FS]",	C0_FS }, | ||||
| 	{ "[GS]",	C0_GS }, | ||||
| 	{ "[RS]",	C0_RS }, | ||||
| 	{ "[US]",	C0_US }, | ||||
|  | ||||
| 	/* Arrow keys. */ | ||||
| 	{ "Up",		KEYC_UP|KEYC_CURSOR|KEYC_IMPLIED_META }, | ||||
| @@ -206,7 +241,6 @@ key_string_get_modifiers(const char **string) | ||||
| key_code | ||||
| key_string_lookup_string(const char *string) | ||||
| { | ||||
| 	static const char	*other = "!#()+,-.0123456789:;<=>'\r\t\177`/"; | ||||
| 	key_code		 key, modifiers; | ||||
| 	u_int			 u, i; | ||||
| 	struct utf8_data	 ud, *udp; | ||||
| @@ -281,26 +315,6 @@ key_string_lookup_string(const char *string) | ||||
| 			key &= ~KEYC_IMPLIED_META; | ||||
| 	} | ||||
|  | ||||
| 	/* Convert the standard control keys. */ | ||||
| 	if (key <= 127 && | ||||
| 	    (modifiers & KEYC_CTRL) && | ||||
| 	    strchr(other, key) == NULL && | ||||
| 	    key != 9 && | ||||
| 	    key != 13 && | ||||
| 	    key != 27) { | ||||
| 		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 = 127; | ||||
| 		else | ||||
| 			return (KEYC_UNKNOWN); | ||||
| 		modifiers &= ~KEYC_CTRL; | ||||
| 	} | ||||
|  | ||||
| 	return (key|modifiers); | ||||
| } | ||||
|  | ||||
| @@ -324,10 +338,6 @@ key_string_lookup_key(key_code key, int with_flags) | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	/* Display C-@ as C-Space. */ | ||||
| 	if ((key & (KEYC_MASK_KEY|KEYC_MASK_MODIFIERS)) == 0) | ||||
| 		key = ' '|KEYC_CTRL; | ||||
|  | ||||
| 	/* Fill in the modifiers. */ | ||||
| 	if (key & KEYC_CTRL) | ||||
| 		strlcat(out, "C-", sizeof out); | ||||
| @@ -427,13 +437,8 @@ key_string_lookup_key(key_code key, int with_flags) | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	/* Check for standard or control key. */ | ||||
| 	if (key <= 32) { | ||||
| 		if (key == 0 || key > 26) | ||||
| 			xsnprintf(tmp, sizeof tmp, "C-%c", (int)(64 + key)); | ||||
| 		else | ||||
| 			xsnprintf(tmp, sizeof tmp, "C-%c", (int)(96 + key)); | ||||
| 	} else if (key >= 32 && key <= 126) { | ||||
| 	/* Printable ASCII keys. */ | ||||
| 	if (key > 32 && key <= 126) { | ||||
| 		tmp[0] = key; | ||||
| 		tmp[1] = '\0'; | ||||
| 	} else if (key == 127) | ||||
| @@ -460,8 +465,6 @@ out: | ||||
| 			strlcat(out, "I", sizeof out); | ||||
| 		if (saved & KEYC_BUILD_MODIFIERS) | ||||
| 			strlcat(out, "B", sizeof out); | ||||
| 		if (saved & KEYC_EXTENDED) | ||||
| 			strlcat(out, "E", sizeof out); | ||||
| 		if (saved & KEYC_SENT) | ||||
| 			strlcat(out, "S", sizeof out); | ||||
| 		strlcat(out, "]", sizeof out); | ||||
|   | ||||
							
								
								
									
										200
									
								
								layout-set.c
									
									
									
									
									
								
							
							
						
						
									
										200
									
								
								layout-set.c
									
									
									
									
									
								
							| @@ -31,7 +31,9 @@ | ||||
| static void	layout_set_even_h(struct window *); | ||||
| static void	layout_set_even_v(struct window *); | ||||
| static void	layout_set_main_h(struct window *); | ||||
| static void	layout_set_main_h_mirrored(struct window *); | ||||
| static void	layout_set_main_v(struct window *); | ||||
| static void	layout_set_main_v_mirrored(struct window *); | ||||
| static void	layout_set_tiled(struct window *); | ||||
|  | ||||
| static const struct { | ||||
| @@ -41,7 +43,9 @@ static const struct { | ||||
| 	{ "even-horizontal", layout_set_even_h }, | ||||
| 	{ "even-vertical", layout_set_even_v }, | ||||
| 	{ "main-horizontal", layout_set_main_h }, | ||||
| 	{ "main-horizontal-mirrored", layout_set_main_h_mirrored }, | ||||
| 	{ "main-vertical", layout_set_main_v }, | ||||
| 	{ "main-vertical-mirrored", layout_set_main_v_mirrored }, | ||||
| 	{ "tiled", layout_set_tiled }, | ||||
| }; | ||||
|  | ||||
| @@ -279,6 +283,104 @@ layout_set_main_h(struct window *w) | ||||
| 	server_redraw_window(w); | ||||
| } | ||||
|  | ||||
| static void | ||||
| layout_set_main_h_mirrored(struct window *w) | ||||
| { | ||||
| 	struct window_pane	*wp; | ||||
| 	struct layout_cell	*lc, *lcmain, *lcother, *lcchild; | ||||
| 	u_int			 n, mainh, otherh, sx, sy; | ||||
| 	char			*cause; | ||||
| 	const char		*s; | ||||
|  | ||||
| 	layout_print_cell(w->layout_root, __func__, 1); | ||||
|  | ||||
| 	/* Get number of panes. */ | ||||
| 	n = window_count_panes(w); | ||||
| 	if (n <= 1) | ||||
| 		return; | ||||
| 	n--;	/* take off main pane */ | ||||
|  | ||||
| 	/* Find available height - take off one line for the border. */ | ||||
| 	sy = w->sy - 1; | ||||
|  | ||||
| 	/* Get the main pane height. */ | ||||
| 	s = options_get_string(w->options, "main-pane-height"); | ||||
| 	mainh = args_string_percentage(s, 0, sy, sy, &cause); | ||||
| 	if (cause != NULL) { | ||||
| 		mainh = 24; | ||||
| 		free(cause); | ||||
| 	} | ||||
|  | ||||
| 	/* Work out the other pane height. */ | ||||
| 	if (mainh + PANE_MINIMUM >= sy) { | ||||
| 		if (sy <= PANE_MINIMUM + PANE_MINIMUM) | ||||
| 			mainh = PANE_MINIMUM; | ||||
| 		else | ||||
| 			mainh = sy - PANE_MINIMUM; | ||||
| 		otherh = PANE_MINIMUM; | ||||
| 	} else { | ||||
| 		s = options_get_string(w->options, "other-pane-height"); | ||||
| 		otherh = args_string_percentage(s, 0, sy, sy, &cause); | ||||
| 		if (cause != NULL || otherh == 0) { | ||||
| 			otherh = sy - mainh; | ||||
| 			free(cause); | ||||
| 		} else if (otherh > sy || sy - otherh < mainh) | ||||
| 			otherh = sy - mainh; | ||||
| 		else | ||||
| 			mainh = sy - otherh; | ||||
| 	} | ||||
|  | ||||
| 	/* Work out what width is needed. */ | ||||
| 	sx = (n * (PANE_MINIMUM + 1)) - 1; | ||||
| 	if (sx < w->sx) | ||||
| 		sx = w->sx; | ||||
|  | ||||
| 	/* Free old tree and create a new root. */ | ||||
| 	layout_free(w); | ||||
| 	lc = w->layout_root = layout_create_cell(NULL); | ||||
| 	layout_set_size(lc, sx, mainh + otherh + 1, 0, 0); | ||||
| 	layout_make_node(lc, LAYOUT_TOPBOTTOM); | ||||
|  | ||||
| 	/* Create the other pane. */ | ||||
| 	lcother = layout_create_cell(lc); | ||||
| 	layout_set_size(lcother, sx, otherh, 0, 0); | ||||
| 	if (n == 1) { | ||||
| 		wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry); | ||||
| 		layout_make_leaf(lcother, wp); | ||||
| 		TAILQ_INSERT_TAIL(&lc->cells, lcother, entry); | ||||
| 	} else { | ||||
| 		layout_make_node(lcother, LAYOUT_LEFTRIGHT); | ||||
| 		TAILQ_INSERT_TAIL(&lc->cells, lcother, entry); | ||||
|  | ||||
| 		/* Add the remaining panes as children. */ | ||||
| 		TAILQ_FOREACH(wp, &w->panes, entry) { | ||||
| 			if (wp == TAILQ_FIRST(&w->panes)) | ||||
| 				continue; | ||||
| 			lcchild = layout_create_cell(lcother); | ||||
| 			layout_set_size(lcchild, PANE_MINIMUM, otherh, 0, 0); | ||||
| 			layout_make_leaf(lcchild, wp); | ||||
| 			TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry); | ||||
| 		} | ||||
| 		layout_spread_cell(w, lcother); | ||||
| 	} | ||||
|  | ||||
| 	/* Create the main pane. */ | ||||
| 	lcmain = layout_create_cell(lc); | ||||
| 	layout_set_size(lcmain, sx, mainh, 0, 0); | ||||
| 	layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes)); | ||||
| 	TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry); | ||||
|  | ||||
| 	/* Fix cell offsets. */ | ||||
| 	layout_fix_offsets(w); | ||||
| 	layout_fix_panes(w, NULL); | ||||
|  | ||||
| 	layout_print_cell(w->layout_root, __func__, 1); | ||||
|  | ||||
| 	window_resize(w, lc->sx, lc->sy, -1, -1); | ||||
| 	notify_window("window-layout-changed", w); | ||||
| 	server_redraw_window(w); | ||||
| } | ||||
|  | ||||
| static void | ||||
| layout_set_main_v(struct window *w) | ||||
| { | ||||
| @@ -377,6 +479,104 @@ layout_set_main_v(struct window *w) | ||||
| 	server_redraw_window(w); | ||||
| } | ||||
|  | ||||
| static void | ||||
| layout_set_main_v_mirrored(struct window *w) | ||||
| { | ||||
| 	struct window_pane	*wp; | ||||
| 	struct layout_cell	*lc, *lcmain, *lcother, *lcchild; | ||||
| 	u_int			 n, mainw, otherw, sx, sy; | ||||
| 	char			*cause; | ||||
| 	const char		*s; | ||||
|  | ||||
| 	layout_print_cell(w->layout_root, __func__, 1); | ||||
|  | ||||
| 	/* Get number of panes. */ | ||||
| 	n = window_count_panes(w); | ||||
| 	if (n <= 1) | ||||
| 		return; | ||||
| 	n--;	/* take off main pane */ | ||||
|  | ||||
| 	/* Find available width - take off one line for the border. */ | ||||
| 	sx = w->sx - 1; | ||||
|  | ||||
| 	/* Get the main pane width. */ | ||||
| 	s = options_get_string(w->options, "main-pane-width"); | ||||
| 	mainw = args_string_percentage(s, 0, sx, sx, &cause); | ||||
| 	if (cause != NULL) { | ||||
| 		mainw = 80; | ||||
| 		free(cause); | ||||
| 	} | ||||
|  | ||||
| 	/* Work out the other pane width. */ | ||||
| 	if (mainw + PANE_MINIMUM >= sx) { | ||||
| 		if (sx <= PANE_MINIMUM + PANE_MINIMUM) | ||||
| 			mainw = PANE_MINIMUM; | ||||
| 		else | ||||
| 			mainw = sx - PANE_MINIMUM; | ||||
| 		otherw = PANE_MINIMUM; | ||||
| 	} else { | ||||
| 		s = options_get_string(w->options, "other-pane-width"); | ||||
| 		otherw = args_string_percentage(s, 0, sx, sx, &cause); | ||||
| 		if (cause != NULL || otherw == 0) { | ||||
| 			otherw = sx - mainw; | ||||
| 			free(cause); | ||||
| 		} else if (otherw > sx || sx - otherw < mainw) | ||||
| 			otherw = sx - mainw; | ||||
| 		else | ||||
| 			mainw = sx - otherw; | ||||
| 	} | ||||
|  | ||||
| 	/* Work out what height is needed. */ | ||||
| 	sy = (n * (PANE_MINIMUM + 1)) - 1; | ||||
| 	if (sy < w->sy) | ||||
| 		sy = w->sy; | ||||
|  | ||||
| 	/* Free old tree and create a new root. */ | ||||
| 	layout_free(w); | ||||
| 	lc = w->layout_root = layout_create_cell(NULL); | ||||
| 	layout_set_size(lc, mainw + otherw + 1, sy, 0, 0); | ||||
| 	layout_make_node(lc, LAYOUT_LEFTRIGHT); | ||||
|  | ||||
| 	/* Create the other pane. */ | ||||
| 	lcother = layout_create_cell(lc); | ||||
| 	layout_set_size(lcother, otherw, sy, 0, 0); | ||||
| 	if (n == 1) { | ||||
| 		wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry); | ||||
| 		layout_make_leaf(lcother, wp); | ||||
| 		TAILQ_INSERT_TAIL(&lc->cells, lcother, entry); | ||||
| 	} else { | ||||
| 		layout_make_node(lcother, LAYOUT_TOPBOTTOM); | ||||
| 		TAILQ_INSERT_TAIL(&lc->cells, lcother, entry); | ||||
|  | ||||
| 		/* Add the remaining panes as children. */ | ||||
| 		TAILQ_FOREACH(wp, &w->panes, entry) { | ||||
| 			if (wp == TAILQ_FIRST(&w->panes)) | ||||
| 				continue; | ||||
| 			lcchild = layout_create_cell(lcother); | ||||
| 			layout_set_size(lcchild, otherw, PANE_MINIMUM, 0, 0); | ||||
| 			layout_make_leaf(lcchild, wp); | ||||
| 			TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry); | ||||
| 		} | ||||
| 		layout_spread_cell(w, lcother); | ||||
| 	} | ||||
|  | ||||
| 	/* Create the main pane. */ | ||||
| 	lcmain = layout_create_cell(lc); | ||||
| 	layout_set_size(lcmain, mainw, sy, 0, 0); | ||||
| 	layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes)); | ||||
| 	TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry); | ||||
|  | ||||
| 	/* Fix cell offsets. */ | ||||
| 	layout_fix_offsets(w); | ||||
| 	layout_fix_panes(w, NULL); | ||||
|  | ||||
| 	layout_print_cell(w->layout_root, __func__, 1); | ||||
|  | ||||
| 	window_resize(w, lc->sx, lc->sy, -1, -1); | ||||
| 	notify_window("window-layout-changed", w); | ||||
| 	server_redraw_window(w); | ||||
| } | ||||
|  | ||||
| void | ||||
| layout_set_tiled(struct window *w) | ||||
| { | ||||
|   | ||||
							
								
								
									
										8
									
								
								menu.c
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								menu.c
									
									
									
									
									
								
							| @@ -335,7 +335,7 @@ menu_key_cb(struct client *c, void *data, struct key_event *event) | ||||
| 		c->flags |= CLIENT_REDRAWOVERLAY; | ||||
| 		return (0); | ||||
| 	case KEYC_PPAGE: | ||||
| 	case '\002': /* C-b */ | ||||
| 	case 'b'|KEYC_CTRL: | ||||
| 		if (md->choice < 6) | ||||
| 			md->choice = 0; | ||||
| 		else { | ||||
| @@ -394,13 +394,13 @@ menu_key_cb(struct client *c, void *data, struct key_event *event) | ||||
| 		} | ||||
| 		c->flags |= CLIENT_REDRAWOVERLAY; | ||||
| 		break; | ||||
| 	case '\006': /* C-f */ | ||||
| 	case 'f'|KEYC_CTRL: | ||||
| 		break; | ||||
| 	case '\r': | ||||
| 		goto chosen; | ||||
| 	case '\033': /* Escape */ | ||||
| 	case '\003': /* C-c */ | ||||
| 	case '\007': /* C-g */ | ||||
| 	case 'c'|KEYC_CTRL: | ||||
| 	case 'g'|KEYC_CTRL: | ||||
| 	case 'q': | ||||
| 		return (1); | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										14
									
								
								mode-tree.c
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								mode-tree.c
									
									
									
									
									
								
							| @@ -1088,22 +1088,22 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key, | ||||
| 	switch (*key) { | ||||
| 	case 'q': | ||||
| 	case '\033': /* Escape */ | ||||
| 	case '\007': /* C-g */ | ||||
| 	case 'g'|KEYC_CTRL: | ||||
| 		return (1); | ||||
| 	case KEYC_UP: | ||||
| 	case 'k': | ||||
| 	case KEYC_WHEELUP_PANE: | ||||
| 	case '\020': /* C-p */ | ||||
| 	case 'p'|KEYC_CTRL: | ||||
| 		mode_tree_up(mtd, 1); | ||||
| 		break; | ||||
| 	case KEYC_DOWN: | ||||
| 	case 'j': | ||||
| 	case KEYC_WHEELDOWN_PANE: | ||||
| 	case '\016': /* C-n */ | ||||
| 	case 'n'|KEYC_CTRL: | ||||
| 		mode_tree_down(mtd, 1); | ||||
| 		break; | ||||
| 	case KEYC_PPAGE: | ||||
| 	case '\002': /* C-b */ | ||||
| 	case 'b'|KEYC_CTRL: | ||||
| 		for (i = 0; i < mtd->height; i++) { | ||||
| 			if (mtd->current == 0) | ||||
| 				break; | ||||
| @@ -1111,7 +1111,7 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key, | ||||
| 		} | ||||
| 		break; | ||||
| 	case KEYC_NPAGE: | ||||
| 	case '\006': /* C-f */ | ||||
| 	case 'f'|KEYC_CTRL: | ||||
| 		for (i = 0; i < mtd->height; i++) { | ||||
| 			if (mtd->current == mtd->line_size - 1) | ||||
| 				break; | ||||
| @@ -1155,7 +1155,7 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key, | ||||
| 		for (i = 0; i < mtd->line_size; i++) | ||||
| 			mtd->line_list[i].item->tagged = 0; | ||||
| 		break; | ||||
| 	case '\024': /* C-t */ | ||||
| 	case 't'|KEYC_CTRL: | ||||
| 		for (i = 0; i < mtd->line_size; i++) { | ||||
| 			if ((mtd->line_list[i].item->parent == NULL && | ||||
| 			    !mtd->line_list[i].item->no_tag) || | ||||
| @@ -1211,7 +1211,7 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key, | ||||
| 		break; | ||||
| 	case '?': | ||||
| 	case '/': | ||||
| 	case '\023': /* C-s */ | ||||
| 	case 's'|KEYC_CTRL: | ||||
| 		mtd->references++; | ||||
| 		status_prompt_set(c, NULL, "(search) ", "", | ||||
| 		    mode_tree_search_callback, mode_tree_search_free, mtd, | ||||
|   | ||||
| @@ -93,6 +93,9 @@ static const char *options_table_detach_on_destroy_list[] = { | ||||
| static const char *options_table_extended_keys_list[] = { | ||||
| 	"off", "on", "always", NULL | ||||
| }; | ||||
| static const char *options_table_extended_keys_format_list[] = { | ||||
| 	"csi-u", "xterm", NULL | ||||
| }; | ||||
| static const char *options_table_allow_passthrough_list[] = { | ||||
| 	"off", "on", "all", NULL | ||||
| }; | ||||
| @@ -314,6 +317,14 @@ const struct options_table_entry options_table[] = { | ||||
| 		  "that support it." | ||||
| 	}, | ||||
|  | ||||
| 	{ .name = "extended-keys-format", | ||||
| 	  .type = OPTIONS_TABLE_CHOICE, | ||||
| 	  .scope = OPTIONS_TABLE_SERVER, | ||||
| 	  .choices = options_table_extended_keys_format_list, | ||||
| 	  .default_num = 1, | ||||
| 	  .text = "The format of emitted extended key sequences." | ||||
| 	}, | ||||
|  | ||||
| 	{ .name = "focus-events", | ||||
| 	  .type = OPTIONS_TABLE_FLAG, | ||||
| 	  .scope = OPTIONS_TABLE_SERVER, | ||||
| @@ -613,7 +624,7 @@ const struct options_table_entry options_table[] = { | ||||
| 	{ .name = "prefix", | ||||
| 	  .type = OPTIONS_TABLE_KEY, | ||||
| 	  .scope = OPTIONS_TABLE_SESSION, | ||||
| 	  .default_num = '\002', | ||||
| 	  .default_num = 'b'|KEYC_CTRL, | ||||
| 	  .text = "The prefix key." | ||||
| 	}, | ||||
|  | ||||
|   | ||||
							
								
								
									
										2
									
								
								popup.c
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								popup.c
									
									
									
									
									
								
							| @@ -542,7 +542,7 @@ popup_key_cb(struct client *c, void *data, struct key_event *event) | ||||
| 	} | ||||
| 	if ((((pd->flags & (POPUP_CLOSEEXIT|POPUP_CLOSEEXITZERO)) == 0) || | ||||
| 	    pd->job == NULL) && | ||||
| 	    (event->key == '\033' || event->key == '\003')) | ||||
| 	    (event->key == '\033' || event->key == ('c'|KEYC_CTRL))) | ||||
| 		return (1); | ||||
| 	if (pd->job != NULL) { | ||||
| 		if (KEYC_IS_MOUSE(event->key)) { | ||||
|   | ||||
| @@ -326,8 +326,9 @@ screen_write_reset(struct screen_write_ctx *ctx) | ||||
| 	screen_write_scrollregion(ctx, 0, screen_size_y(s) - 1); | ||||
|  | ||||
| 	s->mode = MODE_CURSOR|MODE_WRAP; | ||||
|  | ||||
| 	if (options_get_number(global_options, "extended-keys") == 2) | ||||
| 		s->mode |= MODE_KEXTENDED; | ||||
| 		s->mode = (s->mode & ~EXTENDED_KEY_MODES)|MODE_KEYS_EXTENDED; | ||||
|  | ||||
| 	screen_write_clearscreen(ctx, 8); | ||||
| 	screen_write_set_cursor(ctx, 0, 0); | ||||
|   | ||||
							
								
								
									
										9
									
								
								screen.c
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								screen.c
									
									
									
									
									
								
							| @@ -110,8 +110,9 @@ screen_reinit(struct screen *s) | ||||
| 	s->rlower = screen_size_y(s) - 1; | ||||
|  | ||||
| 	s->mode = MODE_CURSOR|MODE_WRAP|(s->mode & MODE_CRLF); | ||||
|  | ||||
| 	if (options_get_number(global_options, "extended-keys") == 2) | ||||
| 		s->mode |= MODE_KEXTENDED; | ||||
| 		s->mode = (s->mode & ~EXTENDED_KEY_MODES)|MODE_KEYS_EXTENDED; | ||||
|  | ||||
| 	if (s->saved_grid != NULL) | ||||
| 		screen_alternate_off(s, NULL, 0); | ||||
| @@ -730,8 +731,10 @@ screen_mode_to_string(int mode) | ||||
| 		strlcat(tmp, "ORIGIN,", sizeof tmp); | ||||
| 	if (mode & MODE_CRLF) | ||||
| 		strlcat(tmp, "CRLF,", sizeof tmp); | ||||
| 	if (mode & MODE_KEXTENDED) | ||||
| 		strlcat(tmp, "KEXTENDED,", sizeof tmp); | ||||
| 	if (mode & MODE_KEYS_EXTENDED) | ||||
| 		strlcat(tmp, "KEYS_EXTENDED,", sizeof tmp); | ||||
| 	if (mode & MODE_KEYS_EXTENDED_2) | ||||
| 		strlcat(tmp, "KEYS_EXTENDED_2,", sizeof tmp); | ||||
| 	tmp[strlen(tmp) - 1] = '\0'; | ||||
| 	return (tmp); | ||||
| } | ||||
|   | ||||
							
								
								
									
										77
									
								
								status.c
									
									
									
									
									
								
							
							
						
						
									
										77
									
								
								status.c
									
									
									
									
									
								
							| @@ -839,19 +839,19 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key) | ||||
| { | ||||
| 	if (c->prompt_mode == PROMPT_ENTRY) { | ||||
| 		switch (key) { | ||||
| 		case '\001': /* C-a */ | ||||
| 		case '\003': /* C-c */ | ||||
| 		case '\005': /* C-e */ | ||||
| 		case '\007': /* C-g */ | ||||
| 		case '\010': /* C-h */ | ||||
| 		case 'a'|KEYC_CTRL: | ||||
| 		case 'c'|KEYC_CTRL: | ||||
| 		case 'e'|KEYC_CTRL: | ||||
| 		case 'g'|KEYC_CTRL: | ||||
| 		case 'h'|KEYC_CTRL: | ||||
| 		case '\011': /* Tab */ | ||||
| 		case '\013': /* C-k */ | ||||
| 		case '\016': /* C-n */ | ||||
| 		case '\020': /* C-p */ | ||||
| 		case '\024': /* C-t */ | ||||
| 		case '\025': /* C-u */ | ||||
| 		case '\027': /* C-w */ | ||||
| 		case '\031': /* C-y */ | ||||
| 		case 'k'|KEYC_CTRL: | ||||
| 		case 'n'|KEYC_CTRL: | ||||
| 		case 'p'|KEYC_CTRL: | ||||
| 		case 't'|KEYC_CTRL: | ||||
| 		case 'u'|KEYC_CTRL: | ||||
| 		case 'w'|KEYC_CTRL: | ||||
| 		case 'y'|KEYC_CTRL: | ||||
| 		case '\n': | ||||
| 		case '\r': | ||||
| 		case KEYC_LEFT|KEYC_CTRL: | ||||
| @@ -890,7 +890,7 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key) | ||||
| 	case 'S': | ||||
| 		c->prompt_mode = PROMPT_ENTRY; | ||||
| 		c->flags |= CLIENT_REDRAWSTATUS; | ||||
| 		*new_key = '\025'; /* C-u */ | ||||
| 		*new_key = 'u'|KEYC_CTRL; | ||||
| 		return (1); | ||||
| 	case 'i': | ||||
| 	case '\033': /* Escape */ | ||||
| @@ -911,7 +911,7 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key) | ||||
| 		return (1); | ||||
| 	case 'C': | ||||
| 	case 'D': | ||||
| 		*new_key = '\013'; /* C-k */ | ||||
| 		*new_key = 'k'|KEYC_CTRL; | ||||
| 		return (1); | ||||
| 	case KEYC_BSPACE: | ||||
| 	case 'X': | ||||
| @@ -924,7 +924,7 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key) | ||||
| 		*new_key = 'B'|KEYC_VI; | ||||
| 		return (1); | ||||
| 	case 'd': | ||||
| 		*new_key = '\025'; /* C-u */ | ||||
| 		*new_key = 'u'|KEYC_CTRL; | ||||
| 		return (1); | ||||
| 	case 'e': | ||||
| 		*new_key = 'e'|KEYC_VI; | ||||
| @@ -939,10 +939,10 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key) | ||||
| 		*new_key = 'W'|KEYC_VI; | ||||
| 		return (1); | ||||
| 	case 'p': | ||||
| 		*new_key = '\031'; /* C-y */ | ||||
| 		*new_key = 'y'|KEYC_CTRL; | ||||
| 		return (1); | ||||
| 	case 'q': | ||||
| 		*new_key = '\003'; /* C-c */ | ||||
| 		*new_key = 'c'|KEYC_CTRL; | ||||
| 		return (1); | ||||
| 	case 's': | ||||
| 	case KEYC_DC: | ||||
| @@ -966,8 +966,8 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key) | ||||
| 	case 'k': | ||||
| 		*new_key = KEYC_UP; | ||||
| 		return (1); | ||||
| 	case '\010' /* C-h */: | ||||
| 	case '\003' /* C-c */: | ||||
| 	case 'h'|KEYC_CTRL: | ||||
| 	case 'c'|KEYC_CTRL: | ||||
| 	case '\n': | ||||
| 	case '\r': | ||||
| 		return (1); | ||||
| @@ -1263,28 +1263,28 @@ status_prompt_key(struct client *c, key_code key) | ||||
| process_key: | ||||
| 	switch (key) { | ||||
| 	case KEYC_LEFT: | ||||
| 	case '\002': /* C-b */ | ||||
| 	case 'b'|KEYC_CTRL: | ||||
| 		if (c->prompt_index > 0) { | ||||
| 			c->prompt_index--; | ||||
| 			break; | ||||
| 		} | ||||
| 		break; | ||||
| 	case KEYC_RIGHT: | ||||
| 	case '\006': /* C-f */ | ||||
| 	case 'f'|KEYC_CTRL: | ||||
| 		if (c->prompt_index < size) { | ||||
| 			c->prompt_index++; | ||||
| 			break; | ||||
| 		} | ||||
| 		break; | ||||
| 	case KEYC_HOME: | ||||
| 	case '\001': /* C-a */ | ||||
| 	case 'a'|KEYC_CTRL: | ||||
| 		if (c->prompt_index != 0) { | ||||
| 			c->prompt_index = 0; | ||||
| 			break; | ||||
| 		} | ||||
| 		break; | ||||
| 	case KEYC_END: | ||||
| 	case '\005': /* C-e */ | ||||
| 	case 'e'|KEYC_CTRL: | ||||
| 		if (c->prompt_index != size) { | ||||
| 			c->prompt_index = size; | ||||
| 			break; | ||||
| @@ -1295,7 +1295,7 @@ process_key: | ||||
| 			goto changed; | ||||
| 		break; | ||||
| 	case KEYC_BSPACE: | ||||
| 	case '\010': /* C-h */ | ||||
| 	case 'h'|KEYC_CTRL: | ||||
| 		if (c->prompt_index != 0) { | ||||
| 			if (c->prompt_index == size) | ||||
| 				c->prompt_buffer[--c->prompt_index].size = 0; | ||||
| @@ -1310,7 +1310,7 @@ process_key: | ||||
| 		} | ||||
| 		break; | ||||
| 	case KEYC_DC: | ||||
| 	case '\004': /* C-d */ | ||||
| 	case 'd'|KEYC_CTRL: | ||||
| 		if (c->prompt_index != size) { | ||||
| 			memmove(c->prompt_buffer + c->prompt_index, | ||||
| 			    c->prompt_buffer + c->prompt_index + 1, | ||||
| @@ -1319,17 +1319,17 @@ process_key: | ||||
| 			goto changed; | ||||
| 		} | ||||
| 		break; | ||||
| 	case '\025': /* C-u */ | ||||
| 	case 'u'|KEYC_CTRL: | ||||
| 		c->prompt_buffer[0].size = 0; | ||||
| 		c->prompt_index = 0; | ||||
| 		goto changed; | ||||
| 	case '\013': /* C-k */ | ||||
| 	case 'k'|KEYC_CTRL: | ||||
| 		if (c->prompt_index < size) { | ||||
| 			c->prompt_buffer[c->prompt_index].size = 0; | ||||
| 			goto changed; | ||||
| 		} | ||||
| 		break; | ||||
| 	case '\027': /* C-w */ | ||||
| 	case 'w'|KEYC_CTRL: | ||||
| 		separators = options_get_string(oo, "word-separators"); | ||||
| 		idx = c->prompt_index; | ||||
|  | ||||
| @@ -1397,7 +1397,7 @@ process_key: | ||||
| 		status_prompt_backward_word(c, separators); | ||||
| 		goto changed; | ||||
| 	case KEYC_UP: | ||||
| 	case '\020': /* C-p */ | ||||
| 	case 'p'|KEYC_CTRL: | ||||
| 		histstr = status_prompt_up_history(c->prompt_hindex, | ||||
| 		    c->prompt_type); | ||||
| 		if (histstr == NULL) | ||||
| @@ -1407,7 +1407,7 @@ process_key: | ||||
| 		c->prompt_index = utf8_strlen(c->prompt_buffer); | ||||
| 		goto changed; | ||||
| 	case KEYC_DOWN: | ||||
| 	case '\016': /* C-n */ | ||||
| 	case 'n'|KEYC_CTRL: | ||||
| 		histstr = status_prompt_down_history(c->prompt_hindex, | ||||
| 		    c->prompt_type); | ||||
| 		if (histstr == NULL) | ||||
| @@ -1416,11 +1416,11 @@ process_key: | ||||
| 		c->prompt_buffer = utf8_fromcstr(histstr); | ||||
| 		c->prompt_index = utf8_strlen(c->prompt_buffer); | ||||
| 		goto changed; | ||||
| 	case '\031': /* C-y */ | ||||
| 	case 'y'|KEYC_CTRL: | ||||
| 		if (status_prompt_paste(c)) | ||||
| 			goto changed; | ||||
| 		break; | ||||
| 	case '\024': /* C-t */ | ||||
| 	case 't'|KEYC_CTRL: | ||||
| 		idx = c->prompt_index; | ||||
| 		if (idx < size) | ||||
| 			idx++; | ||||
| @@ -1443,12 +1443,12 @@ process_key: | ||||
| 		free(s); | ||||
| 		break; | ||||
| 	case '\033': /* Escape */ | ||||
| 	case '\003': /* C-c */ | ||||
| 	case '\007': /* C-g */ | ||||
| 	case 'c'|KEYC_CTRL: | ||||
| 	case 'g'|KEYC_CTRL: | ||||
| 		if (c->prompt_inputcb(c, c->prompt_data, NULL, 1) == 0) | ||||
| 			status_prompt_clear(c); | ||||
| 		break; | ||||
| 	case '\022': /* C-r */ | ||||
| 	case 'r'|KEYC_CTRL: | ||||
| 		if (~c->prompt_flags & PROMPT_INCREMENTAL) | ||||
| 			break; | ||||
| 		if (c->prompt_buffer[0].size == 0) { | ||||
| @@ -1459,7 +1459,7 @@ process_key: | ||||
| 		} else | ||||
| 			prefix = '-'; | ||||
| 		goto changed; | ||||
| 	case '\023': /* C-s */ | ||||
| 	case 's'|KEYC_CTRL: | ||||
| 		if (~c->prompt_flags & PROMPT_INCREMENTAL) | ||||
| 			break; | ||||
| 		if (c->prompt_buffer[0].size == 0) { | ||||
| @@ -1626,8 +1626,9 @@ status_prompt_complete_list(u_int *size, const char *s, int at_start) | ||||
| 	struct options_entry			 *o; | ||||
| 	struct options_array_item		 *a; | ||||
| 	const char				 *layouts[] = { | ||||
| 		"even-horizontal", "even-vertical", "main-horizontal", | ||||
| 		"main-vertical", "tiled", NULL | ||||
| 		"even-horizontal", "even-vertical", | ||||
| 		"main-horizontal", "main-horizontal-mirrored", | ||||
| 		"main-vertical", "main-vertical-mirrored", "tiled", NULL | ||||
| 	}; | ||||
|  | ||||
| 	*size = 0; | ||||
|   | ||||
							
								
								
									
										114
									
								
								tmux.1
									
									
									
									
									
								
							
							
						
						
									
										114
									
								
								tmux.1
									
									
									
									
									
								
							| @@ -372,8 +372,10 @@ Enter copy mode and scroll one page up. | ||||
| Change to the pane above, below, to the left, or to the right of the current | ||||
| pane. | ||||
| .It M-1 to M-5 | ||||
| Arrange panes in one of the five preset layouts: even-horizontal, | ||||
| even-vertical, main-horizontal, main-vertical, or tiled. | ||||
| Arrange panes in one of the seven preset layouts: | ||||
| even-horizontal, even-vertical, | ||||
| main-horizontal, main-horizontal-mirrored, | ||||
| main-vertical, main-vertical, or tiled. | ||||
| .It Space | ||||
| Arrange the current window in the next preset layout. | ||||
| .It M-n | ||||
| @@ -2164,14 +2166,20 @@ are spread from left to right in the leftover space at the bottom. | ||||
| Use the | ||||
| .Em main-pane-height | ||||
| window option to specify the height of the top pane. | ||||
| .It Ic main-vertical | ||||
| Similar to | ||||
| .It Ic main-horizontal-mirrored | ||||
| The same as | ||||
| .Ic main-horizontal | ||||
| but the large pane is placed on the left and the others spread from top to | ||||
| bottom along the right. | ||||
| See the | ||||
| but mirrored so the main pane is at the bottom of the window. | ||||
| .It Ic main-vertical | ||||
| A large (main) pane is shown on the left of the window and the remaining panes | ||||
| are spread from top to bottom in the leftover space on the right. | ||||
| Use the | ||||
| .Em main-pane-width | ||||
| window option. | ||||
| window option to specify the width of the left pane. | ||||
| .It Ic main-vertical-mirrored | ||||
| The same as | ||||
| .Ic main-vertical | ||||
| but mirrored so the main pane is on the right of the window. | ||||
| .It Ic tiled | ||||
| Panes are spread out as evenly as possible over the window in both rows and | ||||
| columns. | ||||
| @@ -3735,6 +3743,10 @@ Note that aliases are expanded when a command is parsed rather than when it is | ||||
| executed, so binding an alias with | ||||
| .Ic bind-key | ||||
| will bind the expanded form. | ||||
| .It Ic copy-command Ar shell-command | ||||
| Give the command to pipe to if the | ||||
| .Ic copy-pipe | ||||
| copy mode command is used without arguments. | ||||
| .It Ic default-terminal Ar terminal | ||||
| Set the default terminal for new windows created in this session - the | ||||
| default value of the | ||||
| @@ -3748,10 +3760,6 @@ be set to | ||||
| .Ql screen , | ||||
| .Ql tmux | ||||
| or a derivative of them. | ||||
| .It Ic copy-command Ar shell-command | ||||
| Give the command to pipe to if the | ||||
| .Ic copy-pipe | ||||
| copy mode command is used without arguments. | ||||
| .It Ic escape-time Ar time | ||||
| Set the time in milliseconds for which | ||||
| .Nm | ||||
| @@ -3773,22 +3781,53 @@ If enabled, the server will exit when there are no attached clients. | ||||
| .It Xo Ic extended-keys | ||||
| .Op Ic on | off | always | ||||
| .Xc | ||||
| When | ||||
| .Ic on | ||||
| or | ||||
| .Ic always , | ||||
| the escape sequence to enable extended keys is sent to the terminal, if | ||||
| .Nm | ||||
| knows that it is supported. | ||||
| .Nm | ||||
| always recognises extended keys itself. | ||||
| If this option is | ||||
| Controls how modified keys (keys pressed together with Control, Meta, or Shift) | ||||
| are reported. | ||||
| This is the equivalent of the | ||||
| .Ic modifyOtherKeys | ||||
| .Xr xterm 1 | ||||
| resource. | ||||
| .Pp | ||||
| When set to | ||||
| .Ic on , | ||||
| .Nm | ||||
| will only forward extended keys to applications when they request them; if | ||||
| the program inside the pane can request one of two modes: mode 1 which changes | ||||
| the sequence for only keys which lack an existing well-known representation; or | ||||
| mode 2 which changes the sequence for all keys. | ||||
| When set to | ||||
| .Ic always , | ||||
| mode 1 output is forced and the program cannot change it. | ||||
| When set to | ||||
| .Ic off , | ||||
| this feature is disabled and only standard keys are reported. | ||||
| .Pp | ||||
| .Nm | ||||
| will always forward the keys. | ||||
| will always request extended keys itself if the terminal supports them. | ||||
| See also the | ||||
| .Ic extkeys | ||||
| feature for the | ||||
| .Ic terminal-features | ||||
| option, the | ||||
| .Ic extended-keys-format | ||||
| option and the | ||||
| .Ic pane_key_mode | ||||
| variable. | ||||
| .It Xo Ic extended-keys-format | ||||
| .Op Ic csi-u | xterm | ||||
| .Xc | ||||
| Selects one of the two possible formats for reporting modified keys to | ||||
| applications. | ||||
| This is the equivalent of the | ||||
| .Ic formatOtherKeys | ||||
| .Xr xterm 1 | ||||
| resource. | ||||
| For example, C-S-a will be reported as | ||||
| .Ql ^[[27;6;65~ | ||||
| when set to | ||||
| .Ic xterm , | ||||
| and as | ||||
| .Ql ^[[65;6u | ||||
| when set to | ||||
| .Ic csi-u . | ||||
| .It Xo Ic focus-events | ||||
| .Op Ic on | off | ||||
| .Xc | ||||
| @@ -4454,9 +4493,11 @@ Set the character used to fill areas of the terminal unused by a window. | ||||
| .It Ic main-pane-height Ar height | ||||
| .It Ic main-pane-width Ar width | ||||
| Set the width or height of the main (left or top) pane in the | ||||
| .Ic main-horizontal | ||||
| .Ic main-horizontal, | ||||
| .Ic main-horizontal-mirrored, | ||||
| .Ic main-vertical, | ||||
| or | ||||
| .Ic main-vertical | ||||
| .Ic main-vertical-mirrored | ||||
| layouts. | ||||
| If suffixed by | ||||
| .Ql % , | ||||
| @@ -4530,7 +4571,9 @@ An interval of zero disables the monitoring. | ||||
| .It Ic other-pane-height Ar height | ||||
| Set the height of the other panes (not the main pane) in the | ||||
| .Ic main-horizontal | ||||
| layout. | ||||
| and | ||||
| .Ic main-horizontal-mirrored | ||||
| layouts. | ||||
| If this option is set to 0 (the default), it will have no effect. | ||||
| If both the | ||||
| .Ic main-pane-height | ||||
| @@ -4547,7 +4590,9 @@ Like | ||||
| .Ic other-pane-height , | ||||
| but set the width of other panes in the | ||||
| .Ic main-vertical | ||||
| layout. | ||||
| and | ||||
| .Ic main-vertical-mirrored | ||||
| layouts. | ||||
| .Pp | ||||
| .It Ic pane-active-border-style Ar style | ||||
| Set the pane border style for the currently active pane. | ||||
| @@ -5514,6 +5559,7 @@ The following variables are available, where appropriate: | ||||
| .It Li "pane_in_mode" Ta "" Ta "1 if pane is in a mode" | ||||
| .It Li "pane_index" Ta "#P" Ta "Index of pane" | ||||
| .It Li "pane_input_off" Ta "" Ta "1 if input to pane is disabled" | ||||
| .It Li "pane_key_mode" Ta "" Ta "Extended key reporting mode in this pane" | ||||
| .It Li "pane_last" Ta "" Ta "1 if last pane" | ||||
| .It Li "pane_left" Ta "" Ta "Left of pane" | ||||
| .It Li "pane_marked" Ta "" Ta "1 if this is the marked pane" | ||||
| @@ -6572,6 +6618,11 @@ is given, the buffer is also sent to the clipboard for | ||||
| using the | ||||
| .Xr xterm 1 | ||||
| escape sequence, if possible. | ||||
| If | ||||
| .Ar path | ||||
| is | ||||
| .Ql - , | ||||
| the contents are read from stdin. | ||||
| .Tg pasteb | ||||
| .It Xo Ic paste-buffer | ||||
| .Op Fl dpr | ||||
| @@ -6609,6 +6660,11 @@ Save the contents of the specified paste buffer to | ||||
| The | ||||
| .Fl a | ||||
| option appends to rather than overwriting the file. | ||||
| If | ||||
| .Ar path | ||||
| is | ||||
| .Ql - , | ||||
| the contents are read from stdin. | ||||
| .It Xo Ic set-buffer | ||||
| .Op Fl aw | ||||
| .Op Fl b Ar buffer-name | ||||
|   | ||||
							
								
								
									
										43
									
								
								tmux.h
									
									
									
									
									
								
							
							
						
						
									
										43
									
								
								tmux.h
									
									
									
									
									
								
							| @@ -147,8 +147,7 @@ struct winlink; | ||||
| #define KEYC_IMPLIED_META    0x08000000000000ULL | ||||
| #define KEYC_BUILD_MODIFIERS 0x10000000000000ULL | ||||
| #define KEYC_VI		     0x20000000000000ULL | ||||
| #define KEYC_EXTENDED	     0x40000000000000ULL | ||||
| #define KEYC_SENT	     0x80000000000000ULL | ||||
| #define KEYC_SENT	     0x40000000000000ULL | ||||
|  | ||||
| /* Masks for key bits. */ | ||||
| #define KEYC_MASK_MODIFIERS  0x00f00000000000ULL | ||||
| @@ -196,6 +195,42 @@ struct winlink; | ||||
|  */ | ||||
| typedef unsigned long long key_code; | ||||
|  | ||||
| /* C0 control characters */ | ||||
| enum { | ||||
| 	C0_NUL, | ||||
| 	C0_SOH, | ||||
| 	C0_STX, | ||||
| 	C0_ETX, | ||||
| 	C0_EOT, | ||||
| 	C0_ENQ, | ||||
| 	C0_ASC, | ||||
| 	C0_BEL, | ||||
| 	C0_BS, | ||||
| 	C0_HT, | ||||
| 	C0_LF, | ||||
| 	C0_VT, | ||||
| 	C0_FF, | ||||
| 	C0_CR, | ||||
| 	C0_SO, | ||||
| 	C0_SI, | ||||
| 	C0_DLE, | ||||
| 	C0_DC1, | ||||
| 	C0_DC2, | ||||
| 	C0_DC3, | ||||
| 	C0_DC4, | ||||
| 	C0_NAK, | ||||
| 	C0_SYN, | ||||
| 	C0_ETB, | ||||
| 	C0_CAN, | ||||
| 	C0_EM, | ||||
| 	C0_SUB, | ||||
| 	C0_ESC, | ||||
| 	C0_FS, | ||||
| 	C0_GS, | ||||
| 	C0_RS, | ||||
| 	C0_US | ||||
| }; | ||||
|  | ||||
| /* Special key codes. */ | ||||
| enum { | ||||
| 	/* Focus events. */ | ||||
| @@ -591,14 +626,16 @@ enum tty_code_code { | ||||
| #define MODE_MOUSE_ALL 0x1000 | ||||
| #define MODE_ORIGIN 0x2000 | ||||
| #define MODE_CRLF 0x4000 | ||||
| #define MODE_KEXTENDED 0x8000 | ||||
| #define MODE_KEYS_EXTENDED 0x8000 | ||||
| #define MODE_CURSOR_VERY_VISIBLE 0x10000 | ||||
| #define MODE_CURSOR_BLINKING_SET 0x20000 | ||||
| #define MODE_KEYS_EXTENDED_2 0x40000 | ||||
|  | ||||
| #define ALL_MODES 0xffffff | ||||
| #define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD|MODE_MOUSE_BUTTON|MODE_MOUSE_ALL) | ||||
| #define MOTION_MOUSE_MODES (MODE_MOUSE_BUTTON|MODE_MOUSE_ALL) | ||||
| #define CURSOR_MODES (MODE_CURSOR|MODE_CURSOR_BLINKING|MODE_CURSOR_VERY_VISIBLE) | ||||
| #define EXTENDED_KEY_MODES (MODE_KEYS_EXTENDED|MODE_KEYS_EXTENDED_2) | ||||
|  | ||||
| /* Mouse protocol constants. */ | ||||
| #define MOUSE_PARAM_MAX 0xff | ||||
|   | ||||
| @@ -237,7 +237,7 @@ static const struct tty_feature tty_feature_sync = { | ||||
|  | ||||
| /* Terminal supports extended keys. */ | ||||
| static const char *const tty_feature_extkeys_capabilities[] = { | ||||
| 	"Eneks=\\E[>4;1m", | ||||
| 	"Eneks=\\E[>4;2m", | ||||
| 	"Dseks=\\E[>4m", | ||||
| 	NULL | ||||
| }; | ||||
|   | ||||
							
								
								
									
										58
									
								
								tty-keys.c
									
									
									
									
									
								
							
							
						
						
									
										58
									
								
								tty-keys.c
									
									
									
									
									
								
							| @@ -664,7 +664,7 @@ tty_keys_next(struct tty *tty) | ||||
| 	size_t			 len, size; | ||||
| 	cc_t			 bspace; | ||||
| 	int			 delay, expired = 0, n; | ||||
| 	key_code		 key; | ||||
| 	key_code		 key, onlykey; | ||||
| 	struct mouse_event	 m = { 0 }; | ||||
| 	struct key_event	*event; | ||||
|  | ||||
| @@ -801,6 +801,26 @@ first_key: | ||||
| 		key = (u_char)buf[0]; | ||||
| 		size = 1; | ||||
| 	} | ||||
|  | ||||
| 	/* C-Space is special. */ | ||||
| 	if ((key & KEYC_MASK_KEY) == C0_NUL) | ||||
| 		key = ' ' | KEYC_CTRL | (key & KEYC_META); | ||||
|  | ||||
| 	/* | ||||
| 	 * Fix up all C0 control codes that don't have a dedicated key into | ||||
| 	 * corresponding Ctrl keys. Convert characters in the A-Z range into | ||||
| 	 * lowercase, so ^A becomes a|CTRL. | ||||
| 	 */ | ||||
| 	onlykey = key & KEYC_MASK_KEY; | ||||
| 	if (onlykey < 0x20 && onlykey != C0_BS && | ||||
| 	    onlykey != C0_HT && onlykey != C0_CR && | ||||
| 	    onlykey != C0_ESC) { | ||||
| 		onlykey |= 0x40; | ||||
| 		if (onlykey >= 'A' && onlykey <= 'Z') | ||||
| 			onlykey |= 0x20; | ||||
| 		key = onlykey | KEYC_CTRL | (key & KEYC_META); | ||||
| 	} | ||||
|  | ||||
| 	goto complete_key; | ||||
|  | ||||
| partial_key: | ||||
| @@ -910,7 +930,6 @@ tty_keys_extended_key(struct tty *tty, const char *buf, size_t len, | ||||
| 	char		 tmp[64]; | ||||
| 	cc_t		 bspace; | ||||
| 	key_code	 nkey; | ||||
| 	key_code	 onlykey; | ||||
| 	struct utf8_data ud; | ||||
| 	utf8_char        uc; | ||||
|  | ||||
| @@ -974,7 +993,13 @@ tty_keys_extended_key(struct tty *tty, const char *buf, size_t len, | ||||
| 	/* Update the modifiers. */ | ||||
| 	if (modifiers > 0) { | ||||
| 		modifiers--; | ||||
| 		if (modifiers & 1) | ||||
| 		/* | ||||
| 		 * The Shift modifier may not be reported in some input modes, | ||||
| 		 * which is unfortunate, as in general case determining if a | ||||
| 		 * character is shifted or not requires knowing the input | ||||
| 		 * keyboard layout. So we only fix up the trivial case. | ||||
| 		 */ | ||||
| 		if (modifiers & 1 || (nkey >= 'A' && nkey <= 'Z')) | ||||
| 			nkey |= KEYC_SHIFT; | ||||
| 		if (modifiers & 2) | ||||
| 			nkey |= (KEYC_META|KEYC_IMPLIED_META); /* Alt */ | ||||
| @@ -984,34 +1009,15 @@ tty_keys_extended_key(struct tty *tty, const char *buf, size_t len, | ||||
| 			nkey |= (KEYC_META|KEYC_IMPLIED_META); /* Meta */ | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Don't allow both KEYC_CTRL and as an implied modifier. Also convert | ||||
| 	 * C-X into C-x and so on. | ||||
| 	 */ | ||||
| 	if (nkey & KEYC_CTRL) { | ||||
| 		onlykey = (nkey & KEYC_MASK_KEY); | ||||
| 		if (onlykey < 32 && | ||||
| 		    onlykey != 9 && | ||||
| 		    onlykey != 13 && | ||||
| 		    onlykey != 27) | ||||
| 			/* nothing */; | ||||
| 		else if (onlykey >= 97 && onlykey <= 122) | ||||
| 			onlykey -= 96; | ||||
| 		else if (onlykey >= 64 && onlykey <= 95) | ||||
| 			onlykey -= 64; | ||||
| 		else if (onlykey == 32) | ||||
| 			onlykey = 0; | ||||
| 		else if (onlykey == 63) | ||||
| 			onlykey = 127; | ||||
| 		else | ||||
| 			onlykey |= KEYC_CTRL; | ||||
| 		nkey = onlykey|((nkey & KEYC_MASK_MODIFIERS) & ~KEYC_CTRL); | ||||
| 	} | ||||
| 	/* Convert S-Tab into Backtab. */ | ||||
| 	if ((nkey & KEYC_MASK_KEY) == '\011' && (nkey & KEYC_SHIFT)) | ||||
| 		nkey = KEYC_BTAB | (nkey & ~KEYC_MASK_KEY & ~KEYC_SHIFT); | ||||
|  | ||||
| 	if (log_get_level() != 0) { | ||||
| 		log_debug("%s: extended key %.*s is %llx (%s)", c->name, | ||||
| 		    (int)*size, buf, nkey, key_string_lookup_key(nkey, 1)); | ||||
| 	} | ||||
|  | ||||
| 	*key = nkey; | ||||
| 	return (0); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Thomas Adam
					Thomas Adam