mirror of
https://github.com/tmate-io/tmate.git
synced 2024-12-26 16:48:56 +01:00
219442cff7
Support for UTF-8 mouse input (\033[1005h). This was added in xterm 262 and supports larger terminals than the older way. If the new mouse-utf8 option is on, UTF-8 mouse input is enabled for all UTF-8 terminals. The option defaults to on if LANG etc are set in the same manner as the utf8 option. With help and based on code from hsim at gmx.li.
1521 lines
36 KiB
C
1521 lines
36 KiB
C
/* $Id: input.c,v 1.113 2011-01-07 14:34:45 tcunha Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
|
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
|
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "tmux.h"
|
|
|
|
/*
|
|
* Based on the description by Paul Williams at:
|
|
*
|
|
* http://vt100.net/emu/dec_ansi_parser
|
|
*
|
|
* With the following changes:
|
|
*
|
|
* - 7-bit only.
|
|
*
|
|
* - Support for UTF-8.
|
|
*
|
|
* - OSC (but not APC) may be terminated by \007 as well as ST.
|
|
*
|
|
* - A state for APC similar to OSC. Some terminals appear to use this to set
|
|
* the title.
|
|
*
|
|
* - A state for the screen \033k...\033\\ sequence to rename a window. This is
|
|
* pretty stupid but not supporting it is more trouble than it is worth.
|
|
*/
|
|
|
|
/* Helper functions. */
|
|
int input_split(struct input_ctx *);
|
|
int input_get(struct input_ctx *, u_int, int, int);
|
|
void input_reply(struct input_ctx *, const char *, ...);
|
|
|
|
/* Transition entry/exit handlers. */
|
|
void input_clear(struct input_ctx *);
|
|
void input_enter_dcs(struct input_ctx *);
|
|
void input_exit_dcs(struct input_ctx *);
|
|
void input_enter_osc(struct input_ctx *);
|
|
void input_exit_osc(struct input_ctx *);
|
|
void input_enter_apc(struct input_ctx *);
|
|
void input_exit_apc(struct input_ctx *);
|
|
void input_enter_rename(struct input_ctx *);
|
|
void input_exit_rename(struct input_ctx *);
|
|
|
|
/* Input state handlers. */
|
|
int input_print(struct input_ctx *);
|
|
int input_intermediate(struct input_ctx *);
|
|
int input_parameter(struct input_ctx *);
|
|
int input_input(struct input_ctx *);
|
|
int input_c0_dispatch(struct input_ctx *);
|
|
int input_esc_dispatch(struct input_ctx *);
|
|
int input_csi_dispatch(struct input_ctx *);
|
|
void input_csi_dispatch_sgr(struct input_ctx *);
|
|
int input_utf8_open(struct input_ctx *);
|
|
int input_utf8_add(struct input_ctx *);
|
|
int input_utf8_close(struct input_ctx *);
|
|
|
|
/* Command table comparison function. */
|
|
int input_table_compare(const void *, const void *);
|
|
|
|
/* Command table entry. */
|
|
struct input_table_entry {
|
|
int ch;
|
|
const char *interm;
|
|
int type;
|
|
};
|
|
|
|
/* Escape commands. */
|
|
enum input_esc_type {
|
|
INPUT_ESC_DECALN,
|
|
INPUT_ESC_DECKPAM,
|
|
INPUT_ESC_DECKPNM,
|
|
INPUT_ESC_DECRC,
|
|
INPUT_ESC_DECSC,
|
|
INPUT_ESC_HTS,
|
|
INPUT_ESC_IND,
|
|
INPUT_ESC_NEL,
|
|
INPUT_ESC_RI,
|
|
INPUT_ESC_RIS,
|
|
INPUT_ESC_SCSOFF_G0,
|
|
INPUT_ESC_SCSON_G0,
|
|
};
|
|
|
|
/* Escape command table. */
|
|
const struct input_table_entry input_esc_table[] = {
|
|
{ '0', "(", INPUT_ESC_SCSOFF_G0 },
|
|
{ '7', "", INPUT_ESC_DECSC },
|
|
{ '8', "", INPUT_ESC_DECRC },
|
|
{ '8', "#", INPUT_ESC_DECALN },
|
|
{ '=', "", INPUT_ESC_DECKPAM },
|
|
{ '>', "", INPUT_ESC_DECKPNM },
|
|
{ 'B', "(", INPUT_ESC_SCSON_G0 },
|
|
{ 'D', "", INPUT_ESC_IND },
|
|
{ 'E', "", INPUT_ESC_NEL },
|
|
{ 'H', "", INPUT_ESC_HTS },
|
|
{ 'M', "", INPUT_ESC_RI },
|
|
{ 'c', "", INPUT_ESC_RIS },
|
|
};
|
|
|
|
/* Control (CSI) commands. */
|
|
enum input_csi_type {
|
|
INPUT_CSI_CBT,
|
|
INPUT_CSI_CUB,
|
|
INPUT_CSI_CUD,
|
|
INPUT_CSI_CUF,
|
|
INPUT_CSI_CUP,
|
|
INPUT_CSI_CUU,
|
|
INPUT_CSI_DA,
|
|
INPUT_CSI_DCH,
|
|
INPUT_CSI_DECSTBM,
|
|
INPUT_CSI_DL,
|
|
INPUT_CSI_DSR,
|
|
INPUT_CSI_ED,
|
|
INPUT_CSI_EL,
|
|
INPUT_CSI_HPA,
|
|
INPUT_CSI_ICH,
|
|
INPUT_CSI_IL,
|
|
INPUT_CSI_RM,
|
|
INPUT_CSI_RM_PRIVATE,
|
|
INPUT_CSI_SGR,
|
|
INPUT_CSI_SM,
|
|
INPUT_CSI_SM_PRIVATE,
|
|
INPUT_CSI_TBC,
|
|
INPUT_CSI_VPA,
|
|
};
|
|
|
|
/* Control (CSI) command table. */
|
|
const struct input_table_entry input_csi_table[] = {
|
|
{ '@', "", INPUT_CSI_ICH },
|
|
{ 'A', "", INPUT_CSI_CUU },
|
|
{ 'B', "", INPUT_CSI_CUD },
|
|
{ 'C', "", INPUT_CSI_CUF },
|
|
{ 'D', "", INPUT_CSI_CUB },
|
|
{ 'G', "", INPUT_CSI_HPA },
|
|
{ 'H', "", INPUT_CSI_CUP },
|
|
{ 'J', "", INPUT_CSI_ED },
|
|
{ 'K', "", INPUT_CSI_EL },
|
|
{ 'L', "", INPUT_CSI_IL },
|
|
{ 'M', "", INPUT_CSI_DL },
|
|
{ 'P', "", INPUT_CSI_DCH },
|
|
{ 'Z', "", INPUT_CSI_CBT },
|
|
{ 'c', "", INPUT_CSI_DA },
|
|
{ 'd', "", INPUT_CSI_VPA },
|
|
{ 'f', "", INPUT_CSI_CUP },
|
|
{ 'g', "", INPUT_CSI_TBC },
|
|
{ 'h', "", INPUT_CSI_SM },
|
|
{ 'h', "?", INPUT_CSI_SM_PRIVATE },
|
|
{ 'l', "", INPUT_CSI_RM },
|
|
{ 'l', "?", INPUT_CSI_RM_PRIVATE },
|
|
{ 'm', "", INPUT_CSI_SGR },
|
|
{ 'n', "", INPUT_CSI_DSR },
|
|
{ 'r', "", INPUT_CSI_DECSTBM },
|
|
};
|
|
|
|
/* Input transition. */
|
|
struct input_transition {
|
|
int first;
|
|
int last;
|
|
|
|
int (*handler)(struct input_ctx *);
|
|
const struct input_state *state;
|
|
};
|
|
|
|
/* Input state. */
|
|
struct input_state {
|
|
const char *name;
|
|
void (*enter)(struct input_ctx *);
|
|
void (*exit)(struct input_ctx *);
|
|
const struct input_transition *transitions;
|
|
};
|
|
|
|
/* State transitions available from all states. */
|
|
#define INPUT_STATE_ANYWHERE \
|
|
{ 0x18, 0x18, input_c0_dispatch, &input_state_ground }, \
|
|
{ 0x1a, 0x1a, input_c0_dispatch, &input_state_ground }, \
|
|
{ 0x1b, 0x1b, NULL, &input_state_esc_enter }
|
|
|
|
/* Forward declarations of state tables. */
|
|
const struct input_transition input_state_ground_table[];
|
|
const struct input_transition input_state_esc_enter_table[];
|
|
const struct input_transition input_state_esc_intermediate_table[];
|
|
const struct input_transition input_state_csi_enter_table[];
|
|
const struct input_transition input_state_csi_parameter_table[];
|
|
const struct input_transition input_state_csi_intermediate_table[];
|
|
const struct input_transition input_state_csi_ignore_table[];
|
|
const struct input_transition input_state_dcs_enter_table[];
|
|
const struct input_transition input_state_dcs_parameter_table[];
|
|
const struct input_transition input_state_dcs_intermediate_table[];
|
|
const struct input_transition input_state_dcs_handler_table[];
|
|
const struct input_transition input_state_dcs_ignore_table[];
|
|
const struct input_transition input_state_osc_string_table[];
|
|
const struct input_transition input_state_apc_string_table[];
|
|
const struct input_transition input_state_rename_string_table[];
|
|
const struct input_transition input_state_consume_st_table[];
|
|
const struct input_transition input_state_utf8_three_table[];
|
|
const struct input_transition input_state_utf8_two_table[];
|
|
const struct input_transition input_state_utf8_one_table[];
|
|
|
|
/* ground state definition. */
|
|
const struct input_state input_state_ground = {
|
|
"ground",
|
|
NULL, NULL,
|
|
input_state_ground_table
|
|
};
|
|
|
|
/* esc_enter state definition. */
|
|
const struct input_state input_state_esc_enter = {
|
|
"esc_enter",
|
|
input_clear, NULL,
|
|
input_state_esc_enter_table
|
|
};
|
|
|
|
/* esc_intermediate state definition. */
|
|
const struct input_state input_state_esc_intermediate = {
|
|
"esc_intermediate",
|
|
NULL, NULL,
|
|
input_state_esc_intermediate_table
|
|
};
|
|
|
|
/* csi_enter state definition. */
|
|
const struct input_state input_state_csi_enter = {
|
|
"csi_enter",
|
|
input_clear, NULL,
|
|
input_state_csi_enter_table
|
|
};
|
|
|
|
/* csi_parameter state definition. */
|
|
const struct input_state input_state_csi_parameter = {
|
|
"csi_parameter",
|
|
NULL, NULL,
|
|
input_state_csi_parameter_table
|
|
};
|
|
|
|
/* csi_intermediate state definition. */
|
|
const struct input_state input_state_csi_intermediate = {
|
|
"csi_intermediate",
|
|
NULL, NULL,
|
|
input_state_csi_intermediate_table
|
|
};
|
|
|
|
/* csi_ignore state definition. */
|
|
const struct input_state input_state_csi_ignore = {
|
|
"csi_ignore",
|
|
NULL, NULL,
|
|
input_state_csi_ignore_table
|
|
};
|
|
|
|
/* dcs_enter state definition. */
|
|
const struct input_state input_state_dcs_enter = {
|
|
"dcs_enter",
|
|
input_clear, NULL,
|
|
input_state_dcs_enter_table
|
|
};
|
|
|
|
/* dcs_parameter state definition. */
|
|
const struct input_state input_state_dcs_parameter = {
|
|
"dcs_parameter",
|
|
NULL, NULL,
|
|
input_state_dcs_parameter_table
|
|
};
|
|
|
|
/* dcs_intermediate state definition. */
|
|
const struct input_state input_state_dcs_intermediate = {
|
|
"dcs_intermediate",
|
|
NULL, NULL,
|
|
input_state_dcs_intermediate_table
|
|
};
|
|
|
|
/* dcs_handler state definition. */
|
|
const struct input_state input_state_dcs_handler = {
|
|
"dcs_handler",
|
|
input_enter_dcs, input_exit_dcs,
|
|
input_state_dcs_handler_table
|
|
};
|
|
|
|
/* dcs_ignore state definition. */
|
|
const struct input_state input_state_dcs_ignore = {
|
|
"dcs_ignore",
|
|
NULL, NULL,
|
|
input_state_dcs_ignore_table
|
|
};
|
|
|
|
/* osc_string state definition. */
|
|
const struct input_state input_state_osc_string = {
|
|
"osc_string",
|
|
input_enter_osc, input_exit_osc,
|
|
input_state_osc_string_table
|
|
};
|
|
|
|
/* apc_string state definition. */
|
|
const struct input_state input_state_apc_string = {
|
|
"apc_string",
|
|
input_enter_apc, input_exit_apc,
|
|
input_state_apc_string_table
|
|
};
|
|
|
|
/* rename_string state definition. */
|
|
const struct input_state input_state_rename_string = {
|
|
"rename_string",
|
|
input_enter_rename, input_exit_rename,
|
|
input_state_rename_string_table
|
|
};
|
|
|
|
/* consume_st state definition. */
|
|
const struct input_state input_state_consume_st = {
|
|
"consume_st",
|
|
NULL, NULL,
|
|
input_state_consume_st_table
|
|
};
|
|
|
|
/* utf8_three state definition. */
|
|
const struct input_state input_state_utf8_three = {
|
|
"utf8_three",
|
|
NULL, NULL,
|
|
input_state_utf8_three_table
|
|
};
|
|
|
|
/* utf8_two state definition. */
|
|
const struct input_state input_state_utf8_two = {
|
|
"utf8_two",
|
|
NULL, NULL,
|
|
input_state_utf8_two_table
|
|
};
|
|
|
|
/* utf8_one state definition. */
|
|
const struct input_state input_state_utf8_one = {
|
|
"utf8_one",
|
|
NULL, NULL,
|
|
input_state_utf8_one_table
|
|
};
|
|
|
|
/* ground state table. */
|
|
const struct input_transition input_state_ground_table[] = {
|
|
INPUT_STATE_ANYWHERE,
|
|
|
|
{ 0x00, 0x17, input_c0_dispatch, NULL },
|
|
{ 0x19, 0x19, input_c0_dispatch, NULL },
|
|
{ 0x1c, 0x1f, input_c0_dispatch, NULL },
|
|
{ 0x20, 0x7e, input_print, NULL },
|
|
{ 0x7f, 0x7f, NULL, NULL },
|
|
{ 0x80, 0xc1, input_print, NULL },
|
|
{ 0xc2, 0xdf, input_utf8_open, &input_state_utf8_one },
|
|
{ 0xe0, 0xef, input_utf8_open, &input_state_utf8_two },
|
|
{ 0xf0, 0xf4, input_utf8_open, &input_state_utf8_three },
|
|
{ 0xf5, 0xff, input_print, NULL },
|
|
|
|
{ -1, -1, NULL, NULL }
|
|
};
|
|
|
|
/* esc_enter state table. */
|
|
const struct input_transition input_state_esc_enter_table[] = {
|
|
INPUT_STATE_ANYWHERE,
|
|
|
|
{ 0x00, 0x17, input_c0_dispatch, NULL },
|
|
{ 0x19, 0x19, input_c0_dispatch, NULL },
|
|
{ 0x1c, 0x1f, input_c0_dispatch, NULL },
|
|
{ 0x20, 0x2f, input_intermediate, &input_state_esc_intermediate },
|
|
{ 0x30, 0x4f, input_esc_dispatch, &input_state_ground },
|
|
{ 0x50, 0x50, NULL, &input_state_dcs_enter },
|
|
{ 0x51, 0x57, input_esc_dispatch, &input_state_ground },
|
|
{ 0x58, 0x58, NULL, &input_state_consume_st },
|
|
{ 0x59, 0x59, input_esc_dispatch, &input_state_ground },
|
|
{ 0x5a, 0x5a, input_esc_dispatch, &input_state_ground },
|
|
{ 0x5b, 0x5b, NULL, &input_state_csi_enter },
|
|
{ 0x5c, 0x5c, input_esc_dispatch, &input_state_ground },
|
|
{ 0x5d, 0x5d, NULL, &input_state_osc_string },
|
|
{ 0x5e, 0x5e, NULL, &input_state_consume_st },
|
|
{ 0x5f, 0x5f, NULL, &input_state_apc_string },
|
|
{ 0x60, 0x6a, input_esc_dispatch, &input_state_ground },
|
|
{ 0x6b, 0x6b, NULL, &input_state_rename_string },
|
|
{ 0x6c, 0x7e, input_esc_dispatch, &input_state_ground },
|
|
{ 0x7f, 0xff, NULL, NULL },
|
|
|
|
{ -1, -1, NULL, NULL }
|
|
};
|
|
|
|
/* esc_interm state table. */
|
|
const struct input_transition input_state_esc_intermediate_table[] = {
|
|
INPUT_STATE_ANYWHERE,
|
|
|
|
{ 0x00, 0x17, input_c0_dispatch, NULL },
|
|
{ 0x19, 0x19, input_c0_dispatch, NULL },
|
|
{ 0x1c, 0x1f, input_c0_dispatch, NULL },
|
|
{ 0x20, 0x2f, input_intermediate, NULL },
|
|
{ 0x30, 0x7e, input_esc_dispatch, &input_state_ground },
|
|
{ 0x7f, 0xff, NULL, NULL },
|
|
|
|
{ -1, -1, NULL, NULL }
|
|
};
|
|
|
|
/* csi_enter state table. */
|
|
const struct input_transition input_state_csi_enter_table[] = {
|
|
INPUT_STATE_ANYWHERE,
|
|
|
|
{ 0x00, 0x17, input_c0_dispatch, NULL },
|
|
{ 0x19, 0x19, input_c0_dispatch, NULL },
|
|
{ 0x1c, 0x1f, input_c0_dispatch, NULL },
|
|
{ 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
|
|
{ 0x30, 0x39, input_parameter, &input_state_csi_parameter },
|
|
{ 0x3a, 0x3a, NULL, &input_state_csi_ignore },
|
|
{ 0x3b, 0x3b, input_parameter, &input_state_csi_parameter },
|
|
{ 0x3c, 0x3f, input_intermediate, &input_state_csi_parameter },
|
|
{ 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
|
|
{ 0x7f, 0xff, NULL, NULL },
|
|
|
|
{ -1, -1, NULL, NULL }
|
|
};
|
|
|
|
/* csi_parameter state table. */
|
|
const struct input_transition input_state_csi_parameter_table[] = {
|
|
INPUT_STATE_ANYWHERE,
|
|
|
|
{ 0x00, 0x17, input_c0_dispatch, NULL },
|
|
{ 0x19, 0x19, input_c0_dispatch, NULL },
|
|
{ 0x1c, 0x1f, input_c0_dispatch, NULL },
|
|
{ 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
|
|
{ 0x30, 0x39, input_parameter, NULL },
|
|
{ 0x3a, 0x3a, NULL, &input_state_csi_ignore },
|
|
{ 0x3b, 0x3b, input_parameter, NULL },
|
|
{ 0x3c, 0x3f, NULL, &input_state_csi_ignore },
|
|
{ 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
|
|
{ 0x7f, 0xff, NULL, NULL },
|
|
|
|
{ -1, -1, NULL, NULL }
|
|
};
|
|
|
|
/* csi_intermediate state table. */
|
|
const struct input_transition input_state_csi_intermediate_table[] = {
|
|
INPUT_STATE_ANYWHERE,
|
|
|
|
{ 0x00, 0x17, input_c0_dispatch, NULL },
|
|
{ 0x19, 0x19, input_c0_dispatch, NULL },
|
|
{ 0x1c, 0x1f, input_c0_dispatch, NULL },
|
|
{ 0x20, 0x2f, input_intermediate, NULL },
|
|
{ 0x30, 0x3f, NULL, &input_state_csi_ignore },
|
|
{ 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
|
|
{ 0x7f, 0xff, NULL, NULL },
|
|
|
|
{ -1, -1, NULL, NULL }
|
|
};
|
|
|
|
/* csi_ignore state table. */
|
|
const struct input_transition input_state_csi_ignore_table[] = {
|
|
INPUT_STATE_ANYWHERE,
|
|
|
|
{ 0x00, 0x17, input_c0_dispatch, NULL },
|
|
{ 0x19, 0x19, input_c0_dispatch, NULL },
|
|
{ 0x1c, 0x1f, input_c0_dispatch, NULL },
|
|
{ 0x20, 0x3f, NULL, NULL },
|
|
{ 0x40, 0x7e, NULL, &input_state_ground },
|
|
{ 0x7f, 0xff, NULL, NULL },
|
|
|
|
{ -1, -1, NULL, NULL }
|
|
};
|
|
|
|
/* dcs_enter state table. */
|
|
const struct input_transition input_state_dcs_enter_table[] = {
|
|
INPUT_STATE_ANYWHERE,
|
|
|
|
{ 0x00, 0x17, NULL, NULL },
|
|
{ 0x19, 0x19, NULL, NULL },
|
|
{ 0x1c, 0x1f, NULL, NULL },
|
|
{ 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
|
|
{ 0x30, 0x39, input_parameter, &input_state_dcs_parameter },
|
|
{ 0x3a, 0x3a, NULL, &input_state_dcs_ignore },
|
|
{ 0x3b, 0x3b, input_parameter, &input_state_dcs_parameter },
|
|
{ 0x3c, 0x3f, input_intermediate, &input_state_dcs_parameter },
|
|
{ 0x40, 0x7e, NULL, &input_state_dcs_handler },
|
|
{ 0x7f, 0xff, NULL, NULL },
|
|
|
|
{ -1, -1, NULL, NULL }
|
|
};
|
|
|
|
/* dcs_parameter state table. */
|
|
const struct input_transition input_state_dcs_parameter_table[] = {
|
|
INPUT_STATE_ANYWHERE,
|
|
|
|
{ 0x00, 0x17, NULL, NULL },
|
|
{ 0x19, 0x19, NULL, NULL },
|
|
{ 0x1c, 0x1f, NULL, NULL },
|
|
{ 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
|
|
{ 0x30, 0x39, input_parameter, NULL },
|
|
{ 0x3a, 0x3a, NULL, &input_state_dcs_ignore },
|
|
{ 0x3b, 0x3b, input_parameter, NULL },
|
|
{ 0x3c, 0x3f, NULL, &input_state_dcs_ignore },
|
|
{ 0x40, 0x7e, NULL, &input_state_dcs_handler },
|
|
{ 0x7f, 0xff, NULL, NULL },
|
|
|
|
{ -1, -1, NULL, NULL }
|
|
};
|
|
|
|
/* dcs_interm state table. */
|
|
const struct input_transition input_state_dcs_intermediate_table[] = {
|
|
INPUT_STATE_ANYWHERE,
|
|
|
|
{ 0x00, 0x17, NULL, NULL },
|
|
{ 0x19, 0x19, NULL, NULL },
|
|
{ 0x1c, 0x1f, NULL, NULL },
|
|
{ 0x20, 0x2f, input_intermediate, NULL },
|
|
{ 0x30, 0x3f, NULL, &input_state_dcs_ignore },
|
|
{ 0x40, 0x7e, NULL, &input_state_dcs_handler },
|
|
{ 0x7f, 0xff, NULL, NULL },
|
|
|
|
{ -1, -1, NULL, NULL }
|
|
};
|
|
|
|
/* dcs_handler state table. */
|
|
const struct input_transition input_state_dcs_handler_table[] = {
|
|
INPUT_STATE_ANYWHERE,
|
|
|
|
{ 0x00, 0x17, NULL, NULL },
|
|
{ 0x19, 0x19, input_input, NULL },
|
|
{ 0x1c, 0x1f, input_input, NULL },
|
|
{ 0x20, 0x7e, input_input, NULL },
|
|
{ 0x7f, 0xff, NULL, NULL },
|
|
|
|
{ -1, -1, NULL, NULL }
|
|
};
|
|
|
|
/* device_ignore state table. */
|
|
const struct input_transition input_state_dcs_ignore_table[] = {
|
|
INPUT_STATE_ANYWHERE,
|
|
|
|
{ 0x00, 0x17, NULL, NULL },
|
|
{ 0x19, 0x19, NULL, NULL },
|
|
{ 0x1c, 0x1f, NULL, NULL },
|
|
{ 0x20, 0xff, NULL, NULL },
|
|
|
|
{ -1, -1, NULL, NULL }
|
|
};
|
|
|
|
/* osc_string state table. */
|
|
const struct input_transition input_state_osc_string_table[] = {
|
|
INPUT_STATE_ANYWHERE,
|
|
|
|
{ 0x00, 0x06, NULL, NULL },
|
|
{ 0x07, 0x07, NULL, &input_state_ground },
|
|
{ 0x08, 0x17, NULL, NULL },
|
|
{ 0x19, 0x19, NULL, NULL },
|
|
{ 0x1c, 0x1f, NULL, NULL },
|
|
{ 0x20, 0xff, input_input, NULL },
|
|
|
|
{ -1, -1, NULL, NULL }
|
|
};
|
|
|
|
/* apc_string state table. */
|
|
const struct input_transition input_state_apc_string_table[] = {
|
|
INPUT_STATE_ANYWHERE,
|
|
|
|
{ 0x00, 0x17, NULL, NULL },
|
|
{ 0x19, 0x19, NULL, NULL },
|
|
{ 0x1c, 0x1f, NULL, NULL },
|
|
{ 0x20, 0xff, input_input, NULL },
|
|
|
|
{ -1, -1, NULL, NULL }
|
|
};
|
|
|
|
/* rename_string state table. */
|
|
const struct input_transition input_state_rename_string_table[] = {
|
|
INPUT_STATE_ANYWHERE,
|
|
|
|
{ 0x00, 0x17, NULL, NULL },
|
|
{ 0x19, 0x19, NULL, NULL },
|
|
{ 0x1c, 0x1f, NULL, NULL },
|
|
{ 0x20, 0xff, input_input, NULL },
|
|
|
|
{ -1, -1, NULL, NULL }
|
|
};
|
|
|
|
/* consume_st state table. */
|
|
const struct input_transition input_state_consume_st_table[] = {
|
|
INPUT_STATE_ANYWHERE,
|
|
|
|
{ 0x00, 0x17, NULL, NULL },
|
|
{ 0x19, 0x19, NULL, NULL },
|
|
{ 0x1c, 0x1f, NULL, NULL },
|
|
{ 0x20, 0xff, NULL, NULL },
|
|
|
|
{ -1, -1, NULL, NULL }
|
|
};
|
|
|
|
/* utf8_three state table. */
|
|
const struct input_transition input_state_utf8_three_table[] = {
|
|
/* No INPUT_STATE_ANYWHERE */
|
|
|
|
{ 0x00, 0x7f, NULL, &input_state_ground },
|
|
{ 0x80, 0xbf, input_utf8_add, &input_state_utf8_two },
|
|
{ 0xc0, 0xff, NULL, &input_state_ground },
|
|
|
|
{ -1, -1, NULL, NULL }
|
|
};
|
|
|
|
/* utf8_two state table. */
|
|
const struct input_transition input_state_utf8_two_table[] = {
|
|
/* No INPUT_STATE_ANYWHERE */
|
|
|
|
{ 0x00, 0x7f, NULL, &input_state_ground },
|
|
{ 0x80, 0xbf, input_utf8_add, &input_state_utf8_one },
|
|
{ 0xc0, 0xff, NULL, &input_state_ground },
|
|
|
|
{ -1, -1, NULL, NULL }
|
|
};
|
|
|
|
/* utf8_one state table. */
|
|
const struct input_transition input_state_utf8_one_table[] = {
|
|
/* No INPUT_STATE_ANYWHERE */
|
|
|
|
{ 0x00, 0x7f, NULL, &input_state_ground },
|
|
{ 0x80, 0xbf, input_utf8_close, &input_state_ground },
|
|
{ 0xc0, 0xff, NULL, &input_state_ground },
|
|
|
|
{ -1, -1, NULL, NULL }
|
|
};
|
|
|
|
/* Input table compare. */
|
|
int
|
|
input_table_compare(const void *key, const void *value)
|
|
{
|
|
const struct input_ctx *ictx = key;
|
|
const struct input_table_entry *entry = value;
|
|
|
|
if (ictx->ch != entry->ch)
|
|
return (ictx->ch - entry->ch);
|
|
return (strcmp(ictx->interm_buf, entry->interm));
|
|
}
|
|
|
|
/* Initialise input parser. */
|
|
void
|
|
input_init(struct window_pane *wp)
|
|
{
|
|
struct input_ctx *ictx = &wp->ictx;
|
|
|
|
memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
|
|
|
|
memcpy(&ictx->old_cell, &grid_default_cell, sizeof ictx->old_cell);
|
|
ictx->old_cx = 0;
|
|
ictx->old_cy = 0;
|
|
|
|
*ictx->interm_buf = '\0';
|
|
ictx->interm_len = 0;
|
|
|
|
*ictx->param_buf = '\0';
|
|
ictx->param_len = 0;
|
|
|
|
ictx->state = &input_state_ground;
|
|
ictx->flags = 0;
|
|
}
|
|
|
|
/* Destroy input parser. */
|
|
void
|
|
input_free(unused struct window_pane *wp)
|
|
{
|
|
}
|
|
|
|
/* Parse input. */
|
|
void
|
|
input_parse(struct window_pane *wp)
|
|
{
|
|
struct input_ctx *ictx = &wp->ictx;
|
|
const struct input_transition *itr;
|
|
struct evbuffer *evb = wp->event->input;
|
|
u_char *buf;
|
|
size_t len, off;
|
|
|
|
if (EVBUFFER_LENGTH(evb) == 0)
|
|
return;
|
|
|
|
wp->window->flags |= WINDOW_ACTIVITY;
|
|
wp->window->flags &= ~WINDOW_SILENCE;
|
|
|
|
/*
|
|
* Open the screen. Use NULL wp if there is a mode set as don't want to
|
|
* update the tty.
|
|
*/
|
|
if (wp->mode == NULL)
|
|
screen_write_start(&ictx->ctx, wp, &wp->base);
|
|
else
|
|
screen_write_start(&ictx->ctx, NULL, &wp->base);
|
|
ictx->wp = wp;
|
|
|
|
buf = EVBUFFER_DATA(evb);
|
|
len = EVBUFFER_LENGTH(evb);
|
|
off = 0;
|
|
|
|
/* Parse the input. */
|
|
while (off < len) {
|
|
ictx->ch = buf[off++];
|
|
log_debug("%s: '%c' %s", __func__, ictx->ch, ictx->state->name);
|
|
|
|
/* Find the transition. */
|
|
itr = ictx->state->transitions;
|
|
while (itr->first != -1 && itr->last != -1) {
|
|
if (ictx->ch >= itr->first && ictx->ch <= itr->last)
|
|
break;
|
|
itr++;
|
|
}
|
|
if (itr->first == -1 || itr->last == -1) {
|
|
/* No transition? Eh? */
|
|
fatalx("No transition from state!");
|
|
}
|
|
|
|
/*
|
|
* Execute the handler, if any. Don't switch state if it
|
|
* returns non-zero.
|
|
*/
|
|
if (itr->handler != NULL && itr->handler(ictx) != 0)
|
|
continue;
|
|
|
|
/* And switch state, if necessary. */
|
|
if (itr->state != NULL) {
|
|
if (ictx->state->exit != NULL)
|
|
ictx->state->exit(ictx);
|
|
ictx->state = itr->state;
|
|
if (ictx->state->enter != NULL)
|
|
ictx->state->enter(ictx);
|
|
}
|
|
}
|
|
|
|
/* Close the screen. */
|
|
screen_write_stop(&ictx->ctx);
|
|
|
|
evbuffer_drain(evb, len);
|
|
}
|
|
|
|
/* Split the parameter list (if any). */
|
|
int
|
|
input_split(struct input_ctx *ictx)
|
|
|
|
{
|
|
const char *errstr;
|
|
char *ptr, *out;
|
|
int n;
|
|
|
|
ictx->param_list_len = 0;
|
|
if (ictx->param_len == 0)
|
|
return (0);
|
|
|
|
ptr = ictx->param_buf;
|
|
while ((out = strsep(&ptr, ";")) != NULL) {
|
|
if (*out == '\0')
|
|
n = -1;
|
|
else {
|
|
n = strtonum(out, 0, INT_MAX, &errstr);
|
|
if (errstr != NULL)
|
|
return (-1);
|
|
}
|
|
|
|
ictx->param_list[ictx->param_list_len++] = n;
|
|
if (ictx->param_list_len == nitems(ictx->param_list))
|
|
return (-1);
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
/* Get an argument or return default value..*/
|
|
int
|
|
input_get(struct input_ctx *ictx, u_int validx, int minval, int defval)
|
|
{
|
|
int retval;
|
|
|
|
if (validx >= ictx->param_list_len)
|
|
return (defval);
|
|
|
|
retval = ictx->param_list[validx];
|
|
if (retval == -1)
|
|
return (defval);
|
|
if (retval < minval)
|
|
return (minval);
|
|
return (retval);
|
|
}
|
|
|
|
/* Reply to terminal query. */
|
|
void
|
|
input_reply(struct input_ctx *ictx, const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
char *reply;
|
|
|
|
va_start(ap, fmt);
|
|
vasprintf(&reply, fmt, ap);
|
|
va_end(ap);
|
|
|
|
bufferevent_write(ictx->wp->event, reply, strlen(reply));
|
|
xfree(reply);
|
|
}
|
|
|
|
/* Clear saved state. */
|
|
void
|
|
input_clear(struct input_ctx *ictx)
|
|
{
|
|
*ictx->interm_buf = '\0';
|
|
ictx->interm_len = 0;
|
|
|
|
*ictx->param_buf = '\0';
|
|
ictx->param_len = 0;
|
|
|
|
ictx->flags &= ~INPUT_DISCARD;
|
|
}
|
|
|
|
/* Output this character to the screen. */
|
|
int
|
|
input_print(struct input_ctx *ictx)
|
|
{
|
|
ictx->cell.data = ictx->ch;
|
|
screen_write_cell(&ictx->ctx, &ictx->cell, NULL);
|
|
|
|
return (0);
|
|
}
|
|
|
|
/* Collect intermediate string. */
|
|
int
|
|
input_intermediate(struct input_ctx *ictx)
|
|
{
|
|
if (ictx->interm_len == (sizeof ictx->interm_buf) - 1)
|
|
ictx->flags |= INPUT_DISCARD;
|
|
else {
|
|
ictx->interm_buf[ictx->interm_len++] = ictx->ch;
|
|
ictx->interm_buf[ictx->interm_len] = '\0';
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
/* Collect parameter string. */
|
|
int
|
|
input_parameter(struct input_ctx *ictx)
|
|
{
|
|
if (ictx->param_len == (sizeof ictx->param_buf) - 1)
|
|
ictx->flags |= INPUT_DISCARD;
|
|
else {
|
|
ictx->param_buf[ictx->param_len++] = ictx->ch;
|
|
ictx->param_buf[ictx->param_len] = '\0';
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
/* Collect input string. */
|
|
int
|
|
input_input(struct input_ctx *ictx)
|
|
{
|
|
if (ictx->input_len == (sizeof ictx->input_buf) - 1)
|
|
ictx->flags |= INPUT_DISCARD;
|
|
else {
|
|
ictx->input_buf[ictx->input_len++] = ictx->ch;
|
|
ictx->input_buf[ictx->input_len] = '\0';
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
/* Execute C0 control sequence. */
|
|
int
|
|
input_c0_dispatch(struct input_ctx *ictx)
|
|
{
|
|
struct screen_write_ctx *sctx = &ictx->ctx;
|
|
struct window_pane *wp = ictx->wp;
|
|
struct screen *s = sctx->s;
|
|
|
|
log_debug("%s: '%c", __func__, ictx->ch);
|
|
|
|
switch (ictx->ch) {
|
|
case '\000': /* NUL */
|
|
break;
|
|
case '\007': /* BEL */
|
|
wp->window->flags |= WINDOW_BELL;
|
|
break;
|
|
case '\010': /* BS */
|
|
screen_write_backspace(sctx);
|
|
break;
|
|
case '\011': /* HT */
|
|
/* Don't tab beyond the end of the line. */
|
|
if (s->cx >= screen_size_x(s) - 1)
|
|
break;
|
|
|
|
/* Find the next tab point, or use the last column if none. */
|
|
do {
|
|
s->cx++;
|
|
if (bit_test(s->tabs, s->cx))
|
|
break;
|
|
} while (s->cx < screen_size_x(s) - 1);
|
|
break;
|
|
case '\012': /* LF */
|
|
case '\013': /* VT */
|
|
case '\014': /* FF */
|
|
screen_write_linefeed(sctx, 0);
|
|
break;
|
|
case '\015': /* CR */
|
|
screen_write_carriagereturn(sctx);
|
|
break;
|
|
case '\016': /* SO */
|
|
ictx->cell.attr |= GRID_ATTR_CHARSET;
|
|
break;
|
|
case '\017': /* SI */
|
|
ictx->cell.attr &= ~GRID_ATTR_CHARSET;
|
|
break;
|
|
default:
|
|
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
|
break;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
/* Execute escape sequence. */
|
|
int
|
|
input_esc_dispatch(struct input_ctx *ictx)
|
|
{
|
|
struct screen_write_ctx *sctx = &ictx->ctx;
|
|
struct screen *s = sctx->s;
|
|
struct input_table_entry *entry;
|
|
|
|
if (ictx->flags & INPUT_DISCARD)
|
|
return (0);
|
|
log_debug("%s: '%c', %s", __func__, ictx->ch, ictx->interm_buf);
|
|
|
|
entry = bsearch(ictx, input_esc_table, nitems(input_esc_table),
|
|
sizeof input_esc_table[0], input_table_compare);
|
|
if (entry == NULL) {
|
|
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
|
return (0);
|
|
}
|
|
|
|
switch (entry->type) {
|
|
case INPUT_ESC_RIS:
|
|
memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
|
|
memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
|
|
ictx->old_cx = 0;
|
|
ictx->old_cy = 0;
|
|
|
|
screen_reset_tabs(sctx->s);
|
|
|
|
screen_write_scrollregion(sctx, 0, screen_size_y(sctx->s) - 1);
|
|
|
|
screen_write_insertmode(sctx, 0);
|
|
screen_write_kcursormode(sctx, 0);
|
|
screen_write_kkeypadmode(sctx, 0);
|
|
screen_write_mousemode_off(sctx);
|
|
|
|
screen_write_clearscreen(sctx);
|
|
screen_write_cursormove(sctx, 0, 0);
|
|
break;
|
|
case INPUT_ESC_IND:
|
|
screen_write_linefeed(sctx, 0);
|
|
break;
|
|
case INPUT_ESC_NEL:
|
|
screen_write_carriagereturn(sctx);
|
|
screen_write_linefeed(sctx, 0);
|
|
break;
|
|
case INPUT_ESC_HTS:
|
|
if (s->cx < screen_size_x(s))
|
|
bit_set(s->tabs, s->cx);
|
|
break;
|
|
case INPUT_ESC_RI:
|
|
screen_write_reverseindex(sctx);
|
|
break;
|
|
case INPUT_ESC_DECKPAM:
|
|
screen_write_kkeypadmode(sctx, 1);
|
|
break;
|
|
case INPUT_ESC_DECKPNM:
|
|
screen_write_kkeypadmode(sctx, 0);
|
|
break;
|
|
case INPUT_ESC_DECSC:
|
|
memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
|
|
ictx->old_cx = s->cx;
|
|
ictx->old_cy = s->cy;
|
|
break;
|
|
case INPUT_ESC_DECRC:
|
|
memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell);
|
|
screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy);
|
|
break;
|
|
case INPUT_ESC_DECALN:
|
|
screen_write_alignmenttest(sctx);
|
|
break;
|
|
case INPUT_ESC_SCSON_G0:
|
|
/*
|
|
* Not really supported, but fake it up enough for those that
|
|
* use it to switch character sets (by redefining G0 to
|
|
* graphics set, rather than switching to G1).
|
|
*/
|
|
ictx->cell.attr &= ~GRID_ATTR_CHARSET;
|
|
break;
|
|
case INPUT_ESC_SCSOFF_G0:
|
|
ictx->cell.attr |= GRID_ATTR_CHARSET;
|
|
break;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
/* Execute control sequence. */
|
|
int
|
|
input_csi_dispatch(struct input_ctx *ictx)
|
|
{
|
|
struct screen_write_ctx *sctx = &ictx->ctx;
|
|
struct window_pane *wp = ictx->wp;
|
|
struct screen *s = sctx->s;
|
|
struct input_table_entry *entry;
|
|
int n, m;
|
|
|
|
if (ictx->flags & INPUT_DISCARD)
|
|
return (0);
|
|
if (input_split(ictx) != 0)
|
|
return (0);
|
|
log_debug("%s: '%c' \"%s\" \"%s\"",
|
|
__func__, ictx->ch, ictx->interm_buf, ictx->param_buf);
|
|
|
|
entry = bsearch(ictx, input_csi_table, nitems(input_csi_table),
|
|
sizeof input_csi_table[0], input_table_compare);
|
|
if (entry == NULL) {
|
|
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
|
return (0);
|
|
}
|
|
|
|
switch (entry->type) {
|
|
case INPUT_CSI_CBT:
|
|
/* Find the previous tab point, n times. */
|
|
n = input_get(ictx, 0, 1, 1);
|
|
while (s->cx > 0 && n-- > 0) {
|
|
do
|
|
s->cx--;
|
|
while (s->cx > 0 && !bit_test(s->tabs, s->cx));
|
|
}
|
|
break;
|
|
case INPUT_CSI_CUB:
|
|
screen_write_cursorleft(sctx, input_get(ictx, 0, 1, 1));
|
|
break;
|
|
case INPUT_CSI_CUD:
|
|
screen_write_cursordown(sctx, input_get(ictx, 0, 1, 1));
|
|
break;
|
|
case INPUT_CSI_CUF:
|
|
screen_write_cursorright(sctx, input_get(ictx, 0, 1, 1));
|
|
break;
|
|
case INPUT_CSI_CUP:
|
|
n = input_get(ictx, 0, 1, 1);
|
|
m = input_get(ictx, 1, 1, 1);
|
|
screen_write_cursormove(sctx, m - 1, n - 1);
|
|
break;
|
|
case INPUT_CSI_CUU:
|
|
screen_write_cursorup(sctx, input_get(ictx, 0, 1, 1));
|
|
break;
|
|
case INPUT_CSI_DA:
|
|
switch (input_get(ictx, 0, 0, 0)) {
|
|
case 0:
|
|
input_reply(ictx, "\033[?1;2c");
|
|
break;
|
|
default:
|
|
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
|
break;
|
|
}
|
|
break;
|
|
case INPUT_CSI_DCH:
|
|
screen_write_deletecharacter(sctx, input_get(ictx, 0, 1, 1));
|
|
break;
|
|
case INPUT_CSI_DECSTBM:
|
|
n = input_get(ictx, 0, 1, 1);
|
|
m = input_get(ictx, 1, 1, screen_size_y(s));
|
|
screen_write_scrollregion(sctx, n - 1, m - 1);
|
|
break;
|
|
case INPUT_CSI_DL:
|
|
screen_write_deleteline(sctx, input_get(ictx, 0, 1, 1));
|
|
break;
|
|
case INPUT_CSI_DSR:
|
|
switch (input_get(ictx, 0, 0, 0)) {
|
|
case 5:
|
|
input_reply(ictx, "\033[0n");
|
|
break;
|
|
case 6:
|
|
input_reply(ictx, "\033[%u;%uR", s->cy + 1, s->cx + 1);
|
|
break;
|
|
default:
|
|
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
|
break;
|
|
}
|
|
break;
|
|
case INPUT_CSI_ED:
|
|
switch (input_get(ictx, 0, 0, 0)) {
|
|
case 0:
|
|
screen_write_clearendofscreen(sctx);
|
|
break;
|
|
case 1:
|
|
screen_write_clearstartofscreen(sctx);
|
|
break;
|
|
case 2:
|
|
screen_write_clearscreen(sctx);
|
|
break;
|
|
default:
|
|
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
|
break;
|
|
}
|
|
break;
|
|
case INPUT_CSI_EL:
|
|
switch (input_get(ictx, 0, 0, 0)) {
|
|
case 0:
|
|
screen_write_clearendofline(sctx);
|
|
break;
|
|
case 1:
|
|
screen_write_clearstartofline(sctx);
|
|
break;
|
|
case 2:
|
|
screen_write_clearline(sctx);
|
|
break;
|
|
default:
|
|
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
|
break;
|
|
}
|
|
break;
|
|
case INPUT_CSI_HPA:
|
|
n = input_get(ictx, 0, 1, 1);
|
|
screen_write_cursormove(sctx, n - 1, s->cy);
|
|
break;
|
|
case INPUT_CSI_ICH:
|
|
screen_write_insertcharacter(sctx, input_get(ictx, 0, 1, 1));
|
|
break;
|
|
case INPUT_CSI_IL:
|
|
screen_write_insertline(sctx, input_get(ictx, 0, 1, 1));
|
|
break;
|
|
case INPUT_CSI_RM:
|
|
switch (input_get(ictx, 0, 0, -1)) {
|
|
case 4: /* IRM */
|
|
screen_write_insertmode(&ictx->ctx, 0);
|
|
break;
|
|
default:
|
|
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
|
break;
|
|
}
|
|
break;
|
|
case INPUT_CSI_RM_PRIVATE:
|
|
switch (input_get(ictx, 0, 0, -1)) {
|
|
case 1: /* GATM */
|
|
screen_write_kcursormode(&ictx->ctx, 0);
|
|
break;
|
|
case 3: /* DECCOLM */
|
|
screen_write_cursormove(&ictx->ctx, 0, 0);
|
|
screen_write_clearscreen(&ictx->ctx);
|
|
break;
|
|
case 25: /* TCEM */
|
|
screen_write_cursormode(&ictx->ctx, 0);
|
|
break;
|
|
case 1000:
|
|
case 1001:
|
|
case 1002:
|
|
case 1003:
|
|
screen_write_mousemode_off(&ictx->ctx);
|
|
break;
|
|
case 1005:
|
|
screen_write_utf8mousemode(&ictx->ctx, 0);
|
|
break;
|
|
case 1049:
|
|
window_pane_alternate_off(wp, &ictx->cell);
|
|
break;
|
|
default:
|
|
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
|
break;
|
|
}
|
|
break;
|
|
case INPUT_CSI_SGR:
|
|
input_csi_dispatch_sgr(ictx);
|
|
break;
|
|
case INPUT_CSI_SM:
|
|
switch (input_get(ictx, 0, 0, -1)) {
|
|
case 4: /* IRM */
|
|
screen_write_insertmode(&ictx->ctx, 1);
|
|
break;
|
|
default:
|
|
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
|
break;
|
|
}
|
|
break;
|
|
case INPUT_CSI_SM_PRIVATE:
|
|
switch (input_get(ictx, 0, 0, -1)) {
|
|
case 1: /* GATM */
|
|
screen_write_kcursormode(&ictx->ctx, 1);
|
|
break;
|
|
case 3: /* DECCOLM */
|
|
screen_write_cursormove(&ictx->ctx, 0, 0);
|
|
screen_write_clearscreen(&ictx->ctx);
|
|
break;
|
|
case 25: /* TCEM */
|
|
screen_write_cursormode(&ictx->ctx, 1);
|
|
break;
|
|
case 1000:
|
|
screen_write_mousemode_on(
|
|
&ictx->ctx, MODE_MOUSE_STANDARD);
|
|
break;
|
|
case 1001:
|
|
screen_write_mousemode_on(
|
|
&ictx->ctx, MODE_MOUSE_HIGHLIGHT);
|
|
break;
|
|
case 1002:
|
|
screen_write_mousemode_on(
|
|
&ictx->ctx, MODE_MOUSE_BUTTON);
|
|
break;
|
|
case 1003:
|
|
screen_write_mousemode_on(&ictx->ctx, MODE_MOUSE_ANY);
|
|
break;
|
|
case 1005:
|
|
screen_write_utf8mousemode(&ictx->ctx, 1);
|
|
break;
|
|
case 1049:
|
|
window_pane_alternate_on(wp, &ictx->cell);
|
|
break;
|
|
default:
|
|
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
|
break;
|
|
}
|
|
break;
|
|
case INPUT_CSI_TBC:
|
|
switch (input_get(ictx, 0, 0, 0)) {
|
|
case 0:
|
|
if (s->cx < screen_size_x(s))
|
|
bit_clear(s->tabs, s->cx);
|
|
break;
|
|
case 3:
|
|
bit_nclear(s->tabs, 0, screen_size_x(s) - 1);
|
|
break;
|
|
default:
|
|
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
|
break;
|
|
}
|
|
break;
|
|
case INPUT_CSI_VPA:
|
|
n = input_get(ictx, 0, 1, 1);
|
|
screen_write_cursormove(sctx, s->cx, n - 1);
|
|
break;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
/* Handle CSI SGR. */
|
|
void
|
|
input_csi_dispatch_sgr(struct input_ctx *ictx)
|
|
{
|
|
struct grid_cell *gc = &ictx->cell;
|
|
u_int i;
|
|
int n, m;
|
|
u_char attr;
|
|
|
|
if (ictx->param_list_len == 0) {
|
|
attr = gc->attr;
|
|
memcpy(gc, &grid_default_cell, sizeof *gc);
|
|
gc->attr |= (attr & GRID_ATTR_CHARSET);
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < ictx->param_list_len; i++) {
|
|
n = input_get(ictx, i, 0, 0);
|
|
|
|
if (n == 38 || n == 48) {
|
|
i++;
|
|
if (input_get(ictx, i, 0, -1) != 5)
|
|
continue;
|
|
|
|
i++;
|
|
m = input_get(ictx, i, 0, -1);
|
|
if (m == -1) {
|
|
if (n == 38) {
|
|
gc->flags &= ~GRID_FLAG_FG256;
|
|
gc->fg = 8;
|
|
} else if (n == 48) {
|
|
gc->flags &= ~GRID_FLAG_BG256;
|
|
gc->fg = 8;
|
|
}
|
|
|
|
} else {
|
|
if (n == 38) {
|
|
gc->flags |= GRID_FLAG_FG256;
|
|
gc->fg = m;
|
|
} else if (n == 48) {
|
|
gc->flags |= GRID_FLAG_BG256;
|
|
gc->bg = m;
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
switch (n) {
|
|
case 0:
|
|
case 10:
|
|
attr = gc->attr;
|
|
memcpy(gc, &grid_default_cell, sizeof *gc);
|
|
gc->attr |= (attr & GRID_ATTR_CHARSET);
|
|
break;
|
|
case 1:
|
|
gc->attr |= GRID_ATTR_BRIGHT;
|
|
break;
|
|
case 2:
|
|
gc->attr |= GRID_ATTR_DIM;
|
|
break;
|
|
case 3:
|
|
gc->attr |= GRID_ATTR_ITALICS;
|
|
break;
|
|
case 4:
|
|
gc->attr |= GRID_ATTR_UNDERSCORE;
|
|
break;
|
|
case 5:
|
|
gc->attr |= GRID_ATTR_BLINK;
|
|
break;
|
|
case 7:
|
|
gc->attr |= GRID_ATTR_REVERSE;
|
|
break;
|
|
case 8:
|
|
gc->attr |= GRID_ATTR_HIDDEN;
|
|
break;
|
|
case 22:
|
|
gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM);
|
|
break;
|
|
case 23:
|
|
gc->attr &= ~GRID_ATTR_ITALICS;
|
|
break;
|
|
case 24:
|
|
gc->attr &= ~GRID_ATTR_UNDERSCORE;
|
|
break;
|
|
case 25:
|
|
gc->attr &= ~GRID_ATTR_BLINK;
|
|
break;
|
|
case 27:
|
|
gc->attr &= ~GRID_ATTR_REVERSE;
|
|
break;
|
|
case 30:
|
|
case 31:
|
|
case 32:
|
|
case 33:
|
|
case 34:
|
|
case 35:
|
|
case 36:
|
|
case 37:
|
|
gc->flags &= ~GRID_FLAG_FG256;
|
|
gc->fg = n - 30;
|
|
break;
|
|
case 39:
|
|
gc->flags &= ~GRID_FLAG_FG256;
|
|
gc->fg = 8;
|
|
break;
|
|
case 40:
|
|
case 41:
|
|
case 42:
|
|
case 43:
|
|
case 44:
|
|
case 45:
|
|
case 46:
|
|
case 47:
|
|
gc->flags &= ~GRID_FLAG_BG256;
|
|
gc->bg = n - 40;
|
|
break;
|
|
case 49:
|
|
gc->flags &= ~GRID_FLAG_BG256;
|
|
gc->bg = 8;
|
|
break;
|
|
case 90:
|
|
case 91:
|
|
case 92:
|
|
case 93:
|
|
case 94:
|
|
case 95:
|
|
case 96:
|
|
case 97:
|
|
gc->flags &= ~GRID_FLAG_FG256;
|
|
gc->fg = n;
|
|
break;
|
|
case 100:
|
|
case 101:
|
|
case 102:
|
|
case 103:
|
|
case 104:
|
|
case 105:
|
|
case 106:
|
|
case 107:
|
|
gc->flags &= ~GRID_FLAG_BG256;
|
|
gc->bg = n;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* DCS string started. */
|
|
void
|
|
input_enter_dcs(struct input_ctx *ictx)
|
|
{
|
|
log_debug("%s", __func__);
|
|
|
|
ictx->input_len = 0;
|
|
}
|
|
|
|
/* DCS terminator (ST) received. */
|
|
void
|
|
input_exit_dcs(unused struct input_ctx *ictx)
|
|
{
|
|
log_debug("%s", __func__);
|
|
}
|
|
|
|
/* OSC string started. */
|
|
void
|
|
input_enter_osc(struct input_ctx *ictx)
|
|
{
|
|
log_debug("%s", __func__);
|
|
|
|
ictx->input_len = 0;
|
|
}
|
|
|
|
/* OSC terminator (ST) received. */
|
|
void
|
|
input_exit_osc(struct input_ctx *ictx)
|
|
{
|
|
if (ictx->flags & INPUT_DISCARD)
|
|
return;
|
|
log_debug("%s: \"%s\"", __func__, ictx->input_buf);
|
|
|
|
if (ictx->input_len < 2 || ictx->input_buf[1] != ';')
|
|
return;
|
|
if (ictx->input_buf[0] != '0' && ictx->input_buf[0] != '2')
|
|
return;
|
|
|
|
screen_set_title(ictx->ctx.s, ictx->input_buf + 2);
|
|
server_status_window(ictx->wp->window);
|
|
}
|
|
|
|
/* APC string started. */
|
|
void
|
|
input_enter_apc(struct input_ctx *ictx)
|
|
{
|
|
log_debug("%s", __func__);
|
|
|
|
ictx->input_len = 0;
|
|
}
|
|
|
|
/* APC terminator (ST) received. */
|
|
void
|
|
input_exit_apc(struct input_ctx *ictx)
|
|
{
|
|
if (ictx->flags & INPUT_DISCARD)
|
|
return;
|
|
log_debug("%s: \"%s\"", __func__, ictx->input_buf);
|
|
|
|
screen_set_title(ictx->ctx.s, ictx->input_buf);
|
|
server_status_window(ictx->wp->window);
|
|
}
|
|
|
|
/* Rename string started. */
|
|
void
|
|
input_enter_rename(struct input_ctx *ictx)
|
|
{
|
|
log_debug("%s", __func__);
|
|
|
|
ictx->input_len = 0;
|
|
}
|
|
|
|
/* Rename terminator (ST) received. */
|
|
void
|
|
input_exit_rename(struct input_ctx *ictx)
|
|
{
|
|
if (ictx->flags & INPUT_DISCARD)
|
|
return;
|
|
log_debug("%s: \"%s\"", __func__, ictx->input_buf);
|
|
|
|
xfree(ictx->wp->window->name);
|
|
ictx->wp->window->name = xstrdup(ictx->input_buf);
|
|
options_set_number(&ictx->wp->window->options, "automatic-rename", 0);
|
|
|
|
server_status_window(ictx->wp->window);
|
|
}
|
|
|
|
/* Open UTF-8 character. */
|
|
int
|
|
input_utf8_open(struct input_ctx *ictx)
|
|
{
|
|
if (!options_get_number(&ictx->wp->window->options, "utf8")) {
|
|
/* Print, and do not switch state. */
|
|
input_print(ictx);
|
|
return (-1);
|
|
}
|
|
log_debug("%s", __func__);
|
|
|
|
utf8_open(&ictx->utf8data, ictx->ch);
|
|
return (0);
|
|
}
|
|
|
|
/* Append to UTF-8 character. */
|
|
int
|
|
input_utf8_add(struct input_ctx *ictx)
|
|
{
|
|
log_debug("%s", __func__);
|
|
|
|
utf8_append(&ictx->utf8data, ictx->ch);
|
|
return (0);
|
|
}
|
|
|
|
/* Close UTF-8 string. */
|
|
int
|
|
input_utf8_close(struct input_ctx *ictx)
|
|
{
|
|
log_debug("%s", __func__);
|
|
|
|
utf8_append(&ictx->utf8data, ictx->ch);
|
|
|
|
ictx->cell.flags |= GRID_FLAG_UTF8;
|
|
screen_write_cell(&ictx->ctx, &ictx->cell, &ictx->utf8data);
|
|
ictx->cell.flags &= ~GRID_FLAG_UTF8;
|
|
|
|
return (0);
|
|
}
|