1 /*
2 * libtsm - VT Emulator
3 *
4 * Copyright (c) 2018 Aetf <aetf@unlimitedcodeworks.xyz>
5 * Copyright (c) 2011-2013 David Herrmann <dh.herrmann@gmail.com>
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files
9 * (the "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sublicense, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27 /*
28 * Virtual Terminal Emulator
29 * This is the VT implementation. It is written from scratch. It uses the
30 * screen state-machine as output and is tightly bound to it. It supports
31 * functionality from vt100 up to vt500 series. It doesn't implement an
32 * explicitly selected terminal but tries to support the most important commands
33 * to be compatible with existing implementations. However, full vt102
34 * compatibility is the least that is provided.
35 *
36 * The main parser in this file controls the parser-state and dispatches the
37 * actions to the related handlers. The parser is based on the state-diagram
38 * from Paul Williams: http://vt100.net/emu/
39 * It is written from scratch, though.
40 * This parser is fully compatible up to the vt500 series. It requires UTF-8 and
41 * does not support any other input encoding. The G0 and G1 sets are therefore
42 * defined as subsets of UTF-8. You may still map G0-G3 into GL, though.
43 *
44 * However, the CSI/DCS/etc handlers are not designed after a specific VT
45 * series. We try to support all vt102 commands but implement several other
46 * often used sequences, too. Feel free to add further.
47 */
48
49 #include <errno.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include "libtsm.h"
54 #include "libtsm-int.h"
55 #include "shl-llog.h"
56
57 #include <xkbcommon/xkbcommon-keysyms.h>
58
59 #define LLOG_SUBSYSTEM "tsm-vte"
60
61 /* Input parser states */
62 enum parser_state {
63 STATE_NONE, /* placeholder */
64 STATE_GROUND, /* initial state and ground */
65 STATE_ESC, /* ESC sequence was started */
66 STATE_ESC_INT, /* intermediate escape characters */
67 STATE_CSI_ENTRY, /* starting CSI sequence */
68 STATE_CSI_PARAM, /* CSI parameters */
69 STATE_CSI_INT, /* intermediate CSI characters */
70 STATE_CSI_IGNORE, /* CSI error; ignore this CSI sequence */
71 STATE_DCS_ENTRY, /* starting DCS sequence */
72 STATE_DCS_PARAM, /* DCS parameters */
73 STATE_DCS_INT, /* intermediate DCS characters */
74 STATE_DCS_PASS, /* DCS data passthrough */
75 STATE_DCS_IGNORE, /* DCS error; ignore this DCS sequence */
76 STATE_OSC_STRING, /* parsing OCS sequence */
77 STATE_ST_IGNORE, /* unimplemented seq; ignore until ST */
78 STATE_NUM
79 };
80
81 /* Input parser actions */
82 enum parser_action {
83 ACTION_NONE, /* placeholder */
84 ACTION_IGNORE, /* ignore the character entirely */
85 ACTION_PRINT, /* print the character on the console */
86 ACTION_EXECUTE, /* execute single control character (C0/C1) */
87 ACTION_CLEAR, /* clear current parameter state */
88 ACTION_COLLECT, /* collect intermediate character */
89 ACTION_PARAM, /* collect parameter character */
90 ACTION_ESC_DISPATCH, /* dispatch escape sequence */
91 ACTION_CSI_DISPATCH, /* dispatch csi sequence */
92 ACTION_DCS_START, /* start of DCS data */
93 ACTION_DCS_COLLECT, /* collect DCS data */
94 ACTION_DCS_END, /* end of DCS data */
95 ACTION_OSC_START, /* start of OSC data */
96 ACTION_OSC_COLLECT, /* collect OSC data */
97 ACTION_OSC_END, /* end of OSC data */
98 ACTION_NUM
99 };
100
101 /* CSI flags */
102 #define CSI_BANG 0x0001 /* CSI: ! */
103 #define CSI_CASH 0x0002 /* CSI: $ */
104 #define CSI_WHAT 0x0004 /* CSI: ? */
105 #define CSI_GT 0x0008 /* CSI: > */
106 #define CSI_SPACE 0x0010 /* CSI: */
107 #define CSI_SQUOTE 0x0020 /* CSI: ' */
108 #define CSI_DQUOTE 0x0040 /* CSI: " */
109 #define CSI_MULT 0x0080 /* CSI: * */
110 #define CSI_PLUS 0x0100 /* CSI: + */
111 #define CSI_POPEN 0x0200 /* CSI: ( */
112 #define CSI_PCLOSE 0x0400 /* CSI: ) */
113
114 /* max CSI arguments */
115 #define CSI_ARG_MAX 16
116
117 /* terminal flags */
118 #define FLAG_CURSOR_KEY_MODE 0x00000001 /* DEC cursor key mode */
119 #define FLAG_KEYPAD_APPLICATION_MODE 0x00000002 /* DEC keypad application mode; TODO: toggle on numlock? */
120 #define FLAG_LINE_FEED_NEW_LINE_MODE 0x00000004 /* DEC line-feed/new-line mode */
121 #define FLAG_8BIT_MODE 0x00000008 /* Disable UTF-8 mode and enable 8bit compatible mode */
122 #define FLAG_7BIT_MODE 0x00000010 /* Disable 8bit mode and use 7bit compatible mode */
123 #define FLAG_USE_C1 0x00000020 /* Explicitly use 8bit C1 codes; TODO: implement */
124 #define FLAG_KEYBOARD_ACTION_MODE 0x00000040 /* Disable keyboard; TODO: implement? */
125 #define FLAG_INSERT_REPLACE_MODE 0x00000080 /* Enable insert mode */
126 #define FLAG_SEND_RECEIVE_MODE 0x00000100 /* Disable local echo */
127 #define FLAG_TEXT_CURSOR_MODE 0x00000200 /* Show cursor */
128 #define FLAG_INVERSE_SCREEN_MODE 0x00000400 /* Inverse colors */
129 #define FLAG_ORIGIN_MODE 0x00000800 /* Relative origin for cursor */
130 #define FLAG_AUTO_WRAP_MODE 0x00001000 /* Auto line wrap mode */
131 #define FLAG_AUTO_REPEAT_MODE 0x00002000 /* Auto repeat key press; TODO: implement */
132 #define FLAG_NATIONAL_CHARSET_MODE 0x00004000 /* Send keys from nation charsets; TODO: implement */
133 #define FLAG_BACKGROUND_COLOR_ERASE_MODE 0x00008000 /* Set background color on erase (bce) */
134 #define FLAG_PREPEND_ESCAPE 0x00010000 /* Prepend escape character to next output */
135 #define FLAG_TITE_INHIBIT_MODE 0x00020000 /* Prevent switching to alternate screen buffer */
136 #define FLAG_BRACKETED_PASTE_MODE 0x00040000
137
138 #define ENDPASTE "\e[201~"
139
140 struct vte_saved_state {
141 int cursor_x;
142 int cursor_y;
143 struct tsm_screen_attr cattr;
144 tsm_vte_charset **gl;
145 tsm_vte_charset **gr;
146 bool wrap_mode;
147 bool origin_mode;
148 };
149
150 struct tsm_vte {
151 unsigned long ref;
152 struct tsm_screen *con;
153 tsm_vte_write_cb write_cb;
154 void *data;
155 char *palette_name;
156
157 struct tsm_utf8_mach *mach;
158 unsigned long parse_cnt;
159
160 unsigned int state;
161 tsm_symbol_t last_sym;
162 int csi_argc;
163 int csi_argv[CSI_ARG_MAX];
164 unsigned int csi_flags;
165
166 uint8_t (*palette)[3];
167 struct tsm_screen_attr def_attr;
168 struct tsm_screen_attr cattr;
169 unsigned int flags;
170
171 tsm_vte_charset **gl;
172 tsm_vte_charset **gr;
173 tsm_vte_charset **glt;
174 tsm_vte_charset **grt;
175 tsm_vte_charset *g0;
176 tsm_vte_charset *g1;
177 tsm_vte_charset *g2;
178 tsm_vte_charset *g3;
179
180 struct vte_saved_state saved_state;
181 int alt_cursor_x;
182 int alt_cursor_y;
183
184 bool pasting;
185 int endpaste_i;
186 };
187
188 static uint8_t default_palette[TSM_COLOR_NUM][3] = {
189 [TSM_COLOR_BLACK] = { 0, 0, 0 }, /* black */
190 [TSM_COLOR_RED] = { 205, 0, 0 }, /* red */
191 [TSM_COLOR_GREEN] = { 0, 205, 0 }, /* green */
192 [TSM_COLOR_YELLOW] = { 205, 205, 0 }, /* yellow */
193 [TSM_COLOR_BLUE] = { 0, 0, 238 }, /* blue */
194 [TSM_COLOR_MAGENTA] = { 205, 0, 205 }, /* magenta */
195 [TSM_COLOR_CYAN] = { 0, 205, 205 }, /* cyan */
196 [TSM_COLOR_LIGHT_GREY] = { 229, 229, 229 }, /* light grey */
197 [TSM_COLOR_DARK_GREY] = { 127, 127, 127 }, /* dark grey */
198 [TSM_COLOR_LIGHT_RED] = { 255, 0, 0 }, /* light red */
199 [TSM_COLOR_LIGHT_GREEN] = { 0, 255, 0 }, /* light green */
200 [TSM_COLOR_LIGHT_YELLOW] = { 255, 255, 0 }, /* light yellow */
201 [TSM_COLOR_LIGHT_BLUE] = { 92, 92, 255 }, /* light blue */
202 [TSM_COLOR_LIGHT_MAGENTA] = { 255, 0, 255 }, /* light magenta */
203 [TSM_COLOR_LIGHT_CYAN] = { 0, 255, 255 }, /* light cyan */
204 [TSM_COLOR_WHITE] = { 255, 255, 255 }, /* white */
205
206 [TSM_COLOR_FOREGROUND] = { 229, 229, 229 }, /* light grey */
207 [TSM_COLOR_BACKGROUND] = { 0, 0, 0 }, /* black */
208 };
209
210 /* Several effects may occur when non-RGB colors are used. For instance, if bold
211 * is enabled, then a dark color code is always converted to a light color to
212 * simulate bold (even though bold may actually be supported!). To support this,
213 * we need to differentiate between a set color-code and a set rgb-color.
214 * This function actually converts a set color-code into an RGB color. This must
215 * be called before passing the attribute to the console layer so the console
216 * layer can always work with RGB values and does not have to care for color
217 * codes. */
to_rgb(struct tsm_vte * vte,struct tsm_screen_attr * attr)218 static void to_rgb(struct tsm_vte *vte, struct tsm_screen_attr *attr)
219 {
220 int8_t code;
221
222 code = attr->fccode;
223 if (code >= 0) {
224 /* bold causes light colors */
225 if (attr->bold && code < 8)
226 code += 8;
227 if (code >= TSM_COLOR_NUM)
228 code = TSM_COLOR_FOREGROUND;
229
230 attr->fr = vte->palette[code][0];
231 attr->fg = vte->palette[code][1];
232 attr->fb = vte->palette[code][2];
233 }
234
235 code = attr->bccode;
236 if (code >= 0) {
237 if (code >= TSM_COLOR_NUM)
238 code = TSM_COLOR_BACKGROUND;
239
240 attr->br = vte->palette[code][0];
241 attr->bg = vte->palette[code][1];
242 attr->bb = vte->palette[code][2];
243 }
244 }
245
copy_fcolor(struct tsm_screen_attr * dest,const struct tsm_screen_attr * src)246 static void copy_fcolor(struct tsm_screen_attr *dest,
247 const struct tsm_screen_attr *src)
248 {
249 dest->fccode = src->fccode;
250 dest->fr = src->fr;
251 dest->fg = src->fg;
252 dest->fb = src->fb;
253 }
254
copy_bcolor(struct tsm_screen_attr * dest,const struct tsm_screen_attr * src)255 static void copy_bcolor(struct tsm_screen_attr *dest,
256 const struct tsm_screen_attr *src)
257 {
258 dest->bccode = src->bccode;
259 dest->br = src->br;
260 dest->bg = src->bg;
261 dest->bb = src->bb;
262 }
263
264 SHL_EXPORT
tsm_vte_new(struct tsm_vte ** out,struct tsm_screen * con,tsm_vte_write_cb write_cb,void * data)265 int tsm_vte_new(struct tsm_vte **out, struct tsm_screen *con,
266 tsm_vte_write_cb write_cb, void *data)
267 {
268 struct tsm_vte *vte;
269 int ret;
270
271 vte = malloc(sizeof(*vte));
272 if (!vte)
273 return -ENOMEM;
274
275 memset(vte, 0, sizeof(*vte));
276 vte->ref = 1;
277 vte->con = con;
278 vte->write_cb = write_cb;
279 vte->data = data;
280 vte->palette = default_palette;
281 vte->def_attr.fccode = TSM_COLOR_FOREGROUND;
282 vte->def_attr.bccode = TSM_COLOR_BACKGROUND;
283 to_rgb(vte, &vte->def_attr);
284
285 ret = tsm_utf8_mach_new(&vte->mach);
286 if (ret)
287 goto err_free;
288
289 tsm_vte_reset(vte);
290 tsm_screen_erase_screen(vte->con, false);
291
292 tsm_screen_ref(vte->con);
293 *out = vte;
294 return 0;
295
296 err_free:
297 free(vte);
298 return ret;
299 }
300
301 SHL_EXPORT
tsm_vte_ref(struct tsm_vte * vte)302 void tsm_vte_ref(struct tsm_vte *vte)
303 {
304 vte->ref++;
305 }
306
307 SHL_EXPORT
tsm_vte_unref(struct tsm_vte * vte)308 void tsm_vte_unref(struct tsm_vte *vte)
309 {
310 if (!vte->ref || --vte->ref)
311 return;
312
313 tsm_screen_unref(vte->con);
314 tsm_utf8_mach_free(vte->mach);
315 free(vte);
316 }
317
318 SHL_EXPORT
tsm_vte_set_palette(struct tsm_vte * vte,uint8_t (* palette)[3])319 int tsm_vte_set_palette(struct tsm_vte *vte, uint8_t (*palette)[3])
320 {
321 vte->palette = palette;
322 vte->def_attr.fccode = TSM_COLOR_FOREGROUND;
323 vte->def_attr.bccode = TSM_COLOR_BACKGROUND;
324
325 to_rgb(vte, &vte->def_attr);
326 memcpy(&vte->cattr, &vte->def_attr, sizeof(vte->cattr));
327
328 tsm_screen_set_def_attr(vte->con, &vte->def_attr);
329 tsm_screen_erase_screen(vte->con, false);
330
331 return 0;
332 }
333
334 SHL_EXPORT
tsm_vte_get_def_attr(struct tsm_vte * vte,struct tsm_screen_attr * out)335 void tsm_vte_get_def_attr(struct tsm_vte *vte, struct tsm_screen_attr *out)
336 {
337 memcpy(out, &vte->def_attr, sizeof(*out));
338 }
339
write_safe(struct tsm_vte * vte,const char * u8,size_t len)340 static void write_safe(struct tsm_vte *vte, const char *u8, size_t len)
341 {
342 if (vte->pasting) {
343 if (*u8 == ENDPASTE[vte->endpaste_i]) {
344 if (ENDPASTE[++vte->endpaste_i] == '\0') {
345 llog_warning(vte, "ignoring ESC[201~ escape "
346 "sequence in pasted text");
347 vte->endpaste_i = 0;
348 }
349 return;
350 } else if (vte->endpaste_i) {
351 vte->write_cb(vte, ENDPASTE, vte->endpaste_i,
352 vte->data);
353 vte->endpaste_i = 0;
354 if (*u8 == '\e')
355 vte->endpaste_i++;
356 }
357 }
358 vte->write_cb(vte, u8, len, vte->data);
359 }
360
361 /*
362 * Write raw byte-stream to pty.
363 * When writing data to the client we must make sure that we send the correct
364 * encoding. For backwards-compatibility reasons we should always send 7bit
365 * characters exclusively. However, when FLAG_7BIT_MODE is not set, then we can
366 * also send raw 8bit characters. For instance, in FLAG_8BIT_MODE we can use the
367 * GR characters as keyboard input and send them directly or even use the C1
368 * escape characters. In unicode mode (default) we can send multi-byte utf-8
369 * characters which are also 8bit. When sending these characters, set the \raw
370 * flag to true so this function does not perform debug checks on data we send.
371 * If debugging is disabled, these checks are also disabled and won't affect
372 * performance.
373 * For better debugging, we also use the __LINE__ and __FILE__ macros. Use the
374 * vte_write() and vte_write_raw() macros below for more convenient use.
375 *
376 * As a rule of thumb do never send 8bit characters in escape sequences and also
377 * avoid all 8bit escape codes including the C1 codes. This will guarantee that
378 * all kind of clients are always compatible to us.
379 *
380 * If SEND_RECEIVE_MODE is off (that is, local echo is on) we have to send all
381 * data directly to ourself again. However, we must avoid recursion when
382 * tsm_vte_input() itself calls vte_write*(), therefore, we increase the
383 * PARSER counter when entering tsm_vte_input() and reset it when leaving it
384 * so we never echo data that origins from tsm_vte_input().
385 * But note that SEND_RECEIVE_MODE is inherently broken for escape sequences
386 * that request answers. That is, if we send a request to the client that awaits
387 * a response and parse that request via local echo ourself, then we will also
388 * send a response to the client even though he didn't request one. This
389 * recursion fix does not avoid this but only prevents us from endless loops
390 * here. Anyway, only few applications rely on local echo so we can safely
391 * ignore this.
392 */
vte_write_debug(struct tsm_vte * vte,const char * u8,size_t len,bool raw,const char * file,int line)393 static void vte_write_debug(struct tsm_vte *vte, const char *u8, size_t len,
394 bool raw, const char *file, int line)
395 {
396 #ifdef BUILD_ENABLE_DEBUG
397 /* in debug mode we check that escape sequences are always <0x7f so they
398 * are correctly parsed by non-unicode and non-8bit-mode clients. */
399 size_t i;
400
401 if (!raw) {
402 for (i = 0; i < len; ++i) {
403 if (u8[i] & 0x80)
404 llog_warning(vte, "sending 8bit character inline to client in %s:%d",
405 file, line);
406 }
407 }
408 #endif
409
410 /* in local echo mode, directly parse the data again */
411 if (!vte->parse_cnt && !(vte->flags & FLAG_SEND_RECEIVE_MODE)) {
412 if (vte->flags & FLAG_PREPEND_ESCAPE && u8[0] != '\e')
413 tsm_vte_input(vte, "\e", 1);
414 tsm_vte_input(vte, u8, len);
415 }
416
417 if (vte->flags & FLAG_PREPEND_ESCAPE && u8[0] != '\e')
418 write_safe(vte, "\e", 1);
419 write_safe(vte, u8, len);
420
421 vte->flags &= ~FLAG_PREPEND_ESCAPE;
422 }
423
424 #define vte_write(_vte, _u8, _len) \
425 vte_write_debug((_vte), (_u8), (_len), false, __FILE__, __LINE__)
426 #define vte_write_raw(_vte, _u8, _len) \
427 vte_write_debug((_vte), (_u8), (_len), true, __FILE__, __LINE__)
428
vte_write_fnkey(struct tsm_vte * vte,bool ss3,unsigned int mods,int index,char c)429 static void vte_write_fnkey(struct tsm_vte *vte, bool ss3, unsigned int mods,
430 int index, char c)
431 {
432 char buf[10];
433 int len;
434 int fnmod = 1
435 + (mods & TSM_SHIFT_MASK ? 1 : 0)
436 + (mods & TSM_ALT_MASK ? 2 : 0)
437 + (mods & TSM_CONTROL_MASK ? 4 : 0);
438
439 if (fnmod > 1) {
440 if (index <= 0)
441 index = 1;
442 len = sprintf(buf, "\e[%d;%d%c", index, fnmod, c);
443 } else {
444 len = sprintf(buf, "\e%c%.0d%c", ss3 ? 'O' : '[', index, c);
445 }
446 vte_write(vte, buf, len);
447 }
448
449 /* write to console */
write_console(struct tsm_vte * vte,tsm_symbol_t sym)450 static void write_console(struct tsm_vte *vte, tsm_symbol_t sym)
451 {
452 vte->last_sym = sym;
453 to_rgb(vte, &vte->cattr);
454 tsm_screen_write(vte->con, sym, &vte->cattr);
455 }
456
reset_state(struct tsm_vte * vte)457 static void reset_state(struct tsm_vte *vte)
458 {
459 vte->saved_state.cursor_x = 0;
460 vte->saved_state.cursor_y = 0;
461 vte->saved_state.origin_mode = false;
462 vte->saved_state.wrap_mode = true;
463 vte->saved_state.gl = &vte->g0;
464 vte->saved_state.gr = &vte->g1;
465
466 copy_fcolor(&vte->saved_state.cattr, &vte->def_attr);
467 copy_bcolor(&vte->saved_state.cattr, &vte->def_attr);
468 vte->saved_state.cattr.bold = 0;
469 vte->saved_state.cattr.underline = 0;
470 vte->saved_state.cattr.inverse = 0;
471 vte->saved_state.cattr.protect = 0;
472 vte->saved_state.cattr.blink = 0;
473 }
474
save_state(struct tsm_vte * vte)475 static void save_state(struct tsm_vte *vte)
476 {
477 vte->saved_state.cursor_x = tsm_screen_get_cursor_x(vte->con);
478 vte->saved_state.cursor_y = tsm_screen_get_cursor_y(vte->con);
479 vte->saved_state.cattr = vte->cattr;
480 vte->saved_state.gl = vte->gl;
481 vte->saved_state.gr = vte->gr;
482 vte->saved_state.wrap_mode = vte->flags & FLAG_AUTO_WRAP_MODE;
483 vte->saved_state.origin_mode = vte->flags & FLAG_ORIGIN_MODE;
484 }
485
restore_state(struct tsm_vte * vte)486 static void restore_state(struct tsm_vte *vte)
487 {
488 tsm_screen_move_to(vte->con, vte->saved_state.cursor_x,
489 vte->saved_state.cursor_y);
490 vte->cattr = vte->saved_state.cattr;
491 to_rgb(vte, &vte->cattr);
492 if (vte->flags & FLAG_BACKGROUND_COLOR_ERASE_MODE)
493 tsm_screen_set_def_attr(vte->con, &vte->cattr);
494 vte->gl = vte->saved_state.gl;
495 vte->gr = vte->saved_state.gr;
496
497 if (vte->saved_state.wrap_mode) {
498 vte->flags |= FLAG_AUTO_WRAP_MODE;
499 tsm_screen_set_flags(vte->con, TSM_SCREEN_AUTO_WRAP);
500 } else {
501 vte->flags &= ~FLAG_AUTO_WRAP_MODE;
502 tsm_screen_reset_flags(vte->con, TSM_SCREEN_AUTO_WRAP);
503 }
504
505 if (vte->saved_state.origin_mode) {
506 vte->flags |= FLAG_ORIGIN_MODE;
507 tsm_screen_set_flags(vte->con, TSM_SCREEN_REL_ORIGIN);
508 } else {
509 vte->flags &= ~FLAG_ORIGIN_MODE;
510 tsm_screen_reset_flags(vte->con, TSM_SCREEN_REL_ORIGIN);
511 }
512 }
513
514 /*
515 * Reset VTE state
516 * This performs a soft reset of the VTE. That is, everything is reset to the
517 * same state as when the VTE was created. This does not affect the console,
518 * though.
519 */
520 SHL_EXPORT
tsm_vte_reset(struct tsm_vte * vte)521 void tsm_vte_reset(struct tsm_vte *vte)
522 {
523 vte->flags = 0;
524 vte->flags |= FLAG_TEXT_CURSOR_MODE;
525 vte->flags |= FLAG_AUTO_REPEAT_MODE;
526 vte->flags |= FLAG_SEND_RECEIVE_MODE;
527 vte->flags |= FLAG_AUTO_WRAP_MODE;
528 vte->flags |= FLAG_BACKGROUND_COLOR_ERASE_MODE;
529 tsm_screen_reset(vte->con);
530 tsm_screen_set_flags(vte->con, TSM_SCREEN_AUTO_WRAP);
531
532 tsm_utf8_mach_reset(vte->mach);
533 vte->state = STATE_GROUND;
534 vte->last_sym = ' ';
535 vte->gl = &vte->g0;
536 vte->gr = &vte->g1;
537 vte->glt = NULL;
538 vte->grt = NULL;
539 vte->g0 = &tsm_vte_unicode_lower;
540 vte->g1 = &tsm_vte_unicode_upper;
541 vte->g2 = &tsm_vte_unicode_lower;
542 vte->g3 = &tsm_vte_unicode_upper;
543
544 memcpy(&vte->cattr, &vte->def_attr, sizeof(vte->cattr));
545 to_rgb(vte, &vte->cattr);
546 tsm_screen_set_def_attr(vte->con, &vte->def_attr);
547
548 reset_state(vte);
549 }
550
551 SHL_EXPORT
tsm_vte_hard_reset(struct tsm_vte * vte)552 void tsm_vte_hard_reset(struct tsm_vte *vte)
553 {
554 tsm_vte_reset(vte);
555 tsm_screen_erase_screen(vte->con, false);
556 tsm_screen_clear_sb(vte->con);
557 tsm_screen_move_to(vte->con, 0, 0);
558 }
559
send_primary_da(struct tsm_vte * vte)560 static void send_primary_da(struct tsm_vte *vte)
561 {
562 vte_write(vte, "\e[?62;1;6;9;15c", 15);
563 }
564
565 /* execute control character (C0 or C1) */
do_execute(struct tsm_vte * vte,uint32_t ctrl)566 static void do_execute(struct tsm_vte *vte, uint32_t ctrl)
567 {
568 switch (ctrl) {
569 case 0x00: /* NUL */
570 /* Ignore on input */
571 break;
572 case 0x05: /* ENQ */
573 /* Transmit answerback message */
574 /* TODO: is there a better answer than ACK? */
575 vte_write(vte, "\x06", 1);
576 break;
577 case 0x07: /* BEL */
578 /* Sound bell tone */
579 /* TODO: I always considered this annying, however, we
580 * should at least provide some way to enable it if the
581 * user *really* wants it.
582 */
583 break;
584 case 0x08: /* BS */
585 /* Move cursor one position left */
586 tsm_screen_move_left(vte->con, 1);
587 break;
588 case 0x09: /* HT */
589 /* Move to next tab stop or end of line */
590 tsm_screen_tab_right(vte->con, 1);
591 break;
592 case 0x0a: /* LF */
593 case 0x0b: /* VT */
594 case 0x0c: /* FF */
595 /* Line feed or newline (CR/NL mode) */
596 if (vte->flags & FLAG_LINE_FEED_NEW_LINE_MODE)
597 tsm_screen_newline(vte->con);
598 else
599 tsm_screen_move_down(vte->con, 1, true);
600 break;
601 case 0x0d: /* CR */
602 /* Move cursor to left margin */
603 tsm_screen_move_line_home(vte->con);
604 break;
605 case 0x0e: /* SO */
606 /* Map G1 character set into GL */
607 vte->gl = &vte->g1;
608 break;
609 case 0x0f: /* SI */
610 /* Map G0 character set into GL */
611 vte->gl = &vte->g0;
612 break;
613 case 0x11: /* XON */
614 /* Resume transmission */
615 /* TODO */
616 break;
617 case 0x13: /* XOFF */
618 /* Stop transmission */
619 /* TODO */
620 break;
621 case 0x18: /* CAN */
622 /* Cancel escape sequence */
623 /* nothing to do here */
624 break;
625 case 0x1a: /* SUB */
626 /* Discard current escape sequence and show err-sym */
627 write_console(vte, 0xbf);
628 break;
629 case 0x1b: /* ESC */
630 /* Invokes an escape sequence */
631 /* nothing to do here */
632 break;
633 case 0x1f: /* DEL */
634 /* Ignored */
635 break;
636 case 0x84: /* IND */
637 /* Move down one row, perform scroll-up if needed */
638 tsm_screen_move_down(vte->con, 1, true);
639 break;
640 case 0x85: /* NEL */
641 /* CR/NL with scroll-up if needed */
642 tsm_screen_newline(vte->con);
643 break;
644 case 0x88: /* HTS */
645 /* Set tab stop at current position */
646 tsm_screen_set_tabstop(vte->con);
647 break;
648 case 0x8d: /* RI */
649 /* Move up one row, perform scroll-down if needed */
650 tsm_screen_move_up(vte->con, 1, true);
651 break;
652 case 0x8e: /* SS2 */
653 /* Temporarily map G2 into GL for next char only */
654 vte->glt = &vte->g2;
655 break;
656 case 0x8f: /* SS3 */
657 /* Temporarily map G3 into GL for next char only */
658 vte->glt = &vte->g3;
659 break;
660 case 0x9a: /* DECID */
661 /* Send device attributes response like ANSI DA */
662 send_primary_da(vte);
663 break;
664 case 0x9c: /* ST */
665 /* End control string */
666 /* nothing to do here */
667 break;
668 default:
669 llog_debug(vte, "unhandled control char %u", ctrl);
670 }
671 }
672
do_clear(struct tsm_vte * vte)673 static void do_clear(struct tsm_vte *vte)
674 {
675 int i;
676
677 vte->csi_argc = 0;
678 for (i = 0; i < CSI_ARG_MAX; ++i)
679 vte->csi_argv[i] = -1;
680 vte->csi_flags = 0;
681 }
682
do_collect(struct tsm_vte * vte,uint32_t data)683 static void do_collect(struct tsm_vte *vte, uint32_t data)
684 {
685 switch (data) {
686 case '!':
687 vte->csi_flags |= CSI_BANG;
688 break;
689 case '$':
690 vte->csi_flags |= CSI_CASH;
691 break;
692 case '?':
693 vte->csi_flags |= CSI_WHAT;
694 break;
695 case '>':
696 vte->csi_flags |= CSI_GT;
697 break;
698 case ' ':
699 vte->csi_flags |= CSI_SPACE;
700 break;
701 case '\'':
702 vte->csi_flags |= CSI_SQUOTE;
703 break;
704 case '"':
705 vte->csi_flags |= CSI_DQUOTE;
706 break;
707 case '*':
708 vte->csi_flags |= CSI_MULT;
709 break;
710 case '+':
711 vte->csi_flags |= CSI_PLUS;
712 break;
713 case '(':
714 vte->csi_flags |= CSI_POPEN;
715 break;
716 case ')':
717 vte->csi_flags |= CSI_PCLOSE;
718 break;
719 }
720 }
721
do_param(struct tsm_vte * vte,uint32_t data)722 static void do_param(struct tsm_vte *vte, uint32_t data)
723 {
724 int new;
725
726 if (data == ';') {
727 if (vte->csi_argc < CSI_ARG_MAX)
728 vte->csi_argc++;
729 return;
730 }
731
732 if (vte->csi_argc >= CSI_ARG_MAX)
733 return;
734
735 /* avoid integer overflows; max allowed value is 16384 anyway */
736 if (vte->csi_argv[vte->csi_argc] > 0xffff)
737 return;
738
739 if (data >= '0' && data <= '9') {
740 new = vte->csi_argv[vte->csi_argc];
741 if (new <= 0)
742 new = data - '0';
743 else
744 new = new * 10 + data - '0';
745 vte->csi_argv[vte->csi_argc] = new;
746 }
747 }
748
set_charset(struct tsm_vte * vte,tsm_vte_charset * set)749 static bool set_charset(struct tsm_vte *vte, tsm_vte_charset *set)
750 {
751 if (vte->csi_flags & CSI_POPEN)
752 vte->g0 = set;
753 else if (vte->csi_flags & CSI_PCLOSE)
754 vte->g1 = set;
755 else if (vte->csi_flags & CSI_MULT)
756 vte->g2 = set;
757 else if (vte->csi_flags & CSI_PLUS)
758 vte->g3 = set;
759 else
760 return false;
761
762 return true;
763 }
764
do_esc(struct tsm_vte * vte,uint32_t data)765 static void do_esc(struct tsm_vte *vte, uint32_t data)
766 {
767 switch (data) {
768 case 'B': /* map ASCII into G0-G3 */
769 if (set_charset(vte, &tsm_vte_unicode_lower))
770 return;
771 break;
772 case '<': /* map DEC supplemental into G0-G3 */
773 if (set_charset(vte, &tsm_vte_dec_supplemental_graphics))
774 return;
775 break;
776 case '0': /* map DEC special into G0-G3 */
777 if (set_charset(vte, &tsm_vte_dec_special_graphics))
778 return;
779 break;
780 case 'A': /* map British into G0-G3 */
781 /* TODO: create British charset from DEC */
782 if (set_charset(vte, &tsm_vte_unicode_upper))
783 return;
784 break;
785 case '4': /* map Dutch into G0-G3 */
786 /* TODO: create Dutch charset from DEC */
787 if (set_charset(vte, &tsm_vte_unicode_upper))
788 return;
789 break;
790 case 'C':
791 case '5': /* map Finnish into G0-G3 */
792 /* TODO: create Finnish charset from DEC */
793 if (set_charset(vte, &tsm_vte_unicode_upper))
794 return;
795 break;
796 case 'R': /* map French into G0-G3 */
797 /* TODO: create French charset from DEC */
798 if (set_charset(vte, &tsm_vte_unicode_upper))
799 return;
800 break;
801 case 'Q': /* map French-Canadian into G0-G3 */
802 /* TODO: create French-Canadian charset from DEC */
803 if (set_charset(vte, &tsm_vte_unicode_upper))
804 return;
805 break;
806 case 'K': /* map German into G0-G3 */
807 /* TODO: create German charset from DEC */
808 if (set_charset(vte, &tsm_vte_unicode_upper))
809 return;
810 break;
811 case 'Y': /* map Italian into G0-G3 */
812 /* TODO: create Italian charset from DEC */
813 if (set_charset(vte, &tsm_vte_unicode_upper))
814 return;
815 break;
816 case 'E':
817 case '6': /* map Norwegian/Danish into G0-G3 */
818 /* TODO: create Norwegian/Danish charset from DEC */
819 if (set_charset(vte, &tsm_vte_unicode_upper))
820 return;
821 break;
822 case 'Z': /* map Spanish into G0-G3 */
823 /* TODO: create Spanish charset from DEC */
824 if (set_charset(vte, &tsm_vte_unicode_upper))
825 return;
826 break;
827 case 'H':
828 case '7': /* map Swedish into G0-G3 */
829 /* TODO: create Swedish charset from DEC */
830 if (set_charset(vte, &tsm_vte_unicode_upper))
831 return;
832 break;
833 case '=': /* map Swiss into G0-G3 */
834 /* TODO: create Swiss charset from DEC */
835 if (set_charset(vte, &tsm_vte_unicode_upper))
836 return;
837 break;
838 case 'F':
839 if (vte->csi_flags & CSI_SPACE) {
840 /* S7C1T */
841 /* Disable 8bit C1 mode */
842 vte->flags &= ~FLAG_USE_C1;
843 return;
844 }
845 break;
846 case 'G':
847 if (vte->csi_flags & CSI_SPACE) {
848 /* S8C1T */
849 /* Enable 8bit C1 mode */
850 vte->flags |= FLAG_USE_C1;
851 return;
852 }
853 break;
854 }
855
856 /* everything below is only valid without CSI flags */
857 if (vte->csi_flags) {
858 llog_debug(vte, "unhandled escape seq %u", data);
859 return;
860 }
861
862 switch (data) {
863 case 'D': /* IND */
864 /* Move down one row, perform scroll-up if needed */
865 tsm_screen_move_down(vte->con, 1, true);
866 break;
867 case 'E': /* NEL */
868 /* CR/NL with scroll-up if needed */
869 tsm_screen_newline(vte->con);
870 break;
871 case 'H': /* HTS */
872 /* Set tab stop at current position */
873 tsm_screen_set_tabstop(vte->con);
874 break;
875 case 'M': /* RI */
876 /* Move up one row, perform scroll-down if needed */
877 tsm_screen_move_up(vte->con, 1, true);
878 break;
879 case 'N': /* SS2 */
880 /* Temporarily map G2 into GL for next char only */
881 vte->glt = &vte->g2;
882 break;
883 case 'O': /* SS3 */
884 /* Temporarily map G3 into GL for next char only */
885 vte->glt = &vte->g3;
886 break;
887 case 'Z': /* DECID */
888 /* Send device attributes response like ANSI DA */
889 send_primary_da(vte);
890 break;
891 case '\\': /* ST */
892 /* End control string */
893 /* nothing to do here */
894 break;
895 case '~': /* LS1R */
896 /* Invoke G1 into GR */
897 vte->gr = &vte->g1;
898 break;
899 case 'n': /* LS2 */
900 /* Invoke G2 into GL */
901 vte->gl = &vte->g2;
902 break;
903 case '}': /* LS2R */
904 /* Invoke G2 into GR */
905 vte->gr = &vte->g2;
906 break;
907 case 'o': /* LS3 */
908 /* Invoke G3 into GL */
909 vte->gl = &vte->g3;
910 break;
911 case '|': /* LS3R */
912 /* Invoke G3 into GR */
913 vte->gr = &vte->g3;
914 break;
915 case '=': /* DECKPAM */
916 /* Set application keypad mode */
917 vte->flags |= FLAG_KEYPAD_APPLICATION_MODE;
918 break;
919 case '>': /* DECKPNM */
920 /* Set numeric keypad mode */
921 vte->flags &= ~FLAG_KEYPAD_APPLICATION_MODE;
922 break;
923 case 'c': /* RIS */
924 /* hard reset */
925 tsm_vte_hard_reset(vte);
926 break;
927 case '7': /* DECSC */
928 /* save console state */
929 save_state(vte);
930 break;
931 case '8': /* DECRC */
932 /* restore console state */
933 restore_state(vte);
934 break;
935 default:
936 llog_debug(vte, "unhandled escape seq %u", data);
937 }
938 }
939
csi_attribute(struct tsm_vte * vte)940 static void csi_attribute(struct tsm_vte *vte)
941 {
942 static const uint8_t bval[6] = { 0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff };
943 int i, code, val;
944 uint8_t cr, cg, cb;
945
946 if (vte->csi_argc <= 1 && vte->csi_argv[0] == -1) {
947 vte->csi_argc = 1;
948 vte->csi_argv[0] = 0;
949 }
950
951 for (i = 0; i < vte->csi_argc; ++i) {
952 switch (vte->csi_argv[i]) {
953 case -1:
954 break;
955 case 0:
956 copy_fcolor(&vte->cattr, &vte->def_attr);
957 copy_bcolor(&vte->cattr, &vte->def_attr);
958 vte->cattr.bold = 0;
959 vte->cattr.underline = 0;
960 vte->cattr.inverse = 0;
961 vte->cattr.blink = 0;
962 break;
963 case 1:
964 vte->cattr.bold = 1;
965 break;
966 case 4:
967 vte->cattr.underline = 1;
968 break;
969 case 5:
970 vte->cattr.blink = 1;
971 break;
972 case 7:
973 vte->cattr.inverse = 1;
974 break;
975 case 22:
976 vte->cattr.bold = 0;
977 break;
978 case 24:
979 vte->cattr.underline = 0;
980 break;
981 case 25:
982 vte->cattr.blink = 0;
983 break;
984 case 27:
985 vte->cattr.inverse = 0;
986 break;
987 case 30:
988 vte->cattr.fccode = TSM_COLOR_BLACK;
989 break;
990 case 31:
991 vte->cattr.fccode = TSM_COLOR_RED;
992 break;
993 case 32:
994 vte->cattr.fccode = TSM_COLOR_GREEN;
995 break;
996 case 33:
997 vte->cattr.fccode = TSM_COLOR_YELLOW;
998 break;
999 case 34:
1000 vte->cattr.fccode = TSM_COLOR_BLUE;
1001 break;
1002 case 35:
1003 vte->cattr.fccode = TSM_COLOR_MAGENTA;
1004 break;
1005 case 36:
1006 vte->cattr.fccode = TSM_COLOR_CYAN;
1007 break;
1008 case 37:
1009 vte->cattr.fccode = TSM_COLOR_LIGHT_GREY;
1010 break;
1011 case 39:
1012 copy_fcolor(&vte->cattr, &vte->def_attr);
1013 break;
1014 case 40:
1015 vte->cattr.bccode = TSM_COLOR_BLACK;
1016 break;
1017 case 41:
1018 vte->cattr.bccode = TSM_COLOR_RED;
1019 break;
1020 case 42:
1021 vte->cattr.bccode = TSM_COLOR_GREEN;
1022 break;
1023 case 43:
1024 vte->cattr.bccode = TSM_COLOR_YELLOW;
1025 break;
1026 case 44:
1027 vte->cattr.bccode = TSM_COLOR_BLUE;
1028 break;
1029 case 45:
1030 vte->cattr.bccode = TSM_COLOR_MAGENTA;
1031 break;
1032 case 46:
1033 vte->cattr.bccode = TSM_COLOR_CYAN;
1034 break;
1035 case 47:
1036 vte->cattr.bccode = TSM_COLOR_LIGHT_GREY;
1037 break;
1038 case 49:
1039 copy_bcolor(&vte->cattr, &vte->def_attr);
1040 break;
1041 case 90:
1042 vte->cattr.fccode = TSM_COLOR_DARK_GREY;
1043 break;
1044 case 91:
1045 vte->cattr.fccode = TSM_COLOR_LIGHT_RED;
1046 break;
1047 case 92:
1048 vte->cattr.fccode = TSM_COLOR_LIGHT_GREEN;
1049 break;
1050 case 93:
1051 vte->cattr.fccode = TSM_COLOR_LIGHT_YELLOW;
1052 break;
1053 case 94:
1054 vte->cattr.fccode = TSM_COLOR_LIGHT_BLUE;
1055 break;
1056 case 95:
1057 vte->cattr.fccode = TSM_COLOR_LIGHT_MAGENTA;
1058 break;
1059 case 96:
1060 vte->cattr.fccode = TSM_COLOR_LIGHT_CYAN;
1061 break;
1062 case 97:
1063 vte->cattr.fccode = TSM_COLOR_WHITE;
1064 break;
1065 case 100:
1066 vte->cattr.bccode = TSM_COLOR_DARK_GREY;
1067 break;
1068 case 101:
1069 vte->cattr.bccode = TSM_COLOR_LIGHT_RED;
1070 break;
1071 case 102:
1072 vte->cattr.bccode = TSM_COLOR_LIGHT_GREEN;
1073 break;
1074 case 103:
1075 vte->cattr.bccode = TSM_COLOR_LIGHT_YELLOW;
1076 break;
1077 case 104:
1078 vte->cattr.bccode = TSM_COLOR_LIGHT_BLUE;
1079 break;
1080 case 105:
1081 vte->cattr.bccode = TSM_COLOR_LIGHT_MAGENTA;
1082 break;
1083 case 106:
1084 vte->cattr.bccode = TSM_COLOR_LIGHT_CYAN;
1085 break;
1086 case 107:
1087 vte->cattr.bccode = TSM_COLOR_WHITE;
1088 break;
1089 case 38:
1090 /* fallthrough */
1091 case 48:
1092 val = vte->csi_argv[i];
1093 if (vte->csi_argv[i + 1] == 5) {
1094 if (i + 2 >= vte->csi_argc ||
1095 vte->csi_argv[i + 2] < 0) {
1096 llog_debug(vte, "invalid 256color SGR");
1097 break;
1098 }
1099 code = vte->csi_argv[i + 2];
1100 if (code < 16) {
1101 } else if (code < 232) {
1102 code -= 16;
1103 cb = bval[code % 6];
1104 code /= 6;
1105 cg = bval[code % 6];
1106 code /= 6;
1107 cr = bval[code % 6];
1108 code = -1;
1109 } else {
1110 code = (code - 232) * 10 + 8;
1111 cr = code;
1112 cg = code;
1113 cb = code;
1114 code = -1;
1115 }
1116 i += 2;
1117 } else if (vte->csi_argv[i + 1] == 2) {
1118 if (i + 4 >= vte->csi_argc ||
1119 vte->csi_argv[i + 2] < 0 ||
1120 vte->csi_argv[i + 3] < 0 ||
1121 vte->csi_argv[i + 4] < 0) {
1122 llog_debug(vte, "invalid true color SGR");
1123 break;
1124 }
1125 cr = vte->csi_argv[i + 2];
1126 cg = vte->csi_argv[i + 3];
1127 cb = vte->csi_argv[i + 4];
1128 code = -1;
1129 i += 4;
1130 } else {
1131 llog_debug(vte, "invalid SGR");
1132 break;
1133 }
1134 if (val == 38) {
1135 vte->cattr.fccode = code;
1136 vte->cattr.fr = cr;
1137 vte->cattr.fg = cg;
1138 vte->cattr.fb = cb;
1139 } else {
1140 vte->cattr.bccode = code;
1141 vte->cattr.br = cr;
1142 vte->cattr.bg = cg;
1143 vte->cattr.bb = cb;
1144 }
1145
1146 break;
1147 default:
1148 llog_debug(vte, "unhandled SGR attr %i",
1149 vte->csi_argv[i]);
1150 }
1151 }
1152
1153 to_rgb(vte, &vte->cattr);
1154 if (vte->flags & FLAG_BACKGROUND_COLOR_ERASE_MODE)
1155 tsm_screen_set_def_attr(vte->con, &vte->cattr);
1156 }
1157
csi_soft_reset(struct tsm_vte * vte)1158 static void csi_soft_reset(struct tsm_vte *vte)
1159 {
1160 tsm_vte_reset(vte);
1161 }
1162
csi_compat_mode(struct tsm_vte * vte)1163 static void csi_compat_mode(struct tsm_vte *vte)
1164 {
1165 /* always perform soft reset */
1166 csi_soft_reset(vte);
1167
1168 if (vte->csi_argv[0] == 61) {
1169 /* Switching to VT100 compatibility mode. We do
1170 * not support this mode, so ignore it. In fact,
1171 * we are almost compatible to it, anyway, so
1172 * there is no need to explicitly select it.
1173 * However, we enable 7bit mode to avoid
1174 * character-table problems */
1175 vte->flags |= FLAG_7BIT_MODE;
1176 vte->g0 = &tsm_vte_unicode_lower;
1177 vte->g1 = &tsm_vte_dec_supplemental_graphics;
1178 } else if (vte->csi_argv[0] == 62 ||
1179 vte->csi_argv[0] == 63 ||
1180 vte->csi_argv[0] == 64) {
1181 /* Switching to VT2/3/4 compatibility mode. We
1182 * are always compatible with this so ignore it.
1183 * We always send 7bit controls so we also do
1184 * not care for the parameter value here that
1185 * select the control-mode.
1186 * VT220 defines argument 2 as 7bit mode but
1187 * VT3xx up to VT5xx use it as 8bit mode. We
1188 * choose to conform with the latter here.
1189 * We also enable 8bit mode when VT220
1190 * compatibility is requested explicitly. */
1191 if (vte->csi_argv[1] == 1 ||
1192 vte->csi_argv[1] == 2)
1193 vte->flags |= FLAG_USE_C1;
1194
1195 vte->flags |= FLAG_8BIT_MODE;
1196 vte->g0 = &tsm_vte_unicode_lower;
1197 vte->g1 = &tsm_vte_dec_supplemental_graphics;
1198 } else {
1199 llog_debug(vte, "unhandled DECSCL 'p' CSI %i, switching to utf-8 mode again",
1200 vte->csi_argv[0]);
1201 }
1202 }
1203
set_reset_flag(struct tsm_vte * vte,bool set,unsigned int flag)1204 static inline void set_reset_flag(struct tsm_vte *vte, bool set,
1205 unsigned int flag)
1206 {
1207 if (set)
1208 vte->flags |= flag;
1209 else
1210 vte->flags &= ~flag;
1211 }
1212
csi_mode(struct tsm_vte * vte,bool set)1213 static void csi_mode(struct tsm_vte *vte, bool set)
1214 {
1215 int i;
1216
1217 for (i = 0; i < vte->csi_argc; ++i) {
1218 if (!(vte->csi_flags & CSI_WHAT)) {
1219 switch (vte->csi_argv[i]) {
1220 case -1:
1221 continue;
1222 case 2: /* KAM */
1223 set_reset_flag(vte, set,
1224 FLAG_KEYBOARD_ACTION_MODE);
1225 continue;
1226 case 4: /* IRM */
1227 set_reset_flag(vte, set,
1228 FLAG_INSERT_REPLACE_MODE);
1229 if (set)
1230 tsm_screen_set_flags(vte->con,
1231 TSM_SCREEN_INSERT_MODE);
1232 else
1233 tsm_screen_reset_flags(vte->con,
1234 TSM_SCREEN_INSERT_MODE);
1235 continue;
1236 case 12: /* SRM */
1237 set_reset_flag(vte, set,
1238 FLAG_SEND_RECEIVE_MODE);
1239 continue;
1240 case 20: /* LNM */
1241 set_reset_flag(vte, set,
1242 FLAG_LINE_FEED_NEW_LINE_MODE);
1243 continue;
1244 default:
1245 llog_debug(vte, "unknown non-DEC (Re)Set-Mode %d",
1246 vte->csi_argv[i]);
1247 continue;
1248 }
1249 }
1250
1251 switch (vte->csi_argv[i]) {
1252 case -1:
1253 continue;
1254 case 1: /* DECCKM */
1255 set_reset_flag(vte, set, FLAG_CURSOR_KEY_MODE);
1256 continue;
1257 case 2: /* DECANM */
1258 /* Select VT52 mode */
1259 /* We do not support VT52 mode. Is there any reason why
1260 * we should support it? We ignore it here and do not
1261 * mark it as to-do item unless someone has strong
1262 * arguments to support it. */
1263 continue;
1264 case 3: /* DECCOLM */
1265 /* If set, select 132 column mode, otherwise use 80
1266 * column mode. If neither is selected explicitly, we
1267 * use dynamic mode, that is, we send SIGWCH when the
1268 * size changes and we allow arbitrary buffer
1269 * dimensions. On soft-reset, we automatically fall back
1270 * to the default, that is, dynamic mode.
1271 * Dynamic-mode can be forced to a static mode in the
1272 * config. That is, every time dynamic-mode becomes
1273 * active, the terminal will be set to the dimensions
1274 * that were selected in the config. This allows setting
1275 * a fixed size for the terminal regardless of the
1276 * display size.
1277 * TODO: Implement this */
1278 continue;
1279 case 4: /* DECSCLM */
1280 /* Select smooth scrolling. We do not support the
1281 * classic smooth scrolling because we have a scrollback
1282 * buffer. There is no need to implement smooth
1283 * scrolling so ignore this here. */
1284 continue;
1285 case 5: /* DECSCNM */
1286 set_reset_flag(vte, set, FLAG_INVERSE_SCREEN_MODE);
1287 if (set)
1288 tsm_screen_set_flags(vte->con,
1289 TSM_SCREEN_INVERSE);
1290 else
1291 tsm_screen_reset_flags(vte->con,
1292 TSM_SCREEN_INVERSE);
1293 continue;
1294 case 6: /* DECOM */
1295 set_reset_flag(vte, set, FLAG_ORIGIN_MODE);
1296 if (set)
1297 tsm_screen_set_flags(vte->con,
1298 TSM_SCREEN_REL_ORIGIN);
1299 else
1300 tsm_screen_reset_flags(vte->con,
1301 TSM_SCREEN_REL_ORIGIN);
1302 continue;
1303 case 7: /* DECAWM */
1304 set_reset_flag(vte, set, FLAG_AUTO_WRAP_MODE);
1305 if (set)
1306 tsm_screen_set_flags(vte->con,
1307 TSM_SCREEN_AUTO_WRAP);
1308 else
1309 tsm_screen_reset_flags(vte->con,
1310 TSM_SCREEN_AUTO_WRAP);
1311 continue;
1312 case 8: /* DECARM */
1313 set_reset_flag(vte, set, FLAG_AUTO_REPEAT_MODE);
1314 continue;
1315 case 12: /* blinking cursor */
1316 /* TODO: implement */
1317 continue;
1318 case 18: /* DECPFF */
1319 /* If set, a form feed (FF) is sent to the printer after
1320 * every screen that is printed. We don't have printers
1321 * these days directly attached to terminals so we
1322 * ignore this here. */
1323 continue;
1324 case 19: /* DECPEX */
1325 /* If set, the full screen is printed instead of
1326 * scrolling region only. We have no printer so ignore
1327 * this mode. */
1328 continue;
1329 case 25: /* DECTCEM */
1330 set_reset_flag(vte, set, FLAG_TEXT_CURSOR_MODE);
1331 if (set)
1332 tsm_screen_reset_flags(vte->con,
1333 TSM_SCREEN_HIDE_CURSOR);
1334 else
1335 tsm_screen_set_flags(vte->con,
1336 TSM_SCREEN_HIDE_CURSOR);
1337 continue;
1338 case 42: /* DECNRCM */
1339 set_reset_flag(vte, set, FLAG_NATIONAL_CHARSET_MODE);
1340 continue;
1341 case 47: /* Alternate screen buffer */
1342 if (vte->flags & FLAG_TITE_INHIBIT_MODE)
1343 continue;
1344
1345 if (set)
1346 tsm_screen_set_flags(vte->con,
1347 TSM_SCREEN_ALTERNATE);
1348 else
1349 tsm_screen_reset_flags(vte->con,
1350 TSM_SCREEN_ALTERNATE);
1351 continue;
1352 case 1047: /* Alternate screen buffer with post-erase */
1353 if (vte->flags & FLAG_TITE_INHIBIT_MODE)
1354 continue;
1355
1356 if (set) {
1357 tsm_screen_set_flags(vte->con,
1358 TSM_SCREEN_ALTERNATE);
1359 } else {
1360 tsm_screen_erase_screen(vte->con, false);
1361 tsm_screen_reset_flags(vte->con,
1362 TSM_SCREEN_ALTERNATE);
1363 }
1364 continue;
1365 case 1048: /* Set/Reset alternate-screen buffer cursor */
1366 if (vte->flags & FLAG_TITE_INHIBIT_MODE)
1367 continue;
1368
1369 if (set) {
1370 vte->alt_cursor_x =
1371 tsm_screen_get_cursor_x(vte->con);
1372 vte->alt_cursor_y =
1373 tsm_screen_get_cursor_y(vte->con);
1374 } else {
1375 tsm_screen_move_to(vte->con, vte->alt_cursor_x,
1376 vte->alt_cursor_y);
1377 }
1378 continue;
1379 case 1049: /* Alternate screen buffer with pre-erase+cursor */
1380 if (vte->flags & FLAG_TITE_INHIBIT_MODE)
1381 continue;
1382
1383 if (set) {
1384 vte->alt_cursor_x =
1385 tsm_screen_get_cursor_x(vte->con);
1386 vte->alt_cursor_y =
1387 tsm_screen_get_cursor_y(vte->con);
1388 tsm_screen_set_flags(vte->con,
1389 TSM_SCREEN_ALTERNATE);
1390 tsm_screen_erase_screen(vte->con, false);
1391 } else {
1392 tsm_screen_reset_flags(vte->con,
1393 TSM_SCREEN_ALTERNATE);
1394 tsm_screen_move_to(vte->con, vte->alt_cursor_x,
1395 vte->alt_cursor_y);
1396 }
1397 continue;
1398 case 2004:
1399 set_reset_flag(vte, set, FLAG_BRACKETED_PASTE_MODE);
1400 continue;
1401 default:
1402 llog_debug(vte, "unknown DEC %set-Mode %d",
1403 set?"S":"Res", vte->csi_argv[i]);
1404 continue;
1405 }
1406 }
1407 }
1408
csi_dev_attr(struct tsm_vte * vte)1409 static void csi_dev_attr(struct tsm_vte *vte)
1410 {
1411 if (vte->csi_argc <= 1 && vte->csi_argv[0] <= 0) {
1412 if (vte->csi_flags == 0) {
1413 send_primary_da(vte);
1414 return;
1415 } else if (vte->csi_flags & CSI_GT) {
1416 vte_write(vte, "\e[>1;1;0c", 9);
1417 return;
1418 }
1419 }
1420
1421 llog_debug(vte, "unhandled DA: %x %d %d %d...", vte->csi_flags,
1422 vte->csi_argv[0], vte->csi_argv[1], vte->csi_argv[2]);
1423 }
1424
csi_dsr(struct tsm_vte * vte)1425 static void csi_dsr(struct tsm_vte *vte)
1426 {
1427 char buf[64];
1428 int x, y;
1429 unsigned int len;
1430
1431 if (vte->csi_argv[0] == 5) {
1432 vte_write(vte, "\e[0n", 4);
1433 } else if (vte->csi_argv[0] == 6) {
1434 x = tsm_screen_get_cursor_x(vte->con);
1435 y = tsm_screen_get_cursor_y(vte->con);
1436 len = snprintf(buf, sizeof(buf), "\e[%u;%uR", y + 1, x + 1);
1437 if (len >= sizeof(buf))
1438 vte_write(vte, "\e[0;0R", 6);
1439 else
1440 vte_write(vte, buf, len);
1441 }
1442 }
1443
do_csi(struct tsm_vte * vte,uint32_t data)1444 static void do_csi(struct tsm_vte *vte, uint32_t data)
1445 {
1446 int num, x, y, upper, lower;
1447 bool protect;
1448
1449 if (vte->csi_argc < CSI_ARG_MAX)
1450 vte->csi_argc++;
1451
1452 switch (data) {
1453 case 'A': /* CUU */
1454 /* move cursor up */
1455 num = vte->csi_argv[0];
1456 if (num <= 0)
1457 num = 1;
1458 tsm_screen_move_up(vte->con, num, false);
1459 break;
1460 case 'B': /* CUD */
1461 /* move cursor down */
1462 num = vte->csi_argv[0];
1463 if (num <= 0)
1464 num = 1;
1465 tsm_screen_move_down(vte->con, num, false);
1466 break;
1467 case 'b': /* REP */
1468 /* repeat the preceding character */
1469 num = vte->csi_argv[0];
1470 if (num <= 0)
1471 num = 1;
1472 while (num--)
1473 write_console(vte, vte->last_sym);
1474 break;
1475 case 'C': /* CUF */
1476 /* move cursor forward */
1477 num = vte->csi_argv[0];
1478 if (num <= 0)
1479 num = 1;
1480 tsm_screen_move_right(vte->con, num);
1481 break;
1482 case 'D': /* CUB */
1483 /* move cursor backward */
1484 num = vte->csi_argv[0];
1485 if (num <= 0)
1486 num = 1;
1487 tsm_screen_move_left(vte->con, num);
1488 break;
1489 case 'd': /* VPA */
1490 /* Vertical Line Position Absolute */
1491 num = vte->csi_argv[0];
1492 if (num <= 0)
1493 num = 1;
1494 x = tsm_screen_get_cursor_x(vte->con);
1495 tsm_screen_move_to(vte->con, x, num - 1);
1496 break;
1497 case 'e': /* VPR */
1498 /* Vertical Line Position Relative */
1499 num = vte->csi_argv[0];
1500 if (num <= 0)
1501 num = 1;
1502 x = tsm_screen_get_cursor_x(vte->con);
1503 y = tsm_screen_get_cursor_y(vte->con);
1504 tsm_screen_move_to(vte->con, x, y + num);
1505 break;
1506 case 'H': /* CUP */
1507 case 'f': /* HVP */
1508 /* position cursor */
1509 x = vte->csi_argv[0];
1510 if (x <= 0)
1511 x = 1;
1512 y = vte->csi_argv[1];
1513 if (y <= 0)
1514 y = 1;
1515 tsm_screen_move_to(vte->con, y - 1, x - 1);
1516 break;
1517 case 'G': /* CHA */
1518 /* Cursor Character Absolute */
1519 num = vte->csi_argv[0];
1520 if (num <= 0)
1521 num = 1;
1522 y = tsm_screen_get_cursor_y(vte->con);
1523 tsm_screen_move_to(vte->con, num - 1, y);
1524 break;
1525 case 'J':
1526 if (vte->csi_flags & CSI_WHAT)
1527 protect = true;
1528 else
1529 protect = false;
1530
1531 if (vte->csi_argv[0] <= 0)
1532 tsm_screen_erase_cursor_to_screen(vte->con,
1533 protect);
1534 else if (vte->csi_argv[0] == 1)
1535 tsm_screen_erase_screen_to_cursor(vte->con,
1536 protect);
1537 else if (vte->csi_argv[0] == 2)
1538 tsm_screen_erase_screen(vte->con, protect);
1539 else
1540 llog_debug(vte, "unknown parameter to CSI-J: %d",
1541 vte->csi_argv[0]);
1542 break;
1543 case 'K':
1544 if (vte->csi_flags & CSI_WHAT)
1545 protect = true;
1546 else
1547 protect = false;
1548
1549 if (vte->csi_argv[0] <= 0)
1550 tsm_screen_erase_cursor_to_end(vte->con, protect);
1551 else if (vte->csi_argv[0] == 1)
1552 tsm_screen_erase_home_to_cursor(vte->con, protect);
1553 else if (vte->csi_argv[0] == 2)
1554 tsm_screen_erase_current_line(vte->con, protect);
1555 else
1556 llog_debug(vte, "unknown parameter to CSI-K: %d",
1557 vte->csi_argv[0]);
1558 break;
1559 case 'X': /* ECH */
1560 /* erase characters */
1561 num = vte->csi_argv[0];
1562 if (num <= 0)
1563 num = 1;
1564 tsm_screen_erase_chars(vte->con, num);
1565 break;
1566 case 'm':
1567 csi_attribute(vte);
1568 break;
1569 case 'p':
1570 if (vte->csi_flags & CSI_GT) {
1571 /* xterm: select X11 visual cursor mode */
1572 csi_soft_reset(vte);
1573 } else if (vte->csi_flags & CSI_BANG) {
1574 /* DECSTR: Soft Reset */
1575 csi_soft_reset(vte);
1576 } else if (vte->csi_flags & CSI_CASH) {
1577 /* DECRQM: Request DEC Private Mode */
1578 /* If CSI_WHAT is set, then enable,
1579 * otherwise disable */
1580 csi_soft_reset(vte);
1581 } else {
1582 /* DECSCL: Compatibility Level */
1583 /* Sometimes CSI_DQUOTE is set here, too */
1584 csi_compat_mode(vte);
1585 }
1586 break;
1587 case 'h': /* SM: Set Mode */
1588 csi_mode(vte, true);
1589 break;
1590 case 'l': /* RM: Reset Mode */
1591 csi_mode(vte, false);
1592 break;
1593 case 'r': /* DECSTBM */
1594 /* set margin size */
1595 upper = vte->csi_argv[0];
1596 if (upper < 0)
1597 upper = 0;
1598 lower = vte->csi_argv[1];
1599 if (lower < 0)
1600 lower = 0;
1601 tsm_screen_set_margins(vte->con, upper, lower);
1602 tsm_screen_move_to(vte->con, 0, 0);
1603 break;
1604 case 'c': /* DA */
1605 /* device attributes */
1606 csi_dev_attr(vte);
1607 break;
1608 case 'L': /* IL */
1609 /* insert lines */
1610 num = vte->csi_argv[0];
1611 if (num <= 0)
1612 num = 1;
1613 tsm_screen_insert_lines(vte->con, num);
1614 break;
1615 case 'M': /* DL */
1616 /* delete lines */
1617 num = vte->csi_argv[0];
1618 if (num <= 0)
1619 num = 1;
1620 tsm_screen_delete_lines(vte->con, num);
1621 break;
1622 case 'g': /* TBC */
1623 /* tabulation clear */
1624 num = vte->csi_argv[0];
1625 if (num <= 0)
1626 tsm_screen_reset_tabstop(vte->con);
1627 else if (num == 3)
1628 tsm_screen_reset_all_tabstops(vte->con);
1629 else
1630 llog_debug(vte, "invalid parameter %d to TBC CSI", num);
1631 break;
1632 case '@': /* ICH */
1633 /* insert characters */
1634 num = vte->csi_argv[0];
1635 if (num <= 0)
1636 num = 1;
1637 tsm_screen_insert_chars(vte->con, num);
1638 break;
1639 case 'P': /* DCH */
1640 /* delete characters */
1641 num = vte->csi_argv[0];
1642 if (num <= 0)
1643 num = 1;
1644 tsm_screen_delete_chars(vte->con, num);
1645 break;
1646 case 'Z': /* CBT */
1647 /* cursor horizontal backwards tab */
1648 num = vte->csi_argv[0];
1649 if (num <= 0)
1650 num = 1;
1651 tsm_screen_tab_left(vte->con, num);
1652 break;
1653 case 'I': /* CHT */
1654 /* cursor horizontal forward tab */
1655 num = vte->csi_argv[0];
1656 if (num <= 0)
1657 num = 1;
1658 tsm_screen_tab_right(vte->con, num);
1659 break;
1660 case 'n': /* DSR */
1661 /* device status reports */
1662 csi_dsr(vte);
1663 break;
1664 case 'S': /* SU */
1665 /* scroll up */
1666 num = vte->csi_argv[0];
1667 if (num <= 0)
1668 num = 1;
1669 tsm_screen_scroll_up(vte->con, num);
1670 break;
1671 case 'T': /* SD */
1672 /* scroll down */
1673 num = vte->csi_argv[0];
1674 if (num <= 0)
1675 num = 1;
1676 tsm_screen_scroll_down(vte->con, num);
1677 break;
1678 default:
1679 llog_debug(vte, "unhandled CSI sequence %c", data);
1680 }
1681 }
1682
1683 /* map a character according to current GL and GR maps */
vte_map(struct tsm_vte * vte,uint32_t val)1684 static uint32_t vte_map(struct tsm_vte *vte, uint32_t val)
1685 {
1686 /* 32, 127, 160 and 255 map to identity like all values >255 */
1687 switch (val) {
1688 case 33 ... 126:
1689 if (vte->glt) {
1690 val = (**vte->glt)[val - 32];
1691 vte->glt = NULL;
1692 } else {
1693 val = (**vte->gl)[val - 32];
1694 }
1695 break;
1696 case 161 ... 254:
1697 if (vte->grt) {
1698 val = (**vte->grt)[val - 160];
1699 vte->grt = NULL;
1700 } else {
1701 val = (**vte->gr)[val - 160];
1702 }
1703 break;
1704 }
1705
1706 return val;
1707 }
1708
1709 /* perform parser action */
do_action(struct tsm_vte * vte,uint32_t data,int action)1710 static void do_action(struct tsm_vte *vte, uint32_t data, int action)
1711 {
1712 tsm_symbol_t sym;
1713
1714 switch (action) {
1715 case ACTION_NONE:
1716 /* do nothing */
1717 return;
1718 case ACTION_IGNORE:
1719 /* ignore character */
1720 break;
1721 case ACTION_PRINT:
1722 sym = tsm_symbol_make(vte_map(vte, data));
1723 write_console(vte, sym);
1724 break;
1725 case ACTION_EXECUTE:
1726 do_execute(vte, data);
1727 break;
1728 case ACTION_CLEAR:
1729 do_clear(vte);
1730 break;
1731 case ACTION_COLLECT:
1732 do_collect(vte, data);
1733 break;
1734 case ACTION_PARAM:
1735 do_param(vte, data);
1736 break;
1737 case ACTION_ESC_DISPATCH:
1738 do_esc(vte, data);
1739 break;
1740 case ACTION_CSI_DISPATCH:
1741 do_csi(vte, data);
1742 break;
1743 case ACTION_DCS_START:
1744 break;
1745 case ACTION_DCS_COLLECT:
1746 break;
1747 case ACTION_DCS_END:
1748 break;
1749 case ACTION_OSC_START:
1750 break;
1751 case ACTION_OSC_COLLECT:
1752 break;
1753 case ACTION_OSC_END:
1754 break;
1755 default:
1756 llog_warning(vte, "invalid action %d", action);
1757 }
1758 }
1759
1760 /* entry actions to be performed when entering the selected state */
1761 static const int entry_action[] = {
1762 [STATE_CSI_ENTRY] = ACTION_CLEAR,
1763 [STATE_DCS_ENTRY] = ACTION_CLEAR,
1764 [STATE_DCS_PASS] = ACTION_DCS_START,
1765 [STATE_ESC] = ACTION_CLEAR,
1766 [STATE_OSC_STRING] = ACTION_OSC_START,
1767 [STATE_NUM] = ACTION_NONE,
1768 };
1769
1770 /* exit actions to be performed when leaving the selected state */
1771 static const int exit_action[] = {
1772 [STATE_DCS_PASS] = ACTION_DCS_END,
1773 [STATE_OSC_STRING] = ACTION_OSC_END,
1774 [STATE_NUM] = ACTION_NONE,
1775 };
1776
1777 /* perform state transition and dispatch related actions */
do_trans(struct tsm_vte * vte,uint32_t data,int state,int act)1778 static void do_trans(struct tsm_vte *vte, uint32_t data, int state, int act)
1779 {
1780 if (state != STATE_NONE) {
1781 /* A state transition occurs. Perform exit-action,
1782 * transition-action and entry-action. Even when performing a
1783 * transition to the same state as the current state we do this.
1784 * Use STATE_NONE if this is not the desired behavior.
1785 */
1786 do_action(vte, data, exit_action[vte->state]);
1787 do_action(vte, data, act);
1788 do_action(vte, data, entry_action[state]);
1789 vte->state = state;
1790 } else {
1791 do_action(vte, data, act);
1792 }
1793 }
1794
1795 /*
1796 * Escape sequence parser
1797 * This parses the new input character \data. It performs state transition and
1798 * calls the right callbacks for each action.
1799 */
parse_data(struct tsm_vte * vte,uint32_t raw)1800 static void parse_data(struct tsm_vte *vte, uint32_t raw)
1801 {
1802 /* events that may occur in any state */
1803 switch (raw) {
1804 case 0x18:
1805 case 0x1a:
1806 case 0x80 ... 0x8f:
1807 case 0x91 ... 0x97:
1808 case 0x99:
1809 case 0x9a:
1810 case 0x9c:
1811 do_trans(vte, raw, STATE_GROUND, ACTION_EXECUTE);
1812 return;
1813 case 0x1b:
1814 do_trans(vte, raw, STATE_ESC, ACTION_NONE);
1815 return;
1816 case 0x98:
1817 case 0x9e:
1818 case 0x9f:
1819 do_trans(vte, raw, STATE_ST_IGNORE, ACTION_NONE);
1820 return;
1821 case 0x90:
1822 do_trans(vte, raw, STATE_DCS_ENTRY, ACTION_NONE);
1823 return;
1824 case 0x9d:
1825 do_trans(vte, raw, STATE_OSC_STRING, ACTION_NONE);
1826 return;
1827 case 0x9b:
1828 do_trans(vte, raw, STATE_CSI_ENTRY, ACTION_NONE);
1829 return;
1830 }
1831
1832 /* events that depend on the current state */
1833 switch (vte->state) {
1834 case STATE_GROUND:
1835 switch (raw) {
1836 case 0x00 ... 0x17:
1837 case 0x19:
1838 case 0x1c ... 0x1f:
1839 case 0x80 ... 0x8f:
1840 case 0x91 ... 0x9a:
1841 case 0x9c:
1842 do_trans(vte, raw, STATE_NONE, ACTION_EXECUTE);
1843 return;
1844 case 0x20 ... 0x7f:
1845 do_trans(vte, raw, STATE_NONE, ACTION_PRINT);
1846 return;
1847 }
1848 do_trans(vte, raw, STATE_NONE, ACTION_PRINT);
1849 return;
1850 case STATE_ESC:
1851 switch (raw) {
1852 case 0x00 ... 0x17:
1853 case 0x19:
1854 case 0x1c ... 0x1f:
1855 do_trans(vte, raw, STATE_NONE, ACTION_EXECUTE);
1856 return;
1857 case 0x7f:
1858 do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
1859 return;
1860 case 0x20 ... 0x2f:
1861 do_trans(vte, raw, STATE_ESC_INT, ACTION_COLLECT);
1862 return;
1863 case 0x30 ... 0x4f:
1864 case 0x51 ... 0x57:
1865 case 0x59:
1866 case 0x5a:
1867 case 0x5c:
1868 case 0x60 ... 0x7e:
1869 do_trans(vte, raw, STATE_GROUND, ACTION_ESC_DISPATCH);
1870 return;
1871 case 0x5b:
1872 do_trans(vte, raw, STATE_CSI_ENTRY, ACTION_NONE);
1873 return;
1874 case 0x5d:
1875 do_trans(vte, raw, STATE_OSC_STRING, ACTION_NONE);
1876 return;
1877 case 0x50:
1878 do_trans(vte, raw, STATE_DCS_ENTRY, ACTION_NONE);
1879 return;
1880 case 0x58:
1881 case 0x5e:
1882 case 0x5f:
1883 do_trans(vte, raw, STATE_ST_IGNORE, ACTION_NONE);
1884 return;
1885 }
1886 do_trans(vte, raw, STATE_ESC_INT, ACTION_COLLECT);
1887 return;
1888 case STATE_ESC_INT:
1889 switch (raw) {
1890 case 0x00 ... 0x17:
1891 case 0x19:
1892 case 0x1c ... 0x1f:
1893 do_trans(vte, raw, STATE_NONE, ACTION_EXECUTE);
1894 return;
1895 case 0x20 ... 0x2f:
1896 do_trans(vte, raw, STATE_NONE, ACTION_COLLECT);
1897 return;
1898 case 0x7f:
1899 do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
1900 return;
1901 case 0x30 ... 0x7e:
1902 do_trans(vte, raw, STATE_GROUND, ACTION_ESC_DISPATCH);
1903 return;
1904 }
1905 do_trans(vte, raw, STATE_NONE, ACTION_COLLECT);
1906 return;
1907 case STATE_CSI_ENTRY:
1908 switch (raw) {
1909 case 0x00 ... 0x17:
1910 case 0x19:
1911 case 0x1c ... 0x1f:
1912 do_trans(vte, raw, STATE_NONE, ACTION_EXECUTE);
1913 return;
1914 case 0x7f:
1915 do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
1916 return;
1917 case 0x20 ... 0x2f:
1918 do_trans(vte, raw, STATE_CSI_INT, ACTION_COLLECT);
1919 return;
1920 case 0x3a:
1921 do_trans(vte, raw, STATE_CSI_IGNORE, ACTION_NONE);
1922 return;
1923 case 0x30 ... 0x39:
1924 case 0x3b:
1925 do_trans(vte, raw, STATE_CSI_PARAM, ACTION_PARAM);
1926 return;
1927 case 0x3c ... 0x3f:
1928 do_trans(vte, raw, STATE_CSI_PARAM, ACTION_COLLECT);
1929 return;
1930 case 0x40 ... 0x7e:
1931 do_trans(vte, raw, STATE_GROUND, ACTION_CSI_DISPATCH);
1932 return;
1933 }
1934 do_trans(vte, raw, STATE_CSI_IGNORE, ACTION_NONE);
1935 return;
1936 case STATE_CSI_PARAM:
1937 switch (raw) {
1938 case 0x00 ... 0x17:
1939 case 0x19:
1940 case 0x1c ... 0x1f:
1941 do_trans(vte, raw, STATE_NONE, ACTION_EXECUTE);
1942 return;
1943 case 0x30 ... 0x39:
1944 case 0x3b:
1945 do_trans(vte, raw, STATE_NONE, ACTION_PARAM);
1946 return;
1947 case 0x7f:
1948 do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
1949 return;
1950 case 0x3a:
1951 case 0x3c ... 0x3f:
1952 do_trans(vte, raw, STATE_CSI_IGNORE, ACTION_NONE);
1953 return;
1954 case 0x20 ... 0x2f:
1955 do_trans(vte, raw, STATE_CSI_INT, ACTION_COLLECT);
1956 return;
1957 case 0x40 ... 0x7e:
1958 do_trans(vte, raw, STATE_GROUND, ACTION_CSI_DISPATCH);
1959 return;
1960 }
1961 do_trans(vte, raw, STATE_CSI_IGNORE, ACTION_NONE);
1962 return;
1963 case STATE_CSI_INT:
1964 switch (raw) {
1965 case 0x00 ... 0x17:
1966 case 0x19:
1967 case 0x1c ... 0x1f:
1968 do_trans(vte, raw, STATE_NONE, ACTION_EXECUTE);
1969 return;
1970 case 0x20 ... 0x2f:
1971 do_trans(vte, raw, STATE_NONE, ACTION_COLLECT);
1972 return;
1973 case 0x7f:
1974 do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
1975 return;
1976 case 0x30 ... 0x3f:
1977 do_trans(vte, raw, STATE_CSI_IGNORE, ACTION_NONE);
1978 return;
1979 case 0x40 ... 0x7e:
1980 do_trans(vte, raw, STATE_GROUND, ACTION_CSI_DISPATCH);
1981 return;
1982 }
1983 do_trans(vte, raw, STATE_CSI_IGNORE, ACTION_NONE);
1984 return;
1985 case STATE_CSI_IGNORE:
1986 switch (raw) {
1987 case 0x00 ... 0x17:
1988 case 0x19:
1989 case 0x1c ... 0x1f:
1990 do_trans(vte, raw, STATE_NONE, ACTION_EXECUTE);
1991 return;
1992 case 0x20 ... 0x3f:
1993 case 0x7f:
1994 do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
1995 return;
1996 case 0x40 ... 0x7e:
1997 do_trans(vte, raw, STATE_GROUND, ACTION_NONE);
1998 return;
1999 }
2000 do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2001 return;
2002 case STATE_DCS_ENTRY:
2003 switch (raw) {
2004 case 0x00 ... 0x17:
2005 case 0x19:
2006 case 0x1c ... 0x1f:
2007 case 0x7f:
2008 do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2009 return;
2010 case 0x3a:
2011 do_trans(vte, raw, STATE_DCS_IGNORE, ACTION_NONE);
2012 return;
2013 case 0x20 ... 0x2f:
2014 do_trans(vte, raw, STATE_DCS_INT, ACTION_COLLECT);
2015 return;
2016 case 0x30 ... 0x39:
2017 case 0x3b:
2018 do_trans(vte, raw, STATE_DCS_PARAM, ACTION_PARAM);
2019 return;
2020 case 0x3c ... 0x3f:
2021 do_trans(vte, raw, STATE_DCS_PARAM, ACTION_COLLECT);
2022 return;
2023 case 0x40 ... 0x7e:
2024 do_trans(vte, raw, STATE_DCS_PASS, ACTION_NONE);
2025 return;
2026 }
2027 do_trans(vte, raw, STATE_DCS_PASS, ACTION_NONE);
2028 return;
2029 case STATE_DCS_PARAM:
2030 switch (raw) {
2031 case 0x00 ... 0x17:
2032 case 0x19:
2033 case 0x1c ... 0x1f:
2034 case 0x7f:
2035 do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2036 return;
2037 case 0x30 ... 0x39:
2038 case 0x3b:
2039 do_trans(vte, raw, STATE_NONE, ACTION_PARAM);
2040 return;
2041 case 0x3a:
2042 case 0x3c ... 0x3f:
2043 do_trans(vte, raw, STATE_DCS_IGNORE, ACTION_NONE);
2044 return;
2045 case 0x20 ... 0x2f:
2046 do_trans(vte, raw, STATE_DCS_INT, ACTION_COLLECT);
2047 return;
2048 case 0x40 ... 0x7e:
2049 do_trans(vte, raw, STATE_DCS_PASS, ACTION_NONE);
2050 return;
2051 }
2052 do_trans(vte, raw, STATE_DCS_PASS, ACTION_NONE);
2053 return;
2054 case STATE_DCS_INT:
2055 switch (raw) {
2056 case 0x00 ... 0x17:
2057 case 0x19:
2058 case 0x1c ... 0x1f:
2059 case 0x7f:
2060 do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2061 return;
2062 case 0x20 ... 0x2f:
2063 do_trans(vte, raw, STATE_NONE, ACTION_COLLECT);
2064 return;
2065 case 0x30 ... 0x3f:
2066 do_trans(vte, raw, STATE_DCS_IGNORE, ACTION_NONE);
2067 return;
2068 case 0x40 ... 0x7e:
2069 do_trans(vte, raw, STATE_DCS_PASS, ACTION_NONE);
2070 return;
2071 }
2072 do_trans(vte, raw, STATE_DCS_PASS, ACTION_NONE);
2073 return;
2074 case STATE_DCS_PASS:
2075 switch (raw) {
2076 case 0x00 ... 0x17:
2077 case 0x19:
2078 case 0x1c ... 0x1f:
2079 case 0x20 ... 0x7e:
2080 do_trans(vte, raw, STATE_NONE, ACTION_DCS_COLLECT);
2081 return;
2082 case 0x7f:
2083 do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2084 return;
2085 case 0x9c:
2086 do_trans(vte, raw, STATE_GROUND, ACTION_NONE);
2087 return;
2088 }
2089 do_trans(vte, raw, STATE_NONE, ACTION_DCS_COLLECT);
2090 return;
2091 case STATE_DCS_IGNORE:
2092 switch (raw) {
2093 case 0x00 ... 0x17:
2094 case 0x19:
2095 case 0x1c ... 0x1f:
2096 case 0x20 ... 0x7f:
2097 do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2098 return;
2099 case 0x9c:
2100 do_trans(vte, raw, STATE_GROUND, ACTION_NONE);
2101 return;
2102 }
2103 do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2104 return;
2105 case STATE_OSC_STRING:
2106 switch (raw) {
2107 case 0x00 ... 0x06:
2108 case 0x08 ... 0x17:
2109 case 0x19:
2110 case 0x1c ... 0x1f:
2111 do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2112 return;
2113 case 0x20 ... 0x7f:
2114 do_trans(vte, raw, STATE_NONE, ACTION_OSC_COLLECT);
2115 return;
2116 case 0x07:
2117 case 0x9c:
2118 do_trans(vte, raw, STATE_GROUND, ACTION_NONE);
2119 return;
2120 }
2121 do_trans(vte, raw, STATE_NONE, ACTION_OSC_COLLECT);
2122 return;
2123 case STATE_ST_IGNORE:
2124 switch (raw) {
2125 case 0x00 ... 0x17:
2126 case 0x19:
2127 case 0x1c ... 0x1f:
2128 case 0x20 ... 0x7f:
2129 do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2130 return;
2131 case 0x9c:
2132 do_trans(vte, raw, STATE_GROUND, ACTION_NONE);
2133 return;
2134 }
2135 do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2136 return;
2137 }
2138
2139 llog_warning(vte, "unhandled input %u in state %d", raw, vte->state);
2140 }
2141
2142 SHL_EXPORT
tsm_vte_input(struct tsm_vte * vte,const char * u8,size_t len)2143 void tsm_vte_input(struct tsm_vte *vte, const char *u8, size_t len)
2144 {
2145 int state;
2146 uint32_t ucs4;
2147 size_t i;
2148
2149 ++vte->parse_cnt;
2150 for (i = 0; i < len; ++i) {
2151 if (vte->flags & FLAG_7BIT_MODE) {
2152 if (u8[i] & 0x80)
2153 llog_debug(vte, "receiving 8bit character U+%d from pty while in 7bit mode",
2154 (int)u8[i]);
2155 parse_data(vte, u8[i] & 0x7f);
2156 } else if (vte->flags & FLAG_8BIT_MODE) {
2157 parse_data(vte, u8[i]);
2158 } else {
2159 state = tsm_utf8_mach_feed(vte->mach, u8[i]);
2160 if (state == TSM_UTF8_ACCEPT ||
2161 state == TSM_UTF8_REJECT) {
2162 ucs4 = tsm_utf8_mach_get(vte->mach);
2163 parse_data(vte, ucs4);
2164 }
2165 }
2166 }
2167 --vte->parse_cnt;
2168 }
2169
2170 SHL_EXPORT
tsm_vte_handle_keyboard(struct tsm_vte * vte,uint32_t keysym,uint32_t ascii,unsigned int mods,uint32_t unicode)2171 bool tsm_vte_handle_keyboard(struct tsm_vte *vte, uint32_t keysym,
2172 uint32_t ascii, unsigned int mods,
2173 uint32_t unicode)
2174 {
2175 char val, u8[4];
2176 size_t len;
2177 uint32_t sym;
2178
2179 /* MOD1 (mostly labeled 'Alt') prepends an escape character to every
2180 * input that is sent by a key.
2181 * TODO: Transform this huge handler into a lookup table to save a lot
2182 * of code and make such modifiers easier to implement.
2183 * Also check whether altSendsEscape should be the default (xterm
2184 * disables this by default, why?) and whether we should implement the
2185 * fallback shifting that xterm does. */
2186 if (mods & TSM_ALT_MASK)
2187 vte->flags |= FLAG_PREPEND_ESCAPE;
2188
2189 /* A user might actually use multiple layouts for keyboard input. The
2190 * @keysym variable contains the actual keysym that the user used. But
2191 * if this keysym is not in the ascii range, the input handler does
2192 * check all other layouts that the user specified whether one of them
2193 * maps the key to some ASCII keysym and provides this via @ascii.
2194 * We always use the real keysym except when handling CTRL+<XY>
2195 * shortcuts we use the ascii keysym. This is for compatibility to xterm
2196 * et. al. so ctrl+c always works regardless of the currently active
2197 * keyboard layout.
2198 * But if no ascii-sym is found, we still use the real keysym. */
2199 sym = ascii;
2200 if (sym == XKB_KEY_NoSymbol)
2201 sym = keysym;
2202
2203 if (mods & TSM_CONTROL_MASK) {
2204 switch (sym) {
2205 case XKB_KEY_2:
2206 case XKB_KEY_space:
2207 vte_write(vte, "\x00", 1);
2208 return true;
2209 case XKB_KEY_a:
2210 case XKB_KEY_A:
2211 vte_write(vte, "\x01", 1);
2212 return true;
2213 case XKB_KEY_b:
2214 case XKB_KEY_B:
2215 vte_write(vte, "\x02", 1);
2216 return true;
2217 case XKB_KEY_c:
2218 case XKB_KEY_C:
2219 vte_write(vte, "\x03", 1);
2220 return true;
2221 case XKB_KEY_d:
2222 case XKB_KEY_D:
2223 vte_write(vte, "\x04", 1);
2224 return true;
2225 case XKB_KEY_e:
2226 case XKB_KEY_E:
2227 vte_write(vte, "\x05", 1);
2228 return true;
2229 case XKB_KEY_f:
2230 case XKB_KEY_F:
2231 vte_write(vte, "\x06", 1);
2232 return true;
2233 case XKB_KEY_g:
2234 case XKB_KEY_G:
2235 vte_write(vte, "\x07", 1);
2236 return true;
2237 case XKB_KEY_h:
2238 case XKB_KEY_H:
2239 vte_write(vte, "\x08", 1);
2240 return true;
2241 case XKB_KEY_i:
2242 case XKB_KEY_I:
2243 vte_write(vte, "\x09", 1);
2244 return true;
2245 case XKB_KEY_j:
2246 case XKB_KEY_J:
2247 vte_write(vte, "\x0a", 1);
2248 return true;
2249 case XKB_KEY_k:
2250 case XKB_KEY_K:
2251 vte_write(vte, "\x0b", 1);
2252 return true;
2253 case XKB_KEY_l:
2254 case XKB_KEY_L:
2255 vte_write(vte, "\x0c", 1);
2256 return true;
2257 case XKB_KEY_m:
2258 case XKB_KEY_M:
2259 vte_write(vte, "\x0d", 1);
2260 return true;
2261 case XKB_KEY_n:
2262 case XKB_KEY_N:
2263 vte_write(vte, "\x0e", 1);
2264 return true;
2265 case XKB_KEY_o:
2266 case XKB_KEY_O:
2267 vte_write(vte, "\x0f", 1);
2268 return true;
2269 case XKB_KEY_p:
2270 case XKB_KEY_P:
2271 vte_write(vte, "\x10", 1);
2272 return true;
2273 case XKB_KEY_q:
2274 case XKB_KEY_Q:
2275 vte_write(vte, "\x11", 1);
2276 return true;
2277 case XKB_KEY_r:
2278 case XKB_KEY_R:
2279 vte_write(vte, "\x12", 1);
2280 return true;
2281 case XKB_KEY_s:
2282 case XKB_KEY_S:
2283 vte_write(vte, "\x13", 1);
2284 return true;
2285 case XKB_KEY_t:
2286 case XKB_KEY_T:
2287 vte_write(vte, "\x14", 1);
2288 return true;
2289 case XKB_KEY_u:
2290 case XKB_KEY_U:
2291 vte_write(vte, "\x15", 1);
2292 return true;
2293 case XKB_KEY_v:
2294 case XKB_KEY_V:
2295 vte_write(vte, "\x16", 1);
2296 return true;
2297 case XKB_KEY_w:
2298 case XKB_KEY_W:
2299 vte_write(vte, "\x17", 1);
2300 return true;
2301 case XKB_KEY_x:
2302 case XKB_KEY_X:
2303 vte_write(vte, "\x18", 1);
2304 return true;
2305 case XKB_KEY_y:
2306 case XKB_KEY_Y:
2307 vte_write(vte, "\x19", 1);
2308 return true;
2309 case XKB_KEY_z:
2310 case XKB_KEY_Z:
2311 vte_write(vte, "\x1a", 1);
2312 return true;
2313 case XKB_KEY_3:
2314 case XKB_KEY_bracketleft:
2315 case XKB_KEY_braceleft:
2316 vte_write(vte, "\x1b", 1);
2317 return true;
2318 case XKB_KEY_4:
2319 case XKB_KEY_backslash:
2320 case XKB_KEY_bar:
2321 vte_write(vte, "\x1c", 1);
2322 return true;
2323 case XKB_KEY_5:
2324 case XKB_KEY_bracketright:
2325 case XKB_KEY_braceright:
2326 vte_write(vte, "\x1d", 1);
2327 return true;
2328 case XKB_KEY_6:
2329 case XKB_KEY_grave:
2330 case XKB_KEY_asciitilde:
2331 vte_write(vte, "\x1e", 1);
2332 return true;
2333 case XKB_KEY_7:
2334 case XKB_KEY_slash:
2335 case XKB_KEY_question:
2336 vte_write(vte, "\x1f", 1);
2337 return true;
2338 case XKB_KEY_8:
2339 vte_write(vte, "\x7f", 1);
2340 return true;
2341 }
2342 }
2343
2344 switch (keysym) {
2345 case XKB_KEY_BackSpace:
2346 vte_write(vte, "\x7f", 1);
2347 return true;
2348 case XKB_KEY_Tab:
2349 case XKB_KEY_KP_Tab:
2350 vte_write(vte, "\x09", 1);
2351 return true;
2352 case XKB_KEY_ISO_Left_Tab:
2353 vte_write(vte, "\e[Z", 3);
2354 return true;
2355 case XKB_KEY_Linefeed:
2356 vte_write(vte, "\x0a", 1);
2357 return true;
2358 case XKB_KEY_Clear:
2359 vte_write(vte, "\x0b", 1);
2360 return true;
2361 /*
2362 TODO: What should we do with this key? Sending XOFF is awful as
2363 there is no simple way on modern keyboards to send XON
2364 again. If someone wants this, we can re-eanble it and set
2365 some flag.
2366 case XKB_KEY_Pause:
2367 vte_write(vte, "\x13", 1);
2368 return true;
2369 */
2370 /*
2371 TODO: What should we do on scroll-lock? Sending 0x14 is what
2372 the specs say but it is not used today the way most
2373 users would expect so we disable it. If someone wants
2374 this, we can re-enable it and set some flag.
2375 case XKB_KEY_Scroll_Lock:
2376 vte_write(vte, "\x14", 1);
2377 return true;
2378 */
2379 case XKB_KEY_Sys_Req:
2380 vte_write(vte, "\x15", 1);
2381 return true;
2382 case XKB_KEY_Escape:
2383 vte_write(vte, "\x1b", 1);
2384 return true;
2385 case XKB_KEY_KP_Enter:
2386 if (vte->flags & FLAG_KEYPAD_APPLICATION_MODE) {
2387 vte_write(vte, "\eOM", 3);
2388 return true;
2389 }
2390 /* fallthrough */
2391 case XKB_KEY_Return:
2392 if (vte->flags & FLAG_LINE_FEED_NEW_LINE_MODE)
2393 vte_write(vte, "\x0d\x0a", 2);
2394 else
2395 vte_write(vte, "\x0d", 1);
2396 return true;
2397 case XKB_KEY_Find:
2398 vte_write_fnkey(vte, false, mods, 1, '~');
2399 return true;
2400 case XKB_KEY_Insert:
2401 vte_write_fnkey(vte, false, mods, 2, '~');
2402 return true;
2403 case XKB_KEY_Delete:
2404 vte_write_fnkey(vte, false, mods, 3, '~');
2405 return true;
2406 case XKB_KEY_Select:
2407 vte_write_fnkey(vte, false, mods, 4, '~');
2408 return true;
2409 case XKB_KEY_Page_Up:
2410 case XKB_KEY_KP_Page_Up:
2411 vte_write_fnkey(vte, false, mods, 5, '~');
2412 return true;
2413 case XKB_KEY_Page_Down:
2414 case XKB_KEY_KP_Page_Down:
2415 vte_write_fnkey(vte, false, mods, 6, '~');
2416 return true;
2417 case XKB_KEY_Up:
2418 case XKB_KEY_KP_Up:
2419 vte_write_fnkey(vte, vte->flags & FLAG_CURSOR_KEY_MODE,
2420 mods, 0, 'A');
2421 return true;
2422 case XKB_KEY_Down:
2423 case XKB_KEY_KP_Down:
2424 vte_write_fnkey(vte, vte->flags & FLAG_CURSOR_KEY_MODE,
2425 mods, 0, 'B');
2426 return true;
2427 case XKB_KEY_Right:
2428 case XKB_KEY_KP_Right:
2429 vte_write_fnkey(vte, vte->flags & FLAG_CURSOR_KEY_MODE,
2430 mods, 0, 'C');
2431 return true;
2432 case XKB_KEY_Left:
2433 case XKB_KEY_KP_Left:
2434 vte_write_fnkey(vte, vte->flags & FLAG_CURSOR_KEY_MODE,
2435 mods, 0, 'D');
2436 return true;
2437 case XKB_KEY_KP_Insert:
2438 case XKB_KEY_KP_0:
2439 if (vte->flags & FLAG_KEYPAD_APPLICATION_MODE)
2440 vte_write(vte, "\eOp", 3);
2441 else
2442 vte_write(vte, "0", 1);
2443 return true;
2444 case XKB_KEY_KP_1:
2445 if (vte->flags & FLAG_KEYPAD_APPLICATION_MODE)
2446 vte_write(vte, "\eOq", 3);
2447 else
2448 vte_write(vte, "1", 1);
2449 return true;
2450 case XKB_KEY_KP_2:
2451 if (vte->flags & FLAG_KEYPAD_APPLICATION_MODE)
2452 vte_write(vte, "\eOr", 3);
2453 else
2454 vte_write(vte, "2", 1);
2455 return true;
2456 case XKB_KEY_KP_3:
2457 if (vte->flags & FLAG_KEYPAD_APPLICATION_MODE)
2458 vte_write(vte, "\eOs", 3);
2459 else
2460 vte_write(vte, "3", 1);
2461 return true;
2462 case XKB_KEY_KP_4:
2463 if (vte->flags & FLAG_KEYPAD_APPLICATION_MODE)
2464 vte_write(vte, "\eOt", 3);
2465 else
2466 vte_write(vte, "4", 1);
2467 return true;
2468 case XKB_KEY_KP_5:
2469 if (vte->flags & FLAG_KEYPAD_APPLICATION_MODE)
2470 vte_write(vte, "\eOu", 3);
2471 else
2472 vte_write(vte, "5", 1);
2473 return true;
2474 case XKB_KEY_KP_6:
2475 if (vte->flags & FLAG_KEYPAD_APPLICATION_MODE)
2476 vte_write(vte, "\eOv", 3);
2477 else
2478 vte_write(vte, "6", 1);
2479 return true;
2480 case XKB_KEY_KP_7:
2481 if (vte->flags & FLAG_KEYPAD_APPLICATION_MODE)
2482 vte_write(vte, "\eOw", 3);
2483 else
2484 vte_write(vte, "7", 1);
2485 return true;
2486 case XKB_KEY_KP_8:
2487 if (vte->flags & FLAG_KEYPAD_APPLICATION_MODE)
2488 vte_write(vte, "\eOx", 3);
2489 else
2490 vte_write(vte, "8", 1);
2491 return true;
2492 case XKB_KEY_KP_9:
2493 if (vte->flags & FLAG_KEYPAD_APPLICATION_MODE)
2494 vte_write(vte, "\eOy", 3);
2495 else
2496 vte_write(vte, "9", 1);
2497 return true;
2498 case XKB_KEY_KP_Subtract:
2499 if (vte->flags & FLAG_KEYPAD_APPLICATION_MODE)
2500 vte_write(vte, "\eOm", 3);
2501 else
2502 vte_write(vte, "-", 1);
2503 return true;
2504 case XKB_KEY_KP_Separator:
2505 if (vte->flags & FLAG_KEYPAD_APPLICATION_MODE)
2506 vte_write(vte, "\eOl", 3);
2507 else
2508 vte_write(vte, ",", 1);
2509 return true;
2510 case XKB_KEY_KP_Delete:
2511 case XKB_KEY_KP_Decimal:
2512 if (vte->flags & FLAG_KEYPAD_APPLICATION_MODE)
2513 vte_write(vte, "\eOn", 3);
2514 else
2515 vte_write(vte, ".", 1);
2516 return true;
2517 case XKB_KEY_KP_Equal:
2518 case XKB_KEY_KP_Divide:
2519 if (vte->flags & FLAG_KEYPAD_APPLICATION_MODE)
2520 vte_write(vte, "\eOj", 3);
2521 else
2522 vte_write(vte, "/", 1);
2523 return true;
2524 case XKB_KEY_KP_Multiply:
2525 if (vte->flags & FLAG_KEYPAD_APPLICATION_MODE)
2526 vte_write(vte, "\eOo", 3);
2527 else
2528 vte_write(vte, "*", 1);
2529 return true;
2530 case XKB_KEY_KP_Add:
2531 if (vte->flags & FLAG_KEYPAD_APPLICATION_MODE)
2532 vte_write(vte, "\eOk", 3);
2533 else
2534 vte_write(vte, "+", 1);
2535 return true;
2536 case XKB_KEY_Home:
2537 case XKB_KEY_KP_Home:
2538 vte_write_fnkey(vte, vte->flags & FLAG_CURSOR_KEY_MODE,
2539 mods, 0, 'H');
2540 return true;
2541 case XKB_KEY_End:
2542 case XKB_KEY_KP_End:
2543 vte_write_fnkey(vte, vte->flags & FLAG_CURSOR_KEY_MODE,
2544 mods, 0, 'F');
2545 return true;
2546 case XKB_KEY_KP_Space:
2547 vte_write(vte, " ", 1);
2548 return true;
2549 case XKB_KEY_F1:
2550 case XKB_KEY_KP_F1:
2551 vte_write_fnkey(vte, true, mods, 0, 'P');
2552 return true;
2553 case XKB_KEY_F2:
2554 case XKB_KEY_KP_F2:
2555 vte_write_fnkey(vte, true, mods, 0, 'Q');
2556 return true;
2557 case XKB_KEY_F3:
2558 case XKB_KEY_KP_F3:
2559 vte_write_fnkey(vte, true, mods, 0, 'R');
2560 return true;
2561 case XKB_KEY_F4:
2562 case XKB_KEY_KP_F4:
2563 vte_write_fnkey(vte, true, mods, 0, 'S');
2564 return true;
2565 case XKB_KEY_F5:
2566 vte_write_fnkey(vte, false, mods, 15, '~');
2567 return true;
2568 case XKB_KEY_F6:
2569 vte_write_fnkey(vte, false, mods, 17, '~');
2570 return true;
2571 case XKB_KEY_F7:
2572 vte_write_fnkey(vte, false, mods, 18, '~');
2573 return true;
2574 case XKB_KEY_F8:
2575 vte_write_fnkey(vte, false, mods, 19, '~');
2576 return true;
2577 case XKB_KEY_F9:
2578 vte_write_fnkey(vte, false, mods, 20, '~');
2579 return true;
2580 case XKB_KEY_F10:
2581 vte_write_fnkey(vte, false, mods, 21, '~');
2582 return true;
2583 case XKB_KEY_F11:
2584 vte_write_fnkey(vte, false, mods, 23, '~');
2585 return true;
2586 case XKB_KEY_F12:
2587 vte_write_fnkey(vte, false, mods, 24, '~');
2588 return true;
2589 case XKB_KEY_F13:
2590 vte_write_fnkey(vte, false, mods, 25, '~');
2591 return true;
2592 case XKB_KEY_F14:
2593 vte_write_fnkey(vte, false, mods, 26, '~');
2594 return true;
2595 case XKB_KEY_F15:
2596 vte_write_fnkey(vte, false, mods, 28, '~');
2597 return true;
2598 case XKB_KEY_F16:
2599 vte_write_fnkey(vte, false, mods, 29, '~');
2600 return true;
2601 case XKB_KEY_F17:
2602 vte_write_fnkey(vte, false, mods, 31, '~');
2603 return true;
2604 case XKB_KEY_F18:
2605 vte_write_fnkey(vte, false, mods, 32, '~');
2606 return true;
2607 case XKB_KEY_F19:
2608 vte_write_fnkey(vte, false, mods, 33, '~');
2609 return true;
2610 case XKB_KEY_F20:
2611 vte_write_fnkey(vte, false, mods, 34, '~');
2612 return true;
2613 }
2614
2615 if (unicode != TSM_VTE_INVALID) {
2616 if (vte->flags & FLAG_7BIT_MODE) {
2617 val = unicode;
2618 if (unicode & 0x80) {
2619 llog_debug(vte, "invalid keyboard input in 7bit mode U+%x; mapping to '?'",
2620 unicode);
2621 val = '?';
2622 }
2623 vte_write(vte, &val, 1);
2624 } else if (vte->flags & FLAG_8BIT_MODE) {
2625 val = unicode;
2626 if (unicode > 0xff) {
2627 llog_debug(vte, "invalid keyboard input in 8bit mode U+%x; mapping to '?'",
2628 unicode);
2629 val = '?';
2630 }
2631 vte_write_raw(vte, &val, 1);
2632 } else {
2633 len = tsm_ucs4_to_utf8(tsm_symbol_make(unicode), u8);
2634 vte_write_raw(vte, u8, len);
2635 }
2636 return true;
2637 }
2638
2639 vte->flags &= ~FLAG_PREPEND_ESCAPE;
2640 return false;
2641 }
2642
2643 SHL_EXPORT
tsm_vte_paste_begin(struct tsm_vte * vte)2644 void tsm_vte_paste_begin(struct tsm_vte *vte)
2645 {
2646 if (vte->flags & FLAG_BRACKETED_PASTE_MODE) {
2647 vte_write(vte, "\e[200~", 6);
2648 vte->pasting = true;
2649 vte->endpaste_i = 0;
2650 }
2651 }
2652
2653 SHL_EXPORT
tsm_vte_paste_end(struct tsm_vte * vte)2654 void tsm_vte_paste_end(struct tsm_vte *vte)
2655 {
2656 if (vte->pasting) {
2657 vte->pasting = false;
2658 if (vte->endpaste_i)
2659 vte->write_cb(vte, ENDPASTE, vte->endpaste_i,
2660 vte->data);
2661 vte_write(vte, "\e[201~", 6);
2662 }
2663 }
2664