1 /*
2 * libtsm - VT Emulator
3 *
4 * Copyright (c) 2011-2013 David Herrmann <dh.herrmann@gmail.com>
5 * Copyright (c) 2015-2018 Bjorn Stahl <contact@arcan-fe.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 <stdarg.h>
51 #include <inttypes.h>
52 #include "libtsm_int.h"
53
54 /* Input parser states */
55 enum parser_state {
56 STATE_NONE, /* placeholder */
57 STATE_GROUND, /* initial state and ground */
58 STATE_ESC, /* ESC sequence was started */
59 STATE_ESC_INT, /* intermediate escape characters */
60 STATE_CSI_ENTRY, /* starting CSI sequence */
61 STATE_CSI_PARAM, /* CSI parameters */
62 STATE_CSI_INT, /* intermediate CSI characters */
63 STATE_CSI_IGNORE, /* CSI error; ignore this CSI sequence */
64 STATE_DCS_ENTRY, /* starting DCS sequence */
65 STATE_DCS_PARAM, /* DCS parameters */
66 STATE_DCS_INT, /* intermediate DCS characters */
67 STATE_DCS_PASS, /* DCS data passthrough */
68 STATE_DCS_IGNORE, /* DCS error; ignore this DCS sequence */
69 STATE_OSC_STRING, /* parsing OCS sequence */
70 STATE_ST_IGNORE, /* unimplemented seq; ignore until ST */
71 STATE_NUM
72 };
73
74 /* Input parser actions */
75 enum parser_action {
76 ACTION_NONE = 0, /* placeholder */
77 ACTION_IGNORE, /* ignore the character entirely */
78 ACTION_PRINT, /* print the character on the console */
79 ACTION_EXECUTE, /* execute single control character (C0/C1) */
80 ACTION_CLEAR, /* clear current parameter state */
81 ACTION_COLLECT, /* collect intermediate character */
82 ACTION_PARAM, /* collect parameter character */
83 ACTION_ESC_DISPATCH, /* dispatch escape sequence */
84 ACTION_CSI_DISPATCH, /* dispatch csi sequence */
85 ACTION_DCS_START, /* start of DCS data */
86 ACTION_DCS_COLLECT, /* collect DCS data */
87 ACTION_DCS_END, /* end of DCS data */
88 ACTION_OSC_START, /* start of OSC data */
89 ACTION_OSC_COLLECT, /* collect OSC data */
90 ACTION_OSC_END, /* end of OSC data */
91 };
92
93 static const char* action_lut[] = {
94 "none",
95 "ignore",
96 "print",
97 "execute",
98 "clear",
99 "collect",
100 "param",
101 "esc",
102 "csi",
103 "dcs_s",
104 "dcs_c",
105 "dcs_e",
106 "osc_s",
107 "osc_c",
108 "osc_e",
109 };
110
111 const static int MOUSE_PROTO = MOUSE_SGR | MOUSE_X10 | MOUSE_RXVT;
112
113 /* CSI flags */
114 #define CSI_BANG 0x0001 /* CSI: ! */
115 #define CSI_CASH 0x0002 /* CSI: $ */
116 #define CSI_WHAT 0x0004 /* CSI: ? */
117 #define CSI_GT 0x0008 /* CSI: > */
118 #define CSI_SPACE 0x0010 /* CSI: */
119 #define CSI_SQUOTE 0x0020 /* CSI: ' */
120 #define CSI_DQUOTE 0x0040 /* CSI: " */
121 #define CSI_MULT 0x0080 /* CSI: * */
122 #define CSI_PLUS 0x0100 /* CSI: + */
123 #define CSI_POPEN 0x0200 /* CSI: ( */
124 #define CSI_PCLOSE 0x0400 /* CSI: ) */
125
126 /* terminal flags */
127 #define FLAG_CURSOR_KEY_MODE 0x00000001 /* DEC cursor key mode */
128 #define FLAG_KEYPAD_APPLICATION_MODE 0x00000002 /* DEC keypad application mode; TODO: toggle on numlock? */
129 #define FLAG_LINE_FEED_NEW_LINE_MODE 0x00000004 /* DEC line-feed/new-line mode */
130 #define FLAG_8BIT_MODE 0x00000008 /* Disable UTF-8 mode and enable 8bit compatible mode */
131 #define FLAG_7BIT_MODE 0x00000010 /* Disable 8bit mode and use 7bit compatible mode */
132 #define FLAG_USE_C1 0x00000020 /* Explicitly use 8bit C1 codes; TODO: implement */
133 #define FLAG_KEYBOARD_ACTION_MODE 0x00000040 /* Disable keyboard; TODO: implement? */
134 #define FLAG_INSERT_REPLACE_MODE 0x00000080 /* Enable insert mode */
135 #define FLAG_SEND_RECEIVE_MODE 0x00000100 /* Disable local echo */
136 #define FLAG_TEXT_CURSOR_MODE 0x00000200 /* Show cursor */
137 #define FLAG_INVERSE_SCREEN_MODE 0x00000400 /* Inverse colors */
138 #define FLAG_ORIGIN_MODE 0x00000800 /* Relative origin for cursor */
139 #define FLAG_AUTO_WRAP_MODE 0x00001000 /* Auto line wrap mode */
140 #define FLAG_AUTO_REPEAT_MODE 0x00002000 /* Auto repeat key press; TODO: implement */
141 #define FLAG_NATIONAL_CHARSET_MODE 0x00004000 /* Send keys from nation charsets; TODO: implement */
142 #define FLAG_BACKGROUND_COLOR_ERASE_MODE 0x00008000 /* Set background color on erase (bce) */
143 #define FLAG_PREPEND_ESCAPE 0x00010000 /* Prepend escape character to next output */
144 #define FLAG_TITE_INHIBIT_MODE 0x00020000 /* Prevent switching to alternate screen buffer */
145 #define FLAG_PASTE_BRACKET 0x00040000 /* Bracketed Paste mode */
146
147 static uint8_t color_palette[VTE_COLOR_NUM][3] = {
148 [VTE_COLOR_BLACK] = { 0, 0, 0 },
149 [VTE_COLOR_RED] = { 205, 0, 0 },
150 [VTE_COLOR_GREEN] = { 0, 205, 0 },
151 [VTE_COLOR_YELLOW] = { 205, 205, 0 },
152 [VTE_COLOR_BLUE] = { 0, 0, 238 },
153 [VTE_COLOR_MAGENTA] = { 205, 0, 205 },
154 [VTE_COLOR_CYAN] = { 0, 205, 205 },
155 [VTE_COLOR_LIGHT_GREY] = { 229, 229, 229 },
156 [VTE_COLOR_DARK_GREY] = { 127, 127, 127 },
157 [VTE_COLOR_LIGHT_RED] = { 255, 0, 0 },
158 [VTE_COLOR_LIGHT_GREEN] = { 0, 255, 0 },
159 [VTE_COLOR_LIGHT_YELLOW] = { 255, 255, 0 },
160 [VTE_COLOR_LIGHT_BLUE] = { 92, 92, 255 },
161 [VTE_COLOR_LIGHT_MAGENTA] = { 255, 0, 255 },
162 [VTE_COLOR_LIGHT_CYAN] = { 0, 255, 255 },
163 [VTE_COLOR_WHITE] = { 255, 255, 255 },
164
165 [VTE_COLOR_FOREGROUND] = { 229, 229, 229 },
166 [VTE_COLOR_BACKGROUND] = { 0, 0, 0 },
167 };
168
169 static uint8_t color_palette_solarized[VTE_COLOR_NUM][3] = {
170 [VTE_COLOR_BLACK] = { 7, 54, 66 },
171 [VTE_COLOR_RED] = { 220, 50, 47 },
172 [VTE_COLOR_GREEN] = { 133, 153, 0 },
173 [VTE_COLOR_YELLOW] = { 181, 137, 0 },
174 [VTE_COLOR_BLUE] = { 38, 139, 210 },
175 [VTE_COLOR_MAGENTA] = { 211, 54, 130 },
176 [VTE_COLOR_CYAN] = { 42, 161, 152 },
177 [VTE_COLOR_LIGHT_GREY] = { 238, 232, 213 },
178 [VTE_COLOR_DARK_GREY] = { 0, 43, 54 },
179 [VTE_COLOR_LIGHT_RED] = { 203, 75, 22 },
180 [VTE_COLOR_LIGHT_GREEN] = { 88, 110, 117 },
181 [VTE_COLOR_LIGHT_YELLOW] = { 101, 123, 131 },
182 [VTE_COLOR_LIGHT_BLUE] = { 131, 148, 150 },
183 [VTE_COLOR_LIGHT_MAGENTA] = { 108, 113, 196 },
184 [VTE_COLOR_LIGHT_CYAN] = { 147, 161, 161 },
185 [VTE_COLOR_WHITE] = { 253, 246, 227 },
186
187 [VTE_COLOR_FOREGROUND] = { 238, 232, 213 },
188 [VTE_COLOR_BACKGROUND] = { 7, 54, 66 },
189 };
190
191 static uint8_t color_palette_solarized_black[VTE_COLOR_NUM][3] = {
192 [VTE_COLOR_BLACK] = { 0, 0, 0 },
193 [VTE_COLOR_RED] = { 220, 50, 47 },
194 [VTE_COLOR_GREEN] = { 133, 153, 0 },
195 [VTE_COLOR_YELLOW] = { 181, 137, 0 },
196 [VTE_COLOR_BLUE] = { 38, 139, 210 },
197 [VTE_COLOR_MAGENTA] = { 211, 54, 130 },
198 [VTE_COLOR_CYAN] = { 42, 161, 152 },
199 [VTE_COLOR_LIGHT_GREY] = { 238, 232, 213 },
200 [VTE_COLOR_DARK_GREY] = { 0, 43, 54 },
201 [VTE_COLOR_LIGHT_RED] = { 203, 75, 22 },
202 [VTE_COLOR_LIGHT_GREEN] = { 88, 110, 117 },
203 [VTE_COLOR_LIGHT_YELLOW] = { 101, 123, 131 },
204 [VTE_COLOR_LIGHT_BLUE] = { 131, 148, 150 },
205 [VTE_COLOR_LIGHT_MAGENTA] = { 108, 113, 196 },
206 [VTE_COLOR_LIGHT_CYAN] = { 147, 161, 161 },
207 [VTE_COLOR_WHITE] = { 253, 246, 227 },
208
209 [VTE_COLOR_FOREGROUND] = { 238, 232, 213 },
210 [VTE_COLOR_BACKGROUND] = { 0, 0, 0 },
211 };
212
213 static uint8_t color_palette_solarized_white[VTE_COLOR_NUM][3] = {
214 [VTE_COLOR_BLACK] = { 7, 54, 66 },
215 [VTE_COLOR_RED] = { 220, 50, 47 },
216 [VTE_COLOR_GREEN] = { 133, 153, 0 },
217 [VTE_COLOR_YELLOW] = { 181, 137, 0 },
218 [VTE_COLOR_BLUE] = { 38, 139, 210 },
219 [VTE_COLOR_MAGENTA] = { 211, 54, 130 },
220 [VTE_COLOR_CYAN] = { 42, 161, 152 },
221 [VTE_COLOR_LIGHT_GREY] = { 238, 232, 213 },
222 [VTE_COLOR_DARK_GREY] = { 0, 43, 54 },
223 [VTE_COLOR_LIGHT_RED] = { 203, 75, 22 },
224 [VTE_COLOR_LIGHT_GREEN] = { 88, 110, 117 },
225 [VTE_COLOR_LIGHT_YELLOW] = { 101, 123, 131 },
226 [VTE_COLOR_LIGHT_BLUE] = { 131, 148, 150 },
227 [VTE_COLOR_LIGHT_MAGENTA] = { 108, 113, 196 },
228 [VTE_COLOR_LIGHT_CYAN] = { 147, 161, 161 },
229 [VTE_COLOR_WHITE] = { 253, 246, 227 },
230
231 [VTE_COLOR_FOREGROUND] = { 7, 54, 66 },
232 [VTE_COLOR_BACKGROUND] = { 238, 232, 213 },
233 };
234
235 static uint8_t color_palette_srcery[VTE_COLOR_NUM][3] = {
236 [VTE_COLOR_BLACK] = { 28, 27, 25 },
237 [VTE_COLOR_RED] = { 239, 47, 39 },
238 [VTE_COLOR_GREEN] = { 81, 159, 80 },
239 [VTE_COLOR_YELLOW] = { 251, 184, 41 },
240 [VTE_COLOR_BLUE] = { 44, 120, 190 },
241 [VTE_COLOR_MAGENTA] = { 224, 44, 109 },
242 [VTE_COLOR_CYAN] = { 10, 174, 179 },
243 [VTE_COLOR_LIGHT_GREY] = { 145, 129, 117 },
244 [VTE_COLOR_DARK_GREY] = { 45, 44, 41 },
245 [VTE_COLOR_LIGHT_RED] = { 247, 83, 65 },
246 [VTE_COLOR_LIGHT_GREEN] = { 152, 188, 55 },
247 [VTE_COLOR_LIGHT_YELLOW] = { 254, 208, 110 },
248 [VTE_COLOR_LIGHT_BLUE] = { 104, 168, 228 },
249 [VTE_COLOR_LIGHT_MAGENTA] = { 255, 92, 143 },
250 [VTE_COLOR_LIGHT_CYAN] = { 83, 253, 233 },
251 [VTE_COLOR_WHITE] = { 252, 232, 195 },
252
253 [VTE_COLOR_FOREGROUND] = {0xfc,0xe8,0xc3 },
254 [VTE_COLOR_BACKGROUND] = {0x12,0x12,0x12 },
255 };
256
get_palette(struct tsm_vte * vte)257 static uint8_t (*get_palette(struct tsm_vte *vte))[3]
258 {
259 if (!vte->palette_name)
260 return color_palette;
261
262 if (!strcmp(vte->palette_name, "solarized"))
263 return color_palette_solarized;
264 if (!strcmp(vte->palette_name, "solarized-black"))
265 return color_palette_solarized_black;
266 if (!strcmp(vte->palette_name, "solarized-white"))
267 return color_palette_solarized_white;
268 if (!strcmp(vte->palette_name, "srcery"))
269 return color_palette_srcery;
270
271 return color_palette;
272 }
273
debug_log(struct tsm_vte * vte,const char * msg,...)274 void debug_log(struct tsm_vte* vte, const char* msg, ...)
275 {
276 if (!vte || !vte->debug)
277 return;
278
279 vte->debug_ofs = 0;
280
281 char* out;
282 ssize_t len;
283
284 va_list args;
285 va_start(args, msg);
286 if ( (len = vasprintf(&out, msg, args)) == -1)
287 out = NULL;
288 va_end(args);
289
290 if (!out)
291 return;
292
293 if (vte->debug_lines[vte->debug_pos] != NULL){
294 free(vte->debug_lines[vte->debug_pos]);
295 }
296
297 vte->debug_lines[vte->debug_pos] = out;
298 vte->debug_pos = (vte->debug_pos + 1) % DEBUG_HISTORY;
299 tsm_vte_update_debug(vte);
300 }
301
302 #define DEBUG_LOG(X, Y, ...) debug_log(X, "%d:" Y, (X)->log_ctr++, ##__VA_ARGS__)
303
304 #define STEP_ROW() { \
305 crow++; \
306 if (crow < rows)\
307 arcan_tui_move_to(*(vte->debug), 0, crow);\
308 else\
309 goto out;\
310 }
311
wrap_write(struct tsm_vte * vte,size_t crow,const char * msg)312 static size_t wrap_write(struct tsm_vte* vte, size_t crow, const char* msg)
313 {
314 if (!msg || strlen(msg) == 0)
315 return crow;
316
317 size_t rows = 0, cols = 0;
318 arcan_tui_dimensions(*(vte->debug), &rows, &cols);
319
320 size_t xpos = 0;
321 const char* cur = msg;
322 while (*cur){
323 size_t next = 0;
324
325 while (cur[next] && (cur[next] != ' ' || (next == 0 || cur[next-1] == ':')))
326 next++;
327
328 if (next >= cols && cols > 1){
329 next = cols-1;
330 }
331
332 if (xpos + next >= cols){
333 xpos = 0;
334 STEP_ROW();
335 }
336
337 arcan_tui_writeu8(*(vte->debug), (uint8_t*) cur, next, NULL);
338 xpos += next;
339 cur += next;
340 }
341
342 STEP_ROW();
343 out:
344 return crow;
345 }
346
tsm_vte_update_debug(struct tsm_vte * vte)347 void tsm_vte_update_debug(struct tsm_vte* vte)
348 {
349 char* msg = NULL;
350
351 if (!vte || !vte->debug)
352 return;
353
354 struct tui_context* debug = *(vte->debug);
355
356 struct tui_screen_attr tattr = {
357 .fg = TUI_COL_TBASE + VTE_COLOR_FOREGROUND,
358 .bg = TUI_COL_TBASE + VTE_COLOR_BACKGROUND,
359 .aflags = TUI_ATTR_COLOR_INDEXED
360 };
361 arcan_tui_defattr(debug, &vte->def_attr);
362 arcan_tui_erase_screen(debug, false);
363 size_t rows = 0, cols = 0, crow = 0;
364 arcan_tui_dimensions(debug, &rows, &cols);
365 arcan_tui_move_to(debug, 0, 0);
366
367 char linebuf[256];
368 unsigned fl = vte->csi_flags;
369 snprintf(linebuf, sizeof(linebuf), "CSI: %s%s%s%s%s%s%s%s%s%s%s debug: %s",
370 (fl & CSI_BANG) ? "!" : "",
371 (fl & CSI_CASH) ? "$" : "",
372 (fl & CSI_WHAT) ? "?" : "",
373 (fl & CSI_GT) ? ">" : "",
374 (fl & CSI_SPACE) ? "'spce'" : "",
375 (fl & CSI_SQUOTE) ? "'" : "",
376 (fl & CSI_DQUOTE) ? "\"" : "",
377 (fl & CSI_MULT) ? "*" : "",
378 (fl & CSI_PLUS) ? "+" : "",
379 (fl & CSI_PLUS) ? "(" : "",
380 (fl & CSI_PLUS) ? ")" : "",
381 (vte->debug_verbose) ? "verbose" : "normal"
382 );
383 arcan_tui_writeu8(debug, (uint8_t*) linebuf, strlen(linebuf), NULL);
384 STEP_ROW();
385
386 const char* state = "none";
387 switch (vte->state){
388 case STATE_NONE: state = "none"; break;
389 case STATE_GROUND: state = "ground"; break;
390 case STATE_ESC: state = "esc"; break;
391 case STATE_ESC_INT: state = "int"; break;
392 case STATE_CSI_ENTRY: state = "entry"; break;
393 case STATE_CSI_PARAM: state = "param"; break;
394 case STATE_CSI_INT: state = "int"; break;
395 case STATE_CSI_IGNORE: state = "csi-ignore"; break;
396 case STATE_DCS_ENTRY: state = "entry"; break;
397 case STATE_DCS_PARAM: state = "param"; break;
398 case STATE_DCS_INT: state = "int"; break;
399 case STATE_DCS_PASS: state = "pass"; break;
400 case STATE_DCS_IGNORE: state = "dcs-ignore"; break;
401 case STATE_OSC_STRING: state = "string"; break;
402 case STATE_ST_IGNORE: state = "st-ignore"; break;
403 }
404 fl = vte->flags;
405
406 snprintf(linebuf, sizeof(linebuf), "State: %s Flags:"
407 " %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", state,
408 (fl & FLAG_CURSOR_KEY_MODE) ? "ckey " : "",
409 (fl & FLAG_KEYPAD_APPLICATION_MODE) ? "kp_app " : "",
410 (fl & FLAG_LINE_FEED_NEW_LINE_MODE) ? "lf_nl " : "",
411 (fl & FLAG_8BIT_MODE) ? "8b " : "",
412 (fl & FLAG_7BIT_MODE) ? "7b " : "",
413 (fl & FLAG_USE_C1) ? "c1 " : "",
414 (fl & FLAG_KEYBOARD_ACTION_MODE) ? "kbd_am " : "",
415 (fl & FLAG_INSERT_REPLACE_MODE) ? "irep " : "",
416 (fl & FLAG_SEND_RECEIVE_MODE) ? "snd_rcv " : "",
417 (fl & FLAG_TEXT_CURSOR_MODE) ? "txt_cursor " : "",
418 (fl & FLAG_INVERSE_SCREEN_MODE) ? "inv_scr " : "",
419 (fl & FLAG_ORIGIN_MODE) ? "origin " : "",
420 (fl & FLAG_AUTO_WRAP_MODE) ? "awrap " : "",
421 (fl & FLAG_AUTO_REPEAT_MODE) ? "arep " : "",
422 (fl & FLAG_NATIONAL_CHARSET_MODE) ? "nch " : "",
423 (fl & FLAG_BACKGROUND_COLOR_ERASE_MODE) ? "bgcl_er " : "",
424 (fl & FLAG_PREPEND_ESCAPE) ? "esc_prep " : "",
425 (fl & FLAG_TITE_INHIBIT_MODE) ? "alt_inhibit " : "",
426 (fl & FLAG_PASTE_BRACKET) ? "bpaste " : ""
427 );
428 crow = wrap_write(vte, crow, linebuf);
429
430 fl = vte->mstate;
431 snprintf(linebuf, sizeof(linebuf), "Mouse @(x,y): %zu, %zu Btn: %d State: "
432 "%s%s%s%s%s%s",
433 vte->saved_state.mouse_x, vte->saved_state.mouse_y, vte->mbutton,
434 (fl & MOUSE_BUTTON) ? "button " : "",
435 (fl & MOUSE_DRAG) ? "drag " : "",
436 (fl & MOUSE_MOTION) ? "motion " : "",
437 (fl & MOUSE_SGR) ? "sgr " : "",
438 (fl & MOUSE_X10) ? "x10 " : "",
439 (fl & MOUSE_RXVT) ? "rxvt " : ""
440 );
441 crow = wrap_write(vte, crow, linebuf);
442
443 /* since this can be arbitrarily long, split on space unless preceeded by a
444 * colon, unless the window is so small that the word doesn't fit, since it's
445 * debugging data, just ignore utf8 - normal TUI applications would use either
446 * autowrap or apply their own wrapping rules */
447 msg = arcan_tui_statedescr(vte->con);
448 crow = wrap_write(vte, crow, msg);
449
450 /* draw the current colorscheme */
451 arcan_tui_move_to(debug, 0, crow);
452 for (size_t i = 0; i < 16; i++){
453 struct tui_screen_attr tattr = {
454 .br = TUI_COL_TBASE + i,
455 .fr = TUI_COL_TBASE + i,
456 .aflags = TUI_ATTR_COLOR_INDEXED
457 };
458 arcan_tui_write(debug, (uint32_t)' ', &tattr);
459 }
460
461 crow++;
462
463 /* fill out with history logent */
464 size_t pos = vte->debug_pos > 0 ? vte->debug_pos - 1 : DEBUG_HISTORY - 1;
465 char* ent;
466
467 size_t row_lim = rows - crow;
468 crow = rows - 1;
469
470 for (size_t i = 0; i < vte->debug_ofs; i++)
471 pos = pos > 0 ? pos - 1 : DEBUG_HISTORY - 1;
472
473 /* should reverse this direction */
474 while ( row_lim-- && (ent = vte->debug_lines[pos]) && pos != vte->debug_pos){
475 arcan_tui_move_to(debug, 0, crow);
476 arcan_tui_writeu8(debug, (uint8_t*)ent, strlen(ent), NULL);
477 crow--;
478 pos = pos > 0 ? pos - 1 : DEBUG_HISTORY - 1;
479 }
480
481 #undef STEP_ROW
482 out:
483 if (msg)
484 free(msg);
485
486 /* last n warnings depending on how many rows we have
487 * inputs before last synch
488 * outputs before last synch
489 * main tui settings (w, h, mode)
490 * current foreground
491 * current background
492 * mouse state
493 * wrap mode
494 * origin mode
495 * decode flags
496 */
497 }
498
499 /* Several effects may occur when non-RGB colors are used. For instance, if bold
500 * is enabled, then a dark color code is always converted to a light color to
501 * simulate bold (even though bold may actually be supported!). To support this,
502 * we need to differentiate between a set color-code and a set rgb-color.
503 * This function actually converts a set color-code into an RGB color. This must
504 * be called before passing the attribute to the console layer so the console
505 * layer can always work with RGB values and does not have to care for color
506 * codes. */
to_rgb(struct tsm_vte * vte,bool defattr)507 static void to_rgb(struct tsm_vte *vte, bool defattr)
508 {
509 struct tui_screen_attr* attr = defattr ? &vte->def_attr : &vte->cattr;
510 int fgc = defattr ? vte->d_fgcode : vte->c_fgcode;
511 int bgc = defattr ? vte->d_bgcode : vte->c_bgcode;
512
513 if (fgc >= 0) {
514 /* bold causes light colors */
515 if (TUI_HAS_ATTR((*attr), TUI_ATTR_BOLD) && fgc < 8 && !vte->faint)
516 fgc += 8;
517 if (fgc >= VTE_COLOR_NUM)
518 fgc = VTE_COLOR_FOREGROUND;
519
520 attr->fr = TUI_COL_TBASE + fgc;
521 attr->aflags |= TUI_ATTR_COLOR_INDEXED;
522 }
523
524 if (bgc >= 0) {
525 if (bgc >= VTE_COLOR_NUM)
526 bgc = VTE_COLOR_BACKGROUND;
527
528 attr->br = TUI_COL_TBASE + bgc;
529 attr->aflags |= TUI_ATTR_COLOR_INDEXED;
530 }
531 }
532
533 /*
534 * update fg or bg attribute field with the palette- lookup based on code
535 */
set_rgb(struct tsm_vte * vte,struct tui_screen_attr * attr,bool fg,int code)536 static void set_rgb(struct tsm_vte* vte,
537 struct tui_screen_attr* attr, bool fg, int code)
538 {
539 if (code >= VTE_COLOR_NUM)
540 code = VTE_COLOR_FOREGROUND;
541
542 if (attr == &vte->def_attr){
543 if (fg)
544 vte->d_fgcode = code;
545 else
546 vte->d_bgcode = code;
547 }
548 else {
549 if (fg)
550 vte->c_fgcode = code;
551 else
552 vte->c_bgcode = code;
553 }
554
555 if (code < 0)
556 return;
557
558 if (fg){
559 attr->fr = TUI_COL_TBASE + code;
560 attr->aflags |= TUI_ATTR_COLOR_INDEXED;
561 }
562 else{
563 attr->br = TUI_COL_TBASE + code;
564 attr->aflags |= TUI_ATTR_COLOR_INDEXED;
565 }
566 }
567
568 SHL_EXPORT
tsm_vte_new(struct tsm_vte ** out,struct tui_context * con,tsm_vte_write_cb write_cb,void * data)569 int tsm_vte_new(struct tsm_vte **out, struct tui_context *con,
570 tsm_vte_write_cb write_cb, void *data)
571 {
572 struct tsm_vte *vte;
573 int ret;
574
575 if (!out || !con || !write_cb)
576 return -EINVAL;
577
578 vte = malloc(sizeof(*vte));
579 if (!vte)
580 return -ENOMEM;
581
582 memset(vte, 0, sizeof(*vte));
583 vte->ref = 1;
584 vte->con = con;
585 vte->write_cb = write_cb;
586 vte->data = data;
587 uint8_t* palette = (uint8_t*) get_palette(vte);
588 memcpy(vte->palette, palette, 3 * VTE_COLOR_NUM);
589 set_rgb(vte, &vte->def_attr, true, VTE_COLOR_FOREGROUND);
590 set_rgb(vte, &vte->def_attr, false, VTE_COLOR_BACKGROUND);
591 memcpy(&vte->cattr, &vte->def_attr, sizeof(struct tui_screen_attr));
592
593 for (size_t i = 0; i < VTE_COLOR_NUM; i++)
594 arcan_tui_set_color(vte->con, TUI_COL_TBASE+i, &palette[i * 3]);
595
596 ret = tsm_utf8_mach_new(&vte->mach);
597 if (ret)
598 goto err_free;
599
600 tsm_vte_reset(vte);
601 arcan_tui_erase_screen(vte->con, false);
602
603 DEBUG_LOG(vte, "new vte object");
604 arcan_tui_refinc(vte->con);
605 *out = vte;
606 return 0;
607
608 err_free:
609 free(vte);
610 return ret;
611 }
612
613 SHL_EXPORT
tsm_vte_ref(struct tsm_vte * vte)614 void tsm_vte_ref(struct tsm_vte *vte)
615 {
616 if (!vte)
617 return;
618
619 vte->ref++;
620 }
621
622 SHL_EXPORT
tsm_vte_unref(struct tsm_vte * vte)623 void tsm_vte_unref(struct tsm_vte *vte)
624 {
625 if (!vte || !vte->ref)
626 return;
627
628 if (--vte->ref)
629 return;
630
631 arcan_tui_refdec(vte->con);
632 tsm_utf8_mach_free(vte->mach);
633
634 for (size_t i = 0; i < DEBUG_HISTORY; i++){
635 if (vte->debug_lines[i])
636 free(vte->debug_lines[i]);
637 }
638
639 if (vte->debug){
640 arcan_tui_destroy(*(vte->debug), NULL);
641 *(vte->debug) = NULL;
642 vte->debug = NULL;
643 }
644
645 free(vte);
646 }
647
648 SHL_EXPORT
tsm_vte_set_color(struct tsm_vte * vte,enum vte_color ind,const uint8_t rgb[3])649 void tsm_vte_set_color(struct tsm_vte *vte,
650 enum vte_color ind, const uint8_t rgb[3])
651 {
652
653 if (ind >= VTE_COLOR_NUM || (int)ind < 0)
654 return;
655
656 uint8_t rgb_rw[3];
657 memcpy(rgb_rw, rgb, 3);
658
659 vte->palette[ind][0] = rgb[0];
660 vte->palette[ind][1] = rgb[1];
661 vte->palette[ind][2] = rgb[2];
662 arcan_tui_set_color(vte->con, TUI_COL_TBASE + ind, rgb_rw);
663
664 /*
665 * NOTE: this does not update the actual color on cattr/def_attr
666 */
667 }
668
669 SHL_EXPORT
tsm_vte_get_color(struct tsm_vte * vte,enum vte_color ind,uint8_t * rgb)670 void tsm_vte_get_color(struct tsm_vte *vte,
671 enum vte_color ind, uint8_t *rgb)
672 {
673 if (ind >= VTE_COLOR_NUM || ind < 0)
674 return;
675
676 rgb[0] = vte->palette[ind][0];
677 rgb[1] = vte->palette[ind][1];
678 rgb[2] = vte->palette[ind][2];
679 }
680
681 SHL_EXPORT
tsm_vte_set_palette(struct tsm_vte * vte,const char * pstr)682 int tsm_vte_set_palette(struct tsm_vte *vte, const char *pstr)
683 {
684 char *tmp = NULL;
685
686 if (!vte)
687 return -EINVAL;
688
689 if (pstr) {
690 tmp = strdup(pstr);
691 if (!tmp)
692 return -ENOMEM;
693 }
694
695 free(vte->palette_name);
696 vte->palette_name = tmp;
697 uint8_t* palette = (uint8_t*) get_palette(vte);
698 memcpy(vte->palette, palette, 3 * VTE_COLOR_NUM);
699 set_rgb(vte, &vte->def_attr, true, VTE_COLOR_FOREGROUND);
700 set_rgb(vte, &vte->def_attr, false, VTE_COLOR_BACKGROUND);
701 to_rgb(vte, true);
702 memcpy(&vte->cattr, &vte->def_attr, sizeof(vte->cattr));
703
704 /* forward the palette into the tui context in the terminal slots */
705 for (size_t i = 0; i < VTE_COLOR_NUM; i++)
706 arcan_tui_set_color(vte->con, TUI_COL_TBASE+i, &palette[i * 3]);
707
708 arcan_tui_defattr(vte->con, &vte->def_attr);
709 arcan_tui_erase_screen(vte->con, false);
710
711 return 0;
712 }
713
714 /*
715 * Write raw byte-stream to pty.
716 * When writing data to the client we must make sure that we send the correct
717 * encoding. For backwards-compatibility reasons we should always send 7bit
718 * characters exclusively. However, when FLAG_7BIT_MODE is not set, then we can
719 * also send raw 8bit characters. For instance, in FLAG_8BIT_MODE we can use the
720 * GR characters as keyboard input and send them directly or even use the C1
721 * escape characters. In unicode mode (default) we can send multi-byte utf-8
722 * characters which are also 8bit. When sending these characters, set the \raw
723 * flag to true so this function does not perform debug checks on data we send.
724 * If debugging is disabled, these checks are also disabled and won't affect
725 * performance.
726 * For better debugging, we also use the __LINE__ and __FILE__ macros. Use the
727 * vte_write() and vte_write_raw() macros below for more convenient use.
728 *
729 * As a rule of thumb do never send 8bit characters in escape sequences and also
730 * avoid all 8bit escape codes including the C1 codes. This will guarantee that
731 * all kind of clients are always compatible to us.
732 *
733 * If SEND_RECEIVE_MODE is off (that is, local echo is on) we have to send all
734 * data directly to ourself again. However, we must avoid recursion when
735 * tsm_vte_input() itself calls vte_write*(), therefore, we increase the
736 * PARSER counter when entering tsm_vte_input() and reset it when leaving it
737 * so we never echo data that origins from tsm_vte_input().
738 * But note that SEND_RECEIVE_MODE is inherently broken for escape sequences
739 * that request answers. That is, if we send a request to the client that awaits
740 * a response and parse that request via local echo ourself, then we will also
741 * send a response to the client even though he didn't request one. This
742 * recursion fix does not avoid this but only prevents us from endless loops
743 * here. Anyway, only few applications rely on local echo so we can safely
744 * ignore this.
745 */
vte_write_debug(struct tsm_vte * vte,const char * u8,size_t len,bool raw,const char * file,int line)746 static void vte_write_debug(struct tsm_vte *vte, const char *u8, size_t len,
747 bool raw, const char *file, int line)
748 {
749 #ifdef BUILD_ENABLE_DEBUG
750 /* in debug mode we check that escape sequences are always <0x7f so they
751 * are correctly parsed by non-unicode and non-8bit-mode clients. */
752 size_t i;
753
754 if (!raw) {
755 for (i = 0; i < len; ++i) {
756 if (u8[i] & 0x80)
757 DEBUG_LOG(vte,
758 "sending 8bit character inline to client in %s:%d", file, line);
759 }
760 }
761 #endif
762
763 /* in local echo mode, directly parse the data again */
764 if (!vte->parse_cnt && !(vte->flags & FLAG_SEND_RECEIVE_MODE)) {
765 if (vte->flags & FLAG_PREPEND_ESCAPE)
766 tsm_vte_input(vte, "\e", 1);
767 tsm_vte_input(vte, u8, len);
768 }
769
770 if (vte->flags & FLAG_PREPEND_ESCAPE)
771 vte->write_cb(vte, "\e", 1, vte->data);
772 vte->write_cb(vte, u8, len, vte->data);
773
774 vte->flags &= ~FLAG_PREPEND_ESCAPE;
775 }
776
777 #define vte_write(_vte, _u8, _len) \
778 vte_write_debug((_vte), (_u8), (_len), false, __FILE__, __LINE__)
779 #define vte_write_raw(_vte, _u8, _len) \
780 vte_write_debug((_vte), (_u8), (_len), true, __FILE__, __LINE__)
781
782 /* write to console */
write_console(struct tsm_vte * vte,tsm_symbol_t sym)783 static void write_console(struct tsm_vte *vte, tsm_symbol_t sym)
784 {
785 vte->last_symbol = sym;
786 to_rgb(vte, false);
787 arcan_tui_write(vte->con, sym, &vte->cattr);
788 }
789
reset_state(struct tsm_vte * vte)790 static void reset_state(struct tsm_vte *vte)
791 {
792 vte->saved_state.cursor_x = 0;
793 vte->saved_state.cursor_y = 0;
794 vte->saved_state.mouse_x = 0;
795 vte->saved_state.mouse_y = 0;
796 vte->saved_state.mouse_state = 0;
797 vte->mbutton = 0;
798 vte->saved_state.origin_mode = false;
799 vte->saved_state.wrap_mode = true;
800 vte->saved_state.gl = &vte->g0;
801 vte->saved_state.gr = &vte->g1;
802
803 vte->saved_state.c_fgcode = vte->d_fgcode;
804 vte->saved_state.cattr.fr = vte->def_attr.fr;
805 vte->saved_state.cattr.fg = vte->def_attr.fg;
806 vte->saved_state.cattr.fb = vte->def_attr.fb;
807 vte->saved_state.c_bgcode = vte->d_bgcode;
808 vte->saved_state.cattr.br = vte->def_attr.br;
809 vte->saved_state.cattr.bg = vte->def_attr.bg;
810 vte->saved_state.cattr.bb = vte->def_attr.bb;
811 vte->saved_state.cattr.aflags = 0;
812 vte->saved_state.cattr.custom_id = 0;
813 }
814
save_state(struct tsm_vte * vte)815 static void save_state(struct tsm_vte *vte)
816 {
817 arcan_tui_cursorpos(vte->con,
818 &vte->saved_state.cursor_x, &vte->saved_state.cursor_y);
819 vte->saved_state.cattr = vte->cattr;
820 vte->saved_state.faint = vte->faint;
821 vte->saved_state.gl = vte->gl;
822 vte->saved_state.gr = vte->gr;
823 vte->saved_state.mouse_state = vte->mstate;
824 vte->saved_state.wrap_mode = vte->flags & FLAG_AUTO_WRAP_MODE;
825 vte->saved_state.origin_mode = vte->flags & FLAG_ORIGIN_MODE;
826 }
827
restore_state(struct tsm_vte * vte)828 static void restore_state(struct tsm_vte *vte)
829 {
830 arcan_tui_move_to(vte->con, vte->saved_state.cursor_x,
831 vte->saved_state.cursor_y);
832 vte->cattr = vte->saved_state.cattr;
833 to_rgb(vte, false);
834 if (vte->flags & FLAG_BACKGROUND_COLOR_ERASE_MODE)
835 arcan_tui_defattr(vte->con, &vte->cattr);
836 vte->gl = vte->saved_state.gl;
837 vte->gr = vte->saved_state.gr;
838 vte->faint = vte->saved_state.faint;
839 vte->mstate = vte->saved_state.mouse_state;
840
841 if (vte->saved_state.wrap_mode) {
842 vte->flags |= FLAG_AUTO_WRAP_MODE;
843 arcan_tui_set_flags(vte->con, TUI_AUTO_WRAP);
844 } else {
845 vte->flags &= ~FLAG_AUTO_WRAP_MODE;
846 arcan_tui_reset_flags(vte->con, TUI_AUTO_WRAP);
847 }
848
849 if (vte->saved_state.origin_mode) {
850 vte->flags |= FLAG_ORIGIN_MODE;
851 arcan_tui_set_flags(vte->con, TUI_REL_ORIGIN);
852 } else {
853 vte->flags &= ~FLAG_ORIGIN_MODE;
854 arcan_tui_reset_flags(vte->con, TUI_REL_ORIGIN);
855 }
856 }
857
858 /*
859 * Reset VTE state
860 * This performs a soft reset of the VTE. That is, everything is reset to the
861 * same state as when the VTE was created. This does not affect the console,
862 * though.
863 */
864 SHL_EXPORT
tsm_vte_reset(struct tsm_vte * vte)865 void tsm_vte_reset(struct tsm_vte *vte)
866 {
867 if (!vte)
868 return;
869
870 vte->flags = 0;
871 vte->flags |= FLAG_TEXT_CURSOR_MODE;
872 vte->flags |= FLAG_AUTO_REPEAT_MODE;
873 vte->flags |= FLAG_SEND_RECEIVE_MODE;
874 vte->flags |= FLAG_AUTO_WRAP_MODE;
875 vte->flags |= FLAG_BACKGROUND_COLOR_ERASE_MODE;
876 vte->last_symbol = ' ';
877 arcan_tui_reset(vte->con);
878 arcan_tui_set_flags(vte->con, TUI_AUTO_WRAP);
879
880 tsm_utf8_mach_reset(vte->mach);
881 vte->state = STATE_GROUND;
882 vte->gl = &vte->g0;
883 vte->gr = &vte->g1;
884 vte->glt = NULL;
885 vte->grt = NULL;
886 vte->g0 = &tsm_vte_unicode_lower;
887 vte->g1 = &tsm_vte_unicode_upper;
888 vte->g2 = &tsm_vte_unicode_lower;
889 vte->g3 = &tsm_vte_unicode_upper;
890
891 memcpy(&vte->cattr, &vte->def_attr, sizeof(vte->cattr));
892 vte->c_fgcode = vte->d_fgcode;
893 vte->c_bgcode = vte->d_bgcode;
894 to_rgb(vte, false);
895 arcan_tui_defattr(vte->con, &vte->def_attr);
896
897 reset_state(vte);
898 }
899
900 SHL_EXPORT
tsm_vte_hard_reset(struct tsm_vte * vte)901 void tsm_vte_hard_reset(struct tsm_vte *vte)
902 {
903 tsm_vte_reset(vte);
904 arcan_tui_erase_screen(vte->con, false);
905 arcan_tui_erase_sb(vte->con);
906 arcan_tui_move_to(vte->con, 0, 0);
907 }
908
mouse_wr(struct tsm_vte * vte,int btni,int press,int mods,int row,int col)909 static void mouse_wr(struct tsm_vte *vte,
910 int btni, int press, int mods, int row, int col)
911 {
912 size_t nw = 0;
913 char buf[32];
914
915 if (vte->mstate & MOUSE_SGR){
916 nw = snprintf(buf, 32, "\e[%d;%d;%d%c", btni | mods, col, row, press ? 'M' : 'm');
917 }
918 else if (vte->mstate & MOUSE_X10){
919 if (col > 222)
920 col -= 32;
921 if (row > 222)
922 row -= 32;
923 nw = snprintf(buf, 32, "\e[<M%c%c%c", (btni | mods) + 32, col+32, row+32);
924 }
925 else if (vte->mstate & MOUSE_RXVT){
926 if (!press)
927 btni = 3;
928
929 nw = snprintf(buf, 32, "\e[<%d;%d;%dM", btni | mods, col, row);
930 }
931
932 if (nw && nw < 32)
933 vte_write(vte, buf, nw);
934 }
935
936 SHL_EXPORT
tsm_vte_paste(struct tsm_vte * vte,const char * u8,size_t len)937 void tsm_vte_paste(struct tsm_vte *vte, const char *u8, size_t len)
938 {
939 if (vte->flags & FLAG_PASTE_BRACKET){
940 vte_write(vte, "\e[200~", 6);
941 }
942
943 vte_write(vte, u8, len);
944
945 if (vte->flags & FLAG_PASTE_BRACKET){
946 vte_write(vte, "\e[201~", 6);
947 }
948 }
949
950 SHL_EXPORT
tsm_vte_mouse_motion(struct tsm_vte * vte,int x,int y,int mods)951 void tsm_vte_mouse_motion(struct tsm_vte *vte, int x, int y, int mods)
952 {
953 if (x == vte->saved_state.mouse_x &&
954 y == vte->saved_state.mouse_y)
955 return;
956
957 /* convert mouse state mask to match protocol */
958 int mc = 0;
959 mc |= (mods & TSM_SHIFT_MASK) ? 1 : 0;
960 mc |= (mods & TSM_ALT_MASK) ? 2 : 0;
961 mc |= (mods & TSM_CONTROL_MASK) ? 4 : 0;
962
963 vte->saved_state.mouse_x = x;
964 vte->saved_state.mouse_y = y;
965
966 if ( ((vte->mstate & MOUSE_DRAG) && vte->mbutton) ||
967 ((vte->mstate & MOUSE_MOTION)) ){
968 int btnind =
969 vte->mbutton & 0x01 ? 1 :
970 vte->mbutton & 0x02 ? 2 :
971 vte->mbutton & 0x04 ? 3 : 4;
972 mouse_wr(vte, btnind-1+32, 1, mc, y+1, x+1);
973 }
974 }
975
976 SHL_EXPORT
tsm_vte_mouse_button(struct tsm_vte * vte,int index,bool press,int mods)977 void tsm_vte_mouse_button(struct tsm_vte *vte, int index, bool press, int mods)
978 {
979 int old = vte->mbutton;
980
981 /* out of buttons? */
982 if (index < 0 || index > 5)
983 return;
984
985 /* modify held- mask */
986 else if (index <= 3){
987 if (press)
988 vte->mbutton |= (1 << (index - 1));
989 else
990 vte->mbutton &= ~(1 << (index - 1));
991 }
992
993 /* only report on change (but not for wheel) */
994 if (old == vte->mbutton && index < 4)
995 return;
996
997 int mc = 0;
998 mc |= (mods & TSM_SHIFT_MASK) ? 1 : 0;
999 mc |= (mods & TSM_ALT_MASK) ? 2 : 0;
1000 mc |= (mods & TSM_CONTROL_MASK) ? 4 : 0;
1001
1002 mouse_wr(vte, index < 4 ? index-1 : index-4+64, press, mods,
1003 vte->saved_state.mouse_y+1, vte->saved_state.mouse_x+1);
1004 }
1005
send_primary_da(struct tsm_vte * vte)1006 static void send_primary_da(struct tsm_vte *vte)
1007 {
1008 vte_write(vte, "\e[?60;1;6;9;15c", 15);
1009 }
1010
1011 /* execute control character (C0 or C1) */
do_execute(struct tsm_vte * vte,uint32_t ctrl)1012 static void do_execute(struct tsm_vte *vte, uint32_t ctrl)
1013 {
1014 switch (ctrl) {
1015 case 0x00: /* NUL */
1016 /* Ignore on input */
1017 break;
1018 case 0x05: /* ENQ */
1019 /* Transmit answerback message */
1020 /* TODO: is there a better answer than ACK? */
1021 vte_write(vte, "\x06", 1);
1022 break;
1023 case 0x07: /* BEL */
1024 /* Sound bell tone */
1025 /* TODO: I always considered this annying, however, we
1026 * should at least provide some way to enable it if the
1027 * user *really* wants it.
1028 */
1029 break;
1030 case 0x08: /* BS */
1031 /* Move cursor one position left */
1032 arcan_tui_move_left(vte->con, 1);
1033 break;
1034 case 0x09: /* HT */
1035 /* Move to next tab stop or end of line */
1036 arcan_tui_tab_right(vte->con, 1);
1037 break;
1038 case 0x0a: /* LF */
1039 case 0x0b: /* VT */
1040 case 0x0c: /* FF */
1041 /* Line feed or newline (CR/NL mode) */
1042 if (vte->flags & FLAG_LINE_FEED_NEW_LINE_MODE)
1043 arcan_tui_newline(vte->con);
1044 else
1045 arcan_tui_move_down(vte->con, 1, true);
1046 break;
1047 case 0x0d: /* CR */
1048 /* Move cursor to left margin */
1049 arcan_tui_move_line_home(vte->con);
1050 break;
1051 case 0x0e: /* SO */
1052 /* Map G1 character set into GL */
1053 vte->gl = &vte->g1;
1054 break;
1055 case 0x0f: /* SI */
1056 /* Map G0 character set into GL */
1057 vte->gl = &vte->g0;
1058 break;
1059 case 0x11: /* XON */
1060 /* Resume transmission */
1061 /* TODO */
1062 break;
1063 case 0x13: /* XOFF */
1064 /* Stop transmission */
1065 /* TODO */
1066 break;
1067 case 0x18: /* CAN */
1068 /* Cancel escape sequence */
1069 /* nothing to do here */
1070 break;
1071 case 0x1a: /* SUB */
1072 /* Discard current escape sequence and show err-sym */
1073 write_console(vte, 0xbf);
1074 break;
1075 case 0x1b: /* ESC */
1076 /* Invokes an escape sequence */
1077 /* nothing to do here */
1078 break;
1079 case 0x1f: /* DEL */
1080 /* Ignored */
1081 break;
1082 case 0x84: /* IND */
1083 /* Move down one row, perform scroll-up if needed */
1084 arcan_tui_move_down(vte->con, 1, true);
1085 break;
1086 case 0x85: /* NEL */
1087 /* CR/NL with scroll-up if needed */
1088 arcan_tui_newline(vte->con);
1089 break;
1090 case 0x88: /* HTS */
1091 /* Set tab stop at current position */
1092 arcan_tui_set_tabstop(vte->con);
1093 break;
1094 case 0x8d: /* RI */
1095 /* Move up one row, perform scroll-down if needed */
1096 arcan_tui_move_up(vte->con, 1, true);
1097 break;
1098 case 0x8e: /* SS2 */
1099 /* Temporarily map G2 into GL for next char only */
1100 vte->glt = &vte->g2;
1101 break;
1102 case 0x8f: /* SS3 */
1103 /* Temporarily map G3 into GL for next char only */
1104 vte->glt = &vte->g3;
1105 break;
1106 case 0x9a: /* DECID */
1107 /* Send device attributes response like ANSI DA */
1108 send_primary_da(vte);
1109 break;
1110 case 0x9c: /* ST */
1111 /* End control string */
1112 /* nothing to do here */
1113 break;
1114 default:
1115 DEBUG_LOG(vte, "unhandled control char %u", ctrl);
1116 }
1117 }
1118
do_clear(struct tsm_vte * vte)1119 static void do_clear(struct tsm_vte *vte)
1120 {
1121 int i;
1122
1123 vte->csi_argc = 0;
1124 for (i = 0; i < CSI_ARG_MAX; ++i)
1125 vte->csi_argv[i] = -1;
1126 vte->csi_flags = 0;
1127 }
1128
do_collect(struct tsm_vte * vte,uint32_t data)1129 static void do_collect(struct tsm_vte *vte, uint32_t data)
1130 {
1131 switch (data) {
1132 case '!':
1133 vte->csi_flags |= CSI_BANG;
1134 break;
1135 case '$':
1136 vte->csi_flags |= CSI_CASH;
1137 break;
1138 case '?':
1139 vte->csi_flags |= CSI_WHAT;
1140 break;
1141 case '>':
1142 vte->csi_flags |= CSI_GT;
1143 break;
1144 case ' ':
1145 vte->csi_flags |= CSI_SPACE;
1146 break;
1147 case '\'':
1148 vte->csi_flags |= CSI_SQUOTE;
1149 break;
1150 case '"':
1151 vte->csi_flags |= CSI_DQUOTE;
1152 break;
1153 case '*':
1154 vte->csi_flags |= CSI_MULT;
1155 break;
1156 case '+':
1157 vte->csi_flags |= CSI_PLUS;
1158 break;
1159 case '(':
1160 vte->csi_flags |= CSI_POPEN;
1161 break;
1162 case ')':
1163 vte->csi_flags |= CSI_PCLOSE;
1164 break;
1165 }
1166 }
1167
do_param(struct tsm_vte * vte,uint32_t data)1168 static void do_param(struct tsm_vte *vte, uint32_t data)
1169 {
1170 int new;
1171
1172 if (data == ';') {
1173 if (vte->csi_argc < CSI_ARG_MAX)
1174 vte->csi_argc++;
1175 return;
1176 }
1177
1178 if (vte->csi_argc >= CSI_ARG_MAX)
1179 return;
1180
1181 /* avoid integer overflows; max allowed value is 16384 anyway */
1182 if (vte->csi_argv[vte->csi_argc] > 0xffff)
1183 return;
1184
1185 if (data >= '0' && data <= '9') {
1186 new = vte->csi_argv[vte->csi_argc];
1187 if (new <= 0)
1188 new = data - '0';
1189 else
1190 new = new * 10 + data - '0';
1191 vte->csi_argv[vte->csi_argc] = new;
1192 }
1193 }
1194
set_charset(struct tsm_vte * vte,tsm_vte_charset * set)1195 static bool set_charset(struct tsm_vte *vte, tsm_vte_charset *set)
1196 {
1197 if (vte->csi_flags & CSI_POPEN)
1198 vte->g0 = set;
1199 else if (vte->csi_flags & CSI_PCLOSE)
1200 vte->g1 = set;
1201 else if (vte->csi_flags & CSI_MULT)
1202 vte->g2 = set;
1203 else if (vte->csi_flags & CSI_PLUS)
1204 vte->g3 = set;
1205 else
1206 return false;
1207
1208 return true;
1209 }
1210
do_esc(struct tsm_vte * vte,uint32_t data)1211 static void do_esc(struct tsm_vte *vte, uint32_t data)
1212 {
1213 switch (data) {
1214 case 'B': /* map ASCII into G0-G3 */
1215 if (set_charset(vte, &tsm_vte_unicode_lower))
1216 return;
1217 break;
1218 case '<': /* map DEC supplemental into G0-G3 */
1219 if (set_charset(vte, &tsm_vte_dec_supplemental_graphics))
1220 return;
1221 break;
1222 case '0': /* map DEC special into G0-G3 */
1223 if (set_charset(vte, &tsm_vte_dec_special_graphics))
1224 return;
1225 break;
1226 case 'A': /* map British into G0-G3 */
1227 /* TODO: create British charset from DEC */
1228 if (set_charset(vte, &tsm_vte_unicode_upper))
1229 return;
1230 break;
1231 case '4': /* map Dutch into G0-G3 */
1232 /* TODO: create Dutch charset from DEC */
1233 if (set_charset(vte, &tsm_vte_unicode_upper))
1234 return;
1235 break;
1236 case 'C':
1237 case '5': /* map Finnish into G0-G3 */
1238 /* TODO: create Finnish charset from DEC */
1239 if (set_charset(vte, &tsm_vte_unicode_upper))
1240 return;
1241 break;
1242 case 'R': /* map French into G0-G3 */
1243 /* TODO: create French charset from DEC */
1244 if (set_charset(vte, &tsm_vte_unicode_upper))
1245 return;
1246 break;
1247 case 'Q': /* map French-Canadian into G0-G3 */
1248 /* TODO: create French-Canadian charset from DEC */
1249 if (set_charset(vte, &tsm_vte_unicode_upper))
1250 return;
1251 break;
1252 case 'K': /* map German into G0-G3 */
1253 /* TODO: create German charset from DEC */
1254 if (set_charset(vte, &tsm_vte_unicode_upper))
1255 return;
1256 break;
1257 case 'Y': /* map Italian into G0-G3 */
1258 /* TODO: create Italian charset from DEC */
1259 if (set_charset(vte, &tsm_vte_unicode_upper))
1260 return;
1261 break;
1262 case 'E':
1263 case '6': /* map Norwegian/Danish into G0-G3 */
1264 /* TODO: create Norwegian/Danish charset from DEC */
1265 if (set_charset(vte, &tsm_vte_unicode_upper))
1266 return;
1267 break;
1268 case 'Z': /* map Spanish into G0-G3 */
1269 /* TODO: create Spanish charset from DEC */
1270 if (set_charset(vte, &tsm_vte_unicode_upper))
1271 return;
1272 break;
1273 case 'H':
1274 case '7': /* map Swedish into G0-G3 */
1275 /* TODO: create Swedish charset from DEC */
1276 if (set_charset(vte, &tsm_vte_unicode_upper))
1277 return;
1278 break;
1279 case '=': /* map Swiss into G0-G3 */
1280 /* TODO: create Swiss charset from DEC */
1281 if (set_charset(vte, &tsm_vte_unicode_upper))
1282 return;
1283 break;
1284 case 'F':
1285 if (vte->csi_flags & CSI_SPACE) {
1286 /* S7C1T */
1287 /* Disable 8bit C1 mode */
1288 vte->flags &= ~FLAG_USE_C1;
1289 return;
1290 }
1291 break;
1292 case 'G':
1293 if (vte->csi_flags & CSI_SPACE) {
1294 /* S8C1T */
1295 /* Enable 8bit C1 mode */
1296 vte->flags |= FLAG_USE_C1;
1297 return;
1298 }
1299 break;
1300 }
1301
1302 /* everything below is only valid without CSI flags */
1303 if (vte->csi_flags) {
1304 DEBUG_LOG(vte, "unhandled escape seq %u", data);
1305 return;
1306 }
1307
1308 switch (data) {
1309 case 'D': /* IND */
1310 /* Move down one row, perform scroll-up if needed */
1311 arcan_tui_move_down(vte->con, 1, true);
1312 break;
1313 case 'E': /* NEL */
1314 /* CR/NL with scroll-up if needed */
1315 arcan_tui_newline(vte->con);
1316 break;
1317 case 'H': /* HTS */
1318 /* Set tab stop at current position */
1319 arcan_tui_set_tabstop(vte->con);
1320 break;
1321 case 'M': /* RI */
1322 /* Move up one row, perform scroll-down if needed */
1323 arcan_tui_move_up(vte->con, 1, true);
1324 break;
1325 case 'N': /* SS2 */
1326 /* Temporarily map G2 into GL for next char only */
1327 vte->glt = &vte->g2;
1328 break;
1329 case 'O': /* SS3 */
1330 /* Temporarily map G3 into GL for next char only */
1331 vte->glt = &vte->g3;
1332 break;
1333 case 'Z': /* DECID */
1334 /* Send device attributes response like ANSI DA */
1335 send_primary_da(vte);
1336 break;
1337 case '\\': /* ST */
1338 /* End control string */
1339 /* nothing to do here */
1340 break;
1341 case '~': /* LS1R */
1342 /* Invoke G1 into GR */
1343 vte->gr = &vte->g1;
1344 break;
1345 case 'n': /* LS2 */
1346 /* Invoke G2 into GL */
1347 vte->gl = &vte->g2;
1348 break;
1349 case '}': /* LS2R */
1350 /* Invoke G2 into GR */
1351 vte->gr = &vte->g2;
1352 break;
1353 case 'o': /* LS3 */
1354 /* Invoke G3 into GL */
1355 vte->gl = &vte->g3;
1356 break;
1357 case '|': /* LS3R */
1358 /* Invoke G3 into GR */
1359 vte->gr = &vte->g3;
1360 break;
1361 case '=': /* DECKPAM */
1362 /* Set application keypad mode */
1363 vte->flags |= FLAG_KEYPAD_APPLICATION_MODE;
1364 break;
1365 case '>': /* DECKPNM */
1366 /* Set numeric keypad mode */
1367 vte->flags &= ~FLAG_KEYPAD_APPLICATION_MODE;
1368 break;
1369 case 'c': /* RIS */
1370 /* hard reset */
1371 tsm_vte_hard_reset(vte);
1372 break;
1373 case '7': /* DECSC */
1374 /* save console state */
1375 save_state(vte);
1376 break;
1377 case '8': /* DECRC */
1378 /* restore console state */
1379 restore_state(vte);
1380 break;
1381 default:
1382 DEBUG_LOG(vte, "unhandled escape seq %u", data);
1383 }
1384 }
1385
csi_attribute(struct tsm_vte * vte)1386 static void csi_attribute(struct tsm_vte *vte)
1387 {
1388 static const uint8_t bval[6] = { 0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff };
1389 unsigned int i, val;
1390 int code;
1391 uint8_t cr = 0, cg = 0, cb = 0;
1392
1393 if (vte->csi_argc <= 1 && vte->csi_argv[0] == -1) {
1394 vte->csi_argc = 1;
1395 vte->csi_argv[0] = 0;
1396 }
1397
1398 for (i = 0; i < vte->csi_argc; ++i) {
1399 switch (vte->csi_argv[i]) {
1400 case -1:
1401 break;
1402 case 0:
1403 vte->c_fgcode = vte->d_fgcode;
1404 vte->cattr.fr = vte->def_attr.fr;
1405 vte->cattr.fg = vte->def_attr.fg;
1406 vte->cattr.fb = vte->def_attr.fb;
1407 vte->c_bgcode = vte->d_bgcode;
1408 vte->cattr.br = vte->def_attr.br;
1409 vte->cattr.bg = vte->def_attr.bg;
1410 vte->cattr.bb = vte->def_attr.bb;
1411 vte->cattr.aflags = 0;
1412 vte->faint = false;
1413 break;
1414 case 1:
1415 vte->cattr.aflags |= TUI_ATTR_BOLD;
1416 break;
1417 case 2:
1418 vte->faint = true;
1419 break;
1420 case 3:
1421 vte->cattr.aflags |= TUI_ATTR_ITALIC;
1422 break;
1423 case 4:
1424 vte->cattr.aflags |= TUI_ATTR_UNDERLINE;
1425 break;
1426 case 5:
1427 vte->cattr.aflags |= TUI_ATTR_BLINK;
1428 break;
1429 case 7:
1430 vte->cattr.aflags |= TUI_ATTR_INVERSE;
1431 break;
1432 case 22:
1433 vte->cattr.aflags &= ~TUI_ATTR_BOLD;
1434 vte->faint = false;
1435 break;
1436 case 23:
1437 vte->cattr.aflags &= ~TUI_ATTR_ITALIC;
1438 break;
1439 case 24:
1440 vte->cattr.aflags &= ~TUI_ATTR_UNDERLINE;
1441 break;
1442 case 25:
1443 vte->cattr.aflags &= ~TUI_ATTR_BLINK;
1444 break;
1445 case 27:
1446 vte->cattr.aflags &= ~TUI_ATTR_INVERSE;
1447 break;
1448 case 29:
1449 /* 'not crossed out' */
1450 break;
1451 case 30:
1452 set_rgb(vte, &vte->cattr, true, VTE_COLOR_BLACK);
1453 break;
1454 case 31:
1455 set_rgb(vte, &vte->cattr, true, VTE_COLOR_RED);
1456 break;
1457 case 32:
1458 set_rgb(vte, &vte->cattr, true, VTE_COLOR_GREEN);
1459 break;
1460 case 33:
1461 set_rgb(vte, &vte->cattr, true, VTE_COLOR_YELLOW);
1462 break;
1463 case 34:
1464 set_rgb(vte, &vte->cattr, true, VTE_COLOR_BLUE);
1465 break;
1466 case 35:
1467 set_rgb(vte, &vte->cattr, true, VTE_COLOR_MAGENTA);
1468 break;
1469 case 36:
1470 set_rgb(vte, &vte->cattr, true, VTE_COLOR_CYAN);
1471 break;
1472 case 37:
1473 set_rgb(vte, &vte->cattr, true, VTE_COLOR_LIGHT_GREY);
1474 break;
1475 case 39:
1476 vte->c_fgcode = vte->d_fgcode;
1477 vte->cattr.fr = vte->def_attr.fr;
1478 vte->cattr.fg = vte->def_attr.fg;
1479 vte->cattr.fb = vte->def_attr.fb;
1480 break;
1481 case 40:
1482 set_rgb(vte, &vte->cattr, false, VTE_COLOR_BLACK);
1483 break;
1484 case 41:
1485 set_rgb(vte, &vte->cattr, false, VTE_COLOR_RED);
1486 break;
1487 case 42:
1488 set_rgb(vte, &vte->cattr, false, VTE_COLOR_GREEN);
1489 break;
1490 case 43:
1491 set_rgb(vte, &vte->cattr, false, VTE_COLOR_YELLOW);
1492 break;
1493 case 44:
1494 set_rgb(vte, &vte->cattr, false, VTE_COLOR_BLUE);
1495 break;
1496 case 45:
1497 set_rgb(vte, &vte->cattr, false, VTE_COLOR_MAGENTA);
1498 break;
1499 case 46:
1500 set_rgb(vte, &vte->cattr, false, VTE_COLOR_CYAN);
1501 break;
1502 case 47:
1503 set_rgb(vte, &vte->cattr, false, VTE_COLOR_LIGHT_GREY);
1504 break;
1505 case 49:
1506 vte->c_bgcode = vte->d_bgcode;
1507 vte->cattr.br = vte->def_attr.br;
1508 vte->cattr.bg = vte->def_attr.bg;
1509 vte->cattr.bb = vte->def_attr.bb;
1510 break;
1511 case 90:
1512 set_rgb(vte, &vte->cattr, true, VTE_COLOR_DARK_GREY);
1513 break;
1514 case 91:
1515 set_rgb(vte, &vte->cattr, true, VTE_COLOR_LIGHT_RED);
1516 break;
1517 case 92:
1518 set_rgb(vte, &vte->cattr, true, VTE_COLOR_LIGHT_GREEN);
1519 break;
1520 case 93:
1521 set_rgb(vte, &vte->cattr, true, VTE_COLOR_LIGHT_YELLOW);
1522 break;
1523 case 94:
1524 set_rgb(vte, &vte->cattr, true, VTE_COLOR_LIGHT_BLUE);
1525 break;
1526 case 95:
1527 set_rgb(vte, &vte->cattr, true, VTE_COLOR_LIGHT_MAGENTA);
1528 break;
1529 case 96:
1530 set_rgb(vte, &vte->cattr, true, VTE_COLOR_LIGHT_CYAN);
1531 break;
1532 case 97:
1533 set_rgb(vte, &vte->cattr, true, VTE_COLOR_WHITE);
1534 break;
1535 case 100:
1536 set_rgb(vte, &vte->cattr, false, VTE_COLOR_DARK_GREY);
1537 break;
1538 case 101:
1539 set_rgb(vte, &vte->cattr, false, VTE_COLOR_LIGHT_RED);
1540 break;
1541 case 102:
1542 set_rgb(vte, &vte->cattr, false, VTE_COLOR_LIGHT_GREEN);
1543 break;
1544 case 103:
1545 set_rgb(vte, &vte->cattr, false, VTE_COLOR_LIGHT_YELLOW);
1546 break;
1547 case 104:
1548 set_rgb(vte, &vte->cattr, false, VTE_COLOR_LIGHT_BLUE);
1549 break;
1550 case 105:
1551 set_rgb(vte, &vte->cattr, false, VTE_COLOR_LIGHT_MAGENTA);
1552 break;
1553 case 106:
1554 set_rgb(vte, &vte->cattr, false, VTE_COLOR_LIGHT_CYAN);
1555 break;
1556 case 107:
1557 set_rgb(vte, &vte->cattr, false, VTE_COLOR_WHITE);
1558 break;
1559 case 38:
1560 /* fallthrough */
1561 case 48:
1562 val = vte->csi_argv[i];
1563 if (vte->csi_argv[i + 1] == 5) { // 256color mode
1564 if (i + 2 >= vte->csi_argc ||
1565 vte->csi_argv[i + 2] < 0) {
1566 DEBUG_LOG(vte, "invalid 256color SGR");
1567 break;
1568 }
1569 code = vte->csi_argv[i + 2];
1570 if (code < 16) {
1571 //nochange
1572 } else if (code < 232) {
1573 code -= 16;
1574 cb = bval[code % 6];
1575 code /= 6;
1576 cg = bval[code % 6];
1577 code /= 6;
1578 cr = bval[code % 6];
1579 code = -1;
1580 } else {
1581 code = (code - 232) * 10 + 8;
1582 cr = code;
1583 cg = code;
1584 cb = code;
1585 code = -1;
1586 }
1587 i += 2;
1588 } else if (vte->csi_argv[i + 1] == 2) { // true color mode
1589 if (i + 4 >= vte->csi_argc ||
1590 vte->csi_argv[i + 2] < 0 ||
1591 vte->csi_argv[i + 3] < 0 ||
1592 vte->csi_argv[i + 4] < 0) {
1593 DEBUG_LOG(vte, "invalid true color SGR");
1594 break;
1595 }
1596 cr = vte->csi_argv[i + 2];
1597 cg = vte->csi_argv[i + 3];
1598 cb = vte->csi_argv[i + 4];
1599 code = -1;
1600 i += 4;
1601 } else {
1602 DEBUG_LOG(vte, "invalid SGR");
1603 break;
1604 }
1605 if (val == 38) {
1606 vte->c_fgcode = code;
1607 if (code >= 0){
1608 set_rgb(vte, &vte->cattr, true, code);
1609 }
1610 else{
1611 vte->cattr.aflags &= ~TUI_ATTR_COLOR_INDEXED;
1612 vte->cattr.fr = cr;
1613 vte->cattr.fg = cg;
1614 vte->cattr.fb = cb;
1615 }
1616 } else {
1617 vte->c_bgcode = code;
1618 if (code >= 0){
1619 set_rgb(vte, &vte->cattr, false, code);
1620 }
1621 else {
1622 vte->cattr.aflags &= ~TUI_ATTR_COLOR_INDEXED;
1623 vte->cattr.br = cr;
1624 vte->cattr.bg = cg;
1625 vte->cattr.bb = cb;
1626 }
1627 }
1628 break;
1629 default:
1630 DEBUG_LOG(vte, "unhandled SGR attr %i",
1631 vte->csi_argv[i]);
1632 }
1633 }
1634
1635 to_rgb(vte, false);
1636 if (vte->flags & FLAG_BACKGROUND_COLOR_ERASE_MODE)
1637 arcan_tui_defattr(vte->con, &vte->cattr);
1638 }
1639
csi_soft_reset(struct tsm_vte * vte)1640 static void csi_soft_reset(struct tsm_vte *vte)
1641 {
1642 tsm_vte_reset(vte);
1643 }
1644
csi_compat_mode(struct tsm_vte * vte)1645 static void csi_compat_mode(struct tsm_vte *vte)
1646 {
1647 /* always perform soft reset */
1648 csi_soft_reset(vte);
1649
1650 if (vte->csi_argv[0] == 61) {
1651 /* Switching to VT100 compatibility mode. We do
1652 * not support this mode, so ignore it. In fact,
1653 * we are almost compatible to it, anyway, so
1654 * there is no need to explicitly select it.
1655 * However, we enable 7bit mode to avoid
1656 * character-table problems */
1657 vte->flags |= FLAG_7BIT_MODE;
1658 vte->g0 = &tsm_vte_unicode_lower;
1659 vte->g1 = &tsm_vte_dec_supplemental_graphics;
1660 } else if (vte->csi_argv[0] == 62 ||
1661 vte->csi_argv[0] == 63 ||
1662 vte->csi_argv[0] == 64) {
1663 /* Switching to VT2/3/4 compatibility mode. We
1664 * are always compatible with this so ignore it.
1665 * We always send 7bit controls so we also do
1666 * not care for the parameter value here that
1667 * select the control-mode.
1668 * VT220 defines argument 2 as 7bit mode but
1669 * VT3xx up to VT5xx use it as 8bit mode. We
1670 * choose to conform with the latter here.
1671 * We also enable 8bit mode when VT220
1672 * compatibility is requested explicitly. */
1673 if (vte->csi_argv[1] == 1 ||
1674 vte->csi_argv[1] == 2)
1675 vte->flags |= FLAG_USE_C1;
1676
1677 vte->flags |= FLAG_8BIT_MODE;
1678 vte->g0 = &tsm_vte_unicode_lower;
1679 vte->g1 = &tsm_vte_dec_supplemental_graphics;
1680 } else {
1681 DEBUG_LOG(vte, "unhandled DECSCL 'p' CSI %i, switching to utf-8 mode again",
1682 vte->csi_argv[0]);
1683 }
1684 }
1685
set_reset_flag(struct tsm_vte * vte,bool set,unsigned int flag)1686 static inline void set_reset_flag(struct tsm_vte *vte, bool set,
1687 unsigned int flag)
1688 {
1689 if (set)
1690 vte->flags |= flag;
1691 else
1692 vte->flags &= ~flag;
1693 }
1694
csi_mode(struct tsm_vte * vte,bool set)1695 static void csi_mode(struct tsm_vte *vte, bool set)
1696 {
1697 unsigned int i;
1698
1699 for (i = 0; i < vte->csi_argc; ++i) {
1700 if (!(vte->csi_flags & CSI_WHAT)) {
1701 switch (vte->csi_argv[i]) {
1702 case -1:
1703 continue;
1704 case 2: /* KAM */
1705 set_reset_flag(vte, set,
1706 FLAG_KEYBOARD_ACTION_MODE);
1707 continue;
1708 case 4: /* IRM */
1709 set_reset_flag(vte, set,
1710 FLAG_INSERT_REPLACE_MODE);
1711 if (set)
1712 arcan_tui_set_flags(vte->con,
1713 TUI_INSERT_MODE);
1714 else
1715 arcan_tui_reset_flags(vte->con,
1716 TUI_INSERT_MODE);
1717 continue;
1718 case 12: /* SRM */
1719 set_reset_flag(vte, set,
1720 FLAG_SEND_RECEIVE_MODE);
1721 continue;
1722 case 20: /* LNM */
1723 set_reset_flag(vte, set,
1724 FLAG_LINE_FEED_NEW_LINE_MODE);
1725 continue;
1726 default:
1727 DEBUG_LOG(vte, "unknown non-DEC (Re)Set-Mode %d",
1728 vte->csi_argv[i]);
1729 continue;
1730 }
1731 }
1732
1733 switch (vte->csi_argv[i]) {
1734 case -1:
1735 continue;
1736 case 1: /* DECCKM */
1737 set_reset_flag(vte, set, FLAG_CURSOR_KEY_MODE);
1738 continue;
1739 case 2: /* DECANM */
1740 /* Select VT52 mode */
1741 /* We do not support VT52 mode. Is there any reason why
1742 * we should support it? We ignore it here and do not
1743 * mark it as to-do item unless someone has strong
1744 * arguments to support it. */
1745 continue;
1746 case 3: /* DECCOLM */
1747 /* If set, select 132 column mode, otherwise use 80
1748 * column mode. If neither is selected explicitly, we
1749 * use dynamic mode, that is, we send SIGWCH when the
1750 * size changes and we allow arbitrary buffer
1751 * dimensions. On soft-reset, we automatically fall back
1752 * to the default, that is, dynamic mode.
1753 * Dynamic-mode can be forced to a static mode in the
1754 * config. That is, every time dynamic-mode becomes
1755 * active, the terminal will be set to the dimensions
1756 * that were selected in the config. This allows setting
1757 * a fixed size for the terminal regardless of the
1758 * display size.
1759 * TODO: Implement this */
1760 continue;
1761 case 4: /* DECSCLM */
1762 /* Select smooth scrolling. We do not support the
1763 * classic smooth scrolling because we have a scrollback
1764 * buffer. There is no need to implement smooth
1765 * scrolling so ignore this here. */
1766 continue;
1767 case 5: /* DECSCNM */
1768 set_reset_flag(vte, set, FLAG_INVERSE_SCREEN_MODE);
1769 if (set)
1770 arcan_tui_set_flags(vte->con,
1771 TUI_INVERSE);
1772 else
1773 arcan_tui_reset_flags(vte->con,
1774 TUI_INVERSE);
1775 continue;
1776 case 6: /* DECOM */
1777 set_reset_flag(vte, set, FLAG_ORIGIN_MODE);
1778 if (set)
1779 arcan_tui_set_flags(vte->con, TUI_REL_ORIGIN);
1780 else
1781 arcan_tui_reset_flags(vte->con, TUI_REL_ORIGIN);
1782 continue;
1783 case 7: /* DECAWM */
1784 set_reset_flag(vte, set, FLAG_AUTO_WRAP_MODE);
1785 if (set)
1786 arcan_tui_set_flags(vte->con, TUI_AUTO_WRAP);
1787 else
1788 arcan_tui_reset_flags(vte->con, TUI_AUTO_WRAP);
1789 continue;
1790 case 8: /* DECARM */
1791 set_reset_flag(vte, set, FLAG_AUTO_REPEAT_MODE);
1792 continue;
1793 case 9: /* X10 mouse compatibility mode */
1794 // set_reset_flag(vte, set, FLAG_ */
1795 continue;
1796 case 12: /* blinking cursor */
1797 /* TODO: implement */
1798 continue;
1799 case 18: /* DECPFF */
1800 /* If set, a form feed (FF) is sent to the printer after
1801 * every screen that is printed. We don't have printers
1802 * these days directly attached to terminals so we
1803 * ignore this here. */
1804 continue;
1805 case 19: /* DECPEX */
1806 /* If set, the full screen is printed instead of
1807 * scrolling region only. We have no printer so ignore
1808 * this mode. */
1809 continue;
1810
1811 /* 20: CRLF mode */
1812
1813 case 25: /* DECTCEM */
1814 set_reset_flag(vte, set, FLAG_TEXT_CURSOR_MODE);
1815 if (set)
1816 arcan_tui_reset_flags(vte->con,
1817 TUI_HIDE_CURSOR);
1818 else
1819 arcan_tui_set_flags(vte->con,
1820 TUI_HIDE_CURSOR);
1821 continue;
1822
1823 /* 40: 80 -> 132 mode */
1824
1825 case 42: /* DECNRCM */
1826 set_reset_flag(vte, set, FLAG_NATIONAL_CHARSET_MODE);
1827 continue;
1828
1829 /* 45: reverse wrap-around */
1830
1831 case 47: /* Alternate screen buffer */
1832 if (vte->flags & FLAG_TITE_INHIBIT_MODE)
1833 continue;
1834
1835 if (set)
1836 arcan_tui_set_flags(vte->con, TUI_ALTERNATE);
1837 else
1838 arcan_tui_reset_flags(vte->con, TUI_ALTERNATE);
1839 continue;
1840
1841 /* 59: kanji terminal
1842 * 66: app keypad
1843 * 67: backspace as bs not del
1844 * 69: l/r margins */
1845
1846 case 1000:
1847 vte->mstate = MOUSE_BUTTON;
1848 if (0)
1849 case 1002:
1850 vte->mstate = MOUSE_DRAG;
1851 if (0)
1852 case 1003:
1853 vte->mstate = MOUSE_MOTION;
1854 vte->mstate |= MOUSE_X10;
1855 if (!set)
1856 vte->mstate = 0;
1857 continue;
1858 case 1006:
1859 vte->mstate = (vte->mstate & (~MOUSE_PROTO)) |
1860 ( set ? MOUSE_SGR : MOUSE_X10);
1861 continue;
1862 case 1015:
1863 vte->mstate = (vte->mstate & (~MOUSE_PROTO)) |
1864 ( set ? MOUSE_RXVT : MOUSE_X10);
1865 break;
1866 case 1042:
1867 arcan_tui_message(vte->con, TUI_MESSAGE_ALERT, "");
1868 break;
1869
1870 /* 1001: x-mouse highlight
1871 * 1004: report focus event
1872 * 1005: UTF-8 mouse mode
1873 * 1012: set home on input
1874 * 1015: mouse-ext
1875 */
1876 case 1047: /* Alternate screen buffer with post-erase */
1877 if (vte->flags & FLAG_TITE_INHIBIT_MODE)
1878 continue;
1879
1880 if (set) {
1881 arcan_tui_set_flags(vte->con, TUI_ALTERNATE);
1882 } else {
1883 arcan_tui_erase_screen(vte->con, false);
1884 arcan_tui_reset_flags(vte->con, TUI_ALTERNATE);
1885 }
1886 continue;
1887 case 1048: /* Set/Reset alternate-screen buffer cursor */
1888 if (vte->flags & FLAG_TITE_INHIBIT_MODE)
1889 continue;
1890
1891 if (set) {
1892 arcan_tui_cursorpos(vte->con, &vte->alt_cursor_x, &vte->alt_cursor_y);
1893 } else {
1894 arcan_tui_move_to(vte->con, vte->alt_cursor_x, vte->alt_cursor_y);
1895 }
1896 continue;
1897 case 1049: /* Alternate screen buffer with pre-erase+cursor */
1898 if (vte->flags & FLAG_TITE_INHIBIT_MODE)
1899 continue;
1900
1901 if (set) {
1902 arcan_tui_cursorpos(vte->con, &vte->alt_cursor_x, &vte->alt_cursor_y);
1903 arcan_tui_set_flags(vte->con, TUI_ALTERNATE);
1904 arcan_tui_erase_screen(vte->con, false);
1905 } else {
1906 arcan_tui_erase_screen(vte->con, false);
1907 arcan_tui_reset_flags(vte->con, TUI_ALTERNATE);
1908 arcan_tui_move_to(vte->con, vte->alt_cursor_x, vte->alt_cursor_y);
1909 }
1910 continue;
1911 case 2004: /* Bracketed paste mode, pref.postf.paste with \e[200~ \e[201~ */
1912 set_reset_flag(vte, set, FLAG_PASTE_BRACKET);
1913 continue;
1914 default:
1915 DEBUG_LOG(vte, "unknown DEC %set-Mode %d",
1916 set?"S":"Res", vte->csi_argv[i]);
1917 continue;
1918 }
1919 }
1920 }
1921
csi_dev_attr(struct tsm_vte * vte)1922 static void csi_dev_attr(struct tsm_vte *vte)
1923 {
1924 if (vte->csi_argc <= 1 && vte->csi_argv[0] <= 0) {
1925 if (vte->csi_flags == 0) {
1926 send_primary_da(vte);
1927 return;
1928 } else if (vte->csi_flags & CSI_GT) {
1929 vte_write(vte, "\e[>1;1;0c", 9);
1930 return;
1931 }
1932 }
1933
1934 DEBUG_LOG(vte, "unhandled DA: %x %d %d %d...", vte->csi_flags,
1935 vte->csi_argv[0], vte->csi_argv[1], vte->csi_argv[2]);
1936 }
1937
csi_dsr(struct tsm_vte * vte)1938 static void csi_dsr(struct tsm_vte *vte)
1939 {
1940 char buf[64];
1941 size_t x, y, len;
1942
1943 if (vte->csi_argv[0] == 5) {
1944 vte_write(vte, "\e[0n", 4);
1945 } else if (vte->csi_argv[0] == 6) {
1946 arcan_tui_cursorpos(vte->con, &x, &y);
1947 len = snprintf(buf, sizeof(buf), "\e[%zu;%zuR", y+1, x+1);
1948 if (len >= sizeof(buf))
1949 vte_write(vte, "\e[0;0R", 6);
1950 else
1951 vte_write(vte, buf, len);
1952 }
1953 }
1954
do_csi(struct tsm_vte * vte,uint32_t data)1955 static void do_csi(struct tsm_vte *vte, uint32_t data)
1956 {
1957 int num, upper, lower;
1958 int x, y;
1959 bool protect;
1960
1961 if (vte->csi_argc < CSI_ARG_MAX)
1962 vte->csi_argc++;
1963
1964 switch (data) {
1965 case 'A': /* CUU */
1966 /* move cursor up */
1967 num = vte->csi_argv[0];
1968 if (num <= 0)
1969 num = 1;
1970 arcan_tui_move_up(vte->con, num, false);
1971 break;
1972 case 'B': /* CUD */
1973 /* move cursor down */
1974 num = vte->csi_argv[0];
1975 if (num <= 0)
1976 num = 1;
1977 arcan_tui_move_down(vte->con, num, false);
1978 break;
1979 case 'C': /* CUF */
1980 /* move cursor forward */
1981 num = vte->csi_argv[0];
1982 if (num <= 0)
1983 num = 1;
1984 arcan_tui_move_right(vte->con, num);
1985 break;
1986 case 'D': /* CUB */
1987 /* move cursor backward */
1988 num = vte->csi_argv[0];
1989 if (num <= 0)
1990 num = 1;
1991 arcan_tui_move_left(vte->con, num);
1992 break;
1993 case 'b': /* REP */
1994 num = vte->csi_argv[0];
1995 if (num <= 0)
1996 num = 1;
1997 while(num--)
1998 write_console(vte, vte->last_symbol);
1999 break;
2000 case 'd':{ /* VPA */
2001 /* Vertical Line Position Absolute */
2002 num = vte->csi_argv[0];
2003 if (num <= 0)
2004 num = 1;
2005 size_t cx, cy;
2006 arcan_tui_cursorpos(vte->con, &cx, &cy);
2007 x = cx; y = cy;
2008 arcan_tui_move_to(vte->con, x, num - 1);
2009 break;
2010 }
2011 case 'e':{ /* VPR */
2012 /* Vertical Line Position Relative */
2013 num = vte->csi_argv[0];
2014 if (num <= 0)
2015 num = 1;
2016 size_t cx, cy;
2017 arcan_tui_cursorpos(vte->con, &cx, &cy);
2018 x = cx; y = cy;
2019 arcan_tui_move_to(vte->con, x, y + num);
2020 break;
2021 }
2022 case 'H': /* CUP */
2023 case 'f': /* HVP */
2024 /* position cursor */
2025 x = vte->csi_argv[0];
2026 if (x <= 0)
2027 x = 1;
2028 y = vte->csi_argv[1];
2029 if (y <= 0)
2030 y = 1;
2031 arcan_tui_move_to(vte->con, y - 1, x - 1);
2032 break;
2033 case 'G':{ /* CHA */
2034 /* Cursor Character Absolute */
2035 num = vte->csi_argv[0];
2036 if (num <= 0)
2037 num = 1;
2038 size_t cx, cy;
2039 arcan_tui_cursorpos(vte->con, &cx, &cy);
2040 x = cx; y = cy;
2041 arcan_tui_move_to(vte->con, num - 1, y);
2042 break;
2043 }
2044 case 'J':
2045 if (vte->csi_flags & CSI_WHAT)
2046 protect = true;
2047 else
2048 protect = false;
2049
2050 if (vte->csi_argv[0] <= 0)
2051 arcan_tui_erase_cursor_to_screen(vte->con,
2052 protect);
2053 else if (vte->csi_argv[0] == 1)
2054 arcan_tui_erase_screen_to_cursor(vte->con,
2055 protect);
2056 else if (vte->csi_argv[0] == 2)
2057 arcan_tui_erase_screen(vte->con, protect);
2058 else
2059 DEBUG_LOG(vte, "unknown parameter to CSI-J: %d",
2060 vte->csi_argv[0]);
2061 break;
2062 case 'K':
2063 if (vte->csi_flags & CSI_WHAT)
2064 protect = true;
2065 else
2066 protect = false;
2067
2068 /*CTE: con, x, y, size_x - 1, cursor_y, protect) */
2069 if (vte->csi_argv[0] <= 0)
2070 arcan_tui_erase_cursor_to_end(vte->con, protect);
2071 else if (vte->csi_argv[0] == 1)
2072 /* HTC: 0, cursor_y, cursor_x, cursor_y, protet) */
2073 arcan_tui_erase_home_to_cursor(vte->con, protect);
2074 else if (vte->csi_argv[0] == 2)
2075 /* CL: 0, y, size_x - 1, y, protect */
2076 arcan_tui_erase_current_line(vte->con, protect);
2077 else
2078 DEBUG_LOG(vte, "unknown parameter to CSI-K: %d",
2079 vte->csi_argv[0]);
2080 break;
2081 case 'X': /* ECH */
2082 /* erase characters */
2083 num = vte->csi_argv[0];
2084 if (num <= 0)
2085 num = 1;
2086 arcan_tui_erase_chars(vte->con, num);
2087 break;
2088 case 'm':
2089 csi_attribute(vte);
2090 break;
2091 case 'p':
2092 if (vte->csi_flags & CSI_GT) {
2093 /* xterm: select X11 visual cursor mode */
2094 csi_soft_reset(vte);
2095 } else if (vte->csi_flags & CSI_BANG) {
2096 /* DECSTR: Soft Reset */
2097 csi_soft_reset(vte);
2098 } else if (vte->csi_flags & CSI_CASH) {
2099 /* DECRQM: Request DEC Private Mode */
2100 /* If CSI_WHAT is set, then enable,
2101 * otherwise disable */
2102 csi_soft_reset(vte);
2103 } else {
2104 /* DECSCL: Compatibility Level */
2105 /* Sometimes CSI_DQUOTE is set here, too */
2106 csi_compat_mode(vte);
2107 }
2108 break;
2109 case 'h': /* SM: Set Mode */
2110 csi_mode(vte, true);
2111 break;
2112 case 'l': /* RM: Reset Mode */
2113 csi_mode(vte, false);
2114 break;
2115 case 'r': /* DECSTBM */
2116 /* set margin size */
2117 upper = vte->csi_argv[0];
2118 if (upper < 0)
2119 upper = 0;
2120 lower = vte->csi_argv[1];
2121 if (lower < 0)
2122 lower = 0;
2123 arcan_tui_set_margins(vte->con, upper, lower);
2124 arcan_tui_move_to(vte->con, 0, 0);
2125 break;
2126 case 'c': /* DA */
2127 /* device attributes */
2128 csi_dev_attr(vte);
2129 break;
2130 case 'L': /* IL */
2131 /* insert lines */
2132 num = vte->csi_argv[0];
2133 if (num <= 0)
2134 num = 1;
2135 arcan_tui_insert_lines(vte->con, num);
2136 break;
2137 case 'M': /* DL */
2138 /* delete lines */
2139 num = vte->csi_argv[0];
2140 if (num <= 0)
2141 num = 1;
2142 arcan_tui_delete_lines(vte->con, num);
2143 break;
2144 case 'g': /* TBC */
2145 /* tabulation clear */
2146 num = vte->csi_argv[0];
2147 if (num <= 0)
2148 arcan_tui_reset_tabstop(vte->con);
2149 else if (num == 3)
2150 arcan_tui_reset_all_tabstops(vte->con);
2151 else
2152 DEBUG_LOG(vte, "invalid parameter %d to TBC CSI", num);
2153 break;
2154 case '@': /* ICH */
2155 /* insert characters */
2156 num = vte->csi_argv[0];
2157 if (num <= 0)
2158 num = 1;
2159 arcan_tui_insert_chars(vte->con, num);
2160 break;
2161 case 'P': /* DCH */
2162 /* delete characters */
2163 num = vte->csi_argv[0];
2164 if (num <= 0)
2165 num = 1;
2166 arcan_tui_delete_chars(vte->con, num);
2167 break;
2168 case 'Z': /* CBT */
2169 /* cursor horizontal backwards tab */
2170 num = vte->csi_argv[0];
2171 if (num <= 0)
2172 num = 1;
2173 arcan_tui_tab_left(vte->con, num);
2174 break;
2175 case 'I': /* CHT */
2176 /* cursor horizontal forward tab */
2177 num = vte->csi_argv[0];
2178 if (num <= 0)
2179 num = 1;
2180 arcan_tui_tab_right(vte->con, num);
2181 break;
2182 case 'n': /* DSR */
2183 /* device status reports */
2184 csi_dsr(vte);
2185 break;
2186 case 'S': /* SU */
2187 /* scroll up */
2188 num = vte->csi_argv[0];
2189 if (num <= 0)
2190 num = 1;
2191 arcan_tui_scroll_up(vte->con, num);
2192 break;
2193 case 'T': /* SD */
2194 /* scroll down */
2195 num = vte->csi_argv[0];
2196 if (num <= 0)
2197 num = 1;
2198 arcan_tui_scroll_down(vte->con, num);
2199 break;
2200 default:
2201 DEBUG_LOG(vte, "unhandled CSI sequence %c", data);
2202 }
2203 }
2204
2205 /* map a character according to current GL and GR maps */
vte_map(struct tsm_vte * vte,uint32_t val)2206 static uint32_t vte_map(struct tsm_vte *vte, uint32_t val)
2207 {
2208 /* 32, 127, 160 and 255 map to identity like all values >255 */
2209 switch (val) {
2210 case 33 ... 126:
2211 if (vte->glt) {
2212 val = (**vte->glt)[val - 32];
2213 vte->glt = NULL;
2214 } else {
2215 val = (**vte->gl)[val - 32];
2216 }
2217 break;
2218 case 161 ... 254:
2219 if (vte->grt) {
2220 val = (**vte->grt)[val - 160];
2221 vte->grt = NULL;
2222 } else {
2223 val = (**vte->gr)[val - 160];
2224 }
2225 break;
2226 }
2227
2228 return val;
2229 }
2230
2231 /* perform parser action */
do_action(struct tsm_vte * vte,uint32_t data,int action)2232 static void do_action(struct tsm_vte *vte, uint32_t data, int action)
2233 {
2234 tsm_symbol_t sym;
2235 if (vte->debug && vte->debug_verbose && action != ACTION_PRINT){
2236 DEBUG_LOG(vte, "%s(%"PRIu32")", action_lut[action], data);
2237 }
2238
2239 switch (action) {
2240 case ACTION_NONE:
2241 /* do nothing */
2242 return;
2243 case ACTION_IGNORE:
2244 /* ignore character */
2245 break;
2246 case ACTION_PRINT:
2247 sym = tsm_symbol_make(vte_map(vte, data));
2248 write_console(vte, sym);
2249 break;
2250 case ACTION_EXECUTE:
2251 do_execute(vte, data);
2252 break;
2253 case ACTION_CLEAR:
2254 do_clear(vte);
2255 break;
2256 case ACTION_COLLECT:
2257 do_collect(vte, data);
2258 break;
2259 case ACTION_PARAM:
2260 do_param(vte, data);
2261 break;
2262 case ACTION_ESC_DISPATCH:
2263 do_esc(vte, data);
2264 break;
2265 case ACTION_CSI_DISPATCH:
2266 do_csi(vte, data);
2267 break;
2268 case ACTION_DCS_START:
2269 break;
2270 case ACTION_DCS_COLLECT:
2271 break;
2272 case ACTION_DCS_END:
2273 break;
2274 /* just dumbly buffer these and callback- forward to the frontend */
2275 case ACTION_OSC_START:
2276 vte->colbuf_pos = 0;
2277 break;
2278 case ACTION_OSC_COLLECT:
2279 vte->colbuf[vte->colbuf_pos] = data;
2280 if (vte->colbuf_pos < vte->colbuf_sz-1)
2281 vte->colbuf_pos++;
2282 break;
2283 case ACTION_OSC_END:
2284 if (vte->colbuf_pos && vte->strcb){
2285 vte->colbuf[vte->colbuf_pos] = '\0';
2286 vte->strcb(vte, TSM_GROUP_OSC, vte->colbuf, vte->colbuf_pos+1,
2287 vte->colbuf_pos == vte->colbuf_sz, vte->strcb_data);
2288 }
2289 break;
2290 default:
2291 DEBUG_LOG(vte, "invalid action %d", action);
2292 }
2293 }
2294
2295 /* entry actions to be performed when entering the selected state */
2296 static const int entry_action[] = {
2297 [STATE_CSI_ENTRY] = ACTION_CLEAR,
2298 [STATE_DCS_ENTRY] = ACTION_CLEAR,
2299 [STATE_DCS_PASS] = ACTION_DCS_START,
2300 [STATE_ESC] = ACTION_CLEAR,
2301 [STATE_OSC_STRING] = ACTION_OSC_START,
2302 [STATE_NUM] = ACTION_NONE,
2303 };
2304
2305 /* exit actions to be performed when leaving the selected state */
2306 static const int exit_action[] = {
2307 [STATE_DCS_PASS] = ACTION_DCS_END,
2308 [STATE_OSC_STRING] = ACTION_OSC_END,
2309 [STATE_NUM] = ACTION_NONE,
2310 };
2311
tsm_vte_inseq(struct tsm_vte * vte)2312 bool tsm_vte_inseq(struct tsm_vte *vte)
2313 {
2314 return (vte->state != STATE_NONE && vte->state != STATE_GROUND);
2315 }
2316
2317 /* perform state transition and dispatch related actions */
do_trans(struct tsm_vte * vte,uint32_t data,int state,int act)2318 static void do_trans(struct tsm_vte *vte, uint32_t data, int state, int act)
2319 {
2320 if (state != STATE_NONE) {
2321 /* A state transition occurs. Perform exit-action,
2322 * transition-action and entry-action. Even when performing a
2323 * transition to the same state as the current state we do this.
2324 * Use STATE_NONE if this is not the desired behavior.
2325 */
2326 do_action(vte, data, exit_action[vte->state]);
2327 do_action(vte, data, act);
2328 do_action(vte, data, entry_action[state]);
2329 vte->state = state;
2330 } else {
2331 do_action(vte, data, act);
2332 }
2333 }
2334
2335 /*
2336 * Escape sequence parser
2337 * This parses the new input character \data. It performs state transition and
2338 * calls the right callbacks for each action.
2339 */
parse_data(struct tsm_vte * vte,uint32_t raw)2340 static void parse_data(struct tsm_vte *vte, uint32_t raw)
2341 {
2342 /* events that may occur in any state */
2343 switch (raw) {
2344 case 0x18:
2345 case 0x1a:
2346 case 0x80 ... 0x8f:
2347 case 0x91 ... 0x97:
2348 case 0x99:
2349 case 0x9a:
2350 case 0x9c:
2351 do_trans(vte, raw, STATE_GROUND, ACTION_EXECUTE);
2352 return;
2353 case 0x1b:
2354 do_trans(vte, raw, STATE_ESC, ACTION_NONE);
2355 return;
2356 case 0x98:
2357 case 0x9e:
2358 case 0x9f:
2359 do_trans(vte, raw, STATE_ST_IGNORE, ACTION_NONE);
2360 return;
2361 case 0x90:
2362 do_trans(vte, raw, STATE_DCS_ENTRY, ACTION_NONE);
2363 return;
2364 case 0x9d:
2365 do_trans(vte, raw, STATE_OSC_STRING, ACTION_NONE);
2366 return;
2367 case 0x9b:
2368 do_trans(vte, raw, STATE_CSI_ENTRY, ACTION_NONE);
2369 return;
2370 }
2371
2372 /* events that depend on the current state */
2373 switch (vte->state) {
2374 case STATE_GROUND:
2375 switch (raw) {
2376 case 0x00 ... 0x17:
2377 case 0x19:
2378 case 0x1c ... 0x1f:
2379 case 0x80 ... 0x8f:
2380 case 0x91 ... 0x9a:
2381 case 0x9c:
2382 do_trans(vte, raw, STATE_NONE, ACTION_EXECUTE);
2383 return;
2384 case 0x20 ... 0x7f:
2385 do_trans(vte, raw, STATE_NONE, ACTION_PRINT);
2386 return;
2387 }
2388 do_trans(vte, raw, STATE_NONE, ACTION_PRINT);
2389 return;
2390 case STATE_ESC:
2391 switch (raw) {
2392 case 0x00 ... 0x17:
2393 case 0x19:
2394 case 0x1c ... 0x1f:
2395 do_trans(vte, raw, STATE_NONE, ACTION_EXECUTE);
2396 return;
2397 case 0x7f:
2398 do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2399 return;
2400 case 0x20 ... 0x2f:
2401 do_trans(vte, raw, STATE_ESC_INT, ACTION_COLLECT);
2402 return;
2403 case 0x30 ... 0x4f:
2404 case 0x51 ... 0x57:
2405 case 0x59:
2406 case 0x5a:
2407 case 0x5c:
2408 case 0x60 ... 0x7e:
2409 do_trans(vte, raw, STATE_GROUND, ACTION_ESC_DISPATCH);
2410 return;
2411 case 0x5b:
2412 do_trans(vte, raw, STATE_CSI_ENTRY, ACTION_NONE);
2413 return;
2414 case 0x5d:
2415 do_trans(vte, raw, STATE_OSC_STRING, ACTION_NONE);
2416 return;
2417 case 0x50:
2418 do_trans(vte, raw, STATE_DCS_ENTRY, ACTION_NONE);
2419 return;
2420 case 0x58:
2421 case 0x5e:
2422 case 0x5f:
2423 do_trans(vte, raw, STATE_ST_IGNORE, ACTION_NONE);
2424 return;
2425 }
2426 do_trans(vte, raw, STATE_ESC_INT, ACTION_COLLECT);
2427 return;
2428 case STATE_ESC_INT:
2429 switch (raw) {
2430 case 0x00 ... 0x17:
2431 case 0x19:
2432 case 0x1c ... 0x1f:
2433 do_trans(vte, raw, STATE_NONE, ACTION_EXECUTE);
2434 return;
2435 case 0x20 ... 0x2f:
2436 do_trans(vte, raw, STATE_NONE, ACTION_COLLECT);
2437 return;
2438 case 0x7f:
2439 do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2440 return;
2441 case 0x30 ... 0x7e:
2442 do_trans(vte, raw, STATE_GROUND, ACTION_ESC_DISPATCH);
2443 return;
2444 }
2445 do_trans(vte, raw, STATE_NONE, ACTION_COLLECT);
2446 return;
2447 case STATE_CSI_ENTRY:
2448 switch (raw) {
2449 case 0x00 ... 0x17:
2450 case 0x19:
2451 case 0x1c ... 0x1f:
2452 do_trans(vte, raw, STATE_NONE, ACTION_EXECUTE);
2453 return;
2454 case 0x7f:
2455 do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2456 return;
2457 case 0x20 ... 0x2f:
2458 do_trans(vte, raw, STATE_CSI_INT, ACTION_COLLECT);
2459 return;
2460 case 0x3a:
2461 do_trans(vte, raw, STATE_CSI_IGNORE, ACTION_NONE);
2462 return;
2463 case 0x30 ... 0x39:
2464 case 0x3b:
2465 do_trans(vte, raw, STATE_CSI_PARAM, ACTION_PARAM);
2466 return;
2467 case 0x3c ... 0x3f:
2468 do_trans(vte, raw, STATE_CSI_PARAM, ACTION_COLLECT);
2469 return;
2470 case 0x40 ... 0x7e:
2471 do_trans(vte, raw, STATE_GROUND, ACTION_CSI_DISPATCH);
2472 return;
2473 }
2474 do_trans(vte, raw, STATE_CSI_IGNORE, ACTION_NONE);
2475 return;
2476 case STATE_CSI_PARAM:
2477 switch (raw) {
2478 case 0x00 ... 0x17:
2479 case 0x19:
2480 case 0x1c ... 0x1f:
2481 do_trans(vte, raw, STATE_NONE, ACTION_EXECUTE);
2482 return;
2483 case 0x30 ... 0x39:
2484 case 0x3b:
2485 do_trans(vte, raw, STATE_NONE, ACTION_PARAM);
2486 return;
2487 case 0x7f:
2488 do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2489 return;
2490 case 0x3a:
2491 case 0x3c ... 0x3f:
2492 do_trans(vte, raw, STATE_CSI_IGNORE, ACTION_NONE);
2493 return;
2494 case 0x20 ... 0x2f:
2495 do_trans(vte, raw, STATE_CSI_INT, ACTION_COLLECT);
2496 return;
2497 case 0x40 ... 0x7e:
2498 do_trans(vte, raw, STATE_GROUND, ACTION_CSI_DISPATCH);
2499 return;
2500 }
2501 do_trans(vte, raw, STATE_CSI_IGNORE, ACTION_NONE);
2502 return;
2503 case STATE_CSI_INT:
2504 switch (raw) {
2505 case 0x00 ... 0x17:
2506 case 0x19:
2507 case 0x1c ... 0x1f:
2508 do_trans(vte, raw, STATE_NONE, ACTION_EXECUTE);
2509 return;
2510 case 0x20 ... 0x2f:
2511 do_trans(vte, raw, STATE_NONE, ACTION_COLLECT);
2512 return;
2513 case 0x7f:
2514 do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2515 return;
2516 case 0x30 ... 0x3f:
2517 do_trans(vte, raw, STATE_CSI_IGNORE, ACTION_NONE);
2518 return;
2519 case 0x40 ... 0x7e:
2520 do_trans(vte, raw, STATE_GROUND, ACTION_CSI_DISPATCH);
2521 return;
2522 }
2523 do_trans(vte, raw, STATE_CSI_IGNORE, ACTION_NONE);
2524 return;
2525 case STATE_CSI_IGNORE:
2526 switch (raw) {
2527 case 0x00 ... 0x17:
2528 case 0x19:
2529 case 0x1c ... 0x1f:
2530 do_trans(vte, raw, STATE_NONE, ACTION_EXECUTE);
2531 return;
2532 case 0x20 ... 0x3f:
2533 case 0x7f:
2534 do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2535 return;
2536 case 0x40 ... 0x7e:
2537 do_trans(vte, raw, STATE_GROUND, ACTION_NONE);
2538 return;
2539 }
2540 do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2541 return;
2542 case STATE_DCS_ENTRY:
2543 switch (raw) {
2544 case 0x00 ... 0x17:
2545 case 0x19:
2546 case 0x1c ... 0x1f:
2547 case 0x7f:
2548 do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2549 return;
2550 case 0x3a:
2551 do_trans(vte, raw, STATE_DCS_IGNORE, ACTION_NONE);
2552 return;
2553 case 0x20 ... 0x2f:
2554 do_trans(vte, raw, STATE_DCS_INT, ACTION_COLLECT);
2555 return;
2556 case 0x30 ... 0x39:
2557 case 0x3b:
2558 do_trans(vte, raw, STATE_DCS_PARAM, ACTION_PARAM);
2559 return;
2560 case 0x3c ... 0x3f:
2561 do_trans(vte, raw, STATE_DCS_PARAM, ACTION_COLLECT);
2562 return;
2563 case 0x40 ... 0x7e:
2564 do_trans(vte, raw, STATE_DCS_PASS, ACTION_NONE);
2565 return;
2566 }
2567 do_trans(vte, raw, STATE_DCS_PASS, ACTION_NONE);
2568 return;
2569 case STATE_DCS_PARAM:
2570 switch (raw) {
2571 case 0x00 ... 0x17:
2572 case 0x19:
2573 case 0x1c ... 0x1f:
2574 case 0x7f:
2575 do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2576 return;
2577 case 0x30 ... 0x39:
2578 case 0x3b:
2579 do_trans(vte, raw, STATE_NONE, ACTION_PARAM);
2580 return;
2581 case 0x3a:
2582 case 0x3c ... 0x3f:
2583 do_trans(vte, raw, STATE_DCS_IGNORE, ACTION_NONE);
2584 return;
2585 case 0x20 ... 0x2f:
2586 do_trans(vte, raw, STATE_DCS_INT, ACTION_COLLECT);
2587 return;
2588 case 0x40 ... 0x7e:
2589 do_trans(vte, raw, STATE_DCS_PASS, ACTION_NONE);
2590 return;
2591 }
2592 do_trans(vte, raw, STATE_DCS_PASS, ACTION_NONE);
2593 return;
2594 case STATE_DCS_INT:
2595 switch (raw) {
2596 case 0x00 ... 0x17:
2597 case 0x19:
2598 case 0x1c ... 0x1f:
2599 case 0x7f:
2600 do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2601 return;
2602 case 0x20 ... 0x2f:
2603 do_trans(vte, raw, STATE_NONE, ACTION_COLLECT);
2604 return;
2605 case 0x30 ... 0x3f:
2606 do_trans(vte, raw, STATE_DCS_IGNORE, ACTION_NONE);
2607 return;
2608 case 0x40 ... 0x7e:
2609 do_trans(vte, raw, STATE_DCS_PASS, ACTION_NONE);
2610 return;
2611 }
2612 do_trans(vte, raw, STATE_DCS_PASS, ACTION_NONE);
2613 return;
2614 case STATE_DCS_PASS:
2615 switch (raw) {
2616 case 0x00 ... 0x17:
2617 case 0x19:
2618 case 0x1c ... 0x1f:
2619 case 0x20 ... 0x7e:
2620 do_trans(vte, raw, STATE_NONE, ACTION_DCS_COLLECT);
2621 return;
2622 case 0x7f:
2623 do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2624 return;
2625 case 0x9c:
2626 do_trans(vte, raw, STATE_GROUND, ACTION_NONE);
2627 return;
2628 }
2629 do_trans(vte, raw, STATE_NONE, ACTION_DCS_COLLECT);
2630 return;
2631 case STATE_DCS_IGNORE:
2632 switch (raw) {
2633 case 0x00 ... 0x17:
2634 case 0x19:
2635 case 0x1c ... 0x1f:
2636 case 0x20 ... 0x7f:
2637 do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2638 return;
2639 case 0x9c:
2640 do_trans(vte, raw, STATE_GROUND, ACTION_NONE);
2641 return;
2642 }
2643 do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2644 return;
2645 case STATE_OSC_STRING:
2646 switch (raw) {
2647 case 0x00 ... 0x06:
2648 case 0x08 ... 0x17:
2649 case 0x19:
2650 case 0x1c ... 0x1f:
2651 do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2652 return;
2653 case 0x20 ... 0x7f:
2654 do_trans(vte, raw, STATE_NONE, ACTION_OSC_COLLECT);
2655 return;
2656 case 0x07:
2657 case 0x9c:
2658 do_trans(vte, raw, STATE_GROUND, ACTION_NONE);
2659 return;
2660 }
2661 do_trans(vte, raw, STATE_NONE, ACTION_OSC_COLLECT);
2662 return;
2663 case STATE_ST_IGNORE:
2664 switch (raw) {
2665 case 0x00 ... 0x17:
2666 case 0x19:
2667 case 0x1c ... 0x1f:
2668 case 0x20 ... 0x7f:
2669 do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2670 return;
2671 case 0x9c:
2672 do_trans(vte, raw, STATE_GROUND, ACTION_NONE);
2673 return;
2674 }
2675 do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2676 return;
2677 }
2678
2679 DEBUG_LOG(vte, "unhandled input %u in state %d", raw, vte->state);
2680 }
2681
2682 SHL_EXPORT
tsm_vte_input(struct tsm_vte * vte,const char * u8,size_t len)2683 void tsm_vte_input(struct tsm_vte *vte, const char *u8, size_t len)
2684 {
2685 int state;
2686 uint32_t ucs4;
2687 size_t i;
2688
2689 if (!vte || !vte->con)
2690 return;
2691
2692 ++vte->parse_cnt;
2693 for (i = 0; i < len; ++i) {
2694 if (vte->flags & FLAG_7BIT_MODE) {
2695 if (u8[i] & 0x80)
2696 DEBUG_LOG(vte, "receiving 8bit character U+%d from pty while in 7bit mode",
2697 (int)u8[i]);
2698 parse_data(vte, u8[i] & 0x7f);
2699 } else if (vte->flags & FLAG_8BIT_MODE) {
2700 parse_data(vte, u8[i]);
2701 } else {
2702 state = tsm_utf8_mach_feed(vte->mach, u8[i]);
2703 if (state == TSM_UTF8_ACCEPT ||
2704 state == TSM_UTF8_REJECT) {
2705 ucs4 = tsm_utf8_mach_get(vte->mach);
2706 parse_data(vte, ucs4);
2707 }
2708 }
2709 }
2710 }
2711
on_key(struct tui_context * c,uint32_t keysym,uint8_t scancode,uint8_t mods,uint16_t subid,void * t)2712 static void on_key(struct tui_context* c, uint32_t keysym,
2713 uint8_t scancode, uint8_t mods, uint16_t subid, void* t)
2714 {
2715 struct tsm_vte* in = t;
2716 if (keysym == TUIK_TAB){
2717 in->debug_verbose = !in->debug_verbose;
2718 }
2719 else if (keysym == TUIK_J || keysym == TUIK_DOWN){
2720 in->debug_ofs++;
2721 }
2722 else if (keysym == TUIK_K || keysym == TUIK_UP){
2723 if (in->debug_ofs > 0)
2724 in->debug_ofs--;
2725 }
2726 else if (keysym == TUIK_M){
2727 }
2728 else if (keysym == TUIK_ESCAPE){
2729 for (size_t i = 0; i < DEBUG_HISTORY; i++){
2730 if (in->debug_lines[i]){
2731 free(in->debug_lines[i]);
2732 in->debug_lines[i] = NULL;
2733 }
2734 }
2735 in->debug_ofs = 0;
2736 in->debug_pos = 0;
2737 }
2738 }
2739
on_resize(struct tui_context * tui,size_t neww,size_t newh,size_t cols,size_t rows,void * tag)2740 static void on_resize(struct tui_context* tui,
2741 size_t neww, size_t newh, size_t cols, size_t rows, void* tag)
2742 {
2743 tsm_vte_update_debug(tag);
2744 }
2745
on_recolor(struct tui_context * tui,void * tag)2746 static void on_recolor(struct tui_context* tui, void* tag)
2747 {
2748 tsm_vte_update_debug(tag);
2749 }
2750
tsm_vte_debug(struct tsm_vte * in,struct tui_context ** dst,arcan_tui_conn * conn,struct tui_context * c)2751 SHL_EXPORT bool tsm_vte_debug(struct tsm_vte* in,
2752 struct tui_context** dst, arcan_tui_conn* conn, struct tui_context* c)
2753 {
2754 struct tui_cbcfg cbcfg = {
2755 .tag = in,
2756 .input_key = on_key,
2757 .resized = on_resize,
2758 .recolor = on_recolor
2759 };
2760
2761 /* already have one, let other implementations take a stab at it */
2762 if (in->debug){
2763 return false;
2764 }
2765
2766 *dst = arcan_tui_setup(conn, c, &cbcfg, sizeof(cbcfg));
2767
2768 if (!*dst)
2769 return false;
2770
2771 /* no cursor, no scrollback, synch resize */
2772 in->debug = dst;
2773 arcan_tui_set_flags(*dst, TUI_ALTERNATE | TUI_HIDE_CURSOR);
2774
2775 tsm_vte_update_debug(in);
2776 return true;
2777 }
2778
2779 SHL_EXPORT
tsm_set_strhandler(struct tsm_vte * vte,tsm_str_cb cb,size_t limit,void * data)2780 void tsm_set_strhandler(struct tsm_vte *vte, tsm_str_cb cb, size_t limit, void* data)
2781 {
2782 if (vte->strcb)
2783 vte->strcb(vte, TSM_GROUP_FREE, NULL, 0, false, vte->strcb_data);
2784
2785 free(vte->colbuf);
2786 vte->colbuf = NULL;
2787 if (!cb)
2788 return;
2789
2790 vte->colbuf = malloc(limit);
2791 if (!vte->colbuf){
2792 vte->strcb(vte, TSM_GROUP_FREE, NULL, 0, false, data);
2793 return;
2794 }
2795
2796 vte->colbuf_sz = limit;
2797 vte->colbuf_pos = 0;
2798 vte->colbuf[0] = '\0';
2799 vte->strcb = cb;
2800 vte->strcb_data = data;
2801 }
2802
2803 SHL_EXPORT
tsm_vte_handle_keyboard(struct tsm_vte * vte,uint32_t keysym,uint32_t ascii,unsigned int mods,uint32_t unicode)2804 bool tsm_vte_handle_keyboard(struct tsm_vte *vte, uint32_t keysym,
2805 uint32_t ascii, unsigned int mods,
2806 uint32_t unicode)
2807 {
2808 char val, u8[4];
2809 size_t len;
2810 uint32_t sym;
2811
2812 /* MOD1 (mostly labeled 'Alt') prepends an escape character to every
2813 * input that is sent by a key.
2814 * TODO: Transform this huge handler into a lookup table to save a lot
2815 * of code and make such modifiers easier to implement.
2816 * Also check whether altSendsEscape should be the default (xterm
2817 * disables this by default, why?) and whether we should implement the
2818 * fallback shifting that xterm does. */
2819 if (mods & TSM_ALT_MASK)
2820 vte->flags |= FLAG_PREPEND_ESCAPE;
2821
2822 /* A user might actually use multiple layouts for keyboard input. The
2823 * @keysym variable contains the actual keysym that the user used. But
2824 * if this keysym is not in the ascii range, the input handler does
2825 * check all other layouts that the user specified whether one of them
2826 * maps the key to some ASCII keysym and provides this via @ascii.
2827 * We always use the real keysym except when handling CTRL+<XY>
2828 * shortcuts we use the ascii keysym. This is for compatibility to xterm
2829 * et. al. so ctrl+c always works regardless of the currently active
2830 * keyboard layout.
2831 * But if no ascii-sym is found, we still use the real keysym. */
2832 sym = ascii;
2833 if (!sym)
2834 sym = keysym;
2835
2836 if (mods & TSM_CONTROL_MASK) {
2837 switch (sym) {
2838 case TUIK_2:
2839 case TUIK_SPACE:
2840 vte_write(vte, "\x00", 1);
2841 return true;
2842 case TUIK_A:
2843 vte_write(vte, "\x01", 1);
2844 return true;
2845 case TUIK_B:
2846 vte_write(vte, "\x02", 1);
2847 return true;
2848 case TUIK_C:
2849 vte_write(vte, "\x03", 1);
2850 return true;
2851 case TUIK_D:
2852 vte_write(vte, "\x04", 1);
2853 return true;
2854 case TUIK_E:
2855 vte_write(vte, "\x05", 1);
2856 return true;
2857 case TUIK_F:
2858 vte_write(vte, "\x06", 1);
2859 return true;
2860 case TUIK_G:
2861 vte_write(vte, "\x07", 1);
2862 return true;
2863 case TUIK_H:
2864 vte_write(vte, "\x08", 1);
2865 return true;
2866 case TUIK_I:
2867 vte_write(vte, "\x09", 1);
2868 return true;
2869 case TUIK_J:
2870 vte_write(vte, "\x0a", 1);
2871 return true;
2872 case TUIK_K:
2873 vte_write(vte, "\x0b", 1);
2874 return true;
2875 case TUIK_L:
2876 vte_write(vte, "\x0c", 1);
2877 return true;
2878 case TUIK_M:
2879 vte_write(vte, "\x0d", 1);
2880 return true;
2881 case TUIK_N:
2882 vte_write(vte, "\x0e", 1);
2883 return true;
2884 case TUIK_O:
2885 vte_write(vte, "\x0f", 1);
2886 return true;
2887 case TUIK_P:
2888 vte_write(vte, "\x10", 1);
2889 return true;
2890 case TUIK_Q:
2891 vte_write(vte, "\x11", 1);
2892 return true;
2893 case TUIK_R:
2894 vte_write(vte, "\x12", 1);
2895 return true;
2896 case TUIK_S:
2897 vte_write(vte, "\x13", 1);
2898 return true;
2899 case TUIK_T:
2900 vte_write(vte, "\x14", 1);
2901 return true;
2902 case TUIK_U:
2903 vte_write(vte, "\x15", 1);
2904 return true;
2905 case TUIK_V:
2906 vte_write(vte, "\x16", 1);
2907 return true;
2908 case TUIK_W:
2909 vte_write(vte, "\x17", 1);
2910 return true;
2911 case TUIK_X:
2912 vte_write(vte, "\x18", 1);
2913 return true;
2914 case TUIK_Y:
2915 vte_write(vte, "\x19", 1);
2916 return true;
2917 case TUIK_Z:
2918 vte_write(vte, "\x1a", 1);
2919 return true;
2920 case TUIK_3:
2921 case TUIK_KP_LEFTBRACE:
2922 vte_write(vte, "\x1b", 1);
2923 return true;
2924 case TUIK_4:
2925 case TUIK_BACKSLASH:
2926 vte_write(vte, "\x1c", 1);
2927 return true;
2928 case TUIK_5:
2929 case TUIK_KP_RIGHTBRACE:
2930 vte_write(vte, "\x1d", 1);
2931 return true;
2932 case TUIK_6:
2933 case TUIK_GRAVE:
2934 vte_write(vte, "\x1e", 1);
2935 return true;
2936 case TUIK_7:
2937 case TUIK_SLASH:
2938 vte_write(vte, "\x1f", 1);
2939 return true;
2940 case TUIK_8:
2941 case TUIK_BACKSPACE:
2942 vte_write(vte, "\x7f", 1);
2943 return true;
2944 }
2945 }
2946
2947 /* NOTE: arcan >typically< (this varies between platform ,but ideally) does NOT
2948 * deal with numlock as a valid state (or caps lock for that matter). Such
2949 * state is up to the running set of scripts to maintain. Therefore, the
2950 * translation here ACT as numlock and is always in its "special keys" mode and
2951 * the numbers should be provided in the UTF8 field rather than as state
2952 * dependent keysyms */
2953 switch (keysym) {
2954 case TUIK_BACKSPACE:
2955 vte_write(vte, "\x08", 1);
2956 return true;
2957 case TUIK_TAB:
2958 vte_write(vte, "\x09", 1);
2959 return true;
2960 /*
2961 * Some X keysyms that we don't have access to:
2962 * LINEFEED, LeftTab
2963 case TUIK_ISO_Left_Tab:
2964 vte_write(vte, "\e[Z", 3);
2965 return true;
2966 case TUIK_RETURN:
2967 vte_write(vte, "\x0a", 1);
2968 return true;
2969 */
2970 case TUIK_CLEAR:
2971 vte_write(vte, "\x0b", 1);
2972 return true;
2973 /*
2974 TODO: What should we do with this key? Sending XOFF is awful as
2975 there is no simple way on modern keyboards to send XON
2976 again. If someone wants this, we can re-enable it and set
2977 some flag.
2978 case TUIK_Pause:
2979 vte_write(vte, "\x13", 1);
2980 return true;
2981 */
2982 /*
2983 TODO: What should we do on scroll-lock? Sending 0x14 is what
2984 the specs say but it is not used today the way most
2985 users would expect so we disable it. If someone wants
2986 this, we can re-enable it and set some flag.
2987 case TUIK_Scroll_Lock:
2988 vte_write(vte, "\x14", 1);
2989 return true;
2990 */
2991 case TUIK_SYSREQ:
2992 vte_write(vte, "\x15", 1);
2993 return true;
2994 case TUIK_ESCAPE:
2995 vte_write(vte, "\x1b", 1);
2996 return true;
2997 case TUIK_KP_ENTER:
2998 if (vte->flags & FLAG_KEYPAD_APPLICATION_MODE) {
2999 vte_write(vte, "\eOM", 3);
3000 return true;
3001 }
3002 /* fallthrough */
3003 case TUIK_RETURN:
3004 if (vte->flags & FLAG_LINE_FEED_NEW_LINE_MODE)
3005 vte_write(vte, "\x0d\x0a", 2);
3006 else
3007 vte_write(vte, "\x0d", 1);
3008 return true;
3009 case TUIK_HOME:
3010 case TUIK_KP_7:
3011 if (vte->flags & FLAG_CURSOR_KEY_MODE)
3012 vte_write(vte, "\eOH", 3);
3013 else
3014 vte_write(vte, "\e[H", 3);
3015 return true;
3016 case TUIK_INSERT:
3017 case TUIK_KP_0:
3018 vte_write(vte, "\e[2~", 4);
3019 return true;
3020 case TUIK_DELETE:
3021 case TUIK_KP_PERIOD:
3022 vte_write(vte, "\e[3~", 4);
3023 return true;
3024 case TUIK_END:
3025 case TUIK_KP_1:
3026 if (vte->flags & FLAG_CURSOR_KEY_MODE)
3027 vte_write(vte, "\eOF", 3);
3028 else
3029 vte_write(vte, "\e[F", 3);
3030 return true;
3031 case TUIK_PAGEUP:
3032 case TUIK_KP_9:
3033 vte_write(vte, "\e[5~", 4);
3034 return true;
3035 case TUIK_PAGEDOWN:
3036 case TUIK_KP_3:
3037 vte_write(vte, "\e[6~", 4);
3038 return true;
3039 case TUIK_UP:
3040 case TUIK_KP_8:
3041 if (vte->flags & FLAG_CURSOR_KEY_MODE)
3042 vte_write(vte, "\eOA", 3);
3043 else
3044 vte_write(vte, "\e[A", 3);
3045 return true;
3046 case TUIK_DOWN:
3047 case TUIK_KP_2:
3048 if (vte->flags & FLAG_CURSOR_KEY_MODE)
3049 vte_write(vte, "\eOB", 3);
3050 else
3051 vte_write(vte, "\e[B", 3);
3052 return true;
3053 case TUIK_RIGHT:
3054 case TUIK_KP_6:
3055 if (vte->flags & FLAG_CURSOR_KEY_MODE)
3056 vte_write(vte, "\eOC", 3);
3057 else
3058 vte_write(vte, "\e[C", 3);
3059 return true;
3060 case TUIK_LEFT:
3061 case TUIK_KP_4:
3062 if (vte->flags & FLAG_CURSOR_KEY_MODE)
3063 vte_write(vte, "\eOD", 3);
3064 else
3065 vte_write(vte, "\e[D", 3);
3066 return true;
3067 case TUIK_KP_5:
3068 if (vte->flags & FLAG_KEYPAD_APPLICATION_MODE)
3069 vte_write(vte, "\eOu", 3);
3070 else
3071 vte_write(vte, "5", 1);
3072 return true;
3073 case TUIK_KP_MINUS:
3074 if (vte->flags & FLAG_KEYPAD_APPLICATION_MODE)
3075 vte_write(vte, "\eOm", 3);
3076 else
3077 vte_write(vte, "-", 1);
3078 return true;
3079 case TUIK_KP_EQUALS:
3080 case TUIK_KP_DIVIDE:
3081 if (vte->flags & FLAG_KEYPAD_APPLICATION_MODE)
3082 vte_write(vte, "\eOj", 3);
3083 else
3084 vte_write(vte, "/", 1);
3085 return true;
3086 case TUIK_KP_MULTIPLY:
3087 if (vte->flags & FLAG_KEYPAD_APPLICATION_MODE)
3088 vte_write(vte, "\eOo", 3);
3089 else
3090 vte_write(vte, "*", 1);
3091 return true;
3092 case TUIK_KP_PLUS:
3093 if (vte->flags & FLAG_KEYPAD_APPLICATION_MODE)
3094 vte_write(vte, "\eOk", 3);
3095 else
3096 vte_write(vte, "+", 1);
3097 return true;
3098 /* case TUIK_KP_Space:
3099 vte_write(vte, " ", 1);
3100 return true;
3101 */
3102 /* TODO: check what to transmit for functions keys when
3103 * shift/ctrl etc. are pressed. Every terminal behaves
3104 * differently here which is really weird.
3105 * We now map F4 to F14 if shift is pressed and so on for all
3106 * keys. However, such mappings should rather be done via
3107 * xkb-configurations and we should instead add a flags argument
3108 * to the CSIs as some of the keys here already do. */
3109 case TUIK_F1:
3110 if (mods & TSM_SHIFT_MASK)
3111 vte_write(vte, "\e[23~", 5);
3112 else
3113 vte_write(vte, "\eOP", 3);
3114 return true;
3115 case TUIK_F2:
3116 if (mods & TSM_SHIFT_MASK)
3117 vte_write(vte, "\e[24~", 5);
3118 else
3119 vte_write(vte, "\eOQ", 3);
3120 return true;
3121 case TUIK_F3:
3122 if (mods & TSM_SHIFT_MASK)
3123 vte_write(vte, "\e[25~", 5);
3124 else
3125 vte_write(vte, "\eOR", 3);
3126 return true;
3127 case TUIK_F4:
3128 if (mods & TSM_SHIFT_MASK)
3129 //vte_write(vte, "\e[1;2S", 6);
3130 vte_write(vte, "\e[26~", 5);
3131 else
3132 vte_write(vte, "\eOS", 3);
3133 return true;
3134 case TUIK_F5:
3135 if (mods & TSM_SHIFT_MASK)
3136 //vte_write(vte, "\e[15;2~", 7);
3137 vte_write(vte, "\e[28~", 5);
3138 else
3139 vte_write(vte, "\e[15~", 5);
3140 return true;
3141 case TUIK_F6:
3142 if (mods & TSM_SHIFT_MASK)
3143 //vte_write(vte, "\e[17;2~", 7);
3144 vte_write(vte, "\e[29~", 5);
3145 else
3146 vte_write(vte, "\e[17~", 5);
3147 return true;
3148 case TUIK_F7:
3149 if (mods & TSM_SHIFT_MASK)
3150 //vte_write(vte, "\e[18;2~", 7);
3151 vte_write(vte, "\e[31~", 5);
3152 else
3153 vte_write(vte, "\e[18~", 5);
3154 return true;
3155 case TUIK_F8:
3156 if (mods & TSM_SHIFT_MASK)
3157 //vte_write(vte, "\e[19;2~", 7);
3158 vte_write(vte, "\e[32~", 5);
3159 else
3160 vte_write(vte, "\e[19~", 5);
3161 return true;
3162 case TUIK_F9:
3163 if (mods & TSM_SHIFT_MASK)
3164 //vte_write(vte, "\e[20;2~", 7);
3165 vte_write(vte, "\e[33~", 5);
3166 else
3167 vte_write(vte, "\e[20~", 5);
3168 return true;
3169 case TUIK_F10:
3170 if (mods & TSM_SHIFT_MASK)
3171 //vte_write(vte, "\e[21;2~", 7);
3172 vte_write(vte, "\e[34~", 5);
3173 else
3174 vte_write(vte, "\e[21~", 5);
3175 return true;
3176 case TUIK_F11:
3177 if (mods & TSM_SHIFT_MASK)
3178 vte_write(vte, "\e[23;2~", 7);
3179 else
3180 vte_write(vte, "\e[23~", 5);
3181 return true;
3182 case TUIK_F12:
3183 if (mods & TSM_SHIFT_MASK)
3184 vte_write(vte, "\e[24;2~", 7);
3185 else
3186 vte_write(vte, "\e[24~", 5);
3187 return true;
3188 }
3189
3190 if (unicode != TSM_VTE_INVALID) {
3191 if (vte->flags & FLAG_7BIT_MODE) {
3192 val = unicode;
3193 if (unicode & 0x80) {
3194 DEBUG_LOG(vte, "invalid keyboard input in 7bit mode U+%x; mapping to '?'",
3195 unicode);
3196 val = '?';
3197 }
3198 vte_write(vte, &val, 1);
3199 } else if (vte->flags & FLAG_8BIT_MODE) {
3200 val = unicode;
3201 if (unicode > 0xff) {
3202 DEBUG_LOG(vte, "invalid keyboard input in 8bit mode U+%x; mapping to '?'",
3203 unicode);
3204 val = '?';
3205 }
3206 vte_write_raw(vte, &val, 1);
3207 }
3208 /*
3209 this should already be handled in arcan- vte
3210 else {
3211 len = tsm_ucs4_to_utf8(tsm_symbol_make(unicode), u8);
3212 vte_write_raw(vte, u8, len);
3213 }
3214 */
3215 return true;
3216 }
3217
3218 vte->flags &= ~FLAG_PREPEND_ESCAPE;
3219 return false;
3220 }
3221