199e242abSchristos /* $OpenBSD$ */ 2698d5317Sjmmv 3698d5317Sjmmv /* 4f26e8bc9Schristos * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> 5698d5317Sjmmv * 6698d5317Sjmmv * Permission to use, copy, modify, and distribute this software for any 7698d5317Sjmmv * purpose with or without fee is hereby granted, provided that the above 8698d5317Sjmmv * copyright notice and this permission notice appear in all copies. 9698d5317Sjmmv * 10698d5317Sjmmv * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11698d5317Sjmmv * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12698d5317Sjmmv * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13698d5317Sjmmv * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14698d5317Sjmmv * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15698d5317Sjmmv * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16698d5317Sjmmv * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17698d5317Sjmmv */ 18698d5317Sjmmv 19698d5317Sjmmv #include <sys/types.h> 20698d5317Sjmmv 21e9a2d6faSchristos #include <netinet/in.h> 22e9a2d6faSchristos 2368e6ba84Schristos #include <ctype.h> 24e9a2d6faSchristos #include <resolv.h> 25698d5317Sjmmv #include <stdlib.h> 26698d5317Sjmmv #include <string.h> 2799e242abSchristos #include <time.h> 28698d5317Sjmmv 29698d5317Sjmmv #include "tmux.h" 30698d5317Sjmmv 31698d5317Sjmmv /* 32698d5317Sjmmv * Based on the description by Paul Williams at: 33698d5317Sjmmv * 34c7e17de0Schristos * https://vt100.net/emu/dec_ansi_parser 35698d5317Sjmmv * 36698d5317Sjmmv * With the following changes: 37698d5317Sjmmv * 38698d5317Sjmmv * - 7-bit only. 39698d5317Sjmmv * 40698d5317Sjmmv * - Support for UTF-8. 41698d5317Sjmmv * 42698d5317Sjmmv * - OSC (but not APC) may be terminated by \007 as well as ST. 43698d5317Sjmmv * 44698d5317Sjmmv * - A state for APC similar to OSC. Some terminals appear to use this to set 45698d5317Sjmmv * the title. 46698d5317Sjmmv * 47698d5317Sjmmv * - A state for the screen \033k...\033\\ sequence to rename a window. This is 48698d5317Sjmmv * pretty stupid but not supporting it is more trouble than it is worth. 490f3d2746Sjmmv * 500f3d2746Sjmmv * - Special handling for ESC inside a DCS to allow arbitrary byte sequences to 5199e242abSchristos * be passed to the underlying terminals. 52698d5317Sjmmv */ 53698d5317Sjmmv 5499e242abSchristos /* Input parser cell. */ 5599e242abSchristos struct input_cell { 5699e242abSchristos struct grid_cell cell; 5799e242abSchristos int set; 5899e242abSchristos int g0set; /* 1 if ACS */ 5999e242abSchristos int g1set; /* 1 if ACS */ 6099e242abSchristos }; 6199e242abSchristos 62c7e17de0Schristos /* Input parser argument. */ 63c7e17de0Schristos struct input_param { 64c7e17de0Schristos enum { 65c7e17de0Schristos INPUT_MISSING, 66c7e17de0Schristos INPUT_NUMBER, 67c7e17de0Schristos INPUT_STRING 68c7e17de0Schristos } type; 69c7e17de0Schristos union { 70c7e17de0Schristos int num; 71c7e17de0Schristos char *str; 72c7e17de0Schristos }; 73c7e17de0Schristos }; 74c7e17de0Schristos 7599e242abSchristos /* Input parser context. */ 7699e242abSchristos struct input_ctx { 7799e242abSchristos struct window_pane *wp; 78e271dbb8Schristos struct bufferevent *event; 7999e242abSchristos struct screen_write_ctx ctx; 8046548964Swiz struct colour_palette *palette; 8199e242abSchristos 8299e242abSchristos struct input_cell cell; 8399e242abSchristos 8499e242abSchristos struct input_cell old_cell; 8599e242abSchristos u_int old_cx; 8699e242abSchristos u_int old_cy; 870a274e86Schristos int old_mode; 8899e242abSchristos 8999e242abSchristos u_char interm_buf[4]; 9099e242abSchristos size_t interm_len; 9199e242abSchristos 9299e242abSchristos u_char param_buf[64]; 9399e242abSchristos size_t param_len; 9499e242abSchristos 9599e242abSchristos #define INPUT_BUF_START 32 9699e242abSchristos #define INPUT_BUF_LIMIT 1048576 9799e242abSchristos u_char *input_buf; 9899e242abSchristos size_t input_len; 9999e242abSchristos size_t input_space; 1000a274e86Schristos enum { 1010a274e86Schristos INPUT_END_ST, 1020a274e86Schristos INPUT_END_BEL 1030a274e86Schristos } input_end; 10499e242abSchristos 105c7e17de0Schristos struct input_param param_list[24]; 10699e242abSchristos u_int param_list_len; 10799e242abSchristos 10899e242abSchristos struct utf8_data utf8data; 109c7e17de0Schristos int utf8started; 11099e242abSchristos 11199e242abSchristos int ch; 112*890b6d91Swiz struct utf8_data last; 113e9a2d6faSchristos 11499e242abSchristos int flags; 11599e242abSchristos #define INPUT_DISCARD 0x1 116*890b6d91Swiz #define INPUT_LAST 0x2 11799e242abSchristos 11899e242abSchristos const struct input_state *state; 11999e242abSchristos 120fe99a117Schristos struct event timer; 121fe99a117Schristos 12299e242abSchristos /* 12399e242abSchristos * All input received since we were last in the ground state. Sent to 12499e242abSchristos * control clients on connection. 12599e242abSchristos */ 12699e242abSchristos struct evbuffer *since_ground; 12799e242abSchristos }; 12899e242abSchristos 129698d5317Sjmmv /* Helper functions. */ 13061fba46bSchristos struct input_transition; 131e9a2d6faSchristos static int input_split(struct input_ctx *); 132e9a2d6faSchristos static int input_get(struct input_ctx *, u_int, int, int); 133e9a2d6faSchristos static void printflike(2, 3) input_reply(struct input_ctx *, const char *, ...); 134e271dbb8Schristos static void input_set_state(struct input_ctx *, 135e9a2d6faSchristos const struct input_transition *); 136e9a2d6faSchristos static void input_reset_cell(struct input_ctx *); 137e9a2d6faSchristos 1380a274e86Schristos static void input_osc_4(struct input_ctx *, const char *); 139f844e94eSwiz static void input_osc_8(struct input_ctx *, const char *); 1400a274e86Schristos static void input_osc_10(struct input_ctx *, const char *); 1410a274e86Schristos static void input_osc_11(struct input_ctx *, const char *); 14246548964Swiz static void input_osc_12(struct input_ctx *, const char *); 1430a274e86Schristos static void input_osc_52(struct input_ctx *, const char *); 1440a274e86Schristos static void input_osc_104(struct input_ctx *, const char *); 145e271dbb8Schristos static void input_osc_110(struct input_ctx *, const char *); 146e271dbb8Schristos static void input_osc_111(struct input_ctx *, const char *); 14746548964Swiz static void input_osc_112(struct input_ctx *, const char *); 148f844e94eSwiz static void input_osc_133(struct input_ctx *, const char *); 149698d5317Sjmmv 150698d5317Sjmmv /* Transition entry/exit handlers. */ 151e9a2d6faSchristos static void input_clear(struct input_ctx *); 152e9a2d6faSchristos static void input_ground(struct input_ctx *); 153fe99a117Schristos static void input_enter_dcs(struct input_ctx *); 154e9a2d6faSchristos static void input_enter_osc(struct input_ctx *); 155e9a2d6faSchristos static void input_exit_osc(struct input_ctx *); 156e9a2d6faSchristos static void input_enter_apc(struct input_ctx *); 157e9a2d6faSchristos static void input_exit_apc(struct input_ctx *); 158e9a2d6faSchristos static void input_enter_rename(struct input_ctx *); 159e9a2d6faSchristos static void input_exit_rename(struct input_ctx *); 160698d5317Sjmmv 161698d5317Sjmmv /* Input state handlers. */ 162e9a2d6faSchristos static int input_print(struct input_ctx *); 163e9a2d6faSchristos static int input_intermediate(struct input_ctx *); 164e9a2d6faSchristos static int input_parameter(struct input_ctx *); 165e9a2d6faSchristos static int input_input(struct input_ctx *); 166e9a2d6faSchristos static int input_c0_dispatch(struct input_ctx *); 167e9a2d6faSchristos static int input_esc_dispatch(struct input_ctx *); 168e9a2d6faSchristos static int input_csi_dispatch(struct input_ctx *); 169e9a2d6faSchristos static void input_csi_dispatch_rm(struct input_ctx *); 170e9a2d6faSchristos static void input_csi_dispatch_rm_private(struct input_ctx *); 171e9a2d6faSchristos static void input_csi_dispatch_sm(struct input_ctx *); 172e9a2d6faSchristos static void input_csi_dispatch_sm_private(struct input_ctx *); 173f844e94eSwiz static void input_csi_dispatch_sm_graphics(struct input_ctx *); 174e9a2d6faSchristos static void input_csi_dispatch_winops(struct input_ctx *); 175e9a2d6faSchristos static void input_csi_dispatch_sgr_256(struct input_ctx *, int, u_int *); 176e9a2d6faSchristos static void input_csi_dispatch_sgr_rgb(struct input_ctx *, int, u_int *); 177e9a2d6faSchristos static void input_csi_dispatch_sgr(struct input_ctx *); 178e9a2d6faSchristos static int input_dcs_dispatch(struct input_ctx *); 179c7e17de0Schristos static int input_top_bit_set(struct input_ctx *); 1800a274e86Schristos static int input_end_bel(struct input_ctx *); 181698d5317Sjmmv 182698d5317Sjmmv /* Command table comparison function. */ 183e9a2d6faSchristos static int input_table_compare(const void *, const void *); 184698d5317Sjmmv 185698d5317Sjmmv /* Command table entry. */ 186698d5317Sjmmv struct input_table_entry { 187698d5317Sjmmv int ch; 188698d5317Sjmmv const char *interm; 189698d5317Sjmmv int type; 190698d5317Sjmmv }; 191698d5317Sjmmv 192698d5317Sjmmv /* Escape commands. */ 193698d5317Sjmmv enum input_esc_type { 194698d5317Sjmmv INPUT_ESC_DECALN, 195698d5317Sjmmv INPUT_ESC_DECKPAM, 196698d5317Sjmmv INPUT_ESC_DECKPNM, 197698d5317Sjmmv INPUT_ESC_DECRC, 198698d5317Sjmmv INPUT_ESC_DECSC, 199698d5317Sjmmv INPUT_ESC_HTS, 200698d5317Sjmmv INPUT_ESC_IND, 201698d5317Sjmmv INPUT_ESC_NEL, 202698d5317Sjmmv INPUT_ESC_RI, 203698d5317Sjmmv INPUT_ESC_RIS, 20499e242abSchristos INPUT_ESC_SCSG0_OFF, 20599e242abSchristos INPUT_ESC_SCSG0_ON, 20699e242abSchristos INPUT_ESC_SCSG1_OFF, 20799e242abSchristos INPUT_ESC_SCSG1_ON, 208f844e94eSwiz INPUT_ESC_ST 209698d5317Sjmmv }; 210698d5317Sjmmv 211698d5317Sjmmv /* Escape command table. */ 212e9a2d6faSchristos static const struct input_table_entry input_esc_table[] = { 21399e242abSchristos { '0', "(", INPUT_ESC_SCSG0_ON }, 21499e242abSchristos { '0', ")", INPUT_ESC_SCSG1_ON }, 215698d5317Sjmmv { '7', "", INPUT_ESC_DECSC }, 216698d5317Sjmmv { '8', "", INPUT_ESC_DECRC }, 217698d5317Sjmmv { '8', "#", INPUT_ESC_DECALN }, 218698d5317Sjmmv { '=', "", INPUT_ESC_DECKPAM }, 219698d5317Sjmmv { '>', "", INPUT_ESC_DECKPNM }, 22099e242abSchristos { 'B', "(", INPUT_ESC_SCSG0_OFF }, 22199e242abSchristos { 'B', ")", INPUT_ESC_SCSG1_OFF }, 222698d5317Sjmmv { 'D', "", INPUT_ESC_IND }, 223698d5317Sjmmv { 'E', "", INPUT_ESC_NEL }, 224698d5317Sjmmv { 'H', "", INPUT_ESC_HTS }, 225698d5317Sjmmv { 'M', "", INPUT_ESC_RI }, 226e9a2d6faSchristos { '\\', "", INPUT_ESC_ST }, 227698d5317Sjmmv { 'c', "", INPUT_ESC_RIS }, 228698d5317Sjmmv }; 229698d5317Sjmmv 230698d5317Sjmmv /* Control (CSI) commands. */ 231698d5317Sjmmv enum input_csi_type { 232698d5317Sjmmv INPUT_CSI_CBT, 23361fba46bSchristos INPUT_CSI_CNL, 23461fba46bSchristos INPUT_CSI_CPL, 235698d5317Sjmmv INPUT_CSI_CUB, 236698d5317Sjmmv INPUT_CSI_CUD, 237698d5317Sjmmv INPUT_CSI_CUF, 238698d5317Sjmmv INPUT_CSI_CUP, 239698d5317Sjmmv INPUT_CSI_CUU, 240698d5317Sjmmv INPUT_CSI_DA, 24161fba46bSchristos INPUT_CSI_DA_TWO, 242698d5317Sjmmv INPUT_CSI_DCH, 2430f3d2746Sjmmv INPUT_CSI_DECSCUSR, 244698d5317Sjmmv INPUT_CSI_DECSTBM, 245698d5317Sjmmv INPUT_CSI_DL, 246698d5317Sjmmv INPUT_CSI_DSR, 24761fba46bSchristos INPUT_CSI_ECH, 248698d5317Sjmmv INPUT_CSI_ED, 249698d5317Sjmmv INPUT_CSI_EL, 250698d5317Sjmmv INPUT_CSI_HPA, 251698d5317Sjmmv INPUT_CSI_ICH, 252698d5317Sjmmv INPUT_CSI_IL, 253e271dbb8Schristos INPUT_CSI_MODOFF, 254e271dbb8Schristos INPUT_CSI_MODSET, 25561fba46bSchristos INPUT_CSI_RCP, 256fe99a117Schristos INPUT_CSI_REP, 257698d5317Sjmmv INPUT_CSI_RM, 258698d5317Sjmmv INPUT_CSI_RM_PRIVATE, 25961fba46bSchristos INPUT_CSI_SCP, 26030744affSchristos INPUT_CSI_SD, 261698d5317Sjmmv INPUT_CSI_SGR, 262698d5317Sjmmv INPUT_CSI_SM, 263698d5317Sjmmv INPUT_CSI_SM_PRIVATE, 264f844e94eSwiz INPUT_CSI_SM_GRAPHICS, 265e9a2d6faSchristos INPUT_CSI_SU, 266698d5317Sjmmv INPUT_CSI_TBC, 267698d5317Sjmmv INPUT_CSI_VPA, 26861fba46bSchristos INPUT_CSI_WINOPS, 269f844e94eSwiz INPUT_CSI_XDA 270698d5317Sjmmv }; 271698d5317Sjmmv 272698d5317Sjmmv /* Control (CSI) command table. */ 273e9a2d6faSchristos static const struct input_table_entry input_csi_table[] = { 274698d5317Sjmmv { '@', "", INPUT_CSI_ICH }, 275698d5317Sjmmv { 'A', "", INPUT_CSI_CUU }, 276698d5317Sjmmv { 'B', "", INPUT_CSI_CUD }, 277698d5317Sjmmv { 'C', "", INPUT_CSI_CUF }, 278698d5317Sjmmv { 'D', "", INPUT_CSI_CUB }, 27961fba46bSchristos { 'E', "", INPUT_CSI_CNL }, 28061fba46bSchristos { 'F', "", INPUT_CSI_CPL }, 281698d5317Sjmmv { 'G', "", INPUT_CSI_HPA }, 282698d5317Sjmmv { 'H', "", INPUT_CSI_CUP }, 283698d5317Sjmmv { 'J', "", INPUT_CSI_ED }, 284698d5317Sjmmv { 'K', "", INPUT_CSI_EL }, 285698d5317Sjmmv { 'L', "", INPUT_CSI_IL }, 286698d5317Sjmmv { 'M', "", INPUT_CSI_DL }, 287698d5317Sjmmv { 'P', "", INPUT_CSI_DCH }, 288e9a2d6faSchristos { 'S', "", INPUT_CSI_SU }, 289f844e94eSwiz { 'S', "?", INPUT_CSI_SM_GRAPHICS }, 29030744affSchristos { 'T', "", INPUT_CSI_SD }, 29161fba46bSchristos { 'X', "", INPUT_CSI_ECH }, 292698d5317Sjmmv { 'Z', "", INPUT_CSI_CBT }, 2930a274e86Schristos { '`', "", INPUT_CSI_HPA }, 294fe99a117Schristos { 'b', "", INPUT_CSI_REP }, 295698d5317Sjmmv { 'c', "", INPUT_CSI_DA }, 29661fba46bSchristos { 'c', ">", INPUT_CSI_DA_TWO }, 297698d5317Sjmmv { 'd', "", INPUT_CSI_VPA }, 298698d5317Sjmmv { 'f', "", INPUT_CSI_CUP }, 299698d5317Sjmmv { 'g', "", INPUT_CSI_TBC }, 300698d5317Sjmmv { 'h', "", INPUT_CSI_SM }, 301698d5317Sjmmv { 'h', "?", INPUT_CSI_SM_PRIVATE }, 302698d5317Sjmmv { 'l', "", INPUT_CSI_RM }, 303698d5317Sjmmv { 'l', "?", INPUT_CSI_RM_PRIVATE }, 304698d5317Sjmmv { 'm', "", INPUT_CSI_SGR }, 305e271dbb8Schristos { 'm', ">", INPUT_CSI_MODSET }, 306698d5317Sjmmv { 'n', "", INPUT_CSI_DSR }, 307e271dbb8Schristos { 'n', ">", INPUT_CSI_MODOFF }, 3080f3d2746Sjmmv { 'q', " ", INPUT_CSI_DECSCUSR }, 309e271dbb8Schristos { 'q', ">", INPUT_CSI_XDA }, 310698d5317Sjmmv { 'r', "", INPUT_CSI_DECSTBM }, 31161fba46bSchristos { 's', "", INPUT_CSI_SCP }, 31261fba46bSchristos { 't', "", INPUT_CSI_WINOPS }, 313f844e94eSwiz { 'u', "", INPUT_CSI_RCP } 314698d5317Sjmmv }; 315698d5317Sjmmv 316698d5317Sjmmv /* Input transition. */ 317698d5317Sjmmv struct input_transition { 318698d5317Sjmmv int first; 319698d5317Sjmmv int last; 320698d5317Sjmmv 321698d5317Sjmmv int (*handler)(struct input_ctx *); 322698d5317Sjmmv const struct input_state *state; 323698d5317Sjmmv }; 324698d5317Sjmmv 325698d5317Sjmmv /* Input state. */ 326698d5317Sjmmv struct input_state { 327698d5317Sjmmv const char *name; 328698d5317Sjmmv void (*enter)(struct input_ctx *); 329698d5317Sjmmv void (*exit)(struct input_ctx *); 330698d5317Sjmmv const struct input_transition *transitions; 331698d5317Sjmmv }; 332698d5317Sjmmv 333698d5317Sjmmv /* State transitions available from all states. */ 334698d5317Sjmmv #define INPUT_STATE_ANYWHERE \ 335698d5317Sjmmv { 0x18, 0x18, input_c0_dispatch, &input_state_ground }, \ 336698d5317Sjmmv { 0x1a, 0x1a, input_c0_dispatch, &input_state_ground }, \ 337698d5317Sjmmv { 0x1b, 0x1b, NULL, &input_state_esc_enter } 338698d5317Sjmmv 339698d5317Sjmmv /* Forward declarations of state tables. */ 340e9a2d6faSchristos static const struct input_transition input_state_ground_table[]; 341e9a2d6faSchristos static const struct input_transition input_state_esc_enter_table[]; 342e9a2d6faSchristos static const struct input_transition input_state_esc_intermediate_table[]; 343e9a2d6faSchristos static const struct input_transition input_state_csi_enter_table[]; 344e9a2d6faSchristos static const struct input_transition input_state_csi_parameter_table[]; 345e9a2d6faSchristos static const struct input_transition input_state_csi_intermediate_table[]; 346e9a2d6faSchristos static const struct input_transition input_state_csi_ignore_table[]; 347e9a2d6faSchristos static const struct input_transition input_state_dcs_enter_table[]; 348e9a2d6faSchristos static const struct input_transition input_state_dcs_parameter_table[]; 349e9a2d6faSchristos static const struct input_transition input_state_dcs_intermediate_table[]; 350e9a2d6faSchristos static const struct input_transition input_state_dcs_handler_table[]; 351e9a2d6faSchristos static const struct input_transition input_state_dcs_escape_table[]; 352e9a2d6faSchristos static const struct input_transition input_state_dcs_ignore_table[]; 353e9a2d6faSchristos static const struct input_transition input_state_osc_string_table[]; 354e9a2d6faSchristos static const struct input_transition input_state_apc_string_table[]; 355e9a2d6faSchristos static const struct input_transition input_state_rename_string_table[]; 356e9a2d6faSchristos static const struct input_transition input_state_consume_st_table[]; 357698d5317Sjmmv 358698d5317Sjmmv /* ground state definition. */ 359e9a2d6faSchristos static const struct input_state input_state_ground = { 360698d5317Sjmmv "ground", 36199e242abSchristos input_ground, NULL, 362698d5317Sjmmv input_state_ground_table 363698d5317Sjmmv }; 364698d5317Sjmmv 365698d5317Sjmmv /* esc_enter state definition. */ 366e9a2d6faSchristos static const struct input_state input_state_esc_enter = { 367698d5317Sjmmv "esc_enter", 368698d5317Sjmmv input_clear, NULL, 369698d5317Sjmmv input_state_esc_enter_table 370698d5317Sjmmv }; 371698d5317Sjmmv 372698d5317Sjmmv /* esc_intermediate state definition. */ 373e9a2d6faSchristos static const struct input_state input_state_esc_intermediate = { 374698d5317Sjmmv "esc_intermediate", 375698d5317Sjmmv NULL, NULL, 376698d5317Sjmmv input_state_esc_intermediate_table 377698d5317Sjmmv }; 378698d5317Sjmmv 379698d5317Sjmmv /* csi_enter state definition. */ 380e9a2d6faSchristos static const struct input_state input_state_csi_enter = { 381698d5317Sjmmv "csi_enter", 382698d5317Sjmmv input_clear, NULL, 383698d5317Sjmmv input_state_csi_enter_table 384698d5317Sjmmv }; 385698d5317Sjmmv 386698d5317Sjmmv /* csi_parameter state definition. */ 387e9a2d6faSchristos static const struct input_state input_state_csi_parameter = { 388698d5317Sjmmv "csi_parameter", 389698d5317Sjmmv NULL, NULL, 390698d5317Sjmmv input_state_csi_parameter_table 391698d5317Sjmmv }; 392698d5317Sjmmv 393698d5317Sjmmv /* csi_intermediate state definition. */ 394e9a2d6faSchristos static const struct input_state input_state_csi_intermediate = { 395698d5317Sjmmv "csi_intermediate", 396698d5317Sjmmv NULL, NULL, 397698d5317Sjmmv input_state_csi_intermediate_table 398698d5317Sjmmv }; 399698d5317Sjmmv 400698d5317Sjmmv /* csi_ignore state definition. */ 401e9a2d6faSchristos static const struct input_state input_state_csi_ignore = { 402698d5317Sjmmv "csi_ignore", 403698d5317Sjmmv NULL, NULL, 404698d5317Sjmmv input_state_csi_ignore_table 405698d5317Sjmmv }; 406698d5317Sjmmv 407698d5317Sjmmv /* dcs_enter state definition. */ 408e9a2d6faSchristos static const struct input_state input_state_dcs_enter = { 409698d5317Sjmmv "dcs_enter", 410fe99a117Schristos input_enter_dcs, NULL, 411698d5317Sjmmv input_state_dcs_enter_table 412698d5317Sjmmv }; 413698d5317Sjmmv 414698d5317Sjmmv /* dcs_parameter state definition. */ 415e9a2d6faSchristos static const struct input_state input_state_dcs_parameter = { 416698d5317Sjmmv "dcs_parameter", 417698d5317Sjmmv NULL, NULL, 418698d5317Sjmmv input_state_dcs_parameter_table 419698d5317Sjmmv }; 420698d5317Sjmmv 421698d5317Sjmmv /* dcs_intermediate state definition. */ 422e9a2d6faSchristos static const struct input_state input_state_dcs_intermediate = { 423698d5317Sjmmv "dcs_intermediate", 424698d5317Sjmmv NULL, NULL, 425698d5317Sjmmv input_state_dcs_intermediate_table 426698d5317Sjmmv }; 427698d5317Sjmmv 428698d5317Sjmmv /* dcs_handler state definition. */ 429e9a2d6faSchristos static const struct input_state input_state_dcs_handler = { 430698d5317Sjmmv "dcs_handler", 4310f3d2746Sjmmv NULL, NULL, 432698d5317Sjmmv input_state_dcs_handler_table 433698d5317Sjmmv }; 434698d5317Sjmmv 4350f3d2746Sjmmv /* dcs_escape state definition. */ 436e9a2d6faSchristos static const struct input_state input_state_dcs_escape = { 4370f3d2746Sjmmv "dcs_escape", 4380f3d2746Sjmmv NULL, NULL, 4390f3d2746Sjmmv input_state_dcs_escape_table 4400f3d2746Sjmmv }; 4410f3d2746Sjmmv 442698d5317Sjmmv /* dcs_ignore state definition. */ 443e9a2d6faSchristos static const struct input_state input_state_dcs_ignore = { 444698d5317Sjmmv "dcs_ignore", 445698d5317Sjmmv NULL, NULL, 446698d5317Sjmmv input_state_dcs_ignore_table 447698d5317Sjmmv }; 448698d5317Sjmmv 449698d5317Sjmmv /* osc_string state definition. */ 450e9a2d6faSchristos static const struct input_state input_state_osc_string = { 451698d5317Sjmmv "osc_string", 452698d5317Sjmmv input_enter_osc, input_exit_osc, 453698d5317Sjmmv input_state_osc_string_table 454698d5317Sjmmv }; 455698d5317Sjmmv 456698d5317Sjmmv /* apc_string state definition. */ 457e9a2d6faSchristos static const struct input_state input_state_apc_string = { 458698d5317Sjmmv "apc_string", 459698d5317Sjmmv input_enter_apc, input_exit_apc, 460698d5317Sjmmv input_state_apc_string_table 461698d5317Sjmmv }; 462698d5317Sjmmv 463698d5317Sjmmv /* rename_string state definition. */ 464e9a2d6faSchristos static const struct input_state input_state_rename_string = { 465698d5317Sjmmv "rename_string", 466698d5317Sjmmv input_enter_rename, input_exit_rename, 467698d5317Sjmmv input_state_rename_string_table 468698d5317Sjmmv }; 469698d5317Sjmmv 470698d5317Sjmmv /* consume_st state definition. */ 471e9a2d6faSchristos static const struct input_state input_state_consume_st = { 472698d5317Sjmmv "consume_st", 473fe99a117Schristos input_enter_rename, NULL, /* rename also waits for ST */ 474698d5317Sjmmv input_state_consume_st_table 475698d5317Sjmmv }; 476698d5317Sjmmv 477698d5317Sjmmv /* ground state table. */ 478e9a2d6faSchristos static const struct input_transition input_state_ground_table[] = { 479698d5317Sjmmv INPUT_STATE_ANYWHERE, 480698d5317Sjmmv 481698d5317Sjmmv { 0x00, 0x17, input_c0_dispatch, NULL }, 482698d5317Sjmmv { 0x19, 0x19, input_c0_dispatch, NULL }, 483698d5317Sjmmv { 0x1c, 0x1f, input_c0_dispatch, NULL }, 484698d5317Sjmmv { 0x20, 0x7e, input_print, NULL }, 485698d5317Sjmmv { 0x7f, 0x7f, NULL, NULL }, 486c7e17de0Schristos { 0x80, 0xff, input_top_bit_set, NULL }, 487698d5317Sjmmv 488698d5317Sjmmv { -1, -1, NULL, NULL } 489698d5317Sjmmv }; 490698d5317Sjmmv 491698d5317Sjmmv /* esc_enter state table. */ 492e9a2d6faSchristos static const struct input_transition input_state_esc_enter_table[] = { 493698d5317Sjmmv INPUT_STATE_ANYWHERE, 494698d5317Sjmmv 495698d5317Sjmmv { 0x00, 0x17, input_c0_dispatch, NULL }, 496698d5317Sjmmv { 0x19, 0x19, input_c0_dispatch, NULL }, 497698d5317Sjmmv { 0x1c, 0x1f, input_c0_dispatch, NULL }, 498698d5317Sjmmv { 0x20, 0x2f, input_intermediate, &input_state_esc_intermediate }, 499698d5317Sjmmv { 0x30, 0x4f, input_esc_dispatch, &input_state_ground }, 500698d5317Sjmmv { 0x50, 0x50, NULL, &input_state_dcs_enter }, 501698d5317Sjmmv { 0x51, 0x57, input_esc_dispatch, &input_state_ground }, 502698d5317Sjmmv { 0x58, 0x58, NULL, &input_state_consume_st }, 503698d5317Sjmmv { 0x59, 0x59, input_esc_dispatch, &input_state_ground }, 504698d5317Sjmmv { 0x5a, 0x5a, input_esc_dispatch, &input_state_ground }, 505698d5317Sjmmv { 0x5b, 0x5b, NULL, &input_state_csi_enter }, 506698d5317Sjmmv { 0x5c, 0x5c, input_esc_dispatch, &input_state_ground }, 507698d5317Sjmmv { 0x5d, 0x5d, NULL, &input_state_osc_string }, 508698d5317Sjmmv { 0x5e, 0x5e, NULL, &input_state_consume_st }, 509698d5317Sjmmv { 0x5f, 0x5f, NULL, &input_state_apc_string }, 510698d5317Sjmmv { 0x60, 0x6a, input_esc_dispatch, &input_state_ground }, 511698d5317Sjmmv { 0x6b, 0x6b, NULL, &input_state_rename_string }, 512698d5317Sjmmv { 0x6c, 0x7e, input_esc_dispatch, &input_state_ground }, 513698d5317Sjmmv { 0x7f, 0xff, NULL, NULL }, 514698d5317Sjmmv 515698d5317Sjmmv { -1, -1, NULL, NULL } 516698d5317Sjmmv }; 517698d5317Sjmmv 5180a274e86Schristos /* esc_intermediate state table. */ 519e9a2d6faSchristos static const struct input_transition input_state_esc_intermediate_table[] = { 520698d5317Sjmmv INPUT_STATE_ANYWHERE, 521698d5317Sjmmv 522698d5317Sjmmv { 0x00, 0x17, input_c0_dispatch, NULL }, 523698d5317Sjmmv { 0x19, 0x19, input_c0_dispatch, NULL }, 524698d5317Sjmmv { 0x1c, 0x1f, input_c0_dispatch, NULL }, 525698d5317Sjmmv { 0x20, 0x2f, input_intermediate, NULL }, 526698d5317Sjmmv { 0x30, 0x7e, input_esc_dispatch, &input_state_ground }, 527698d5317Sjmmv { 0x7f, 0xff, NULL, NULL }, 528698d5317Sjmmv 529698d5317Sjmmv { -1, -1, NULL, NULL } 530698d5317Sjmmv }; 531698d5317Sjmmv 532698d5317Sjmmv /* csi_enter state table. */ 533e9a2d6faSchristos static const struct input_transition input_state_csi_enter_table[] = { 534698d5317Sjmmv INPUT_STATE_ANYWHERE, 535698d5317Sjmmv 536698d5317Sjmmv { 0x00, 0x17, input_c0_dispatch, NULL }, 537698d5317Sjmmv { 0x19, 0x19, input_c0_dispatch, NULL }, 538698d5317Sjmmv { 0x1c, 0x1f, input_c0_dispatch, NULL }, 539698d5317Sjmmv { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate }, 540698d5317Sjmmv { 0x30, 0x39, input_parameter, &input_state_csi_parameter }, 541c7e17de0Schristos { 0x3a, 0x3a, input_parameter, &input_state_csi_parameter }, 542698d5317Sjmmv { 0x3b, 0x3b, input_parameter, &input_state_csi_parameter }, 543698d5317Sjmmv { 0x3c, 0x3f, input_intermediate, &input_state_csi_parameter }, 544698d5317Sjmmv { 0x40, 0x7e, input_csi_dispatch, &input_state_ground }, 545698d5317Sjmmv { 0x7f, 0xff, NULL, NULL }, 546698d5317Sjmmv 547698d5317Sjmmv { -1, -1, NULL, NULL } 548698d5317Sjmmv }; 549698d5317Sjmmv 550698d5317Sjmmv /* csi_parameter state table. */ 551e9a2d6faSchristos static const struct input_transition input_state_csi_parameter_table[] = { 552698d5317Sjmmv INPUT_STATE_ANYWHERE, 553698d5317Sjmmv 554698d5317Sjmmv { 0x00, 0x17, input_c0_dispatch, NULL }, 555698d5317Sjmmv { 0x19, 0x19, input_c0_dispatch, NULL }, 556698d5317Sjmmv { 0x1c, 0x1f, input_c0_dispatch, NULL }, 557698d5317Sjmmv { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate }, 558698d5317Sjmmv { 0x30, 0x39, input_parameter, NULL }, 559c7e17de0Schristos { 0x3a, 0x3a, input_parameter, NULL }, 560698d5317Sjmmv { 0x3b, 0x3b, input_parameter, NULL }, 561698d5317Sjmmv { 0x3c, 0x3f, NULL, &input_state_csi_ignore }, 562698d5317Sjmmv { 0x40, 0x7e, input_csi_dispatch, &input_state_ground }, 563698d5317Sjmmv { 0x7f, 0xff, NULL, NULL }, 564698d5317Sjmmv 565698d5317Sjmmv { -1, -1, NULL, NULL } 566698d5317Sjmmv }; 567698d5317Sjmmv 568698d5317Sjmmv /* csi_intermediate state table. */ 569e9a2d6faSchristos static const struct input_transition input_state_csi_intermediate_table[] = { 570698d5317Sjmmv INPUT_STATE_ANYWHERE, 571698d5317Sjmmv 572698d5317Sjmmv { 0x00, 0x17, input_c0_dispatch, NULL }, 573698d5317Sjmmv { 0x19, 0x19, input_c0_dispatch, NULL }, 574698d5317Sjmmv { 0x1c, 0x1f, input_c0_dispatch, NULL }, 575698d5317Sjmmv { 0x20, 0x2f, input_intermediate, NULL }, 576698d5317Sjmmv { 0x30, 0x3f, NULL, &input_state_csi_ignore }, 577698d5317Sjmmv { 0x40, 0x7e, input_csi_dispatch, &input_state_ground }, 578698d5317Sjmmv { 0x7f, 0xff, NULL, NULL }, 579698d5317Sjmmv 580698d5317Sjmmv { -1, -1, NULL, NULL } 581698d5317Sjmmv }; 582698d5317Sjmmv 583698d5317Sjmmv /* csi_ignore state table. */ 584e9a2d6faSchristos static const struct input_transition input_state_csi_ignore_table[] = { 585698d5317Sjmmv INPUT_STATE_ANYWHERE, 586698d5317Sjmmv 587698d5317Sjmmv { 0x00, 0x17, input_c0_dispatch, NULL }, 588698d5317Sjmmv { 0x19, 0x19, input_c0_dispatch, NULL }, 589698d5317Sjmmv { 0x1c, 0x1f, input_c0_dispatch, NULL }, 590698d5317Sjmmv { 0x20, 0x3f, NULL, NULL }, 591698d5317Sjmmv { 0x40, 0x7e, NULL, &input_state_ground }, 592698d5317Sjmmv { 0x7f, 0xff, NULL, NULL }, 593698d5317Sjmmv 594698d5317Sjmmv { -1, -1, NULL, NULL } 595698d5317Sjmmv }; 596698d5317Sjmmv 597698d5317Sjmmv /* dcs_enter state table. */ 598e9a2d6faSchristos static const struct input_transition input_state_dcs_enter_table[] = { 599698d5317Sjmmv INPUT_STATE_ANYWHERE, 600698d5317Sjmmv 601698d5317Sjmmv { 0x00, 0x17, NULL, NULL }, 602698d5317Sjmmv { 0x19, 0x19, NULL, NULL }, 603698d5317Sjmmv { 0x1c, 0x1f, NULL, NULL }, 604698d5317Sjmmv { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate }, 605698d5317Sjmmv { 0x30, 0x39, input_parameter, &input_state_dcs_parameter }, 606698d5317Sjmmv { 0x3a, 0x3a, NULL, &input_state_dcs_ignore }, 607698d5317Sjmmv { 0x3b, 0x3b, input_parameter, &input_state_dcs_parameter }, 608698d5317Sjmmv { 0x3c, 0x3f, input_intermediate, &input_state_dcs_parameter }, 6090f3d2746Sjmmv { 0x40, 0x7e, input_input, &input_state_dcs_handler }, 610698d5317Sjmmv { 0x7f, 0xff, NULL, NULL }, 611698d5317Sjmmv 612698d5317Sjmmv { -1, -1, NULL, NULL } 613698d5317Sjmmv }; 614698d5317Sjmmv 615698d5317Sjmmv /* dcs_parameter state table. */ 616e9a2d6faSchristos static const struct input_transition input_state_dcs_parameter_table[] = { 617698d5317Sjmmv INPUT_STATE_ANYWHERE, 618698d5317Sjmmv 619698d5317Sjmmv { 0x00, 0x17, NULL, NULL }, 620698d5317Sjmmv { 0x19, 0x19, NULL, NULL }, 621698d5317Sjmmv { 0x1c, 0x1f, NULL, NULL }, 622698d5317Sjmmv { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate }, 623698d5317Sjmmv { 0x30, 0x39, input_parameter, NULL }, 624698d5317Sjmmv { 0x3a, 0x3a, NULL, &input_state_dcs_ignore }, 625698d5317Sjmmv { 0x3b, 0x3b, input_parameter, NULL }, 626698d5317Sjmmv { 0x3c, 0x3f, NULL, &input_state_dcs_ignore }, 6270f3d2746Sjmmv { 0x40, 0x7e, input_input, &input_state_dcs_handler }, 628698d5317Sjmmv { 0x7f, 0xff, NULL, NULL }, 629698d5317Sjmmv 630698d5317Sjmmv { -1, -1, NULL, NULL } 631698d5317Sjmmv }; 632698d5317Sjmmv 6330a274e86Schristos /* dcs_intermediate state table. */ 634e9a2d6faSchristos static const struct input_transition input_state_dcs_intermediate_table[] = { 635698d5317Sjmmv INPUT_STATE_ANYWHERE, 636698d5317Sjmmv 637698d5317Sjmmv { 0x00, 0x17, NULL, NULL }, 638698d5317Sjmmv { 0x19, 0x19, NULL, NULL }, 639698d5317Sjmmv { 0x1c, 0x1f, NULL, NULL }, 640698d5317Sjmmv { 0x20, 0x2f, input_intermediate, NULL }, 641698d5317Sjmmv { 0x30, 0x3f, NULL, &input_state_dcs_ignore }, 6420f3d2746Sjmmv { 0x40, 0x7e, input_input, &input_state_dcs_handler }, 643698d5317Sjmmv { 0x7f, 0xff, NULL, NULL }, 644698d5317Sjmmv 645698d5317Sjmmv { -1, -1, NULL, NULL } 646698d5317Sjmmv }; 647698d5317Sjmmv 648698d5317Sjmmv /* dcs_handler state table. */ 649e9a2d6faSchristos static const struct input_transition input_state_dcs_handler_table[] = { 6500f3d2746Sjmmv /* No INPUT_STATE_ANYWHERE */ 651698d5317Sjmmv 6520f3d2746Sjmmv { 0x00, 0x1a, input_input, NULL }, 6530f3d2746Sjmmv { 0x1b, 0x1b, NULL, &input_state_dcs_escape }, 6540f3d2746Sjmmv { 0x1c, 0xff, input_input, NULL }, 655698d5317Sjmmv 656698d5317Sjmmv { -1, -1, NULL, NULL } 657698d5317Sjmmv }; 658698d5317Sjmmv 6590f3d2746Sjmmv /* dcs_escape state table. */ 660e9a2d6faSchristos static const struct input_transition input_state_dcs_escape_table[] = { 6610f3d2746Sjmmv /* No INPUT_STATE_ANYWHERE */ 6620f3d2746Sjmmv 6630f3d2746Sjmmv { 0x00, 0x5b, input_input, &input_state_dcs_handler }, 6640f3d2746Sjmmv { 0x5c, 0x5c, input_dcs_dispatch, &input_state_ground }, 6650f3d2746Sjmmv { 0x5d, 0xff, input_input, &input_state_dcs_handler }, 6660f3d2746Sjmmv 6670f3d2746Sjmmv { -1, -1, NULL, NULL } 6680f3d2746Sjmmv }; 6690f3d2746Sjmmv 6700f3d2746Sjmmv /* dcs_ignore state table. */ 671e9a2d6faSchristos static const struct input_transition input_state_dcs_ignore_table[] = { 672698d5317Sjmmv INPUT_STATE_ANYWHERE, 673698d5317Sjmmv 674698d5317Sjmmv { 0x00, 0x17, NULL, NULL }, 675698d5317Sjmmv { 0x19, 0x19, NULL, NULL }, 676698d5317Sjmmv { 0x1c, 0x1f, NULL, NULL }, 677698d5317Sjmmv { 0x20, 0xff, NULL, NULL }, 678698d5317Sjmmv 679698d5317Sjmmv { -1, -1, NULL, NULL } 680698d5317Sjmmv }; 681698d5317Sjmmv 682698d5317Sjmmv /* osc_string state table. */ 683e9a2d6faSchristos static const struct input_transition input_state_osc_string_table[] = { 684698d5317Sjmmv INPUT_STATE_ANYWHERE, 685698d5317Sjmmv 686698d5317Sjmmv { 0x00, 0x06, NULL, NULL }, 6870a274e86Schristos { 0x07, 0x07, input_end_bel, &input_state_ground }, 688698d5317Sjmmv { 0x08, 0x17, NULL, NULL }, 689698d5317Sjmmv { 0x19, 0x19, NULL, NULL }, 690698d5317Sjmmv { 0x1c, 0x1f, NULL, NULL }, 691698d5317Sjmmv { 0x20, 0xff, input_input, NULL }, 692698d5317Sjmmv 693698d5317Sjmmv { -1, -1, NULL, NULL } 694698d5317Sjmmv }; 695698d5317Sjmmv 696698d5317Sjmmv /* apc_string state table. */ 697e9a2d6faSchristos static const struct input_transition input_state_apc_string_table[] = { 698698d5317Sjmmv INPUT_STATE_ANYWHERE, 699698d5317Sjmmv 700698d5317Sjmmv { 0x00, 0x17, NULL, NULL }, 701698d5317Sjmmv { 0x19, 0x19, NULL, NULL }, 702698d5317Sjmmv { 0x1c, 0x1f, NULL, NULL }, 703698d5317Sjmmv { 0x20, 0xff, input_input, NULL }, 704698d5317Sjmmv 705698d5317Sjmmv { -1, -1, NULL, NULL } 706698d5317Sjmmv }; 707698d5317Sjmmv 708698d5317Sjmmv /* rename_string state table. */ 709e9a2d6faSchristos static const struct input_transition input_state_rename_string_table[] = { 710698d5317Sjmmv INPUT_STATE_ANYWHERE, 711698d5317Sjmmv 712698d5317Sjmmv { 0x00, 0x17, NULL, NULL }, 713698d5317Sjmmv { 0x19, 0x19, NULL, NULL }, 714698d5317Sjmmv { 0x1c, 0x1f, NULL, NULL }, 715698d5317Sjmmv { 0x20, 0xff, input_input, NULL }, 716698d5317Sjmmv 717698d5317Sjmmv { -1, -1, NULL, NULL } 718698d5317Sjmmv }; 719698d5317Sjmmv 720698d5317Sjmmv /* consume_st state table. */ 721e9a2d6faSchristos static const struct input_transition input_state_consume_st_table[] = { 722698d5317Sjmmv INPUT_STATE_ANYWHERE, 723698d5317Sjmmv 724698d5317Sjmmv { 0x00, 0x17, NULL, NULL }, 725698d5317Sjmmv { 0x19, 0x19, NULL, NULL }, 726698d5317Sjmmv { 0x1c, 0x1f, NULL, NULL }, 727698d5317Sjmmv { 0x20, 0xff, NULL, NULL }, 728698d5317Sjmmv 729698d5317Sjmmv { -1, -1, NULL, NULL } 730698d5317Sjmmv }; 731698d5317Sjmmv 732698d5317Sjmmv /* Input table compare. */ 733e9a2d6faSchristos static int 734698d5317Sjmmv input_table_compare(const void *key, const void *value) 735698d5317Sjmmv { 736698d5317Sjmmv const struct input_ctx *ictx = key; 737698d5317Sjmmv const struct input_table_entry *entry = value; 738698d5317Sjmmv 739698d5317Sjmmv if (ictx->ch != entry->ch) 740698d5317Sjmmv return (ictx->ch - entry->ch); 741cad4076fSchristos return (strcmp((const char *)ictx->interm_buf, entry->interm)); 742698d5317Sjmmv } 743698d5317Sjmmv 744fe99a117Schristos /* 745fe99a117Schristos * Timer - if this expires then have been waiting for a terminator for too 746fe99a117Schristos * long, so reset to ground. 747fe99a117Schristos */ 748fe99a117Schristos static void 749fe99a117Schristos input_timer_callback(__unused int fd, __unused short events, void *arg) 750fe99a117Schristos { 751fe99a117Schristos struct input_ctx *ictx = arg; 752fe99a117Schristos 753e271dbb8Schristos log_debug("%s: %s expired" , __func__, ictx->state->name); 754e271dbb8Schristos input_reset(ictx, 0); 755fe99a117Schristos } 756fe99a117Schristos 757fe99a117Schristos /* Start the timer. */ 758fe99a117Schristos static void 759fe99a117Schristos input_start_timer(struct input_ctx *ictx) 760fe99a117Schristos { 76168e6ba84Schristos struct timeval tv = { .tv_sec = 5, .tv_usec = 0 }; 762fe99a117Schristos 763fe99a117Schristos event_del(&ictx->timer); 764fe99a117Schristos event_add(&ictx->timer, &tv); 765fe99a117Schristos } 766fe99a117Schristos 76799e242abSchristos /* Reset cell state to default. */ 768e9a2d6faSchristos static void 76999e242abSchristos input_reset_cell(struct input_ctx *ictx) 77099e242abSchristos { 77199e242abSchristos memcpy(&ictx->cell.cell, &grid_default_cell, sizeof ictx->cell.cell); 77299e242abSchristos ictx->cell.set = 0; 77399e242abSchristos ictx->cell.g0set = ictx->cell.g1set = 0; 77499e242abSchristos 77599e242abSchristos memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell); 77699e242abSchristos ictx->old_cx = 0; 77799e242abSchristos ictx->old_cy = 0; 77899e242abSchristos } 77999e242abSchristos 7800a274e86Schristos /* Save screen state. */ 7810a274e86Schristos static void 7820a274e86Schristos input_save_state(struct input_ctx *ictx) 7830a274e86Schristos { 7840a274e86Schristos struct screen_write_ctx *sctx = &ictx->ctx; 7850a274e86Schristos struct screen *s = sctx->s; 7860a274e86Schristos 7870a274e86Schristos memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell); 7880a274e86Schristos ictx->old_cx = s->cx; 7890a274e86Schristos ictx->old_cy = s->cy; 7900a274e86Schristos ictx->old_mode = s->mode; 7910a274e86Schristos } 7920a274e86Schristos 79368e6ba84Schristos /* Restore screen state. */ 7940a274e86Schristos static void 7950a274e86Schristos input_restore_state(struct input_ctx *ictx) 7960a274e86Schristos { 7970a274e86Schristos struct screen_write_ctx *sctx = &ictx->ctx; 7980a274e86Schristos 7990a274e86Schristos memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell); 8000a274e86Schristos if (ictx->old_mode & MODE_ORIGIN) 8010a274e86Schristos screen_write_mode_set(sctx, MODE_ORIGIN); 8020a274e86Schristos else 8030a274e86Schristos screen_write_mode_clear(sctx, MODE_ORIGIN); 8040a274e86Schristos screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy, 0); 8050a274e86Schristos } 8060a274e86Schristos 807698d5317Sjmmv /* Initialise input parser. */ 808e271dbb8Schristos struct input_ctx * 80946548964Swiz input_init(struct window_pane *wp, struct bufferevent *bev, 81046548964Swiz struct colour_palette *palette) 811698d5317Sjmmv { 81299e242abSchristos struct input_ctx *ictx; 813698d5317Sjmmv 814e271dbb8Schristos ictx = xcalloc(1, sizeof *ictx); 815e271dbb8Schristos ictx->wp = wp; 816e271dbb8Schristos ictx->event = bev; 81746548964Swiz ictx->palette = palette; 818698d5317Sjmmv 81999e242abSchristos ictx->input_space = INPUT_BUF_START; 82099e242abSchristos ictx->input_buf = xmalloc(INPUT_BUF_START); 82199e242abSchristos 82261fba46bSchristos ictx->since_ground = evbuffer_new(); 8230a274e86Schristos if (ictx->since_ground == NULL) 8240a274e86Schristos fatalx("out of memory"); 825f26e8bc9Schristos 826fe99a117Schristos evtimer_set(&ictx->timer, input_timer_callback, ictx); 827fe99a117Schristos 828e271dbb8Schristos input_reset(ictx, 0); 829e271dbb8Schristos return (ictx); 830698d5317Sjmmv } 831698d5317Sjmmv 832698d5317Sjmmv /* Destroy input parser. */ 833698d5317Sjmmv void 834e271dbb8Schristos input_free(struct input_ctx *ictx) 835698d5317Sjmmv { 836c7e17de0Schristos u_int i; 837c7e17de0Schristos 838c7e17de0Schristos for (i = 0; i < ictx->param_list_len; i++) { 839c7e17de0Schristos if (ictx->param_list[i].type == INPUT_STRING) 840c7e17de0Schristos free(ictx->param_list[i].str); 841c7e17de0Schristos } 84299e242abSchristos 843fe99a117Schristos event_del(&ictx->timer); 844fe99a117Schristos 84599e242abSchristos free(ictx->input_buf); 84699e242abSchristos evbuffer_free(ictx->since_ground); 84799e242abSchristos 84899e242abSchristos free(ictx); 84999e242abSchristos } 85099e242abSchristos 85199e242abSchristos /* Reset input state and clear screen. */ 85299e242abSchristos void 853e271dbb8Schristos input_reset(struct input_ctx *ictx, int clear) 85499e242abSchristos { 8550a274e86Schristos struct screen_write_ctx *sctx = &ictx->ctx; 856e271dbb8Schristos struct window_pane *wp = ictx->wp; 85799e242abSchristos 85899e242abSchristos input_reset_cell(ictx); 85999e242abSchristos 860e271dbb8Schristos if (clear && wp != NULL) { 8610a274e86Schristos if (TAILQ_EMPTY(&wp->modes)) 862e271dbb8Schristos screen_write_start_pane(sctx, wp, &wp->base); 86399e242abSchristos else 864e271dbb8Schristos screen_write_start(sctx, &wp->base); 8650a274e86Schristos screen_write_reset(sctx); 8660a274e86Schristos screen_write_stop(sctx); 86799e242abSchristos } 86899e242abSchristos 869fe99a117Schristos input_clear(ictx); 870f26e8bc9Schristos 871f26e8bc9Schristos ictx->state = &input_state_ground; 872f26e8bc9Schristos ictx->flags = 0; 873f26e8bc9Schristos } 874f26e8bc9Schristos 87599e242abSchristos /* Return pending data. */ 87699e242abSchristos struct evbuffer * 877e271dbb8Schristos input_pending(struct input_ctx *ictx) 87899e242abSchristos { 879e271dbb8Schristos return (ictx->since_ground); 88061fba46bSchristos } 88161fba46bSchristos 88261fba46bSchristos /* Change input state. */ 883e9a2d6faSchristos static void 884e271dbb8Schristos input_set_state(struct input_ctx *ictx, const struct input_transition *itr) 88561fba46bSchristos { 88661fba46bSchristos if (ictx->state->exit != NULL) 88761fba46bSchristos ictx->state->exit(ictx); 88861fba46bSchristos ictx->state = itr->state; 88961fba46bSchristos if (ictx->state->enter != NULL) 89061fba46bSchristos ictx->state->enter(ictx); 891698d5317Sjmmv } 892698d5317Sjmmv 893e271dbb8Schristos /* Parse data. */ 894e271dbb8Schristos static void 895e271dbb8Schristos input_parse(struct input_ctx *ictx, u_char *buf, size_t len) 896698d5317Sjmmv { 8970a274e86Schristos struct screen_write_ctx *sctx = &ictx->ctx; 89868e6ba84Schristos const struct input_state *state = NULL; 89968e6ba84Schristos const struct input_transition *itr = NULL; 90030744affSchristos size_t off = 0; 901698d5317Sjmmv 902698d5317Sjmmv /* Parse the input. */ 903698d5317Sjmmv while (off < len) { 904698d5317Sjmmv ictx->ch = buf[off++]; 905698d5317Sjmmv 906698d5317Sjmmv /* Find the transition. */ 90768e6ba84Schristos if (ictx->state != state || 90868e6ba84Schristos itr == NULL || 90968e6ba84Schristos ictx->ch < itr->first || 91068e6ba84Schristos ictx->ch > itr->last) { 911698d5317Sjmmv itr = ictx->state->transitions; 912698d5317Sjmmv while (itr->first != -1 && itr->last != -1) { 91368e6ba84Schristos if (ictx->ch >= itr->first && 91468e6ba84Schristos ictx->ch <= itr->last) 915698d5317Sjmmv break; 916698d5317Sjmmv itr++; 917698d5317Sjmmv } 918698d5317Sjmmv if (itr->first == -1 || itr->last == -1) { 919698d5317Sjmmv /* No transition? Eh? */ 92099e242abSchristos fatalx("no transition from state"); 921698d5317Sjmmv } 92268e6ba84Schristos } 92368e6ba84Schristos state = ictx->state; 924698d5317Sjmmv 925698d5317Sjmmv /* 926e9a2d6faSchristos * Any state except print stops the current collection. This is 927e9a2d6faSchristos * an optimization to avoid checking if the attributes have 928e9a2d6faSchristos * changed for every character. It will stop unnecessarily for 929e9a2d6faSchristos * sequences that don't make a terminal change, but they should 930e9a2d6faSchristos * be the minority. 931e9a2d6faSchristos */ 932e9a2d6faSchristos if (itr->handler != input_print) 9330a274e86Schristos screen_write_collect_end(sctx); 934e9a2d6faSchristos 935e9a2d6faSchristos /* 936698d5317Sjmmv * Execute the handler, if any. Don't switch state if it 937698d5317Sjmmv * returns non-zero. 938698d5317Sjmmv */ 939698d5317Sjmmv if (itr->handler != NULL && itr->handler(ictx) != 0) 940698d5317Sjmmv continue; 941698d5317Sjmmv 942698d5317Sjmmv /* And switch state, if necessary. */ 94361fba46bSchristos if (itr->state != NULL) 944e271dbb8Schristos input_set_state(ictx, itr); 94561fba46bSchristos 94661fba46bSchristos /* If not in ground state, save input. */ 94761fba46bSchristos if (ictx->state != &input_state_ground) 94861fba46bSchristos evbuffer_add(ictx->since_ground, &ictx->ch, 1); 949698d5317Sjmmv } 950e271dbb8Schristos } 951698d5317Sjmmv 952e271dbb8Schristos /* Parse input from pane. */ 953e271dbb8Schristos void 954e271dbb8Schristos input_parse_pane(struct window_pane *wp) 955e271dbb8Schristos { 956e271dbb8Schristos void *new_data; 957e271dbb8Schristos size_t new_size; 958e271dbb8Schristos 959e271dbb8Schristos new_data = window_pane_get_new_data(wp, &wp->offset, &new_size); 960e271dbb8Schristos input_parse_buffer(wp, new_data, new_size); 961e271dbb8Schristos window_pane_update_used_data(wp, &wp->offset, new_size); 962e271dbb8Schristos } 963e271dbb8Schristos 964e271dbb8Schristos /* Parse given input. */ 965e271dbb8Schristos void 966e271dbb8Schristos input_parse_buffer(struct window_pane *wp, u_char *buf, size_t len) 967e271dbb8Schristos { 968e271dbb8Schristos struct input_ctx *ictx = wp->ictx; 969e271dbb8Schristos struct screen_write_ctx *sctx = &ictx->ctx; 970e271dbb8Schristos 971e271dbb8Schristos if (len == 0) 972e271dbb8Schristos return; 973e271dbb8Schristos 974e271dbb8Schristos window_update_activity(wp->window); 975e271dbb8Schristos wp->flags |= PANE_CHANGED; 976e271dbb8Schristos 977f844e94eSwiz /* Flag new input while in a mode. */ 978f844e94eSwiz if (!TAILQ_EMPTY(&wp->modes)) 979f844e94eSwiz wp->flags |= PANE_UNSEENCHANGES; 980f844e94eSwiz 981e271dbb8Schristos /* NULL wp if there is a mode set as don't want to update the tty. */ 982e271dbb8Schristos if (TAILQ_EMPTY(&wp->modes)) 983e271dbb8Schristos screen_write_start_pane(sctx, wp, &wp->base); 984e271dbb8Schristos else 985e271dbb8Schristos screen_write_start(sctx, &wp->base); 986e271dbb8Schristos 987e271dbb8Schristos log_debug("%s: %%%u %s, %zu bytes: %.*s", __func__, wp->id, 988e271dbb8Schristos ictx->state->name, len, (int)len, buf); 989e271dbb8Schristos 990e271dbb8Schristos input_parse(ictx, buf, len); 991e271dbb8Schristos screen_write_stop(sctx); 992e271dbb8Schristos } 993e271dbb8Schristos 994e271dbb8Schristos /* Parse given input for screen. */ 995e271dbb8Schristos void 996e271dbb8Schristos input_parse_screen(struct input_ctx *ictx, struct screen *s, 997e271dbb8Schristos screen_write_init_ctx_cb cb, void *arg, u_char *buf, size_t len) 998e271dbb8Schristos { 999e271dbb8Schristos struct screen_write_ctx *sctx = &ictx->ctx; 1000e271dbb8Schristos 1001e271dbb8Schristos if (len == 0) 1002e271dbb8Schristos return; 1003e271dbb8Schristos 1004e271dbb8Schristos screen_write_start_callback(sctx, s, cb, arg); 1005e271dbb8Schristos input_parse(ictx, buf, len); 10060a274e86Schristos screen_write_stop(sctx); 1007698d5317Sjmmv } 1008698d5317Sjmmv 1009698d5317Sjmmv /* Split the parameter list (if any). */ 1010e9a2d6faSchristos static int 1011698d5317Sjmmv input_split(struct input_ctx *ictx) 1012698d5317Sjmmv { 1013698d5317Sjmmv const char *errstr; 1014698d5317Sjmmv char *ptr, *out; 1015c7e17de0Schristos struct input_param *ip; 1016c7e17de0Schristos u_int i; 1017698d5317Sjmmv 1018c7e17de0Schristos for (i = 0; i < ictx->param_list_len; i++) { 1019c7e17de0Schristos if (ictx->param_list[i].type == INPUT_STRING) 1020c7e17de0Schristos free(ictx->param_list[i].str); 1021c7e17de0Schristos } 1022698d5317Sjmmv ictx->param_list_len = 0; 1023c7e17de0Schristos 1024698d5317Sjmmv if (ictx->param_len == 0) 1025698d5317Sjmmv return (0); 1026c7e17de0Schristos ip = &ictx->param_list[0]; 1027698d5317Sjmmv 1028cad4076fSchristos ptr = (char *)ictx->param_buf; 1029698d5317Sjmmv while ((out = strsep(&ptr, ";")) != NULL) { 1030698d5317Sjmmv if (*out == '\0') 1031c7e17de0Schristos ip->type = INPUT_MISSING; 1032698d5317Sjmmv else { 1033c7e17de0Schristos if (strchr(out, ':') != NULL) { 1034c7e17de0Schristos ip->type = INPUT_STRING; 1035c7e17de0Schristos ip->str = xstrdup(out); 1036c7e17de0Schristos } else { 1037c7e17de0Schristos ip->type = INPUT_NUMBER; 1038c7e17de0Schristos ip->num = strtonum(out, 0, INT_MAX, &errstr); 1039698d5317Sjmmv if (errstr != NULL) 1040698d5317Sjmmv return (-1); 1041698d5317Sjmmv } 1042c7e17de0Schristos } 1043c7e17de0Schristos ip = &ictx->param_list[++ictx->param_list_len]; 1044698d5317Sjmmv if (ictx->param_list_len == nitems(ictx->param_list)) 1045698d5317Sjmmv return (-1); 1046698d5317Sjmmv } 1047698d5317Sjmmv 1048c7e17de0Schristos for (i = 0; i < ictx->param_list_len; i++) { 1049c7e17de0Schristos ip = &ictx->param_list[i]; 1050c7e17de0Schristos if (ip->type == INPUT_MISSING) 1051c7e17de0Schristos log_debug("parameter %u: missing", i); 1052c7e17de0Schristos else if (ip->type == INPUT_STRING) 1053c7e17de0Schristos log_debug("parameter %u: string %s", i, ip->str); 1054c7e17de0Schristos else if (ip->type == INPUT_NUMBER) 1055c7e17de0Schristos log_debug("parameter %u: number %d", i, ip->num); 1056c7e17de0Schristos } 1057c7e17de0Schristos 1058698d5317Sjmmv return (0); 1059698d5317Sjmmv } 1060698d5317Sjmmv 10610f3d2746Sjmmv /* Get an argument or return default value. */ 1062e9a2d6faSchristos static int 1063698d5317Sjmmv input_get(struct input_ctx *ictx, u_int validx, int minval, int defval) 1064698d5317Sjmmv { 1065c7e17de0Schristos struct input_param *ip; 1066698d5317Sjmmv int retval; 1067698d5317Sjmmv 1068698d5317Sjmmv if (validx >= ictx->param_list_len) 1069698d5317Sjmmv return (defval); 1070c7e17de0Schristos ip = &ictx->param_list[validx]; 1071c7e17de0Schristos if (ip->type == INPUT_MISSING) 1072698d5317Sjmmv return (defval); 1073c7e17de0Schristos if (ip->type == INPUT_STRING) 1074c7e17de0Schristos return (-1); 1075c7e17de0Schristos retval = ip->num; 1076698d5317Sjmmv if (retval < minval) 1077698d5317Sjmmv return (minval); 1078698d5317Sjmmv return (retval); 1079698d5317Sjmmv } 1080698d5317Sjmmv 1081698d5317Sjmmv /* Reply to terminal query. */ 1082e9a2d6faSchristos static void 1083698d5317Sjmmv input_reply(struct input_ctx *ictx, const char *fmt, ...) 1084698d5317Sjmmv { 1085e271dbb8Schristos struct bufferevent *bev = ictx->event; 1086698d5317Sjmmv va_list ap; 1087698d5317Sjmmv char *reply; 1088698d5317Sjmmv 108946548964Swiz if (bev == NULL) 109046548964Swiz return; 109146548964Swiz 1092698d5317Sjmmv va_start(ap, fmt); 1093e9a2d6faSchristos xvasprintf(&reply, fmt, ap); 1094698d5317Sjmmv va_end(ap); 1095698d5317Sjmmv 1096f844e94eSwiz log_debug("%s: %s", __func__, reply); 1097e271dbb8Schristos bufferevent_write(bev, reply, strlen(reply)); 109861fba46bSchristos free(reply); 1099698d5317Sjmmv } 1100698d5317Sjmmv 1101698d5317Sjmmv /* Clear saved state. */ 1102e9a2d6faSchristos static void 1103698d5317Sjmmv input_clear(struct input_ctx *ictx) 1104698d5317Sjmmv { 1105fe99a117Schristos event_del(&ictx->timer); 1106fe99a117Schristos 1107698d5317Sjmmv *ictx->interm_buf = '\0'; 1108698d5317Sjmmv ictx->interm_len = 0; 1109698d5317Sjmmv 1110698d5317Sjmmv *ictx->param_buf = '\0'; 1111698d5317Sjmmv ictx->param_len = 0; 1112698d5317Sjmmv 11130f3d2746Sjmmv *ictx->input_buf = '\0'; 11140f3d2746Sjmmv ictx->input_len = 0; 11150f3d2746Sjmmv 11160a274e86Schristos ictx->input_end = INPUT_END_ST; 11170a274e86Schristos 1118698d5317Sjmmv ictx->flags &= ~INPUT_DISCARD; 1119698d5317Sjmmv } 1120698d5317Sjmmv 112199e242abSchristos /* Reset for ground state. */ 1122e9a2d6faSchristos static void 112399e242abSchristos input_ground(struct input_ctx *ictx) 112499e242abSchristos { 1125fe99a117Schristos event_del(&ictx->timer); 112699e242abSchristos evbuffer_drain(ictx->since_ground, EVBUFFER_LENGTH(ictx->since_ground)); 112799e242abSchristos 112899e242abSchristos if (ictx->input_space > INPUT_BUF_START) { 112999e242abSchristos ictx->input_space = INPUT_BUF_START; 113099e242abSchristos ictx->input_buf = xrealloc(ictx->input_buf, INPUT_BUF_START); 113199e242abSchristos } 113299e242abSchristos } 113399e242abSchristos 1134698d5317Sjmmv /* Output this character to the screen. */ 1135e9a2d6faSchristos static int 1136698d5317Sjmmv input_print(struct input_ctx *ictx) 1137698d5317Sjmmv { 11380a274e86Schristos struct screen_write_ctx *sctx = &ictx->ctx; 113999e242abSchristos int set; 114099e242abSchristos 1141c7e17de0Schristos ictx->utf8started = 0; /* can't be valid UTF-8 */ 1142c7e17de0Schristos 114399e242abSchristos set = ictx->cell.set == 0 ? ictx->cell.g0set : ictx->cell.g1set; 114499e242abSchristos if (set == 1) 114599e242abSchristos ictx->cell.cell.attr |= GRID_ATTR_CHARSET; 114699e242abSchristos else 114799e242abSchristos ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET; 114899e242abSchristos 1149f26e8bc9Schristos utf8_set(&ictx->cell.cell.data, ictx->ch); 11500a274e86Schristos screen_write_collect_add(sctx, &ictx->cell.cell); 1151*890b6d91Swiz 1152*890b6d91Swiz utf8_copy(&ictx->last, &ictx->cell.cell.data); 1153*890b6d91Swiz ictx->flags |= INPUT_LAST; 115499e242abSchristos 115599e242abSchristos ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET; 1156698d5317Sjmmv 1157698d5317Sjmmv return (0); 1158698d5317Sjmmv } 1159698d5317Sjmmv 1160698d5317Sjmmv /* Collect intermediate string. */ 1161e9a2d6faSchristos static int 1162698d5317Sjmmv input_intermediate(struct input_ctx *ictx) 1163698d5317Sjmmv { 1164698d5317Sjmmv if (ictx->interm_len == (sizeof ictx->interm_buf) - 1) 1165698d5317Sjmmv ictx->flags |= INPUT_DISCARD; 1166698d5317Sjmmv else { 1167698d5317Sjmmv ictx->interm_buf[ictx->interm_len++] = ictx->ch; 1168698d5317Sjmmv ictx->interm_buf[ictx->interm_len] = '\0'; 1169698d5317Sjmmv } 1170698d5317Sjmmv 1171698d5317Sjmmv return (0); 1172698d5317Sjmmv } 1173698d5317Sjmmv 1174698d5317Sjmmv /* Collect parameter string. */ 1175e9a2d6faSchristos static int 1176698d5317Sjmmv input_parameter(struct input_ctx *ictx) 1177698d5317Sjmmv { 1178698d5317Sjmmv if (ictx->param_len == (sizeof ictx->param_buf) - 1) 1179698d5317Sjmmv ictx->flags |= INPUT_DISCARD; 1180698d5317Sjmmv else { 1181698d5317Sjmmv ictx->param_buf[ictx->param_len++] = ictx->ch; 1182698d5317Sjmmv ictx->param_buf[ictx->param_len] = '\0'; 1183698d5317Sjmmv } 1184698d5317Sjmmv 1185698d5317Sjmmv return (0); 1186698d5317Sjmmv } 1187698d5317Sjmmv 1188698d5317Sjmmv /* Collect input string. */ 1189e9a2d6faSchristos static int 1190698d5317Sjmmv input_input(struct input_ctx *ictx) 1191698d5317Sjmmv { 119299e242abSchristos size_t available; 119399e242abSchristos 119499e242abSchristos available = ictx->input_space; 119599e242abSchristos while (ictx->input_len + 1 >= available) { 119699e242abSchristos available *= 2; 119799e242abSchristos if (available > INPUT_BUF_LIMIT) { 1198698d5317Sjmmv ictx->flags |= INPUT_DISCARD; 119999e242abSchristos return (0); 120099e242abSchristos } 120199e242abSchristos ictx->input_buf = xrealloc(ictx->input_buf, available); 120299e242abSchristos ictx->input_space = available; 120399e242abSchristos } 1204698d5317Sjmmv ictx->input_buf[ictx->input_len++] = ictx->ch; 1205698d5317Sjmmv ictx->input_buf[ictx->input_len] = '\0'; 1206698d5317Sjmmv 1207698d5317Sjmmv return (0); 1208698d5317Sjmmv } 1209698d5317Sjmmv 1210698d5317Sjmmv /* Execute C0 control sequence. */ 1211e9a2d6faSchristos static int 1212698d5317Sjmmv input_c0_dispatch(struct input_ctx *ictx) 1213698d5317Sjmmv { 1214698d5317Sjmmv struct screen_write_ctx *sctx = &ictx->ctx; 1215698d5317Sjmmv struct window_pane *wp = ictx->wp; 1216698d5317Sjmmv struct screen *s = sctx->s; 1217698d5317Sjmmv 1218c7e17de0Schristos ictx->utf8started = 0; /* can't be valid UTF-8 */ 1219c7e17de0Schristos 122099e242abSchristos log_debug("%s: '%c'", __func__, ictx->ch); 1221698d5317Sjmmv 1222698d5317Sjmmv switch (ictx->ch) { 1223698d5317Sjmmv case '\000': /* NUL */ 1224698d5317Sjmmv break; 1225698d5317Sjmmv case '\007': /* BEL */ 1226e271dbb8Schristos if (wp != NULL) 122799e242abSchristos alerts_queue(wp->window, WINDOW_BELL); 1228698d5317Sjmmv break; 1229698d5317Sjmmv case '\010': /* BS */ 1230698d5317Sjmmv screen_write_backspace(sctx); 123199e242abSchristos break; 1232698d5317Sjmmv case '\011': /* HT */ 1233698d5317Sjmmv /* Don't tab beyond the end of the line. */ 1234698d5317Sjmmv if (s->cx >= screen_size_x(s) - 1) 1235698d5317Sjmmv break; 1236698d5317Sjmmv 1237698d5317Sjmmv /* Find the next tab point, or use the last column if none. */ 1238698d5317Sjmmv do { 1239698d5317Sjmmv s->cx++; 1240698d5317Sjmmv if (bit_test(s->tabs, s->cx)) 1241698d5317Sjmmv break; 1242698d5317Sjmmv } while (s->cx < screen_size_x(s) - 1); 1243698d5317Sjmmv break; 1244698d5317Sjmmv case '\012': /* LF */ 1245698d5317Sjmmv case '\013': /* VT */ 1246698d5317Sjmmv case '\014': /* FF */ 1247fe99a117Schristos screen_write_linefeed(sctx, 0, ictx->cell.cell.bg); 124830744affSchristos if (s->mode & MODE_CRLF) 124930744affSchristos screen_write_carriagereturn(sctx); 125099e242abSchristos break; 1251698d5317Sjmmv case '\015': /* CR */ 1252698d5317Sjmmv screen_write_carriagereturn(sctx); 125399e242abSchristos break; 1254698d5317Sjmmv case '\016': /* SO */ 125599e242abSchristos ictx->cell.set = 1; 1256698d5317Sjmmv break; 1257698d5317Sjmmv case '\017': /* SI */ 125899e242abSchristos ictx->cell.set = 0; 1259698d5317Sjmmv break; 1260698d5317Sjmmv default: 1261698d5317Sjmmv log_debug("%s: unknown '%c'", __func__, ictx->ch); 1262698d5317Sjmmv break; 1263698d5317Sjmmv } 1264698d5317Sjmmv 1265*890b6d91Swiz ictx->flags &= ~INPUT_LAST; 1266698d5317Sjmmv return (0); 1267698d5317Sjmmv } 1268698d5317Sjmmv 1269698d5317Sjmmv /* Execute escape sequence. */ 1270e9a2d6faSchristos static int 1271698d5317Sjmmv input_esc_dispatch(struct input_ctx *ictx) 1272698d5317Sjmmv { 1273698d5317Sjmmv struct screen_write_ctx *sctx = &ictx->ctx; 1274698d5317Sjmmv struct screen *s = sctx->s; 1275698d5317Sjmmv struct input_table_entry *entry; 1276698d5317Sjmmv 1277698d5317Sjmmv if (ictx->flags & INPUT_DISCARD) 1278698d5317Sjmmv return (0); 1279698d5317Sjmmv log_debug("%s: '%c', %s", __func__, ictx->ch, ictx->interm_buf); 1280698d5317Sjmmv 1281698d5317Sjmmv entry = bsearch(ictx, input_esc_table, nitems(input_esc_table), 1282698d5317Sjmmv sizeof input_esc_table[0], input_table_compare); 1283698d5317Sjmmv if (entry == NULL) { 1284698d5317Sjmmv log_debug("%s: unknown '%c'", __func__, ictx->ch); 1285698d5317Sjmmv return (0); 1286698d5317Sjmmv } 1287698d5317Sjmmv 1288698d5317Sjmmv switch (entry->type) { 1289698d5317Sjmmv case INPUT_ESC_RIS: 129046548964Swiz colour_palette_clear(ictx->palette); 129199e242abSchristos input_reset_cell(ictx); 129261fba46bSchristos screen_write_reset(sctx); 129346548964Swiz screen_write_fullredraw(sctx); 1294698d5317Sjmmv break; 1295698d5317Sjmmv case INPUT_ESC_IND: 1296fe99a117Schristos screen_write_linefeed(sctx, 0, ictx->cell.cell.bg); 1297698d5317Sjmmv break; 1298698d5317Sjmmv case INPUT_ESC_NEL: 1299698d5317Sjmmv screen_write_carriagereturn(sctx); 1300fe99a117Schristos screen_write_linefeed(sctx, 0, ictx->cell.cell.bg); 1301698d5317Sjmmv break; 1302698d5317Sjmmv case INPUT_ESC_HTS: 1303698d5317Sjmmv if (s->cx < screen_size_x(s)) 1304698d5317Sjmmv bit_set(s->tabs, s->cx); 1305698d5317Sjmmv break; 1306698d5317Sjmmv case INPUT_ESC_RI: 1307fe99a117Schristos screen_write_reverseindex(sctx, ictx->cell.cell.bg); 1308698d5317Sjmmv break; 1309698d5317Sjmmv case INPUT_ESC_DECKPAM: 131061fba46bSchristos screen_write_mode_set(sctx, MODE_KKEYPAD); 1311698d5317Sjmmv break; 1312698d5317Sjmmv case INPUT_ESC_DECKPNM: 131361fba46bSchristos screen_write_mode_clear(sctx, MODE_KKEYPAD); 1314698d5317Sjmmv break; 1315698d5317Sjmmv case INPUT_ESC_DECSC: 13160a274e86Schristos input_save_state(ictx); 1317698d5317Sjmmv break; 1318698d5317Sjmmv case INPUT_ESC_DECRC: 13190a274e86Schristos input_restore_state(ictx); 1320698d5317Sjmmv break; 1321698d5317Sjmmv case INPUT_ESC_DECALN: 1322698d5317Sjmmv screen_write_alignmenttest(sctx); 1323698d5317Sjmmv break; 132499e242abSchristos case INPUT_ESC_SCSG0_ON: 132599e242abSchristos ictx->cell.g0set = 1; 1326698d5317Sjmmv break; 132799e242abSchristos case INPUT_ESC_SCSG0_OFF: 132899e242abSchristos ictx->cell.g0set = 0; 132999e242abSchristos break; 133099e242abSchristos case INPUT_ESC_SCSG1_ON: 133199e242abSchristos ictx->cell.g1set = 1; 133299e242abSchristos break; 133399e242abSchristos case INPUT_ESC_SCSG1_OFF: 133499e242abSchristos ictx->cell.g1set = 0; 1335698d5317Sjmmv break; 1336e9a2d6faSchristos case INPUT_ESC_ST: 1337e9a2d6faSchristos /* ST terminates OSC but the state transition already did it. */ 1338e9a2d6faSchristos break; 1339698d5317Sjmmv } 1340698d5317Sjmmv 1341*890b6d91Swiz ictx->flags &= ~INPUT_LAST; 1342698d5317Sjmmv return (0); 1343698d5317Sjmmv } 1344698d5317Sjmmv 1345698d5317Sjmmv /* Execute control sequence. */ 1346e9a2d6faSchristos static int 1347698d5317Sjmmv input_csi_dispatch(struct input_ctx *ictx) 1348698d5317Sjmmv { 1349698d5317Sjmmv struct screen_write_ctx *sctx = &ictx->ctx; 1350698d5317Sjmmv struct screen *s = sctx->s; 1351698d5317Sjmmv struct input_table_entry *entry; 1352*890b6d91Swiz int i, n, m, ek; 1353c7e17de0Schristos u_int cx, bg = ictx->cell.cell.bg; 1354698d5317Sjmmv 1355698d5317Sjmmv if (ictx->flags & INPUT_DISCARD) 1356698d5317Sjmmv return (0); 1357e9a2d6faSchristos 1358f844e94eSwiz log_debug("%s: '%c' \"%s\" \"%s\"", __func__, ictx->ch, 1359f844e94eSwiz ictx->interm_buf, ictx->param_buf); 1360698d5317Sjmmv 1361e9a2d6faSchristos if (input_split(ictx) != 0) 1362e9a2d6faSchristos return (0); 1363e9a2d6faSchristos 1364698d5317Sjmmv entry = bsearch(ictx, input_csi_table, nitems(input_csi_table), 1365698d5317Sjmmv sizeof input_csi_table[0], input_table_compare); 1366698d5317Sjmmv if (entry == NULL) { 1367698d5317Sjmmv log_debug("%s: unknown '%c'", __func__, ictx->ch); 1368698d5317Sjmmv return (0); 1369698d5317Sjmmv } 1370698d5317Sjmmv 1371698d5317Sjmmv switch (entry->type) { 1372698d5317Sjmmv case INPUT_CSI_CBT: 1373698d5317Sjmmv /* Find the previous tab point, n times. */ 137499e242abSchristos cx = s->cx; 137599e242abSchristos if (cx > screen_size_x(s) - 1) 137699e242abSchristos cx = screen_size_x(s) - 1; 1377698d5317Sjmmv n = input_get(ictx, 0, 1, 1); 1378c7e17de0Schristos if (n == -1) 1379c7e17de0Schristos break; 138099e242abSchristos while (cx > 0 && n-- > 0) { 1381698d5317Sjmmv do 138299e242abSchristos cx--; 138399e242abSchristos while (cx > 0 && !bit_test(s->tabs, cx)); 1384698d5317Sjmmv } 138599e242abSchristos s->cx = cx; 1386698d5317Sjmmv break; 1387698d5317Sjmmv case INPUT_CSI_CUB: 1388c7e17de0Schristos n = input_get(ictx, 0, 1, 1); 1389c7e17de0Schristos if (n != -1) 1390c7e17de0Schristos screen_write_cursorleft(sctx, n); 1391698d5317Sjmmv break; 1392698d5317Sjmmv case INPUT_CSI_CUD: 1393c7e17de0Schristos n = input_get(ictx, 0, 1, 1); 1394c7e17de0Schristos if (n != -1) 1395c7e17de0Schristos screen_write_cursordown(sctx, n); 1396698d5317Sjmmv break; 1397698d5317Sjmmv case INPUT_CSI_CUF: 1398c7e17de0Schristos n = input_get(ictx, 0, 1, 1); 1399c7e17de0Schristos if (n != -1) 1400c7e17de0Schristos screen_write_cursorright(sctx, n); 1401698d5317Sjmmv break; 1402698d5317Sjmmv case INPUT_CSI_CUP: 1403698d5317Sjmmv n = input_get(ictx, 0, 1, 1); 1404698d5317Sjmmv m = input_get(ictx, 1, 1, 1); 1405c7e17de0Schristos if (n != -1 && m != -1) 14060a274e86Schristos screen_write_cursormove(sctx, m - 1, n - 1, 1); 1407698d5317Sjmmv break; 1408e271dbb8Schristos case INPUT_CSI_MODSET: 1409e271dbb8Schristos n = input_get(ictx, 0, 0, 0); 1410*890b6d91Swiz if (n != 4) 141159b94b2cSchristos break; 1412*890b6d91Swiz m = input_get(ictx, 1, 0, 0); 1413*890b6d91Swiz 1414*890b6d91Swiz /* 1415*890b6d91Swiz * Set the extended key reporting mode as per the client 1416*890b6d91Swiz * request, unless "extended-keys" is set to "off". 1417*890b6d91Swiz */ 1418*890b6d91Swiz ek = options_get_number(global_options, "extended-keys"); 1419*890b6d91Swiz if (ek == 0) 1420*890b6d91Swiz break; 1421*890b6d91Swiz screen_write_mode_clear(sctx, EXTENDED_KEY_MODES); 1422*890b6d91Swiz if (m == 2) 1423*890b6d91Swiz screen_write_mode_set(sctx, MODE_KEYS_EXTENDED_2); 1424*890b6d91Swiz else if (m == 1 || ek == 2) 1425*890b6d91Swiz screen_write_mode_set(sctx, MODE_KEYS_EXTENDED); 1426e271dbb8Schristos break; 1427e271dbb8Schristos case INPUT_CSI_MODOFF: 1428e271dbb8Schristos n = input_get(ictx, 0, 0, 0); 1429*890b6d91Swiz if (n != 4) 1430*890b6d91Swiz break; 1431*890b6d91Swiz 1432*890b6d91Swiz /* 1433*890b6d91Swiz * Clear the extended key reporting mode as per the client 1434*890b6d91Swiz * request, unless "extended-keys always" forces into mode 1. 1435*890b6d91Swiz */ 1436*890b6d91Swiz screen_write_mode_clear(sctx, 1437*890b6d91Swiz MODE_KEYS_EXTENDED|MODE_KEYS_EXTENDED_2); 1438*890b6d91Swiz if (options_get_number(global_options, "extended-keys") == 2) 1439*890b6d91Swiz screen_write_mode_set(sctx, MODE_KEYS_EXTENDED); 1440e271dbb8Schristos break; 144161fba46bSchristos case INPUT_CSI_WINOPS: 144261fba46bSchristos input_csi_dispatch_winops(ictx); 144361fba46bSchristos break; 1444698d5317Sjmmv case INPUT_CSI_CUU: 1445c7e17de0Schristos n = input_get(ictx, 0, 1, 1); 1446c7e17de0Schristos if (n != -1) 1447c7e17de0Schristos screen_write_cursorup(sctx, n); 1448698d5317Sjmmv break; 144961fba46bSchristos case INPUT_CSI_CNL: 1450c7e17de0Schristos n = input_get(ictx, 0, 1, 1); 1451c7e17de0Schristos if (n != -1) { 145261fba46bSchristos screen_write_carriagereturn(sctx); 1453c7e17de0Schristos screen_write_cursordown(sctx, n); 1454c7e17de0Schristos } 145561fba46bSchristos break; 145661fba46bSchristos case INPUT_CSI_CPL: 1457c7e17de0Schristos n = input_get(ictx, 0, 1, 1); 1458c7e17de0Schristos if (n != -1) { 145961fba46bSchristos screen_write_carriagereturn(sctx); 1460c7e17de0Schristos screen_write_cursorup(sctx, n); 1461c7e17de0Schristos } 146261fba46bSchristos break; 1463698d5317Sjmmv case INPUT_CSI_DA: 1464698d5317Sjmmv switch (input_get(ictx, 0, 0, 0)) { 1465c7e17de0Schristos case -1: 1466c7e17de0Schristos break; 1467698d5317Sjmmv case 0: 1468f844e94eSwiz #ifdef ENABLE_SIXEL 1469f844e94eSwiz input_reply(ictx, "\033[?1;2;4c"); 1470f844e94eSwiz #else 1471698d5317Sjmmv input_reply(ictx, "\033[?1;2c"); 1472f844e94eSwiz #endif 1473698d5317Sjmmv break; 1474698d5317Sjmmv default: 1475698d5317Sjmmv log_debug("%s: unknown '%c'", __func__, ictx->ch); 1476698d5317Sjmmv break; 1477698d5317Sjmmv } 1478698d5317Sjmmv break; 147961fba46bSchristos case INPUT_CSI_DA_TWO: 148061fba46bSchristos switch (input_get(ictx, 0, 0, 0)) { 1481c7e17de0Schristos case -1: 1482c7e17de0Schristos break; 148361fba46bSchristos case 0: 148499e242abSchristos input_reply(ictx, "\033[>84;0;0c"); 148561fba46bSchristos break; 148661fba46bSchristos default: 148761fba46bSchristos log_debug("%s: unknown '%c'", __func__, ictx->ch); 148861fba46bSchristos break; 148961fba46bSchristos } 149061fba46bSchristos break; 149161fba46bSchristos case INPUT_CSI_ECH: 1492c7e17de0Schristos n = input_get(ictx, 0, 1, 1); 1493c7e17de0Schristos if (n != -1) 1494c7e17de0Schristos screen_write_clearcharacter(sctx, n, bg); 149561fba46bSchristos break; 1496698d5317Sjmmv case INPUT_CSI_DCH: 1497c7e17de0Schristos n = input_get(ictx, 0, 1, 1); 1498c7e17de0Schristos if (n != -1) 1499c7e17de0Schristos screen_write_deletecharacter(sctx, n, bg); 1500698d5317Sjmmv break; 1501698d5317Sjmmv case INPUT_CSI_DECSTBM: 1502698d5317Sjmmv n = input_get(ictx, 0, 1, 1); 1503698d5317Sjmmv m = input_get(ictx, 1, 1, screen_size_y(s)); 1504c7e17de0Schristos if (n != -1 && m != -1) 1505698d5317Sjmmv screen_write_scrollregion(sctx, n - 1, m - 1); 1506698d5317Sjmmv break; 1507698d5317Sjmmv case INPUT_CSI_DL: 1508c7e17de0Schristos n = input_get(ictx, 0, 1, 1); 1509c7e17de0Schristos if (n != -1) 1510c7e17de0Schristos screen_write_deleteline(sctx, n, bg); 1511698d5317Sjmmv break; 1512698d5317Sjmmv case INPUT_CSI_DSR: 1513698d5317Sjmmv switch (input_get(ictx, 0, 0, 0)) { 1514c7e17de0Schristos case -1: 1515c7e17de0Schristos break; 1516698d5317Sjmmv case 5: 1517698d5317Sjmmv input_reply(ictx, "\033[0n"); 1518698d5317Sjmmv break; 1519698d5317Sjmmv case 6: 1520698d5317Sjmmv input_reply(ictx, "\033[%u;%uR", s->cy + 1, s->cx + 1); 1521698d5317Sjmmv break; 1522698d5317Sjmmv default: 1523698d5317Sjmmv log_debug("%s: unknown '%c'", __func__, ictx->ch); 1524698d5317Sjmmv break; 1525698d5317Sjmmv } 1526698d5317Sjmmv break; 1527698d5317Sjmmv case INPUT_CSI_ED: 1528698d5317Sjmmv switch (input_get(ictx, 0, 0, 0)) { 1529c7e17de0Schristos case -1: 1530c7e17de0Schristos break; 1531698d5317Sjmmv case 0: 1532c7e17de0Schristos screen_write_clearendofscreen(sctx, bg); 1533698d5317Sjmmv break; 1534698d5317Sjmmv case 1: 1535c7e17de0Schristos screen_write_clearstartofscreen(sctx, bg); 1536698d5317Sjmmv break; 1537698d5317Sjmmv case 2: 1538c7e17de0Schristos screen_write_clearscreen(sctx, bg); 1539698d5317Sjmmv break; 154061fba46bSchristos case 3: 1541c7e17de0Schristos if (input_get(ictx, 1, 0, 0) == 0) { 154261fba46bSchristos /* 154361fba46bSchristos * Linux console extension to clear history 154461fba46bSchristos * (for example before locking the screen). 154561fba46bSchristos */ 154661fba46bSchristos screen_write_clearhistory(sctx); 154761fba46bSchristos } 154861fba46bSchristos break; 1549698d5317Sjmmv default: 1550698d5317Sjmmv log_debug("%s: unknown '%c'", __func__, ictx->ch); 1551698d5317Sjmmv break; 1552698d5317Sjmmv } 1553698d5317Sjmmv break; 1554698d5317Sjmmv case INPUT_CSI_EL: 1555698d5317Sjmmv switch (input_get(ictx, 0, 0, 0)) { 1556c7e17de0Schristos case -1: 1557c7e17de0Schristos break; 1558698d5317Sjmmv case 0: 1559c7e17de0Schristos screen_write_clearendofline(sctx, bg); 1560698d5317Sjmmv break; 1561698d5317Sjmmv case 1: 1562c7e17de0Schristos screen_write_clearstartofline(sctx, bg); 1563698d5317Sjmmv break; 1564698d5317Sjmmv case 2: 1565c7e17de0Schristos screen_write_clearline(sctx, bg); 1566698d5317Sjmmv break; 1567698d5317Sjmmv default: 1568698d5317Sjmmv log_debug("%s: unknown '%c'", __func__, ictx->ch); 1569698d5317Sjmmv break; 1570698d5317Sjmmv } 1571698d5317Sjmmv break; 1572698d5317Sjmmv case INPUT_CSI_HPA: 1573698d5317Sjmmv n = input_get(ictx, 0, 1, 1); 1574c7e17de0Schristos if (n != -1) 15750a274e86Schristos screen_write_cursormove(sctx, n - 1, -1, 1); 1576698d5317Sjmmv break; 1577698d5317Sjmmv case INPUT_CSI_ICH: 1578c7e17de0Schristos n = input_get(ictx, 0, 1, 1); 1579c7e17de0Schristos if (n != -1) 1580c7e17de0Schristos screen_write_insertcharacter(sctx, n, bg); 1581698d5317Sjmmv break; 1582698d5317Sjmmv case INPUT_CSI_IL: 1583c7e17de0Schristos n = input_get(ictx, 0, 1, 1); 1584c7e17de0Schristos if (n != -1) 1585c7e17de0Schristos screen_write_insertline(sctx, n, bg); 1586698d5317Sjmmv break; 1587fe99a117Schristos case INPUT_CSI_REP: 1588c7e17de0Schristos n = input_get(ictx, 0, 1, 1); 1589c7e17de0Schristos if (n == -1) 1590c7e17de0Schristos break; 1591c7e17de0Schristos 1592e271dbb8Schristos m = screen_size_x(s) - s->cx; 1593e271dbb8Schristos if (n > m) 1594e271dbb8Schristos n = m; 1595e271dbb8Schristos 1596*890b6d91Swiz if (~ictx->flags & INPUT_LAST) 1597fe99a117Schristos break; 1598fe99a117Schristos 1599*890b6d91Swiz utf8_copy(&ictx->cell.cell.data, &ictx->last); 1600fe99a117Schristos for (i = 0; i < n; i++) 1601*890b6d91Swiz screen_write_collect_add(sctx, &ictx->cell.cell); 1602fe99a117Schristos break; 160361fba46bSchristos case INPUT_CSI_RCP: 16040a274e86Schristos input_restore_state(ictx); 160561fba46bSchristos break; 1606698d5317Sjmmv case INPUT_CSI_RM: 160761fba46bSchristos input_csi_dispatch_rm(ictx); 1608698d5317Sjmmv break; 1609698d5317Sjmmv case INPUT_CSI_RM_PRIVATE: 161061fba46bSchristos input_csi_dispatch_rm_private(ictx); 1611698d5317Sjmmv break; 161261fba46bSchristos case INPUT_CSI_SCP: 16130a274e86Schristos input_save_state(ictx); 1614698d5317Sjmmv break; 1615698d5317Sjmmv case INPUT_CSI_SGR: 1616698d5317Sjmmv input_csi_dispatch_sgr(ictx); 1617698d5317Sjmmv break; 1618698d5317Sjmmv case INPUT_CSI_SM: 161961fba46bSchristos input_csi_dispatch_sm(ictx); 1620698d5317Sjmmv break; 1621698d5317Sjmmv case INPUT_CSI_SM_PRIVATE: 162261fba46bSchristos input_csi_dispatch_sm_private(ictx); 1623698d5317Sjmmv break; 1624f844e94eSwiz case INPUT_CSI_SM_GRAPHICS: 1625f844e94eSwiz input_csi_dispatch_sm_graphics(ictx); 1626f844e94eSwiz break; 1627e9a2d6faSchristos case INPUT_CSI_SU: 1628c7e17de0Schristos n = input_get(ictx, 0, 1, 1); 1629c7e17de0Schristos if (n != -1) 1630c7e17de0Schristos screen_write_scrollup(sctx, n, bg); 1631e9a2d6faSchristos break; 163230744affSchristos case INPUT_CSI_SD: 163330744affSchristos n = input_get(ictx, 0, 1, 1); 163430744affSchristos if (n != -1) 163530744affSchristos screen_write_scrolldown(sctx, n, bg); 163630744affSchristos break; 1637698d5317Sjmmv case INPUT_CSI_TBC: 1638698d5317Sjmmv switch (input_get(ictx, 0, 0, 0)) { 1639c7e17de0Schristos case -1: 1640c7e17de0Schristos break; 1641698d5317Sjmmv case 0: 1642698d5317Sjmmv if (s->cx < screen_size_x(s)) 1643698d5317Sjmmv bit_clear(s->tabs, s->cx); 1644698d5317Sjmmv break; 1645698d5317Sjmmv case 3: 1646698d5317Sjmmv bit_nclear(s->tabs, 0, screen_size_x(s) - 1); 1647698d5317Sjmmv break; 1648698d5317Sjmmv default: 1649698d5317Sjmmv log_debug("%s: unknown '%c'", __func__, ictx->ch); 1650698d5317Sjmmv break; 1651698d5317Sjmmv } 1652698d5317Sjmmv break; 1653698d5317Sjmmv case INPUT_CSI_VPA: 1654698d5317Sjmmv n = input_get(ictx, 0, 1, 1); 1655c7e17de0Schristos if (n != -1) 16560a274e86Schristos screen_write_cursormove(sctx, -1, n - 1, 1); 1657698d5317Sjmmv break; 16580f3d2746Sjmmv case INPUT_CSI_DECSCUSR: 16590f3d2746Sjmmv n = input_get(ictx, 0, 0, 0); 1660c7e17de0Schristos if (n != -1) 166146548964Swiz screen_set_cursor_style(n, &s->cstyle, &s->mode); 16620f3d2746Sjmmv break; 1663e271dbb8Schristos case INPUT_CSI_XDA: 1664e271dbb8Schristos n = input_get(ictx, 0, 0, 0); 1665e271dbb8Schristos if (n == 0) 1666e271dbb8Schristos input_reply(ictx, "\033P>|tmux %s\033\\", getversion()); 1667e271dbb8Schristos break; 1668e271dbb8Schristos 1669698d5317Sjmmv } 1670698d5317Sjmmv 1671*890b6d91Swiz ictx->flags &= ~INPUT_LAST; 1672698d5317Sjmmv return (0); 1673698d5317Sjmmv } 1674698d5317Sjmmv 167561fba46bSchristos /* Handle CSI RM. */ 1676e9a2d6faSchristos static void 167761fba46bSchristos input_csi_dispatch_rm(struct input_ctx *ictx) 167861fba46bSchristos { 16790a274e86Schristos struct screen_write_ctx *sctx = &ictx->ctx; 168061fba46bSchristos u_int i; 168161fba46bSchristos 168261fba46bSchristos for (i = 0; i < ictx->param_list_len; i++) { 168361fba46bSchristos switch (input_get(ictx, i, 0, -1)) { 1684c7e17de0Schristos case -1: 1685c7e17de0Schristos break; 168661fba46bSchristos case 4: /* IRM */ 16870a274e86Schristos screen_write_mode_clear(sctx, MODE_INSERT); 168861fba46bSchristos break; 168999e242abSchristos case 34: 169046548964Swiz screen_write_mode_set(sctx, MODE_CURSOR_VERY_VISIBLE); 169199e242abSchristos break; 169261fba46bSchristos default: 169361fba46bSchristos log_debug("%s: unknown '%c'", __func__, ictx->ch); 169461fba46bSchristos break; 169561fba46bSchristos } 169661fba46bSchristos } 169761fba46bSchristos } 169861fba46bSchristos 169961fba46bSchristos /* Handle CSI private RM. */ 1700e9a2d6faSchristos static void 170161fba46bSchristos input_csi_dispatch_rm_private(struct input_ctx *ictx) 170261fba46bSchristos { 17030a274e86Schristos struct screen_write_ctx *sctx = &ictx->ctx; 1704e271dbb8Schristos struct grid_cell *gc = &ictx->cell.cell; 170561fba46bSchristos u_int i; 170661fba46bSchristos 170761fba46bSchristos for (i = 0; i < ictx->param_list_len; i++) { 170861fba46bSchristos switch (input_get(ictx, i, 0, -1)) { 1709c7e17de0Schristos case -1: 1710c7e17de0Schristos break; 171161fba46bSchristos case 1: /* DECCKM */ 17120a274e86Schristos screen_write_mode_clear(sctx, MODE_KCURSOR); 171361fba46bSchristos break; 171461fba46bSchristos case 3: /* DECCOLM */ 17150a274e86Schristos screen_write_cursormove(sctx, 0, 0, 1); 1716e271dbb8Schristos screen_write_clearscreen(sctx, gc->bg); 17170a274e86Schristos break; 17180a274e86Schristos case 6: /* DECOM */ 17190a274e86Schristos screen_write_mode_clear(sctx, MODE_ORIGIN); 17200a274e86Schristos screen_write_cursormove(sctx, 0, 0, 1); 172161fba46bSchristos break; 172261fba46bSchristos case 7: /* DECAWM */ 17230a274e86Schristos screen_write_mode_clear(sctx, MODE_WRAP); 172461fba46bSchristos break; 172599e242abSchristos case 12: 172646548964Swiz screen_write_mode_clear(sctx, MODE_CURSOR_BLINKING); 172746548964Swiz screen_write_mode_set(sctx, MODE_CURSOR_BLINKING_SET); 172899e242abSchristos break; 172961fba46bSchristos case 25: /* TCEM */ 17300a274e86Schristos screen_write_mode_clear(sctx, MODE_CURSOR); 173161fba46bSchristos break; 173261fba46bSchristos case 1000: 173361fba46bSchristos case 1001: 173461fba46bSchristos case 1002: 1735e9a2d6faSchristos case 1003: 17360a274e86Schristos screen_write_mode_clear(sctx, ALL_MOUSE_MODES); 173761fba46bSchristos break; 173861fba46bSchristos case 1004: 17390a274e86Schristos screen_write_mode_clear(sctx, MODE_FOCUSON); 174061fba46bSchristos break; 174161fba46bSchristos case 1005: 17420a274e86Schristos screen_write_mode_clear(sctx, MODE_MOUSE_UTF8); 174361fba46bSchristos break; 174461fba46bSchristos case 1006: 17450a274e86Schristos screen_write_mode_clear(sctx, MODE_MOUSE_SGR); 174661fba46bSchristos break; 174761fba46bSchristos case 47: 174861fba46bSchristos case 1047: 1749e271dbb8Schristos screen_write_alternateoff(sctx, gc, 0); 175061fba46bSchristos break; 175161fba46bSchristos case 1049: 1752e271dbb8Schristos screen_write_alternateoff(sctx, gc, 1); 175361fba46bSchristos break; 175461fba46bSchristos case 2004: 17550a274e86Schristos screen_write_mode_clear(sctx, MODE_BRACKETPASTE); 175661fba46bSchristos break; 175761fba46bSchristos default: 175861fba46bSchristos log_debug("%s: unknown '%c'", __func__, ictx->ch); 175961fba46bSchristos break; 176061fba46bSchristos } 176161fba46bSchristos } 176261fba46bSchristos } 176361fba46bSchristos 176461fba46bSchristos /* Handle CSI SM. */ 1765e9a2d6faSchristos static void 176661fba46bSchristos input_csi_dispatch_sm(struct input_ctx *ictx) 176761fba46bSchristos { 17680a274e86Schristos struct screen_write_ctx *sctx = &ictx->ctx; 176961fba46bSchristos u_int i; 177061fba46bSchristos 177161fba46bSchristos for (i = 0; i < ictx->param_list_len; i++) { 177261fba46bSchristos switch (input_get(ictx, i, 0, -1)) { 1773c7e17de0Schristos case -1: 1774c7e17de0Schristos break; 177561fba46bSchristos case 4: /* IRM */ 17760a274e86Schristos screen_write_mode_set(sctx, MODE_INSERT); 177761fba46bSchristos break; 177899e242abSchristos case 34: 177946548964Swiz screen_write_mode_clear(sctx, MODE_CURSOR_VERY_VISIBLE); 178099e242abSchristos break; 178161fba46bSchristos default: 178261fba46bSchristos log_debug("%s: unknown '%c'", __func__, ictx->ch); 178361fba46bSchristos break; 178461fba46bSchristos } 178561fba46bSchristos } 178661fba46bSchristos } 178761fba46bSchristos 178861fba46bSchristos /* Handle CSI private SM. */ 1789e9a2d6faSchristos static void 179061fba46bSchristos input_csi_dispatch_sm_private(struct input_ctx *ictx) 179161fba46bSchristos { 17920a274e86Schristos struct screen_write_ctx *sctx = &ictx->ctx; 1793e271dbb8Schristos struct grid_cell *gc = &ictx->cell.cell; 179461fba46bSchristos u_int i; 179561fba46bSchristos 179661fba46bSchristos for (i = 0; i < ictx->param_list_len; i++) { 179761fba46bSchristos switch (input_get(ictx, i, 0, -1)) { 1798c7e17de0Schristos case -1: 1799c7e17de0Schristos break; 180061fba46bSchristos case 1: /* DECCKM */ 18010a274e86Schristos screen_write_mode_set(sctx, MODE_KCURSOR); 180261fba46bSchristos break; 180361fba46bSchristos case 3: /* DECCOLM */ 18040a274e86Schristos screen_write_cursormove(sctx, 0, 0, 1); 18050a274e86Schristos screen_write_clearscreen(sctx, ictx->cell.cell.bg); 18060a274e86Schristos break; 18070a274e86Schristos case 6: /* DECOM */ 18080a274e86Schristos screen_write_mode_set(sctx, MODE_ORIGIN); 18090a274e86Schristos screen_write_cursormove(sctx, 0, 0, 1); 181061fba46bSchristos break; 181161fba46bSchristos case 7: /* DECAWM */ 18120a274e86Schristos screen_write_mode_set(sctx, MODE_WRAP); 181361fba46bSchristos break; 181499e242abSchristos case 12: 181546548964Swiz screen_write_mode_set(sctx, MODE_CURSOR_BLINKING); 181646548964Swiz screen_write_mode_set(sctx, MODE_CURSOR_BLINKING_SET); 181799e242abSchristos break; 181861fba46bSchristos case 25: /* TCEM */ 18190a274e86Schristos screen_write_mode_set(sctx, MODE_CURSOR); 182061fba46bSchristos break; 182161fba46bSchristos case 1000: 18220a274e86Schristos screen_write_mode_clear(sctx, ALL_MOUSE_MODES); 18230a274e86Schristos screen_write_mode_set(sctx, MODE_MOUSE_STANDARD); 182461fba46bSchristos break; 182561fba46bSchristos case 1002: 18260a274e86Schristos screen_write_mode_clear(sctx, ALL_MOUSE_MODES); 18270a274e86Schristos screen_write_mode_set(sctx, MODE_MOUSE_BUTTON); 182861fba46bSchristos break; 1829e9a2d6faSchristos case 1003: 18300a274e86Schristos screen_write_mode_clear(sctx, ALL_MOUSE_MODES); 18310a274e86Schristos screen_write_mode_set(sctx, MODE_MOUSE_ALL); 1832e9a2d6faSchristos break; 183361fba46bSchristos case 1004: 18340a274e86Schristos screen_write_mode_set(sctx, MODE_FOCUSON); 183561fba46bSchristos break; 183661fba46bSchristos case 1005: 18370a274e86Schristos screen_write_mode_set(sctx, MODE_MOUSE_UTF8); 183861fba46bSchristos break; 183961fba46bSchristos case 1006: 18400a274e86Schristos screen_write_mode_set(sctx, MODE_MOUSE_SGR); 184161fba46bSchristos break; 184261fba46bSchristos case 47: 184361fba46bSchristos case 1047: 1844e271dbb8Schristos screen_write_alternateon(sctx, gc, 0); 184561fba46bSchristos break; 184661fba46bSchristos case 1049: 1847e271dbb8Schristos screen_write_alternateon(sctx, gc, 1); 184861fba46bSchristos break; 184961fba46bSchristos case 2004: 18500a274e86Schristos screen_write_mode_set(sctx, MODE_BRACKETPASTE); 185161fba46bSchristos break; 185261fba46bSchristos default: 185361fba46bSchristos log_debug("%s: unknown '%c'", __func__, ictx->ch); 185461fba46bSchristos break; 185561fba46bSchristos } 185661fba46bSchristos } 185761fba46bSchristos } 185861fba46bSchristos 1859f844e94eSwiz /* Handle CSI graphics SM. */ 1860f844e94eSwiz static void 1861*890b6d91Swiz input_csi_dispatch_sm_graphics(__unused struct input_ctx *ictx) 1862f844e94eSwiz { 1863f844e94eSwiz #ifdef ENABLE_SIXEL 1864f844e94eSwiz int n, m, o; 1865f844e94eSwiz 1866f844e94eSwiz if (ictx->param_list_len > 3) 1867f844e94eSwiz return; 1868f844e94eSwiz n = input_get(ictx, 0, 0, 0); 1869f844e94eSwiz m = input_get(ictx, 1, 0, 0); 1870f844e94eSwiz o = input_get(ictx, 2, 0, 0); 1871f844e94eSwiz 1872f844e94eSwiz if (n == 1 && (m == 1 || m == 2 || m == 4)) 1873f844e94eSwiz input_reply(ictx, "\033[?%d;0;%uS", n, SIXEL_COLOUR_REGISTERS); 1874f844e94eSwiz else 1875f844e94eSwiz input_reply(ictx, "\033[?%d;3;%dS", n, o); 1876f844e94eSwiz #endif 1877f844e94eSwiz } 1878f844e94eSwiz 187961fba46bSchristos /* Handle CSI window operations. */ 1880e9a2d6faSchristos static void 188161fba46bSchristos input_csi_dispatch_winops(struct input_ctx *ictx) 188261fba46bSchristos { 18830a274e86Schristos struct screen_write_ctx *sctx = &ictx->ctx; 1884e271dbb8Schristos struct screen *s = sctx->s; 188561fba46bSchristos struct window_pane *wp = ictx->wp; 1886f844e94eSwiz struct window *w = NULL; 1887e271dbb8Schristos u_int x = screen_size_x(s), y = screen_size_y(s); 188861fba46bSchristos int n, m; 188961fba46bSchristos 1890f844e94eSwiz if (wp != NULL) 1891f844e94eSwiz w = wp->window; 1892f844e94eSwiz 189361fba46bSchristos m = 0; 189461fba46bSchristos while ((n = input_get(ictx, m, 0, -1)) != -1) { 189561fba46bSchristos switch (n) { 189661fba46bSchristos case 1: 189761fba46bSchristos case 2: 189861fba46bSchristos case 5: 189961fba46bSchristos case 6: 190061fba46bSchristos case 7: 190161fba46bSchristos case 11: 190261fba46bSchristos case 13: 190361fba46bSchristos case 20: 190461fba46bSchristos case 21: 190561fba46bSchristos case 24: 190661fba46bSchristos break; 190761fba46bSchristos case 3: 190861fba46bSchristos case 4: 190961fba46bSchristos case 8: 191061fba46bSchristos m++; 191161fba46bSchristos if (input_get(ictx, m, 0, -1) == -1) 191261fba46bSchristos return; 191361fba46bSchristos /* FALLTHROUGH */ 191461fba46bSchristos case 9: 191561fba46bSchristos case 10: 191661fba46bSchristos m++; 191761fba46bSchristos if (input_get(ictx, m, 0, -1) == -1) 191861fba46bSchristos return; 191961fba46bSchristos break; 1920f844e94eSwiz case 14: 1921f844e94eSwiz if (w == NULL) 1922f844e94eSwiz break; 1923f844e94eSwiz input_reply(ictx, "\033[4;%u;%ut", y * w->ypixel, 1924f844e94eSwiz x * w->xpixel); 1925f844e94eSwiz break; 1926f844e94eSwiz case 15: 1927f844e94eSwiz if (w == NULL) 1928f844e94eSwiz break; 1929f844e94eSwiz input_reply(ictx, "\033[5;%u;%ut", y * w->ypixel, 1930f844e94eSwiz x * w->xpixel); 1931f844e94eSwiz break; 1932f844e94eSwiz case 16: 1933f844e94eSwiz if (w == NULL) 1934f844e94eSwiz break; 1935f844e94eSwiz input_reply(ictx, "\033[6;%u;%ut", w->ypixel, 1936f844e94eSwiz w->xpixel); 1937f844e94eSwiz break; 1938f844e94eSwiz case 18: 1939f844e94eSwiz input_reply(ictx, "\033[8;%u;%ut", y, x); 1940f844e94eSwiz break; 1941f844e94eSwiz case 19: 1942f844e94eSwiz input_reply(ictx, "\033[9;%u;%ut", y, x); 1943f844e94eSwiz break; 1944c7e17de0Schristos case 22: 1945c7e17de0Schristos m++; 1946c7e17de0Schristos switch (input_get(ictx, m, 0, -1)) { 1947c7e17de0Schristos case -1: 1948c7e17de0Schristos return; 1949c7e17de0Schristos case 0: 1950c7e17de0Schristos case 2: 19510a274e86Schristos screen_push_title(sctx->s); 1952c7e17de0Schristos break; 1953c7e17de0Schristos } 1954c7e17de0Schristos break; 1955c7e17de0Schristos case 23: 1956c7e17de0Schristos m++; 1957c7e17de0Schristos switch (input_get(ictx, m, 0, -1)) { 1958c7e17de0Schristos case -1: 1959c7e17de0Schristos return; 1960c7e17de0Schristos case 0: 1961c7e17de0Schristos case 2: 19620a274e86Schristos screen_pop_title(sctx->s); 196346548964Swiz if (wp == NULL) 196446548964Swiz break; 1965e271dbb8Schristos notify_pane("pane-title-changed", wp); 1966f844e94eSwiz server_redraw_window_borders(w); 1967f844e94eSwiz server_status_window(w); 1968c7e17de0Schristos break; 1969c7e17de0Schristos } 1970c7e17de0Schristos break; 197161fba46bSchristos default: 197261fba46bSchristos log_debug("%s: unknown '%c'", __func__, ictx->ch); 197361fba46bSchristos break; 197461fba46bSchristos } 197561fba46bSchristos m++; 197661fba46bSchristos } 197761fba46bSchristos } 197861fba46bSchristos 1979c7e17de0Schristos /* Helper for 256 colour SGR. */ 1980c7e17de0Schristos static int 1981c7e17de0Schristos input_csi_dispatch_sgr_256_do(struct input_ctx *ictx, int fgbg, int c) 198299e242abSchristos { 198399e242abSchristos struct grid_cell *gc = &ictx->cell.cell; 198499e242abSchristos 1985c7e17de0Schristos if (c == -1 || c > 255) { 1986e9a2d6faSchristos if (fgbg == 38) 198799e242abSchristos gc->fg = 8; 1988e9a2d6faSchristos else if (fgbg == 48) 198999e242abSchristos gc->bg = 8; 199099e242abSchristos } else { 1991e9a2d6faSchristos if (fgbg == 38) 1992e9a2d6faSchristos gc->fg = c | COLOUR_FLAG_256; 1993e9a2d6faSchristos else if (fgbg == 48) 1994e9a2d6faSchristos gc->bg = c | COLOUR_FLAG_256; 199530744affSchristos else if (fgbg == 58) 199630744affSchristos gc->us = c | COLOUR_FLAG_256; 199799e242abSchristos } 1998c7e17de0Schristos return (1); 1999c7e17de0Schristos } 2000c7e17de0Schristos 2001c7e17de0Schristos /* Handle CSI SGR for 256 colours. */ 2002c7e17de0Schristos static void 2003c7e17de0Schristos input_csi_dispatch_sgr_256(struct input_ctx *ictx, int fgbg, u_int *i) 2004c7e17de0Schristos { 2005c7e17de0Schristos int c; 2006c7e17de0Schristos 2007c7e17de0Schristos c = input_get(ictx, (*i) + 1, 0, -1); 2008c7e17de0Schristos if (input_csi_dispatch_sgr_256_do(ictx, fgbg, c)) 2009c7e17de0Schristos (*i)++; 2010c7e17de0Schristos } 2011c7e17de0Schristos 2012c7e17de0Schristos /* Helper for RGB colour SGR. */ 2013c7e17de0Schristos static int 2014c7e17de0Schristos input_csi_dispatch_sgr_rgb_do(struct input_ctx *ictx, int fgbg, int r, int g, 2015c7e17de0Schristos int b) 2016c7e17de0Schristos { 2017c7e17de0Schristos struct grid_cell *gc = &ictx->cell.cell; 2018c7e17de0Schristos 2019c7e17de0Schristos if (r == -1 || r > 255) 2020c7e17de0Schristos return (0); 2021c7e17de0Schristos if (g == -1 || g > 255) 2022c7e17de0Schristos return (0); 2023c7e17de0Schristos if (b == -1 || b > 255) 2024c7e17de0Schristos return (0); 2025c7e17de0Schristos 2026c7e17de0Schristos if (fgbg == 38) 2027c7e17de0Schristos gc->fg = colour_join_rgb(r, g, b); 2028c7e17de0Schristos else if (fgbg == 48) 2029c7e17de0Schristos gc->bg = colour_join_rgb(r, g, b); 203030744affSchristos else if (fgbg == 58) 203130744affSchristos gc->us = colour_join_rgb(r, g, b); 2032c7e17de0Schristos return (1); 203399e242abSchristos } 203499e242abSchristos 203599e242abSchristos /* Handle CSI SGR for RGB colours. */ 2036e9a2d6faSchristos static void 203799e242abSchristos input_csi_dispatch_sgr_rgb(struct input_ctx *ictx, int fgbg, u_int *i) 203899e242abSchristos { 2039f26e8bc9Schristos int r, g, b; 204099e242abSchristos 2041c7e17de0Schristos r = input_get(ictx, (*i) + 1, 0, -1); 2042c7e17de0Schristos g = input_get(ictx, (*i) + 2, 0, -1); 2043c7e17de0Schristos b = input_get(ictx, (*i) + 3, 0, -1); 2044c7e17de0Schristos if (input_csi_dispatch_sgr_rgb_do(ictx, fgbg, r, g, b)) 2045c7e17de0Schristos (*i) += 3; 2046c7e17de0Schristos } 204799e242abSchristos 2048c7e17de0Schristos /* Handle CSI SGR with a ISO parameter. */ 2049c7e17de0Schristos static void 2050c7e17de0Schristos input_csi_dispatch_sgr_colon(struct input_ctx *ictx, u_int i) 2051c7e17de0Schristos { 20520a274e86Schristos struct grid_cell *gc = &ictx->cell.cell; 2053c7e17de0Schristos char *s = ictx->param_list[i].str, *copy, *ptr, *out; 2054c7e17de0Schristos int p[8]; 2055c7e17de0Schristos u_int n; 2056c7e17de0Schristos const char *errstr; 2057c7e17de0Schristos 2058c7e17de0Schristos for (n = 0; n < nitems(p); n++) 2059c7e17de0Schristos p[n] = -1; 2060c7e17de0Schristos n = 0; 2061c7e17de0Schristos 2062c7e17de0Schristos ptr = copy = xstrdup(s); 2063c7e17de0Schristos while ((out = strsep(&ptr, ":")) != NULL) { 2064c7e17de0Schristos if (*out != '\0') { 2065c7e17de0Schristos p[n++] = strtonum(out, 0, INT_MAX, &errstr); 2066c7e17de0Schristos if (errstr != NULL || n == nitems(p)) { 2067c7e17de0Schristos free(copy); 2068c7e17de0Schristos return; 2069c7e17de0Schristos } 207068e6ba84Schristos } else { 20710a274e86Schristos n++; 207268e6ba84Schristos if (n == nitems(p)) { 207368e6ba84Schristos free(copy); 207468e6ba84Schristos return; 207568e6ba84Schristos } 207668e6ba84Schristos } 2077c7e17de0Schristos log_debug("%s: %u = %d", __func__, n - 1, p[n - 1]); 2078c7e17de0Schristos } 2079c7e17de0Schristos free(copy); 2080c7e17de0Schristos 20810a274e86Schristos if (n == 0) 20820a274e86Schristos return; 20830a274e86Schristos if (p[0] == 4) { 20840a274e86Schristos if (n != 2) 20850a274e86Schristos return; 20860a274e86Schristos switch (p[1]) { 20870a274e86Schristos case 0: 20880a274e86Schristos gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE; 20890a274e86Schristos break; 20900a274e86Schristos case 1: 20910a274e86Schristos gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE; 20920a274e86Schristos gc->attr |= GRID_ATTR_UNDERSCORE; 20930a274e86Schristos break; 20940a274e86Schristos case 2: 20950a274e86Schristos gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE; 20960a274e86Schristos gc->attr |= GRID_ATTR_UNDERSCORE_2; 20970a274e86Schristos break; 20980a274e86Schristos case 3: 20990a274e86Schristos gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE; 21000a274e86Schristos gc->attr |= GRID_ATTR_UNDERSCORE_3; 21010a274e86Schristos break; 21020a274e86Schristos case 4: 21030a274e86Schristos gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE; 21040a274e86Schristos gc->attr |= GRID_ATTR_UNDERSCORE_4; 21050a274e86Schristos break; 21060a274e86Schristos case 5: 21070a274e86Schristos gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE; 21080a274e86Schristos gc->attr |= GRID_ATTR_UNDERSCORE_5; 21090a274e86Schristos break; 21100a274e86Schristos } 21110a274e86Schristos return; 21120a274e86Schristos } 211330744affSchristos if (n < 2 || (p[0] != 38 && p[0] != 48 && p[0] != 58)) 2114c7e17de0Schristos return; 211530744affSchristos switch (p[1]) { 211630744affSchristos case 2: 211730744affSchristos if (n < 3) 211830744affSchristos break; 211930744affSchristos if (n == 5) 2120c7e17de0Schristos i = 2; 2121c7e17de0Schristos else 212230744affSchristos i = 3; 212330744affSchristos if (n < i + 3) 2124c7e17de0Schristos break; 212530744affSchristos input_csi_dispatch_sgr_rgb_do(ictx, p[0], p[i], p[i + 1], 212630744affSchristos p[i + 2]); 2127c7e17de0Schristos break; 2128c7e17de0Schristos case 5: 212930744affSchristos if (n < 3) 2130c7e17de0Schristos break; 213130744affSchristos input_csi_dispatch_sgr_256_do(ictx, p[0], p[2]); 2132c7e17de0Schristos break; 2133c7e17de0Schristos } 213499e242abSchristos } 213599e242abSchristos 2136698d5317Sjmmv /* Handle CSI SGR. */ 2137e9a2d6faSchristos static void 2138698d5317Sjmmv input_csi_dispatch_sgr(struct input_ctx *ictx) 2139698d5317Sjmmv { 214099e242abSchristos struct grid_cell *gc = &ictx->cell.cell; 2141f844e94eSwiz u_int i, link; 214299e242abSchristos int n; 2143698d5317Sjmmv 2144698d5317Sjmmv if (ictx->param_list_len == 0) { 2145698d5317Sjmmv memcpy(gc, &grid_default_cell, sizeof *gc); 2146698d5317Sjmmv return; 2147698d5317Sjmmv } 2148698d5317Sjmmv 2149698d5317Sjmmv for (i = 0; i < ictx->param_list_len; i++) { 2150c7e17de0Schristos if (ictx->param_list[i].type == INPUT_STRING) { 2151c7e17de0Schristos input_csi_dispatch_sgr_colon(ictx, i); 2152c7e17de0Schristos continue; 2153c7e17de0Schristos } 2154698d5317Sjmmv n = input_get(ictx, i, 0, 0); 2155c7e17de0Schristos if (n == -1) 2156c7e17de0Schristos continue; 2157698d5317Sjmmv 215830744affSchristos if (n == 38 || n == 48 || n == 58) { 2159698d5317Sjmmv i++; 216099e242abSchristos switch (input_get(ictx, i, 0, -1)) { 216199e242abSchristos case 2: 216299e242abSchristos input_csi_dispatch_sgr_rgb(ictx, n, &i); 216399e242abSchristos break; 216499e242abSchristos case 5: 216599e242abSchristos input_csi_dispatch_sgr_256(ictx, n, &i); 216699e242abSchristos break; 2167698d5317Sjmmv } 2168698d5317Sjmmv continue; 2169698d5317Sjmmv } 2170698d5317Sjmmv 2171698d5317Sjmmv switch (n) { 2172698d5317Sjmmv case 0: 2173f844e94eSwiz link = gc->link; 2174698d5317Sjmmv memcpy(gc, &grid_default_cell, sizeof *gc); 2175f844e94eSwiz gc->link = link; 2176698d5317Sjmmv break; 2177698d5317Sjmmv case 1: 2178698d5317Sjmmv gc->attr |= GRID_ATTR_BRIGHT; 2179698d5317Sjmmv break; 2180698d5317Sjmmv case 2: 2181698d5317Sjmmv gc->attr |= GRID_ATTR_DIM; 2182698d5317Sjmmv break; 2183698d5317Sjmmv case 3: 2184698d5317Sjmmv gc->attr |= GRID_ATTR_ITALICS; 2185698d5317Sjmmv break; 2186698d5317Sjmmv case 4: 21870a274e86Schristos gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE; 2188698d5317Sjmmv gc->attr |= GRID_ATTR_UNDERSCORE; 2189698d5317Sjmmv break; 2190698d5317Sjmmv case 5: 2191e271dbb8Schristos case 6: 2192698d5317Sjmmv gc->attr |= GRID_ATTR_BLINK; 2193698d5317Sjmmv break; 2194698d5317Sjmmv case 7: 2195698d5317Sjmmv gc->attr |= GRID_ATTR_REVERSE; 2196698d5317Sjmmv break; 2197698d5317Sjmmv case 8: 2198698d5317Sjmmv gc->attr |= GRID_ATTR_HIDDEN; 2199698d5317Sjmmv break; 2200e9a2d6faSchristos case 9: 2201e9a2d6faSchristos gc->attr |= GRID_ATTR_STRIKETHROUGH; 2202e9a2d6faSchristos break; 2203e271dbb8Schristos case 21: 2204e271dbb8Schristos gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE; 2205e271dbb8Schristos gc->attr |= GRID_ATTR_UNDERSCORE_2; 2206e271dbb8Schristos break; 2207698d5317Sjmmv case 22: 2208698d5317Sjmmv gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM); 2209698d5317Sjmmv break; 2210698d5317Sjmmv case 23: 2211698d5317Sjmmv gc->attr &= ~GRID_ATTR_ITALICS; 2212698d5317Sjmmv break; 2213698d5317Sjmmv case 24: 22140a274e86Schristos gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE; 2215698d5317Sjmmv break; 2216698d5317Sjmmv case 25: 2217698d5317Sjmmv gc->attr &= ~GRID_ATTR_BLINK; 2218698d5317Sjmmv break; 2219698d5317Sjmmv case 27: 2220698d5317Sjmmv gc->attr &= ~GRID_ATTR_REVERSE; 2221698d5317Sjmmv break; 2222e9a2d6faSchristos case 28: 2223e9a2d6faSchristos gc->attr &= ~GRID_ATTR_HIDDEN; 2224e9a2d6faSchristos break; 2225e9a2d6faSchristos case 29: 2226e9a2d6faSchristos gc->attr &= ~GRID_ATTR_STRIKETHROUGH; 2227e9a2d6faSchristos break; 2228698d5317Sjmmv case 30: 2229698d5317Sjmmv case 31: 2230698d5317Sjmmv case 32: 2231698d5317Sjmmv case 33: 2232698d5317Sjmmv case 34: 2233698d5317Sjmmv case 35: 2234698d5317Sjmmv case 36: 2235698d5317Sjmmv case 37: 2236698d5317Sjmmv gc->fg = n - 30; 2237698d5317Sjmmv break; 2238698d5317Sjmmv case 39: 2239698d5317Sjmmv gc->fg = 8; 2240698d5317Sjmmv break; 2241698d5317Sjmmv case 40: 2242698d5317Sjmmv case 41: 2243698d5317Sjmmv case 42: 2244698d5317Sjmmv case 43: 2245698d5317Sjmmv case 44: 2246698d5317Sjmmv case 45: 2247698d5317Sjmmv case 46: 2248698d5317Sjmmv case 47: 2249698d5317Sjmmv gc->bg = n - 40; 2250698d5317Sjmmv break; 2251698d5317Sjmmv case 49: 2252698d5317Sjmmv gc->bg = 8; 2253698d5317Sjmmv break; 225430744affSchristos case 53: 225530744affSchristos gc->attr |= GRID_ATTR_OVERLINE; 225630744affSchristos break; 225730744affSchristos case 55: 225830744affSchristos gc->attr &= ~GRID_ATTR_OVERLINE; 225930744affSchristos break; 226030744affSchristos case 59: 2261f844e94eSwiz gc->us = 8; 226230744affSchristos break; 2263698d5317Sjmmv case 90: 2264698d5317Sjmmv case 91: 2265698d5317Sjmmv case 92: 2266698d5317Sjmmv case 93: 2267698d5317Sjmmv case 94: 2268698d5317Sjmmv case 95: 2269698d5317Sjmmv case 96: 2270698d5317Sjmmv case 97: 2271698d5317Sjmmv gc->fg = n; 2272698d5317Sjmmv break; 2273698d5317Sjmmv case 100: 2274698d5317Sjmmv case 101: 2275698d5317Sjmmv case 102: 2276698d5317Sjmmv case 103: 2277698d5317Sjmmv case 104: 2278698d5317Sjmmv case 105: 2279698d5317Sjmmv case 106: 2280698d5317Sjmmv case 107: 228161fba46bSchristos gc->bg = n - 10; 2282698d5317Sjmmv break; 2283698d5317Sjmmv } 2284698d5317Sjmmv } 2285698d5317Sjmmv } 2286698d5317Sjmmv 22870a274e86Schristos /* End of input with BEL. */ 22880a274e86Schristos static int 22890a274e86Schristos input_end_bel(struct input_ctx *ictx) 22900a274e86Schristos { 22910a274e86Schristos log_debug("%s", __func__); 22920a274e86Schristos 22930a274e86Schristos ictx->input_end = INPUT_END_BEL; 22940a274e86Schristos 22950a274e86Schristos return (0); 22960a274e86Schristos } 22970a274e86Schristos 2298fe99a117Schristos /* DCS string started. */ 2299fe99a117Schristos static void 2300fe99a117Schristos input_enter_dcs(struct input_ctx *ictx) 2301fe99a117Schristos { 2302fe99a117Schristos log_debug("%s", __func__); 2303fe99a117Schristos 2304fe99a117Schristos input_clear(ictx); 2305fe99a117Schristos input_start_timer(ictx); 2306*890b6d91Swiz ictx->flags &= ~INPUT_LAST; 2307fe99a117Schristos } 2308fe99a117Schristos 23090f3d2746Sjmmv /* DCS terminator (ST) received. */ 2310e9a2d6faSchristos static int 23110f3d2746Sjmmv input_dcs_dispatch(struct input_ctx *ictx) 2312698d5317Sjmmv { 231346548964Swiz struct window_pane *wp = ictx->wp; 23140a274e86Schristos struct screen_write_ctx *sctx = &ictx->ctx; 23150a274e86Schristos char *buf = (char *)ictx->input_buf; 23160a274e86Schristos size_t len = ictx->input_len; 23170f3d2746Sjmmv const char prefix[] = "tmux;"; 23180a274e86Schristos const u_int prefixlen = (sizeof prefix) - 1; 2319f844e94eSwiz long long allow_passthrough = 0; 2320f844e94eSwiz #ifdef ENABLE_SIXEL 2321f844e94eSwiz struct window *w; 2322f844e94eSwiz struct sixel_image *si; 2323f844e94eSwiz #endif 2324698d5317Sjmmv 232546548964Swiz if (wp == NULL) 232646548964Swiz return (0); 2327f844e94eSwiz 2328f844e94eSwiz if (ictx->flags & INPUT_DISCARD) { 2329f844e94eSwiz log_debug("%s: %zu bytes (discard)", __func__, len); 23300f3d2746Sjmmv return (0); 2331f844e94eSwiz } 2332f844e94eSwiz 2333f844e94eSwiz #ifdef ENABLE_SIXEL 2334f844e94eSwiz w = wp->window; 2335f844e94eSwiz if (buf[0] == 'q') { 2336f844e94eSwiz si = sixel_parse(buf, len, w->xpixel, w->ypixel); 2337f844e94eSwiz if (si != NULL) 2338f844e94eSwiz screen_write_sixelimage(sctx, si, ictx->cell.cell.bg); 2339f844e94eSwiz } 2340f844e94eSwiz #endif 2341f844e94eSwiz 2342f844e94eSwiz allow_passthrough = options_get_number(wp->options, "allow-passthrough"); 2343f844e94eSwiz if (!allow_passthrough) 234446548964Swiz return (0); 23450a274e86Schristos log_debug("%s: \"%s\"", __func__, buf); 23460f3d2746Sjmmv 2347f844e94eSwiz if (len >= prefixlen && strncmp(buf, prefix, prefixlen) == 0) { 2348f844e94eSwiz screen_write_rawstring(sctx, (u_char *)buf + prefixlen, len - prefixlen, 2349f844e94eSwiz allow_passthrough == 2); 2350f844e94eSwiz } 2351698d5317Sjmmv 23520f3d2746Sjmmv return (0); 2353698d5317Sjmmv } 2354698d5317Sjmmv 2355698d5317Sjmmv /* OSC string started. */ 2356e9a2d6faSchristos static void 2357698d5317Sjmmv input_enter_osc(struct input_ctx *ictx) 2358698d5317Sjmmv { 2359698d5317Sjmmv log_debug("%s", __func__); 2360698d5317Sjmmv 23610f3d2746Sjmmv input_clear(ictx); 2362fe99a117Schristos input_start_timer(ictx); 2363*890b6d91Swiz ictx->flags &= ~INPUT_LAST; 2364698d5317Sjmmv } 2365698d5317Sjmmv 2366698d5317Sjmmv /* OSC terminator (ST) received. */ 2367e9a2d6faSchristos static void 2368698d5317Sjmmv input_exit_osc(struct input_ctx *ictx) 2369698d5317Sjmmv { 23700a274e86Schristos struct screen_write_ctx *sctx = &ictx->ctx; 2371e271dbb8Schristos struct window_pane *wp = ictx->wp; 2372fe99a117Schristos char *p = (char *)ictx->input_buf; 237399e242abSchristos u_int option; 23740f3d2746Sjmmv 2375698d5317Sjmmv if (ictx->flags & INPUT_DISCARD) 2376698d5317Sjmmv return; 23770f3d2746Sjmmv if (ictx->input_len < 1 || *p < '0' || *p > '9') 2378698d5317Sjmmv return; 2379698d5317Sjmmv 23800a274e86Schristos log_debug("%s: \"%s\" (end %s)", __func__, p, 23810a274e86Schristos ictx->input_end == INPUT_END_ST ? "ST" : "BEL"); 23820f3d2746Sjmmv 23830f3d2746Sjmmv option = 0; 23840f3d2746Sjmmv while (*p >= '0' && *p <= '9') 23850f3d2746Sjmmv option = option * 10 + *p++ - '0'; 2386f844e94eSwiz if (*p != ';' && *p != '\0') 2387f844e94eSwiz return; 23880f3d2746Sjmmv if (*p == ';') 23890f3d2746Sjmmv p++; 23900f3d2746Sjmmv 23910f3d2746Sjmmv switch (option) { 23920f3d2746Sjmmv case 0: 23930f3d2746Sjmmv case 2: 2394*890b6d91Swiz if (wp != NULL && 2395*890b6d91Swiz options_get_number(wp->options, "allow-set-title") && 2396*890b6d91Swiz screen_set_title(sctx->s, p)) { 2397e271dbb8Schristos notify_pane("pane-title-changed", wp); 2398e271dbb8Schristos server_redraw_window_borders(wp->window); 2399e271dbb8Schristos server_status_window(wp->window); 2400e271dbb8Schristos } 24010f3d2746Sjmmv break; 2402e9a2d6faSchristos case 4: 24030a274e86Schristos input_osc_4(ictx, p); 2404e9a2d6faSchristos break; 240568e6ba84Schristos case 7: 240668e6ba84Schristos if (utf8_isvalid(p)) { 240768e6ba84Schristos screen_set_path(sctx->s, p); 2408e271dbb8Schristos if (wp != NULL) { 2409e271dbb8Schristos server_redraw_window_borders(wp->window); 2410e271dbb8Schristos server_status_window(wp->window); 2411e271dbb8Schristos } 241268e6ba84Schristos } 241368e6ba84Schristos break; 2414f844e94eSwiz case 8: 2415f844e94eSwiz input_osc_8(ictx, p); 2416f844e94eSwiz break; 2417fe99a117Schristos case 10: 24180a274e86Schristos input_osc_10(ictx, p); 2419fe99a117Schristos break; 2420fe99a117Schristos case 11: 24210a274e86Schristos input_osc_11(ictx, p); 2422e9a2d6faSchristos break; 24230f3d2746Sjmmv case 12: 242446548964Swiz input_osc_12(ictx, p); 2425fe99a117Schristos break; 2426fe99a117Schristos case 52: 24270a274e86Schristos input_osc_52(ictx, p); 24280f3d2746Sjmmv break; 2429e9a2d6faSchristos case 104: 24300a274e86Schristos input_osc_104(ictx, p); 2431e9a2d6faSchristos break; 2432e271dbb8Schristos case 110: 2433e271dbb8Schristos input_osc_110(ictx, p); 2434e271dbb8Schristos break; 2435e271dbb8Schristos case 111: 2436e271dbb8Schristos input_osc_111(ictx, p); 2437e271dbb8Schristos break; 24380f3d2746Sjmmv case 112: 243946548964Swiz input_osc_112(ictx, p); 24400f3d2746Sjmmv break; 2441f844e94eSwiz case 133: 2442f844e94eSwiz input_osc_133(ictx, p); 2443f844e94eSwiz break; 24440f3d2746Sjmmv default: 24450f3d2746Sjmmv log_debug("%s: unknown '%u'", __func__, option); 24460f3d2746Sjmmv break; 24470f3d2746Sjmmv } 2448698d5317Sjmmv } 2449698d5317Sjmmv 2450698d5317Sjmmv /* APC string started. */ 2451e9a2d6faSchristos static void 2452698d5317Sjmmv input_enter_apc(struct input_ctx *ictx) 2453698d5317Sjmmv { 2454698d5317Sjmmv log_debug("%s", __func__); 2455698d5317Sjmmv 24560f3d2746Sjmmv input_clear(ictx); 2457fe99a117Schristos input_start_timer(ictx); 2458*890b6d91Swiz ictx->flags &= ~INPUT_LAST; 2459698d5317Sjmmv } 2460698d5317Sjmmv 2461698d5317Sjmmv /* APC terminator (ST) received. */ 2462e9a2d6faSchristos static void 2463698d5317Sjmmv input_exit_apc(struct input_ctx *ictx) 2464698d5317Sjmmv { 24650a274e86Schristos struct screen_write_ctx *sctx = &ictx->ctx; 2466e271dbb8Schristos struct window_pane *wp = ictx->wp; 2467fe99a117Schristos char *p = (char *)ictx->input_buf; 24680a274e86Schristos 2469698d5317Sjmmv if (ictx->flags & INPUT_DISCARD) 2470698d5317Sjmmv return; 2471fe99a117Schristos log_debug("%s: \"%s\"", __func__, p); 2472698d5317Sjmmv 2473e271dbb8Schristos if (screen_set_title(sctx->s, p) && wp != NULL) { 2474e271dbb8Schristos notify_pane("pane-title-changed", wp); 2475e271dbb8Schristos server_redraw_window_borders(wp->window); 2476e271dbb8Schristos server_status_window(wp->window); 2477e271dbb8Schristos } 2478698d5317Sjmmv } 2479698d5317Sjmmv 2480698d5317Sjmmv /* Rename string started. */ 2481e9a2d6faSchristos static void 2482698d5317Sjmmv input_enter_rename(struct input_ctx *ictx) 2483698d5317Sjmmv { 2484698d5317Sjmmv log_debug("%s", __func__); 2485698d5317Sjmmv 24860f3d2746Sjmmv input_clear(ictx); 2487fe99a117Schristos input_start_timer(ictx); 2488*890b6d91Swiz ictx->flags &= ~INPUT_LAST; 2489698d5317Sjmmv } 2490698d5317Sjmmv 2491698d5317Sjmmv /* Rename terminator (ST) received. */ 2492e9a2d6faSchristos static void 2493698d5317Sjmmv input_exit_rename(struct input_ctx *ictx) 2494698d5317Sjmmv { 249568e6ba84Schristos struct window_pane *wp = ictx->wp; 249646548964Swiz struct window *w; 2497e271dbb8Schristos struct options_entry *o; 2498fe99a117Schristos char *p = (char *)ictx->input_buf; 249968e6ba84Schristos 2500e271dbb8Schristos if (wp == NULL) 2501e271dbb8Schristos return; 2502698d5317Sjmmv if (ictx->flags & INPUT_DISCARD) 2503698d5317Sjmmv return; 250430744affSchristos if (!options_get_number(ictx->wp->options, "allow-rename")) 250561fba46bSchristos return; 2506fe99a117Schristos log_debug("%s: \"%s\"", __func__, p); 2507698d5317Sjmmv 2508fe99a117Schristos if (!utf8_isvalid(p)) 2509fe99a117Schristos return; 251046548964Swiz w = wp->window; 251168e6ba84Schristos 251268e6ba84Schristos if (ictx->input_len == 0) { 251346548964Swiz o = options_get_only(w->options, "automatic-rename"); 2514e271dbb8Schristos if (o != NULL) 2515e271dbb8Schristos options_remove_or_default(o, -1, NULL); 251646548964Swiz if (!options_get_number(w->options, "automatic-rename")) 251746548964Swiz window_set_name(w, ""); 251846548964Swiz } else { 251946548964Swiz options_set_number(w->options, "automatic-rename", 0); 252046548964Swiz window_set_name(w, ictx->input_buf); 252168e6ba84Schristos } 252246548964Swiz server_redraw_window_borders(w); 252346548964Swiz server_status_window(w); 2524698d5317Sjmmv } 2525698d5317Sjmmv 2526698d5317Sjmmv /* Open UTF-8 character. */ 2527e9a2d6faSchristos static int 2528c7e17de0Schristos input_top_bit_set(struct input_ctx *ictx) 2529698d5317Sjmmv { 25300a274e86Schristos struct screen_write_ctx *sctx = &ictx->ctx; 2531f26e8bc9Schristos struct utf8_data *ud = &ictx->utf8data; 2532698d5317Sjmmv 2533*890b6d91Swiz ictx->flags &= ~INPUT_LAST; 2534f26e8bc9Schristos 2535c7e17de0Schristos if (!ictx->utf8started) { 2536c7e17de0Schristos if (utf8_open(ud, ictx->ch) != UTF8_MORE) 2537c7e17de0Schristos return (0); 2538c7e17de0Schristos ictx->utf8started = 1; 2539698d5317Sjmmv return (0); 2540698d5317Sjmmv } 2541698d5317Sjmmv 2542c7e17de0Schristos switch (utf8_append(ud, ictx->ch)) { 2543c7e17de0Schristos case UTF8_MORE: 2544698d5317Sjmmv return (0); 2545c7e17de0Schristos case UTF8_ERROR: 2546c7e17de0Schristos ictx->utf8started = 0; 2547f26e8bc9Schristos return (0); 2548c7e17de0Schristos case UTF8_DONE: 2549c7e17de0Schristos break; 2550f26e8bc9Schristos } 2551c7e17de0Schristos ictx->utf8started = 0; 2552698d5317Sjmmv 2553f26e8bc9Schristos log_debug("%s %hhu '%*s' (width %hhu)", __func__, ud->size, 2554f26e8bc9Schristos (int)ud->size, ud->data, ud->width); 2555f26e8bc9Schristos 2556f26e8bc9Schristos utf8_copy(&ictx->cell.cell.data, ud); 25570a274e86Schristos screen_write_collect_add(sctx, &ictx->cell.cell); 2558698d5317Sjmmv 2559*890b6d91Swiz utf8_copy(&ictx->last, &ictx->cell.cell.data); 2560*890b6d91Swiz ictx->flags |= INPUT_LAST; 2561*890b6d91Swiz 2562698d5317Sjmmv return (0); 2563698d5317Sjmmv } 2564e9a2d6faSchristos 2565e271dbb8Schristos /* Reply to a colour request. */ 2566e271dbb8Schristos static void 2567e271dbb8Schristos input_osc_colour_reply(struct input_ctx *ictx, u_int n, int c) 2568e271dbb8Schristos { 2569e271dbb8Schristos u_char r, g, b; 2570e271dbb8Schristos const char *end; 257168e6ba84Schristos 257246548964Swiz if (c != -1) 257346548964Swiz c = colour_force_rgb(c); 257446548964Swiz if (c == -1) 2575e271dbb8Schristos return; 2576e271dbb8Schristos colour_split_rgb(c, &r, &g, &b); 257768e6ba84Schristos 2578e271dbb8Schristos if (ictx->input_end == INPUT_END_BEL) 2579e271dbb8Schristos end = "\007"; 2580e271dbb8Schristos else 2581e271dbb8Schristos end = "\033\\"; 258246548964Swiz input_reply(ictx, "\033]%u;rgb:%02hhx%02hhx/%02hhx%02hhx/%02hhx%02hhx%s", 258346548964Swiz n, r, r, g, g, b, b, end); 258468e6ba84Schristos } 258568e6ba84Schristos 2586e9a2d6faSchristos /* Handle the OSC 4 sequence for setting (multiple) palette entries. */ 2587e9a2d6faSchristos static void 25880a274e86Schristos input_osc_4(struct input_ctx *ictx, const char *p) 2589e9a2d6faSchristos { 2590e9a2d6faSchristos char *copy, *s, *next = NULL; 2591e9a2d6faSchristos long idx; 259246548964Swiz int c, bad = 0, redraw = 0; 2593e9a2d6faSchristos 2594e9a2d6faSchristos copy = s = xstrdup(p); 2595e9a2d6faSchristos while (s != NULL && *s != '\0') { 2596e9a2d6faSchristos idx = strtol(s, &next, 10); 259746548964Swiz if (*next++ != ';') { 259846548964Swiz bad = 1; 259946548964Swiz break; 260046548964Swiz } 260146548964Swiz if (idx < 0 || idx >= 256) { 260246548964Swiz bad = 1; 260346548964Swiz break; 260446548964Swiz } 2605e9a2d6faSchristos 2606e9a2d6faSchristos s = strsep(&next, ";"); 260746548964Swiz if (strcmp(s, "?") == 0) { 260846548964Swiz c = colour_palette_get(ictx->palette, idx); 260946548964Swiz if (c != -1) 261046548964Swiz input_osc_colour_reply(ictx, 4, c); 261146548964Swiz continue; 261246548964Swiz } 2613f844e94eSwiz if ((c = colour_parseX11(s)) == -1) { 2614e9a2d6faSchristos s = next; 2615e9a2d6faSchristos continue; 2616e9a2d6faSchristos } 261746548964Swiz if (colour_palette_set(ictx->palette, idx, c)) 261846548964Swiz redraw = 1; 2619e9a2d6faSchristos s = next; 2620e9a2d6faSchristos } 262146548964Swiz if (bad) 2622e9a2d6faSchristos log_debug("bad OSC 4: %s", p); 262346548964Swiz if (redraw) 262446548964Swiz screen_write_fullredraw(&ictx->ctx); 2625e9a2d6faSchristos free(copy); 2626e9a2d6faSchristos } 2627e9a2d6faSchristos 2628f844e94eSwiz /* Handle the OSC 8 sequence for embedding hyperlinks. */ 2629f844e94eSwiz static void 2630f844e94eSwiz input_osc_8(struct input_ctx *ictx, const char *p) 2631f844e94eSwiz { 2632f844e94eSwiz struct hyperlinks *hl = ictx->ctx.s->hyperlinks; 2633f844e94eSwiz struct grid_cell *gc = &ictx->cell.cell; 2634f844e94eSwiz const char *start, *end, *uri; 2635f844e94eSwiz char *id = NULL; 2636f844e94eSwiz 2637f844e94eSwiz for (start = p; (end = strpbrk(start, ":;")) != NULL; start = end + 1) { 2638f844e94eSwiz if (end - start >= 4 && strncmp(start, "id=", 3) == 0) { 2639f844e94eSwiz if (id != NULL) 2640f844e94eSwiz goto bad; 2641f844e94eSwiz id = xstrndup(start + 3, end - start - 3); 2642f844e94eSwiz } 2643f844e94eSwiz 2644f844e94eSwiz /* The first ; is the end of parameters and start of the URI. */ 2645f844e94eSwiz if (*end == ';') 2646f844e94eSwiz break; 2647f844e94eSwiz } 2648f844e94eSwiz if (end == NULL || *end != ';') 2649f844e94eSwiz goto bad; 2650f844e94eSwiz uri = end + 1; 2651f844e94eSwiz if (*uri == '\0') { 2652f844e94eSwiz gc->link = 0; 2653f844e94eSwiz free(id); 2654f844e94eSwiz return; 2655f844e94eSwiz } 2656f844e94eSwiz gc->link = hyperlinks_put(hl, uri, id); 2657f844e94eSwiz if (id == NULL) 2658f844e94eSwiz log_debug("hyperlink (anonymous) %s = %u", uri, gc->link); 2659f844e94eSwiz else 2660f844e94eSwiz log_debug("hyperlink (id=%s) %s = %u", id, uri, gc->link); 2661f844e94eSwiz free(id); 2662f844e94eSwiz return; 2663f844e94eSwiz 2664f844e94eSwiz bad: 2665f844e94eSwiz log_debug("bad OSC 8 %s", p); 2666f844e94eSwiz free(id); 2667f844e94eSwiz } 2668f844e94eSwiz 2669f844e94eSwiz /* 2670f844e94eSwiz * Get a client with a foreground for the pane. There isn't much to choose 2671f844e94eSwiz * between them so just use the first. 2672f844e94eSwiz */ 2673f844e94eSwiz static int 2674f844e94eSwiz input_get_fg_client(struct window_pane *wp) 2675f844e94eSwiz { 2676f844e94eSwiz struct window *w = wp->window; 2677f844e94eSwiz struct client *loop; 2678f844e94eSwiz 2679f844e94eSwiz TAILQ_FOREACH(loop, &clients, entry) { 2680f844e94eSwiz if (loop->flags & CLIENT_UNATTACHEDFLAGS) 2681f844e94eSwiz continue; 2682f844e94eSwiz if (loop->session == NULL || !session_has(loop->session, w)) 2683f844e94eSwiz continue; 2684f844e94eSwiz if (loop->tty.fg == -1) 2685f844e94eSwiz continue; 2686f844e94eSwiz return (loop->tty.fg); 2687f844e94eSwiz } 2688f844e94eSwiz return (-1); 2689f844e94eSwiz } 2690f844e94eSwiz 2691f844e94eSwiz /* Get a client with a background for the pane. */ 2692f844e94eSwiz static int 2693f844e94eSwiz input_get_bg_client(struct window_pane *wp) 2694f844e94eSwiz { 2695f844e94eSwiz struct window *w = wp->window; 2696f844e94eSwiz struct client *loop; 2697f844e94eSwiz 2698f844e94eSwiz TAILQ_FOREACH(loop, &clients, entry) { 2699f844e94eSwiz if (loop->flags & CLIENT_UNATTACHEDFLAGS) 2700f844e94eSwiz continue; 2701f844e94eSwiz if (loop->session == NULL || !session_has(loop->session, w)) 2702f844e94eSwiz continue; 2703f844e94eSwiz if (loop->tty.bg == -1) 2704f844e94eSwiz continue; 2705f844e94eSwiz return (loop->tty.bg); 2706f844e94eSwiz } 2707f844e94eSwiz return (-1); 2708f844e94eSwiz } 2709f844e94eSwiz 2710*890b6d91Swiz /* 2711*890b6d91Swiz * If any control mode client exists that has provided a bg color, return it. 2712*890b6d91Swiz * Otherwise, return -1. 2713*890b6d91Swiz */ 2714*890b6d91Swiz static int 2715*890b6d91Swiz input_get_bg_control_client(struct window_pane *wp) 2716*890b6d91Swiz { 2717*890b6d91Swiz struct client *c; 2718*890b6d91Swiz 2719*890b6d91Swiz if (wp->control_bg == -1) 2720*890b6d91Swiz return (-1); 2721*890b6d91Swiz 2722*890b6d91Swiz TAILQ_FOREACH(c, &clients, entry) { 2723*890b6d91Swiz if (c->flags & CLIENT_CONTROL) 2724*890b6d91Swiz return (wp->control_bg); 2725*890b6d91Swiz } 2726*890b6d91Swiz return (-1); 2727*890b6d91Swiz } 2728*890b6d91Swiz 2729*890b6d91Swiz /* 2730*890b6d91Swiz * If any control mode client exists that has provided a fg color, return it. 2731*890b6d91Swiz * Otherwise, return -1. 2732*890b6d91Swiz */ 2733*890b6d91Swiz static int 2734*890b6d91Swiz input_get_fg_control_client(struct window_pane *wp) 2735*890b6d91Swiz { 2736*890b6d91Swiz struct client *c; 2737*890b6d91Swiz 2738*890b6d91Swiz if (wp->control_fg == -1) 2739*890b6d91Swiz return (-1); 2740*890b6d91Swiz 2741*890b6d91Swiz TAILQ_FOREACH(c, &clients, entry) { 2742*890b6d91Swiz if (c->flags & CLIENT_CONTROL) 2743*890b6d91Swiz return (wp->control_fg); 2744*890b6d91Swiz } 2745*890b6d91Swiz return (-1); 2746*890b6d91Swiz } 2747*890b6d91Swiz 2748e271dbb8Schristos /* Handle the OSC 10 sequence for setting and querying foreground colour. */ 2749fe99a117Schristos static void 27500a274e86Schristos input_osc_10(struct input_ctx *ictx, const char *p) 2751fe99a117Schristos { 27520a274e86Schristos struct window_pane *wp = ictx->wp; 2753e271dbb8Schristos struct grid_cell defaults; 2754e271dbb8Schristos int c; 2755fe99a117Schristos 2756e271dbb8Schristos if (strcmp(p, "?") == 0) { 2757f844e94eSwiz if (wp == NULL) 2758f844e94eSwiz return; 2759*890b6d91Swiz c = input_get_fg_control_client(wp); 2760*890b6d91Swiz if (c == -1) { 2761e271dbb8Schristos tty_default_colours(&defaults, wp); 2762f844e94eSwiz if (COLOUR_DEFAULT(defaults.fg)) 2763f844e94eSwiz c = input_get_fg_client(wp); 2764f844e94eSwiz else 2765f844e94eSwiz c = defaults.fg; 2766*890b6d91Swiz } 2767f844e94eSwiz input_osc_colour_reply(ictx, 10, c); 2768e271dbb8Schristos return; 2769e271dbb8Schristos } 2770e271dbb8Schristos 2771f844e94eSwiz if ((c = colour_parseX11(p)) == -1) { 2772fe99a117Schristos log_debug("bad OSC 10: %s", p); 277346548964Swiz return; 277446548964Swiz } 277546548964Swiz if (ictx->palette != NULL) { 277646548964Swiz ictx->palette->fg = c; 277746548964Swiz if (wp != NULL) 277846548964Swiz wp->flags |= PANE_STYLECHANGED; 277946548964Swiz screen_write_fullredraw(&ictx->ctx); 278046548964Swiz } 2781fe99a117Schristos } 2782fe99a117Schristos 278346548964Swiz /* Handle the OSC 110 sequence for resetting foreground colour. */ 2784e271dbb8Schristos static void 2785e271dbb8Schristos input_osc_110(struct input_ctx *ictx, const char *p) 2786e271dbb8Schristos { 2787e271dbb8Schristos struct window_pane *wp = ictx->wp; 2788e271dbb8Schristos 2789e271dbb8Schristos if (*p != '\0') 2790e271dbb8Schristos return; 279146548964Swiz if (ictx->palette != NULL) { 279246548964Swiz ictx->palette->fg = 8; 279346548964Swiz if (wp != NULL) 279446548964Swiz wp->flags |= PANE_STYLECHANGED; 279546548964Swiz screen_write_fullredraw(&ictx->ctx); 279646548964Swiz } 2797e271dbb8Schristos } 2798e271dbb8Schristos 2799e271dbb8Schristos /* Handle the OSC 11 sequence for setting and querying background colour. */ 2800fe99a117Schristos static void 28010a274e86Schristos input_osc_11(struct input_ctx *ictx, const char *p) 2802fe99a117Schristos { 28030a274e86Schristos struct window_pane *wp = ictx->wp; 2804e271dbb8Schristos struct grid_cell defaults; 2805e271dbb8Schristos int c; 2806fe99a117Schristos 2807e271dbb8Schristos if (strcmp(p, "?") == 0) { 2808f844e94eSwiz if (wp == NULL) 2809f844e94eSwiz return; 2810*890b6d91Swiz c = input_get_bg_control_client(wp); 2811*890b6d91Swiz if (c == -1) { 2812e271dbb8Schristos tty_default_colours(&defaults, wp); 2813f844e94eSwiz if (COLOUR_DEFAULT(defaults.bg)) 2814f844e94eSwiz c = input_get_bg_client(wp); 2815f844e94eSwiz else 2816f844e94eSwiz c = defaults.bg; 2817*890b6d91Swiz } 2818f844e94eSwiz input_osc_colour_reply(ictx, 11, c); 2819e271dbb8Schristos return; 2820e271dbb8Schristos } 2821e271dbb8Schristos 2822f844e94eSwiz if ((c = colour_parseX11(p)) == -1) { 2823fe99a117Schristos log_debug("bad OSC 11: %s", p); 282446548964Swiz return; 282546548964Swiz } 282646548964Swiz if (ictx->palette != NULL) { 282746548964Swiz ictx->palette->bg = c; 282846548964Swiz if (wp != NULL) 282946548964Swiz wp->flags |= PANE_STYLECHANGED; 283046548964Swiz screen_write_fullredraw(&ictx->ctx); 283146548964Swiz } 2832fe99a117Schristos } 2833fe99a117Schristos 2834e271dbb8Schristos /* Handle the OSC 111 sequence for resetting background colour. */ 2835e271dbb8Schristos static void 2836e271dbb8Schristos input_osc_111(struct input_ctx *ictx, const char *p) 2837e271dbb8Schristos { 2838e271dbb8Schristos struct window_pane *wp = ictx->wp; 2839e271dbb8Schristos 2840e271dbb8Schristos if (*p != '\0') 2841e271dbb8Schristos return; 284246548964Swiz if (ictx->palette != NULL) { 284346548964Swiz ictx->palette->bg = 8; 284446548964Swiz if (wp != NULL) 284546548964Swiz wp->flags |= PANE_STYLECHANGED; 284646548964Swiz screen_write_fullredraw(&ictx->ctx); 2847e271dbb8Schristos } 284846548964Swiz } 284946548964Swiz 285046548964Swiz /* Handle the OSC 12 sequence for setting and querying cursor colour. */ 285146548964Swiz static void 285246548964Swiz input_osc_12(struct input_ctx *ictx, const char *p) 285346548964Swiz { 285446548964Swiz struct window_pane *wp = ictx->wp; 285546548964Swiz int c; 285646548964Swiz 285746548964Swiz if (strcmp(p, "?") == 0) { 285846548964Swiz if (wp != NULL) { 285946548964Swiz c = ictx->ctx.s->ccolour; 286046548964Swiz if (c == -1) 286146548964Swiz c = ictx->ctx.s->default_ccolour; 286246548964Swiz input_osc_colour_reply(ictx, 12, c); 286346548964Swiz } 286446548964Swiz return; 286546548964Swiz } 286646548964Swiz 2867f844e94eSwiz if ((c = colour_parseX11(p)) == -1) { 286846548964Swiz log_debug("bad OSC 12: %s", p); 286946548964Swiz return; 287046548964Swiz } 287146548964Swiz screen_set_cursor_colour(ictx->ctx.s, c); 287246548964Swiz } 287346548964Swiz 287446548964Swiz /* Handle the OSC 112 sequence for resetting cursor colour. */ 287546548964Swiz static void 287646548964Swiz input_osc_112(struct input_ctx *ictx, const char *p) 287746548964Swiz { 287846548964Swiz if (*p == '\0') /* no arguments allowed */ 287946548964Swiz screen_set_cursor_colour(ictx->ctx.s, -1); 288046548964Swiz } 288146548964Swiz 2882f844e94eSwiz /* Handle the OSC 133 sequence. */ 2883f844e94eSwiz static void 2884f844e94eSwiz input_osc_133(struct input_ctx *ictx, const char *p) 2885f844e94eSwiz { 2886f844e94eSwiz struct grid *gd = ictx->ctx.s->grid; 2887f844e94eSwiz u_int line = ictx->ctx.s->cy + gd->hsize; 2888f844e94eSwiz struct grid_line *gl; 2889f844e94eSwiz 2890f844e94eSwiz if (line > gd->hsize + gd->sy - 1) 2891f844e94eSwiz return; 2892f844e94eSwiz gl = grid_get_line(gd, line); 2893f844e94eSwiz 2894f844e94eSwiz switch (*p) { 2895f844e94eSwiz case 'A': 2896f844e94eSwiz gl->flags |= GRID_LINE_START_PROMPT; 2897f844e94eSwiz break; 2898f844e94eSwiz case 'C': 2899f844e94eSwiz gl->flags |= GRID_LINE_START_OUTPUT; 2900f844e94eSwiz break; 2901f844e94eSwiz } 2902f844e94eSwiz } 2903e271dbb8Schristos 2904e9a2d6faSchristos /* Handle the OSC 52 sequence for setting the clipboard. */ 2905e9a2d6faSchristos static void 29060a274e86Schristos input_osc_52(struct input_ctx *ictx, const char *p) 2907e9a2d6faSchristos { 29080a274e86Schristos struct window_pane *wp = ictx->wp; 2909e9a2d6faSchristos char *end; 291046548964Swiz const char *buf = NULL; 291146548964Swiz size_t len = 0; 2912e9a2d6faSchristos u_char *out; 2913fe99a117Schristos int outlen, state; 2914e9a2d6faSchristos struct screen_write_ctx ctx; 29150a274e86Schristos struct paste_buffer *pb; 2916f844e94eSwiz const char* allow = "cpqs01234567"; 2917f844e94eSwiz char flags[sizeof "cpqs01234567"] = ""; 2918f844e94eSwiz u_int i, j = 0; 2919e9a2d6faSchristos 2920e271dbb8Schristos if (wp == NULL) 2921e271dbb8Schristos return; 2922fe99a117Schristos state = options_get_number(global_options, "set-clipboard"); 2923fe99a117Schristos if (state != 2) 2924fe99a117Schristos return; 2925fe99a117Schristos 2926e9a2d6faSchristos if ((end = strchr(p, ';')) == NULL) 2927e9a2d6faSchristos return; 2928e9a2d6faSchristos end++; 2929e9a2d6faSchristos if (*end == '\0') 2930e9a2d6faSchristos return; 29310a274e86Schristos log_debug("%s: %s", __func__, end); 29320a274e86Schristos 2933f844e94eSwiz for (i = 0; p + i != end; i++) { 2934f844e94eSwiz if (strchr(allow, p[i]) != NULL && strchr(flags, p[i]) == NULL) 2935f844e94eSwiz flags[j++] = p[i]; 2936f844e94eSwiz } 2937f844e94eSwiz log_debug("%s: %.*s %s", __func__, (int)(end - p - 1), p, flags); 2938f844e94eSwiz 29390a274e86Schristos if (strcmp(end, "?") == 0) { 294046548964Swiz if ((pb = paste_get_top(NULL)) != NULL) 29410a274e86Schristos buf = paste_buffer_data(pb, &len); 29420a274e86Schristos if (ictx->input_end == INPUT_END_BEL) 294346548964Swiz input_reply_clipboard(ictx->event, buf, len, "\007"); 29440a274e86Schristos else 294546548964Swiz input_reply_clipboard(ictx->event, buf, len, "\033\\"); 29460a274e86Schristos return; 29470a274e86Schristos } 2948e9a2d6faSchristos 2949e9a2d6faSchristos len = (strlen(end) / 4) * 3; 2950e9a2d6faSchristos if (len == 0) 2951e9a2d6faSchristos return; 2952e9a2d6faSchristos 2953e9a2d6faSchristos out = xmalloc(len); 2954e9a2d6faSchristos if ((outlen = b64_pton(end, out, len)) == -1) { 2955e9a2d6faSchristos free(out); 2956e9a2d6faSchristos return; 2957e9a2d6faSchristos } 2958e9a2d6faSchristos 2959e271dbb8Schristos screen_write_start_pane(&ctx, wp, NULL); 2960f844e94eSwiz screen_write_setselection(&ctx, flags, out, outlen); 2961e9a2d6faSchristos screen_write_stop(&ctx); 2962fe99a117Schristos notify_pane("pane-set-clipboard", wp); 2963fe99a117Schristos 296430744affSchristos paste_add(NULL, (char *)out, outlen); 2965e9a2d6faSchristos } 2966e9a2d6faSchristos 2967e9a2d6faSchristos /* Handle the OSC 104 sequence for unsetting (multiple) palette entries. */ 2968e9a2d6faSchristos static void 29690a274e86Schristos input_osc_104(struct input_ctx *ictx, const char *p) 2970e9a2d6faSchristos { 2971e9a2d6faSchristos char *copy, *s; 2972e9a2d6faSchristos long idx; 297346548964Swiz int bad = 0, redraw = 0; 2974e271dbb8Schristos 2975e9a2d6faSchristos if (*p == '\0') { 297646548964Swiz colour_palette_clear(ictx->palette); 297746548964Swiz screen_write_fullredraw(&ictx->ctx); 2978e9a2d6faSchristos return; 2979e9a2d6faSchristos } 2980e9a2d6faSchristos 2981e9a2d6faSchristos copy = s = xstrdup(p); 2982e9a2d6faSchristos while (*s != '\0') { 2983e9a2d6faSchristos idx = strtol(s, &s, 10); 298446548964Swiz if (*s != '\0' && *s != ';') { 298546548964Swiz bad = 1; 298646548964Swiz break; 298746548964Swiz } 298846548964Swiz if (idx < 0 || idx >= 256) { 298946548964Swiz bad = 1; 299046548964Swiz break; 299146548964Swiz } 299246548964Swiz if (colour_palette_set(ictx->palette, idx, -1)) 299346548964Swiz redraw = 1; 2994e9a2d6faSchristos if (*s == ';') 2995e9a2d6faSchristos s++; 2996e9a2d6faSchristos } 299746548964Swiz if (bad) 2998e9a2d6faSchristos log_debug("bad OSC 104: %s", p); 299946548964Swiz if (redraw) 300046548964Swiz screen_write_fullredraw(&ictx->ctx); 3001e9a2d6faSchristos free(copy); 3002e9a2d6faSchristos } 300346548964Swiz 300446548964Swiz void 300546548964Swiz input_reply_clipboard(struct bufferevent *bev, const char *buf, size_t len, 300646548964Swiz const char *end) 300746548964Swiz { 300846548964Swiz char *out = NULL; 3009f844e94eSwiz int outlen = 0; 301046548964Swiz 301146548964Swiz if (buf != NULL && len != 0) { 3012f844e94eSwiz if (len >= ((size_t)INT_MAX * 3 / 4) - 1) 3013f844e94eSwiz return; 301446548964Swiz outlen = 4 * ((len + 2) / 3) + 1; 301546548964Swiz out = xmalloc(outlen); 301646548964Swiz if ((outlen = b64_ntop(buf, len, out, outlen)) == -1) { 301746548964Swiz free(out); 301846548964Swiz return; 301946548964Swiz } 302046548964Swiz } 302146548964Swiz 302246548964Swiz bufferevent_write(bev, "\033]52;;", 6); 302346548964Swiz if (outlen != 0) 302446548964Swiz bufferevent_write(bev, out, outlen); 302546548964Swiz bufferevent_write(bev, end, strlen(end)); 302646548964Swiz free(out); 302746548964Swiz } 3028