diff --git a/input.c b/input.c index 2be86ec03..1d0458c4e 100644 --- a/input.c +++ b/input.c @@ -209,6 +209,7 @@ static void input_csi_dispatch_sgr_256(struct input_ctx *, int, u_int *); static void input_csi_dispatch_sgr_rgb(struct input_ctx *, int, u_int *); static void input_csi_dispatch_sgr(struct input_ctx *); static int input_dcs_dispatch(struct input_ctx *); +static int input_dcs_escape(struct input_ctx *); static int input_top_bit_set(struct input_ctx *); static int input_end_bel(struct input_ctx *); @@ -699,9 +700,9 @@ static const struct input_transition input_state_dcs_handler_table[] = { static const struct input_transition input_state_dcs_escape_table[] = { /* No INPUT_STATE_ANYWHERE */ - { 0x00, 0x5b, input_input, &input_state_dcs_handler }, + { 0x00, 0x5b, input_dcs_escape, &input_state_dcs_handler }, { 0x5c, 0x5c, input_dcs_dispatch, &input_state_ground }, - { 0x5d, 0xff, input_input, &input_state_dcs_handler }, + { 0x5d, 0xff, input_dcs_escape, &input_state_dcs_handler }, { -1, -1, NULL, NULL } }; @@ -2626,6 +2627,29 @@ not_recognized: return (0); } +/* Escape in a DCS string followed by anything other than a backslash. */ +static int +input_dcs_escape(struct input_ctx *ictx) +{ + static const struct input_transition to_ground = { + 0, 0, NULL, &input_state_ground + }; + u_char buf[2] = { '\033', ictx->ch }; + + /* + * Other strings carry the byte as data, but a SIXEL image ends at the + * Escape, which then starts a new sequence as usual. + */ + if (ictx->input_len == 0 || + ictx->input_buf[0] != 'q' || + ictx->interm_len != 0) + return (input_input(ictx)); + input_dcs_dispatch(ictx); + input_set_state(ictx, &to_ground); + input_parse(ictx, buf, sizeof buf); + return (1); +} + /* DCS terminator (ST) received. */ static int input_dcs_dispatch(struct input_ctx *ictx) diff --git a/regress/image-support.sh b/regress/image-support.sh index 41e97b26a..1d15aac9c 100755 --- a/regress/image-support.sh +++ b/regress/image-support.sh @@ -76,6 +76,15 @@ sleep 1 [ "$($TMUX display-message -pt:sixel-stray '#{cursor_y}')" -gt 0 ] || exit 1 $TMUX kill-window -t:sixel-stray || exit 1 +# A SIXEL string that is not terminated ends at the next Escape, and the +# sequence after it is still processed. +$TMUX new-window -d -n sixel-esc " + printf '\033Pq#0;2;100;0;0#0!8~\033[HXY' + sleep 10" +sleep 1 +[ "$($TMUX capture-pane -pt:sixel-esc -S0 -E0)" = "XY" ] || exit 1 +$TMUX kill-window -t:sixel-esc || exit 1 + # The protocol default is transmit-only; a later placement uses the retained # immutable image and advances by the same canonical one-cell footprint. $TMUX new-window -d "