This patch allows applications to send control sequences to the
underlying terminal by using DCS. It adds the dcs_escape state to the
input state machine, allowing ESC characters in the dcs_handler state.
Following an ESC, a backslash is interpreted as the end of the DCS
string and any other character is added to the DCS string as-is, to be
passed to the underlying terminal later.

As discussed in a previous thread, the prefix "tmux;" is used to trigger
this feature.

In order to write the resulting bytes to the underlying terminal, the
functions screen_write_rawstring and tty_cmd_rawstring have been
introduced.

This patch depends on my patch for input_clear to allow input_buf to be
cleared on entry to the dcs_enter state.

Comments and suggestions welcome.

-Kevin
diff --git a/input.c b/input.c
index 5da8b6d..6869ca1 100644
--- a/input.c
+++ b/input.c
@@ -41,6 +41,9 @@
  *
  * - A state for the screen \033k...\033\\ sequence to rename a window. This is
  *   pretty stupid but not supporting it is more trouble than it is worth.
+ *
+ * - Special handling for ESC inside a DCS to allow arbitrary byte sequences to
+ *   be passed to the underlying teminal(s).
  */
 
 /* Helper functions. */
@@ -50,8 +53,6 @@ void	input_reply(struct input_ctx *, const char *, ...);
 
 /* Transition entry/exit handlers. */
 void	input_clear(struct input_ctx *);
-void	input_enter_dcs(struct input_ctx *);
-void	input_exit_dcs(struct input_ctx *);
 void	input_enter_osc(struct input_ctx *);
 void	input_exit_osc(struct input_ctx *);
 void	input_enter_apc(struct input_ctx *);
@@ -68,6 +69,7 @@ int	input_c0_dispatch(struct input_ctx *);
 int	input_esc_dispatch(struct input_ctx *);
 int	input_csi_dispatch(struct input_ctx *);
 void	input_csi_dispatch_sgr(struct input_ctx *);
+int	input_dcs_dispatch(struct input_ctx *);
 int	input_utf8_open(struct input_ctx *);
 int	input_utf8_add(struct input_ctx *);
 int	input_utf8_close(struct input_ctx *);
@@ -204,6 +206,7 @@ const struct input_transition input_state_dcs_enter_table[];
 const struct input_transition input_state_dcs_parameter_table[];
 const struct input_transition input_state_dcs_intermediate_table[];
 const struct input_transition input_state_dcs_handler_table[];
+const struct input_transition input_state_dcs_escape_table[];
 const struct input_transition input_state_dcs_ignore_table[];
 const struct input_transition input_state_osc_string_table[];
 const struct input_transition input_state_apc_string_table[];
@@ -286,10 +289,17 @@ const struct input_state input_state_dcs_intermediate = {
 /* dcs_handler state definition. */
 const struct input_state input_state_dcs_handler = {
 	"dcs_handler",
-	input_enter_dcs, input_exit_dcs,
+	NULL, NULL,
 	input_state_dcs_handler_table
 };
 
+/* dcs_escape state definition. */
+const struct input_state input_state_dcs_escape = {
+	"dcs_escape",
+	NULL, NULL,
+	input_state_dcs_escape_table
+};
+
 /* dcs_ignore state definition. */
 const struct input_state input_state_dcs_ignore = {
 	"dcs_ignore",
@@ -482,7 +492,7 @@ const struct input_transition input_state_dcs_enter_table[] = {
 	{ 0x3a, 0x3a, NULL,		  &input_state_dcs_ignore },
 	{ 0x3b, 0x3b, input_parameter,	  &input_state_dcs_parameter },
 	{ 0x3c, 0x3f, input_intermediate, &input_state_dcs_parameter },
-	{ 0x40, 0x7e, NULL,		  &input_state_dcs_handler },
+	{ 0x40, 0x7e, input_input,	  &input_state_dcs_handler },
 	{ 0x7f, 0xff, NULL,		  NULL },
 
 	{ -1, -1, NULL, NULL }
@@ -500,7 +510,7 @@ const struct input_transition input_state_dcs_parameter_table[] = {
 	{ 0x3a, 0x3a, NULL,		  &input_state_dcs_ignore },
 	{ 0x3b, 0x3b, input_parameter,	  NULL },
 	{ 0x3c, 0x3f, NULL,		  &input_state_dcs_ignore },
-	{ 0x40, 0x7e, NULL,		  &input_state_dcs_handler },
+	{ 0x40, 0x7e, input_input,	  &input_state_dcs_handler },
 	{ 0x7f, 0xff, NULL,		  NULL },
 
 	{ -1, -1, NULL, NULL }
@@ -515,7 +525,7 @@ const struct input_transition input_state_dcs_intermediate_table[] = {
 	{ 0x1c, 0x1f, NULL,		  NULL },
 	{ 0x20, 0x2f, input_intermediate, NULL },
 	{ 0x30, 0x3f, NULL,		  &input_state_dcs_ignore },
-	{ 0x40, 0x7e, NULL,		  &input_state_dcs_handler },
+	{ 0x40, 0x7e, input_input,	  &input_state_dcs_handler },
 	{ 0x7f, 0xff, NULL,		  NULL },
 
 	{ -1, -1, NULL, NULL }
@@ -523,13 +533,22 @@ const struct input_transition input_state_dcs_intermediate_table[] = {
 
 /* dcs_handler state table. */
 const struct input_transition input_state_dcs_handler_table[] = {
-	INPUT_STATE_ANYWHERE,
+	/* No INPUT_STATE_ANYWHERE */
 
-	{ 0x00, 0x17, NULL,	    NULL },
-	{ 0x19, 0x19, input_input,  NULL },
-	{ 0x1c, 0x1f, input_input,  NULL },
-	{ 0x20, 0x7e, input_input,  NULL },
-	{ 0x7f, 0xff, NULL,	    NULL },
+	{ 0x00, 0x1a, input_input,  NULL },
+	{ 0x1b, 0x1b, NULL,	    &input_state_dcs_escape },
+	{ 0x1c, 0xff, input_input,  NULL },
+
+	{ -1, -1, NULL, NULL }
+};
+
+/* dcs_escape state table. */
+const struct input_transition input_state_dcs_escape_table[] = {
+	/* No INPUT_STATE_ANYWHERE */
+
+	{ 0x00, 0x5b, input_input,	  &input_state_dcs_handler },
+	{ 0x5c, 0x5c, input_dcs_dispatch, &input_state_ground },
+	{ 0x5d, 0xff, input_input,	  &input_state_dcs_handler },
 
 	{ -1, -1, NULL, NULL }
 };
@@ -1374,20 +1393,26 @@ input_csi_dispatch_sgr(struct input_ctx *ictx)
 	}
 }
 
-/* DCS string started. */
-void
-input_enter_dcs(struct input_ctx *ictx)
-{
-	log_debug("%s", __func__);
-
-	input_clear(ictx);
-}
-
 /* DCS terminator (ST) received. */
-void
-input_exit_dcs(unused struct input_ctx *ictx)
+int
+input_dcs_dispatch(unused struct input_ctx *ictx)
 {
+	const char		 prefix[] = "tmux;";
+	const u_int		 prefix_len = sizeof prefix - 1;
+
+	if (ictx->flags & INPUT_DISCARD)
+		return (0);
+
 	log_debug("%s", __func__);
+
+	/* Check for tmux prefix */
+	if (ictx->input_len >= prefix_len &&
+	    strncmp(ictx->input_buf, prefix, prefix_len) == 0) {
+		screen_write_rawstring(&ictx->ctx,
+		    ictx->input_buf + prefix_len, ictx->input_len - prefix_len);
+	}
+
+	return (0);
 }
 
 /* OSC string started. */
diff --git a/screen-write.c b/screen-write.c
index 97bfe9b..84d91e3 100644
--- a/screen-write.c
+++ b/screen-write.c
@@ -1161,3 +1161,15 @@ screen_write_overwrite(struct screen_write_ctx *ctx, u_int width)
 		grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
 	}
 }
+
+void
+screen_write_rawstring(struct screen_write_ctx *ctx, u_char *str, u_int len)
+{
+	struct tty_ctx		 ttyctx;
+
+	screen_write_initctx(ctx, &ttyctx, 0);
+	ttyctx.ptr = str;
+	ttyctx.num = len;
+
+	tty_write(tty_cmd_rawstring, &ttyctx);
+}
diff --git a/tmux.h b/tmux.h
index f2da1ff..2610b2e 100644
--- a/tmux.h
+++ b/tmux.h
@@ -1419,6 +1419,7 @@ void	tty_cmd_insertline(struct tty *, const struct tty_ctx *);
 void	tty_cmd_linefeed(struct tty *, const struct tty_ctx *);
 void	tty_cmd_utf8character(struct tty *, const struct tty_ctx *);
 void	tty_cmd_reverseindex(struct tty *, const struct tty_ctx *);
+void	tty_cmd_rawstring(struct tty *, const struct tty_ctx *);
 
 /* tty-term.c */
 extern struct tty_terms tty_terms;
@@ -1817,6 +1818,7 @@ void	 screen_write_clearstartofscreen(struct screen_write_ctx *);
 void	 screen_write_clearscreen(struct screen_write_ctx *);
 void	 screen_write_cell(struct screen_write_ctx *,
 	     const struct grid_cell *, const struct utf8_data *);
+void	 screen_write_rawstring(struct screen_write_ctx *, u_char *, u_int);
 
 /* screen-redraw.c */
 void	 screen_redraw_screen(struct client *, int, int);
diff --git a/tty.c b/tty.c
index 3fa612b..71e07e8 100644
--- a/tty.c
+++ b/tty.c
@@ -933,6 +933,16 @@ tty_cmd_utf8character(struct tty *tty, const struct tty_ctx *ctx)
 }
 
 void
+tty_cmd_rawstring(struct tty *tty, const struct tty_ctx *ctx)
+{
+	u_int	 i;
+	u_char	*str = ctx->ptr;
+
+	for (i = 0; i < ctx->num; i++)
+		tty_putc(tty, str[i]);
+}
+
+void
 tty_cell(
     struct tty *tty, const struct grid_cell *gc, const struct grid_utf8 *gu)
 {
------------------------------------------------------------------------------
Special Offer-- Download ArcSight Logger for FREE (a $49 USD value)!
Finally, a world-class log management solution at an even better price-free!
Download using promo code Free_Logger_4_Dev2Dev. Offer expires 
February 28th, so secure your free ArcSight Logger TODAY! 
http://p.sf.net/sfu/arcsight-sfd2d
_______________________________________________
tmux-users mailing list
tmux-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/tmux-users

Reply via email to