#include #include #include #include #include #include #include #include #include "emulator.h" #include "resizeable_buf.h" #include "pane.h" #include "script.h" #include "util.h" #include "unix.h" #include "x11.h" #include "defaults.h" #include "colors.h" #include "pty-outfifo.h" #include "debug.h" static wchar_t const * const charset_uk = L" !\"\x00A3$%&'()*+,-./0123456789:;<=>?" L"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" L"`abcdefghijklmnopqrstuvwxyz{|}~"; static wchar_t const * const charset_special = L" !\"#$%&'()*+,-./0123456789:;<=>?" L"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^\x25AE" L"\x25C6\x2592\x2409\x240C\x240D\x240A\x00B0\x00B1" L"\x2424\x240B\x2518\x2510\x250C\x2514\x253C\x23BA" L"\x23BB\x2500\x23BC\x23BD\x251C\x2524\x2534\x252C" L"\x2502\x2264\x2265\x03C0\x2260\x00A3\x00B7"; static void emulate_sdata(struct emulate *e, wchar_t ch, sc_t * output); static void dispatch_csi(struct emulate *e, wchar_t ch, sc_t *p); static void dispatch_esc(struct emulate *e, wchar_t ch, sc_t *p); static void emulate_set_cursor(struct emulate *e, int col, int row); static const char * const default_color_names[] = { "black", "red3", "green3", "yellow3", "blue3", "magenta3", "cyan3", "gray90", "gray30", "red", "green", "yellow", "blue", "magenta", "cyan", "white", #include "256colors.h" }; #define emulator_debug opt_debug static struct color *colors[256]; static struct color * color(int i) { assert( i >= 0 && i < 256); if(!colors[i]) { if(conn) colors[i] = get_alloc_color(conn->dpy, DefaultColormap(conn->dpy,DefaultScreen(conn->dpy)), default_color_names[i]); else colors[i] = get_color(default_color_names[i]); } return colors[i]; } static void scroll(struct emulate *e, int begin, int end, int num, sc_t *p) { if(begin == 0 && end == e->rows && num > 0) pane_scroll(p->pane,num, false); else pane_partial_scroll(p->pane, begin, end - 1, num); } struct emulate * emulate_create(void) { struct emulate *e = malloc(sizeof(struct emulate)); e->state = ground_state; e->cursor.col = e->cursor.row = 0; e->cursor.mode_decom = false; e->cursor.mode_decawm = true; e->cursor.charset = e->cursor.charset_save = 0; e->saved.col = e->saved.row = 0; e->saved.mode_decom = false; e->saved.mode_decawm = true; e->saved.charset = e->saved.charset_save = 0; e->mode_irm = false; e->mode_kam = false; e->mode_srm = true; e->mode_lnm = false; e->mode_decckm = false; e->mode_decanm = true; e->mode_deckpam = false; e->mode_dectcem = true; e->cols = e->rows = 0; RB_INIT(&e->v_param); RB_INIT(&e->v_chars); RB_INIT(&e->v_collect); memset(&e->blank_style, 0, sizeof(struct cell)); //setup_colors(); e->blank_style.fgcolor = DC_foreground; // colors[DEFAULT_FG]; e->blank_style.bgcolor = DC_background; //colors[DEFAULT_BG]; e->style = e->blank_style; e->scroll_begin = 0; e->scroll_end = 0; e->pty = NULL; e->charset[0] = NULL; e->charset[1] = charset_special; e->charset[2] = NULL; e->charset[3] = NULL; e->tabs = NULL; return e; } void emulate_set_size(struct emulate * e, int c, int r) { int i; bitfield_t *tabs; if (e->scroll_end == e->rows || e->scroll_end > r) e->scroll_end = r; if (e->scroll_begin >= e->scroll_end) e->scroll_begin = e->scroll_end - 1; //tabs.resize(c); //for (int i = e->cols; i < c; ++i) tabs[i] = (0 == i % 8); tabs = bitfield_calloc(c); for (i = 0; i < MIN(e->cols,c); ++i) change_bit(tabs,i,test_bit(e->tabs,i)); for (i = e->cols; i < c; ++i) change_bit(tabs, i, (0 == i % 8)); free(e->tabs); e->tabs = tabs; e->cols = c; e->rows = r; emulate_set_cursor(e, e->cursor.col, e->cursor.row); if(emulator_debug) fprintf(stderr,"Set size to %ix%i\n", c, r); } void emulate_set_cursor(struct emulate *e, int col, int row) { e->cursor.col = MIN(e->cols - 1, MAX(0, col)); e->cursor.row = MIN(e->rows - 1, MAX(0, row)); //pane_setcursor(output, MIN((e->cursor.col), e->cols - 1), e->cursor.row); } static inline int is_printable(wchar_t ch) { return (ch >= 0x20 && ch < 0x7F) || ch >= 0xA0; // return iswprint(ch); } void emulate_data(struct emulate *e, void const *text, int length, sc_t *output, bool latin1) { int sz = latin1 ? sizeof(char) : sizeof(wchar_t); do { if (ground_state == e->state && NULL == e->charset[e->cursor.charset] && e->cursor.charset == e->cursor.charset_save) { int i = 0; while (i < length && e->cursor.col + i < e->cols && is_printable(latin1 ? ((char *)text)[i] : ((wchar_t *)text)[i])) ++i; if(i) { if (e->mode_irm) pane_line_copy(output->pane, e->cursor.col, e->cursor.col + i, e->cursor.row, e->cols - e->cursor.col - i); if((!e->mode_irm) && latin1) { //fprintf(stderr, "(%i,%i) %i\r\n", e->cursor.col, e->cursor.row, i ); script_text(output,text,i); } pane_settext_generic(output->pane, e->cursor.col, e->cursor.row, text, i, e->style, latin1); e->cursor.col = e->cursor.col + i; length -= i; text += i*sz; } } if (length > 0) { emulate_sdata(e, latin1 ? *((char *)text) : *((wchar_t *)text), output); text += sz; --length; } } while (length > 0); //output->set_cursor(std::min(int(cursor.col), cols - 1), cursor.row); emulate_set_cursor(e, MIN((e->cursor.col), e->cols - 1), e->cursor.row); pane_showcursor(output->pane, e->mode_dectcem); pane_setcursor(output->pane, e->cursor.col, e->cursor.row); } static void emulate_sdata(struct emulate *e, wchar_t ch, sc_t * output) { switch (e->state) { case osc_string_state: if(ch == 0x07) { e->state = ground_state; return; } else break; case ground_state: //v_collect.clear(); //v_param.resize(1); //v_param[0] = 0; RB_CLEAR(e->v_collect); rb_resize(&e->v_param, sizeof(int), false); RBP(int, &e->v_param)[0] = 0; case csi_param_state: case csi_ignore_state: case csi_intermediate_state: case csi_entry_state: case escape_intermediate_state: case escape_state: switch (ch) { case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: case 0x19: case 0x1C: case 0x1D: case 0x1E: case 0x1F: fprintf(stderr, "unknown C0: %02X\n", (unsigned)ch); return; case 0x00: return; case 0x07: // BEL //output->bell(); if(DB_bell && IS_ATTACHED()) XBell(conn->dpy, 75); return; case 0x08: // BS e->cursor.col = MAX(0, e->cursor.col - 1); return; case 0x09: // HT if (e->cursor.col < e->cols - 1) e->cursor.col = e->cursor.col + 1; while (e->cursor.col < e->cols - 1 && !test_bit(e->tabs,e->cursor.col)) e->cursor.col = e->cursor.col + 1; // e->cursor.col = ((e->cursor.col + 8) / 8) * 8; return; case 0x0A: // LF case 0x0B: // VT case 0x0C: // FF // c_newline(e, output); if (e->cursor.row == e->scroll_end - 1) scroll(e, e->scroll_begin, e->scroll_end, 1, output); else if (e->cursor.row < e->rows - 1) e->cursor.row = e->cursor.row + 1; if (e->mode_lnm) e->cursor.col = 0; return; case 0x0D: // CR e->cursor.col = 0; return; case 0x0E: // SO if (emulator_debug) fputs("SO\n",stderr); e->cursor.charset = e->cursor.charset_save = 1; return; case 0x0F: // SI if (emulator_debug) fputs("SI\n",stderr); e->cursor.charset = e->cursor.charset_save = 0; return; } default: break; } switch (ch) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B: case 0x0C: case 0x0D: case 0x0E: case 0x0F: case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: case 0x19: case 0x1C: case 0x1D: case 0x1E: case 0x1F: if (e->state == dcs_passthrough_state) break; return; case 0x18: case 0x1A: case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: case 0x88: case 0x89: case 0x8A: case 0x8B: case 0x8C: case 0x8D: case 0x8E: case 0x8F: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: case 0x99: case 0x9A: e->state = ground_state; fprintf(stderr, "unknown C1: #%02X\n", (unsigned)ch); return; case 0x1B: e->state = escape_state; return; case 0x90: e->state = dcs_entry_state; return; case 0x9B: e->state = csi_entry_state; return; case 0x9C: e->state = ground_state; return; case 0x9D: e->state = osc_string_state; return; } switch (e->state) { case csi_param_state: case dcs_param_state: switch (ch) { case 0x3B: //v_param.push_back(0); RB_APPEND(int, &e->v_param, 0); return; case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: { int param = RB_LAST(int, &e->v_param); param = 10 * param + (ch - 0x30); RB_LAST(int, &e->v_param) = param; } //int & param = v_param.back(); //param = 10 * param + (ch - 0x30); return; } default: break; } switch (e->state) { case ground_state: if (is_printable(ch)) { if (e->cursor.col >= e->cols) { if (e->cursor.mode_decawm) { e->cursor.col = 0; emulate_sdata(e, 0x0A, output); } else e->cursor.col = MAX(0, e->cols - 1); } if (ch >= 0x20 && ch < 0x7F && NULL != e->charset[e->cursor.charset]) ch = (e->charset[e->cursor.charset])[ch - 0x20]; if (e->mode_irm) pane_line_copy(output->pane, e->cursor.col, e->cursor.col + 1, e->cursor.row, e->cols - e->cursor.col - 1); pane_settext_generic(output->pane, e->cursor.col, e->cursor.row, &ch, 1, e->style, false); e->cursor.col = e->cursor.col + 1; e->cursor.charset = e->cursor.charset_save; } return; case escape_state: switch (ch) { case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29: case 0x2A: case 0x2B: case 0x2C: case 0x2D: case 0x2E: case 0x2F: e->state = escape_intermediate_state; emulate_sdata(e, ch, output); return; case 0x50: e->state = dcs_entry_state; return; case 0x5B: e->state = csi_entry_state; return; case 0x5D: e->state = osc_string_state; return; case 0x58: case 0x5E: case 0x5F: e->state = misc_string_state; return; case 0x7F: return; default: e->state = ground_state; dispatch_esc(e, ch, output); return; } case escape_intermediate_state: switch (ch) { case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29: case 0x2A: case 0x2B: case 0x2C: case 0x2D: case 0x2E: case 0x2F: //v_collect.push_back(ch); RB_APPEND(wchar_t, &e->v_collect, ch); return; case 0x7F: return; default: e->state = ground_state; dispatch_esc(e, ch, output); return; } case csi_entry_state: switch (ch) { case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29: case 0x2A: case 0x2B: case 0x2C: case 0x2D: case 0x2E: case 0x2F: e->state = csi_intermediate_state; emulate_sdata(e, ch, output); return; case 0x3A: e->state = csi_ignore_state; return; case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: case 0x3B: e->state = csi_param_state; emulate_sdata(e, ch, output); return; case 0x3C: case 0x3D: case 0x3E: case 0x3F: //v_collect.push_back(ch); RB_APPEND(wchar_t, &e->v_collect, ch); e->state = csi_param_state; return; case 0x7F: return; default: e->state = ground_state; dispatch_csi(e, ch, output); return; } case csi_ignore_state: switch (ch) { case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29: case 0x2A: case 0x2B: case 0x2C: case 0x2D: case 0x2E: case 0x2F: case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: case 0x3A: case 0x3B: case 0x3C: case 0x3D: case 0x3E: case 0x3F: case 0x7F: return; default: e->state = ground_state; return; } case csi_intermediate_state: switch (ch) { case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29: case 0x2A: case 0x2B: case 0x2C: case 0x2D: case 0x2E: case 0x2F: //v_collect.push_back(ch); RB_APPEND(wchar_t, &e->v_collect, ch); return; case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: case 0x3A: case 0x3B: case 0x3C: case 0x3D: case 0x3E: case 0x3F: e->state = csi_ignore_state; return; case 0x7F: return; default: e->state = ground_state; dispatch_csi(e, ch, output); return; } case csi_param_state: switch (ch) { case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29: case 0x2A: case 0x2B: case 0x2C: case 0x2D: case 0x2E: case 0x2F: e->state = csi_intermediate_state; emulate_sdata(e, ch, output); return; case 0x3A: case 0x3C: case 0x3D: case 0x3E: case 0x3F: e->state = csi_ignore_state; return; case 0x7F: return; default: e->state = ground_state; dispatch_csi(e, ch, output); return; } case misc_string_state: switch (ch) { case 0x9C: e->state = ground_state; return; default: return; } case osc_string_state: switch (ch) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B: case 0x0C: case 0x0D: case 0x0E: case 0x0F: case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: case 0x19: case 0x1C: case 0x1D: case 0x1E: case 0x1F: return; case 0x9C: e->state = ground_state; return; // TODO: osc_end default: return; // TODO: osc_put } case dcs_entry_state: switch (ch) { case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29: case 0x2A: case 0x2B: case 0x2C: case 0x2D: case 0x2E: case 0x2F: //v_collect.push_back(ch); RB_APPEND(wchar_t, &e->v_collect, ch); e->state = dcs_intermediate_state; return; case 0x3A: e->state = dcs_ignore_state; return; case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: case 0x3B: e->state = dcs_param_state; emulate_sdata(e, ch, output); return; case 0x3C: case 0x3D: case 0x3E: case 0x3F: //v_collect.push_back(ch); RB_APPEND(wchar_t, &e->v_collect, ch); e->state = dcs_param_state; return; default: e->state = dcs_passthrough_state; emulate_sdata(e, ch, output); return; } case dcs_ignore_state: switch (ch) { case 0x9C: e->state = ground_state; return; default: return; } case dcs_intermediate_state: switch (ch) { case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: case 0x3A: case 0x3B: case 0x3C: case 0x3D: case 0x3E: case 0x3F: e->state = dcs_ignore_state; return; default: e->state = dcs_passthrough_state; emulate_sdata(e, ch, output); return; } case dcs_param_state: switch (ch) { case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29: case 0x2A: case 0x2B: case 0x2C: case 0x2D: case 0x2E: case 0x2F: //v_collect.push_back(ch); RB_APPEND(wchar_t, &e->v_collect, ch); e->state = dcs_intermediate_state; return; case 0x3A: case 0x3C: case 0x3D: case 0x3E: case 0x3F: e->state = dcs_ignore_state; return; case 0x7F: return; default: e->state = dcs_passthrough_state; emulate_sdata(e, ch, output); return; } case dcs_passthrough_state: switch (ch) { case 0x9C: e->state = ground_state; return; default: return; // TODO: dcs_put } case vt52_1_state: if (ch >= 0x20) { //v_collect.push_back(ch); RB_APPEND(wchar_t, &e->v_collect, ch); e->state = vt52_2_state; } else { e->state = ground_state; emulate_sdata(e, ch, output); } return; case vt52_2_state: e->state = ground_state; // if (ch >= 0x20 && !v_collect.empty()) { // cursor.row = std::min(rows - 1, v_collect.front() - 0x20); // cursor.col = std::min(cols - 1, ch - 0x20); // if (cursor.mode_decom) // cursor.row = scroll_begin + std::min( // scroll_end - scroll_begin - 1, // scroll_begin + cursor.row); // } // else emulate_sdata(e, ch, output); return; } } // #define PARAM(e, i) = RBP(int, &(e)->v_param)[i] #define PARAM(e) RBP(int, &(e)->v_param) #define PARAMSZ(e) RBL(int, &(e)->v_param) // process a CSI initiated command. ch is the final character // parameters have been accumulated in v_param and excess characters // have been put into v_collect void dispatch_csi(struct emulate *e, wchar_t ch, sc_t *p) { int i; bool flag; if(emulator_debug) { fprintf(stderr, "CSI "); for (int i = 0; i < RBL(int, &e->v_param); ++i) fprintf(stderr, "%c%d", (i ? ' ' : '['), RBP(int, &e->v_param)[i]); fprintf(stderr, "] "); for (int i = 0; i < RBL(wchar_t, &e->v_collect); ++i) fprintf(stderr, "%c", (char)RBP(wchar_t, &e->v_collect)[i]); fprintf(stderr, "%c\n", (unsigned)ch); } switch (ch) { case 'A': // CUU e->cursor.row = MAX( (e->cursor.row >= e->scroll_begin) ? e->scroll_begin : 0, e->cursor.row - MAX(1, RBP(int, &e->v_param)[0])); return; case 'B': // CUD e->cursor.row = MIN( (e->cursor.row >= e->scroll_end) ? e->rows - 1 : e->scroll_end - 1, e->cursor.row + MAX(1, RBP(int, &e->v_param)[0])); return; case 'C': // CUF e->cursor.col = MIN(e->cols - 1, e->cursor.col + MAX(1, RBP(int, &e->v_param)[0])); return; case 'D': // CUB e->cursor.col = MAX(0, e->cursor.col - MAX(1, RBP(int, &e->v_param)[0])); return; case 'f': // HVP case 'H': // CUP while (PARAMSZ(e) < 2) { RB_APPEND(int, &e->v_param, 0); } e->cursor.row = MAX(0, MIN(e->rows - 1, MAX(1, PARAM(e)[0]) - 1)); e->cursor.col = MAX(0, MIN(e->cols - 1, MAX(1, PARAM(e)[1]) - 1)); if (e->cursor.mode_decom) e->cursor.row = MAX(0, MIN(e->scroll_end - 1, e->scroll_begin + e->cursor.row)); return; case 'J': // ED switch (PARAM(e)[0]) { case 1: i = e->cursor.row; if (e->cursor.col < e->cols - 1) { dispatch_csi(e, 'K', p); --i; } pane_clear(p->pane, 0, 0, e->cols, i + 1, e->style); return; case 2: pane_clear(p->pane, 0, 0, e->cols, e->rows, e->style); return; default: i = e->cursor.row; if (e->cursor.col > 0) { dispatch_csi(e, 'K', p); ++i; } pane_clear(p->pane, 0, i, e->cols, e->rows - i, e->style); return; } case 'K': // EL switch (PARAM(e)[0]) { case 1: pane_clear(p->pane, 0, e->cursor.row, e->cursor.col + 1, 1, e->style); return; case 2: pane_clear(p->pane, 0, e->cursor.row, e->cols, 1, e->style); return; default: pane_clear(p->pane, e->cursor.col, e->cursor.row, e->cols - e->cursor.col, 1, e->style); return; } case 'm': // SGR { struct cell s = e->style; //s = new Style(*cursor.style); for (int i = 0; i < PARAMSZ(e); ++i) { int v = PARAM(e)[i]; switch (v) { case 0: s = e->blank_style; break; case 1: s.flag.bold = true; break; case 2: s.flag.dim = true; break; // new case 3: s.flag.italic = true; break; // new case 4: s.flag.underline = true; break; case 5: s.flag.blink = true; break; case 6: s.flag.rapidblink = true; break; //new case 7: s.flag.inverse = true; break; case 21: s.flag.bold = false; break; case 22: s.flag.dim = false; break; // new case 23: s.flag.italic = false; break; // new case 24: s.flag.underline = false; break; case 25: s.flag.blink = false; break; case 26: s.flag.rapidblink = false; break; //new case 27: s.flag.inverse = false; break; case 39: s.fgcolor = DC_foreground; break; // colors[DEFAULT_FG]; break; case 49: s.bgcolor = DC_background; break; // colors[DEFAULT_BG]; break; case 30 ... 37: s.fgcolor = color(v - 30); break; case 40 ... 47: s.bgcolor = color(v - 40); break; case 90 ... 97: s.fgcolor = color(v - 90 + 8); break; case 100 ... 107: s.bgcolor = color(v - 100 + 8); break; //case 48: s.flag.subscript = true; break; //new //case 49: s.flag.superscript = true; break; //new case 38: case 48: if(PARAMSZ(e) - (i + 1) >= 2 && PARAM(e)[i + 1] == 5) { int c = PARAM(e)[i+2]; if(c < 0 || c >= 256) fprintf(stderr, "bad color: %d\n", c); else { if(PARAM(e)[i] == 38) s.fgcolor = color(c); else s.bgcolor = color(c); i+=2; } break; } default: fprintf(stderr, "unknown text mode: %d\n", PARAM(e)[i]); break; } } e->style = s; return; } case 'h': // SM case 'l': // RM flag = (ch == 'h'); for (int i = 0; i < PARAMSZ(e); ++i) if (0 == RB_LEN(&e->v_collect) || RBP(wchar_t, &e->v_collect)[0] != '?') switch (PARAM(e)[i]) { case 0: break; case 2: // KAM e->mode_kam = flag; break; case 4: // IRM e->mode_irm = flag; break; case 12: // SRM e->mode_srm = flag; break; case 20: // LNM e->mode_lnm = flag; break; default: fprintf(stderr, "unknown mode: %d %s\n", PARAM(e)[i], (flag ? "set" : "unset")); break; } else switch (PARAM(e)[i]) { case 0: break; case 1: // DECCKM e->mode_decckm = flag; break; case 2: // DECANM e->mode_decanm = flag; break; case 3: break; // TODO: DECCOLM case 4: break; // DECSLM case 5: break; // TODO: DECSCNM case 6: // DECOM e->cursor.mode_decom = flag; e->cursor.col = 0; e->cursor.row = flag ? e->scroll_begin : 0; break; case 7: // DECAWM e->cursor.mode_decawm = flag; break; case 8: break; // TODO: DECARM case 12: break; // TODO: blinking cursor case 18: break; // TODO: DECPFF case 19: break; // TODO: DECPEX case 25: e->mode_dectcem = flag; break; case 1000: break; // mouse mode case 1048: // alternate screen fprintf(stderr, "Alt 1048 %s\n", (flag ? "set" : "unset")); break; case 1049: // alternate screen fprintf(stderr, "Alt 1049 %s\n", (flag ? "set" : "unset")); break; default: fprintf(stderr, "unknown private mode: %d %s\n", PARAM(e)[i], (flag ? "set" : "unset")); break; } return; case 'd': //VPA i = PARAM(e)[0]; if (i > 0) i--; e->cursor.row = i; return; case 'G': // CHA i = PARAM(e)[0]; if (i > 0) i--; e->cursor.col = i; return; case 'r': // DECSTBM while (PARAMSZ(e) < 2) { RB_APPEND(int, &e->v_param, 0); } //while (v_param.size() < 2) v_param.push_back(0); e->scroll_begin = MAX(0, MIN(e->rows - 1, PARAM(e)[0] - 1)); e->scroll_end = MAX( e->scroll_begin + 1, PARAM(e)[1] ? MIN(e->rows, PARAM(e)[1]) : e->rows); e->cursor.col = 0; e->cursor.row = e->cursor.mode_decom ? e->scroll_begin : 0; return; case 'L': // IL if (e->cursor.row < e->scroll_begin || e->cursor.row >= e->scroll_end) return; scroll(e, e->cursor.row, e->scroll_end, -MAX(1, PARAM(e)[0]), p); return; case 'M': // DL if (e->cursor.row < e->scroll_begin || e->cursor.row >= e->scroll_end) return; scroll(e, e->cursor.row, e->scroll_end, MAX(1, PARAM(e)[0]), p); return; case '@': //ICH i = PARAM(e)[0]; if ( 0 == i) i = 1; pane_line_copy(p->pane, e->cursor.col, e->cursor.col + i, e->cursor.row, i); pane_clear(p->pane, e->cursor.col, e->cursor.row, i, 1, e->blank_style); return; case 'X': //ECH i = PARAM(e)[0]; if ( 0 == i) i = 1; pane_clear(p->pane, e->cursor.col, e->cursor.row, i, 1, e->style); return; case 'P': // DCH i = MIN(MAX(1, PARAM(e)[0]), e->cols - e->cursor.col); if (i <= 0) return; //pane_line_copy(p, e->cols - 1, e->cols - i, e->cursor.row, 1); pane_line_copy(p->pane, e->cursor.col + i, e->cursor.col, e->cursor.row, e->cols - e->cursor.col - i); pane_clear(p->pane, e->cols - i, e->cursor.row, i, 1, e->blank_style); return; case 'c': // DA send_string(e->pty, "\e[?6c"); return; case 'n': // DSR switch (PARAM(e)[0]) { case 5: send_string(e->pty, "\e[0n"); return; case 6: { char pos_report[32]; sprintf(pos_report, "\e[%d;%dR", e->cursor.row + 1, e->cursor.col + 1); send_string(e->pty, pos_report); return; } case 15: send_string(e->pty, "\e[?13n"); return; default: fprintf(stderr, "unknown status report: %d\n", PARAM(e)[0]); return; } case 'y': // DECTST send_string(e->pty, "\e[0n"); return; case 'Z': // Backtab if (e->cursor.col > 0) e->cursor.col = e->cursor.col - 1; while (e->cursor.col > 0 && !test_bit(e->tabs,e->cursor.col)) e->cursor.col = e->cursor.col - 1; return; case 'g': // TBC if (3 == PARAM(e)[0]) bitfield_clear(e->tabs, e->cols); else if (0 == PARAM(e)[0] && e->cursor.col >= 0 && e->cursor.col < e->cols) clear_bit(e->tabs, e->cursor.col); return; /* case 'g': // TBC if (3 == v_param[0]) std::fill(tabs.begin(), tabs.end(), false); else if (0 == v_param[0] && cursor.col >= 0 && cursor.col < int(tabs.size())) tabs[cursor.col] = false; return; */ case 'S': // scroll up case 'T': // scroll down { int amount; if (!PARAM(e)[0]) amount = 1; else amount = PARAM(e)[0]; if (ch == 'T') amount = -amount; scroll(e, e->scroll_begin, e->scroll_end, amount , p); return; } case 'p': // DECSTR if(RBL(wchar_t, &e->v_collect) == 1 && RBP(wchar_t, &e->v_collect)[0] == '!') { e->style = e->blank_style; pane_clear(p->pane, 0, 0, e->cols, e->rows, e->style); e->cursor.col = 0; e->cursor.row = 0; e->charset[0] = NULL; e->charset[1] = charset_special; e->charset[2] = NULL; e->charset[3] = NULL; return; } } fprintf(stderr, "unknown CSI: "); for (int i = 0; i < RBL(int, &e->v_param); ++i) fprintf(stderr, "%c%d", (i ? ' ' : '['), RBP(int, &e->v_param)[i]); fprintf(stderr, "] "); for (int i = 0; i < RBL(wchar_t, &e->v_collect); ++i) fprintf(stderr, "%c", (char)RBP(wchar_t, &e->v_collect)[i]); fprintf(stderr, "%c\n", (unsigned)ch); } void dispatch_esc(struct emulate *e, wchar_t ch, sc_t *p) { int i; if(emulator_debug) { fprintf(stderr, "ESC "); for (int i = 0; i < RBL(wchar_t, &e->v_collect); ++i) fprintf(stderr, "%c", (char)RBP(wchar_t, &e->v_collect)[i]); fprintf(stderr, "%c\n", (unsigned)ch); } if (!RB_LEN(&e->v_collect)) { switch (ch) { case '<': // DECANM e->mode_decanm = true; return; case '=': // DECKPAM e->mode_deckpam = true; return; case '>': // DECKPNM e->mode_deckpam = false; e->mode_decckm = false; return; case '7': // DECSC e->saved = e->cursor; return; case '8': // DECRC e->cursor = e->saved; return; case 'A': if (e->cursor.row > 0 && e->cursor.row > e->scroll_begin) e->cursor.row = e->cursor.row - 1; return; case 'B': if (e->cursor.row < e->rows - 1 && e->cursor.row < e->scroll_end - 1) e->cursor.row = e->cursor.row + 1; return; case 'C': e->cursor.col = MIN(e->cols - 1, e->cursor.col + 1); return; case 'D': if (e->mode_decanm) { // IND if (e->cursor.row == e->scroll_end - 1) scroll(e, e->scroll_begin, e->scroll_end, 1, p); else if (e->cursor.row < e->rows - 1) e->cursor.row = e->cursor.row + 1; return; } e->cursor.col = MAX(0, e->cursor.col - 1); return; case 'E': // NEL e->cursor.col = 0; if (e->cursor.row == e->scroll_end - 1) scroll(e, e->scroll_begin, e->scroll_end, 1, p); else if (e->cursor.row < e->rows - 1) e->cursor.row = e->cursor.row + 1; return; case 'K': pane_clear(p->pane, e->cursor.col, e->cursor.row, e->cols - e->cursor.col, 1, e->style); return; case 'I': case 'M': // RI if (e->cursor.row == e->scroll_begin) scroll(e, e->scroll_begin, e->scroll_end, -1, p); else if (e->cursor.row > 0) e->cursor.row = e->cursor.row - 1; return; case 'J': i = e->cursor.row; if (e->cursor.col > 0) { dispatch_csi(e, 'K', p); ++i; } pane_clear(p->pane, 0, i, e->cols, e->rows - i, e->style); return; case '\\': emulate_sdata(e, 0x9C, p); // ST return; case 'H': if (!e->mode_decanm) { e->cursor.col = 0; e->cursor.row = (e->cursor.mode_decom) ? e->scroll_begin : 0; } else if (e->cursor.col >= 0 && e->cursor.col < e->cols) // HTS set_bit(e->tabs,e->cursor.col); //else if (e->cursor.col >= 0 && e->cursor.col < int(tabs.size())) // HTS // e->tabs[e->cursor.col] = true; return; case 'n': e->cursor.charset = 2; return; case 'o': e->cursor.charset = 3; return; case 'c': // RIS e->style = e->blank_style; pane_clear(p->pane, 0, 0, e->cols, e->rows, e->style); e->cursor.col = 0; e->cursor.row = 0; e->charset[0] = NULL; e->charset[1] = charset_special; e->charset[2] = NULL; e->charset[3] = NULL; return; /* case 'F': cursor.charset = cursor.charset_save = charset_special; return; case 'G': cursor.charset = cursor.charset_save = Null(); return; case 'Y': state = vt52_1_state; return; case 'Z': // DECID stuff(L"\e/Z"); return; case 'c': // RIS c = cols; r = rows; *this = Emulator(); set_size(c, r); return; */ } } else switch (RBP(wchar_t, &e->v_collect)[0]) { case '#': switch (ch) { case '8': { fprintf(stderr,"DEC self test\n"); struct cell e_char = e->style; e_char.ch = 'E'; pane_clear(p->pane, 0, 0, e->cols, e->rows, e_char); return; } /* case '8': v_chars.resize(cols); fill(v_chars.begin(), v_chars.end(), 'E'); for (int r = 0; r < rows; ++r) output->set_text(0, r, cols, &v_chars[0], cursor.style); return; */ } break; case '(': // SCS case ')': case '*': case '+': { char *ptr = "()*+"; i = strchr(ptr,RBP(wchar_t, &e->v_collect)[0]) - ptr; switch (ch) { case 'A': e->charset[i] = charset_uk; return; case 'B': e->charset[i] = NULL; return; case '0': e->charset[i] = charset_special; return; case '1': e->charset[i] = NULL; return; case '2': e->charset[i] = NULL; return; default: fprintf(stderr, "unknown character set: %c\n", (int)ch); return; } } } fprintf(stderr, "unknown ESC: "); for (int i = 0; i < RBL(wchar_t, &e->v_collect); ++i) fprintf(stderr, "%c", (char)RBP(wchar_t, &e->v_collect)[i]); fprintf(stderr, "%c\n", (unsigned)ch); } static void print_cursor(FILE *f, struct cursor *c) { fprintf(f, " (%i,%i)\n", c->col, c->row); fprintf(f, " mode_decom: %s\n", c->mode_decom ? "true" : "false"); fprintf(f, " mode_decawm: %s\n", c->mode_decawm ? "true" : "false"); fprintf(f, " charsets: G%i G%i\n", c->charset, c->charset_save); } static char * get_charset(wchar_t const *cs) { if (!cs) return "US"; if (cs == charset_uk) return "UK"; if (cs == charset_special) return "Graphics"; return "Unknown"; } void print_emulator_state(FILE *f, struct emulate *e) { fprintf(f, "state=%i\n", e->state); fprintf(f, "cols=%i, rows=%i\n", e->cols, e->rows); fprintf(f, "v_param/v_collect: "); for (int i = 0; i < RBL(int, &e->v_param); ++i) fprintf(f, "%c%d", (i ? ' ' : '['), RBP(int, &e->v_param)[i]); fprintf(f, "] "); for (int i = 0; i < RBL(wchar_t, &e->v_collect); ++i) fprintf(f, "%c", (char)RBP(wchar_t, &e->v_collect)[i]); fprintf(f, "\n"); fprintf(f, "scroll_begin=%i, scroll_end=%i\n", e->scroll_begin, e->scroll_end); fprintf(f, "mode_irm: %s\n", e->mode_irm ? "true" : "false"); fprintf(f, "mode_kam: %s\n", e->mode_kam ? "true" : "false"); fprintf(f, "mode_srm: %s\n", e->mode_srm ? "true" : "false"); fprintf(f, "mode_lnm: %s\n", e->mode_lnm ? "true" : "false"); fprintf(f, "mode_decckm: %s\n", e->mode_decckm ? "true" : "false"); fprintf(f, "mode_decanm: %s\n", e->mode_decanm ? "true" : "false"); fprintf(f, "mode_deckpam: %s\n", e->mode_deckpam ? "true" : "false"); fprintf(f, "mode_dectcem: %s\n", e->mode_dectcem ? "true" : "false"); fputs("Cursor:\n",f); print_cursor(f,&e->cursor); fputs("Saved cursor:\n",f); print_cursor(f,&e->saved); for(int i = 0; i < 4; i++) fprintf(f,"G%i: %s\n", i, get_charset(e->charset[i])); fputs("Tabs:",f); for(int i = 0; i < e->cols; i++) if(test_bit(e->tabs,i)) fprintf(f, " %i", i); fputc('\n', f); print_pty_state(f, e->pty); } /* void emulate_dispatch_csi(wchar_t ch, Output * output) { using std::max; using std::min; int i; Style * s; bool flag; char pos_report[80]; switch (ch) { case 'A': // CUU cursor.row = max( (cursor.row >= scroll_begin) ? int(scroll_begin) : 0, cursor.row - max(1, v_param[0])); return; case 'B': // CUD cursor.row = min( (cursor.row >= scroll_end) ? rows - 1 : scroll_end - 1, cursor.row + max(1, v_param[0])); return; case 'C': // CUF cursor.col = min(cols - 1, cursor.col + max(1, v_param[0])); return; case 'D': // CUB cursor.col = max(0, cursor.col - max(1, v_param[0])); return; case 'f': // HVP case 'H': // CUP while (v_param.size() < 2) v_param.push_back(0); cursor.row = max(0, min(rows - 1, max(1, v_param[0]) - 1)); cursor.col = max(0, min(cols - 1, max(1, v_param[1]) - 1)); if (cursor.mode_decom) cursor.row = std::max(0, std::min(scroll_end - 1, scroll_begin + cursor.row)); return; case 'J': // ED switch (v_param[0]) { default: i = cursor.row; if (cursor.col > 0) { dispatch_csi('K', output); ++i; } output->clear(0, i, cols, rows - i, blank_style); return; case 1: i = cursor.row; if (cursor.col < cols - 1) { dispatch_csi('K', output); --i; } output->clear(0, 0, cols, i + 1, blank_style); return; case 2: output->clear(0, 0, cols, rows, blank_style); return; } case 'K': // EL switch (v_param[0]) { default: output->clear(cursor.col, cursor.row, cols - cursor.col, 1, blank_style); return; case 1: output->clear(0, cursor.row, cursor.col + 1, 1, blank_style); return; case 2: output->clear(0, cursor.row, cols, 1, blank_style); return; } case 'L': // IL if (cursor.row < scroll_begin || cursor.row >= scroll_end) return; scroll(cursor.row, scroll_end, -max(1, v_param[0]), output); return; case 'M': // DL if (cursor.row < scroll_begin || cursor.row >= scroll_end) return; scroll(cursor.row, scroll_end, max(1, v_param[0]), output); return; case 'P': // DCH i = min(max(1, v_param[0]), cols - cursor.col); if (i <= 0) return; output->copy(cols - 1, cursor.row, cols - i, cursor.row, 1, 1); output->copy( cursor.col + i, cursor.row, cursor.col, cursor.row, cols - cursor.col - i, 1); output->clear(cols - i, cursor.row, i, 1, NULL); return; case 'c': // DA stuff(L"\e[?6c"); return; case 'g': // TBC if (3 == v_param[0]) std::fill(tabs.begin(), tabs.end(), false); else if (0 == v_param[0] && cursor.col >= 0 && cursor.col < int(tabs.size())) tabs[cursor.col] = false; return; case 'h': // SM case 'l': // RM flag = (ch == 'h'); for (int i = 0; i < int(v_param.size()); ++i) if (v_collect.empty() || v_collect.front() != '?') switch (v_param[i]) { case 0: break; case 2: // KAM mode_kam = flag; break; case 4: // IRM mode_irm = flag; break; case 12: // SRM mode_srm = flag; break; case 20: // LNM mode_lnm = flag; break; default: fprintf(stderr, "unknown mode: %d %s\n", v_param[i], (flag ? "set" : "unset")); break; } else switch (v_param[i]) { case 0: break; case 1: // DECCKM mode_decckm = flag; break; case 2: // DECANM mode_decanm = flag; break; case 3: break; // TODO: DECCOLM case 4: break; // DECSLM case 5: break; // TODO: DECSCNM case 6: // DECOM cursor.mode_decom = flag; cursor.col = 0; cursor.row = flag ? int(scroll_begin) : 0; break; case 7: // DECAWM cursor.mode_decawm = flag; break; case 8: break; // TODO: DECARM case 18: break; // TODO: DECPFF case 19: break; // TODO: DECPEX default: fprintf(stderr, "unknown private mode: %d %s\n", v_param[i], (flag ? "set" : "unset")); break; } return; case 'm': // SGR s = new Style(*cursor.style); for (int i = 0; i < int(v_param.size()); ++i) switch (v_param[i]) { case 0: *s = Style(); break; case 1: s->is_bold = true; break; case 4: s->is_underline = true; break; case 5: s->is_blink = true; break; case 7: s->is_inverse = true; break; default: fprintf(stderr, "unknown text mode: %d\n", v_param[i]); break; } cursor.style = s; return; case 'n': // DSR switch (v_param.front()) { case 5: stuff(L"\e[0n"); return; case 6: sprintf(pos_report, "\e[%d;%dR", cursor.row + 1, cursor.col + 1); stuff(pos_report); return; case 15: stuff(L"\e[?13n"); return; default: fprintf(stderr, "unknown status report: %d\n", v_param[0]); return; } return; case 'r': // DECSTBM while (v_param.size() < 2) v_param.push_back(0); scroll_begin = max(0, min(rows - 1, v_param[0] - 1)); scroll_end = max( int(scroll_begin + 1), v_param[1] ? min(int(rows), v_param[1]) : int(rows)); cursor.col = 0; cursor.row = cursor.mode_decom ? int(scroll_begin) : 0; return; case 'y': // DECTST stuff(L"\e[0n"); return; } fprintf(stderr, "unknown CSI: "); for (int i = 0; i < int(v_param.size()); ++i) fprintf(stderr, "%c%d", (i ? ' ' : '['), v_param[i]); fprintf(stderr, "] "); for (int i = 0; i < int(v_collect.size()); ++i) fprintf(stderr, "%c", v_collect[i]); fprintf(stderr, "%c\n", ch); } void emulate_dispatch_esc(wchar_t ch, Output * output) { using std::max; using std::min; int i, c, r; if (v_collect.empty()) { switch (ch) { case '<': // DECANM mode_decanm = true; return; case '=': // DECKPAM mode_deckpam = true; return; case '>': // DECKPNM mode_deckpam = false; mode_decckm = false; return; case '7': // DECSC saved = cursor; return; case '8': // DECRC cursor = saved; return; case 'A': if (cursor.row > 0 && cursor.row > scroll_begin) cursor.row = cursor.row - 1; return; case 'B': if (cursor.row < rows - 1 && cursor.row < scroll_end - 1) cursor.row = cursor.row + 1; return; case 'C': cursor.col = min(cols - 1, cursor.col + 1); return; case 'D': if (mode_decanm) { // IND if (cursor.row == scroll_end - 1) scroll(scroll_begin, scroll_end, 1, output); else if (cursor.row < rows - 1) cursor.row = cursor.row + 1; return; } cursor.col = max(0, cursor.col - 1); return; case 'E': // NEL cursor.col = 0; if (cursor.row == scroll_end - 1) scroll(scroll_begin, scroll_end, 1, output); else if (cursor.row < rows - 1) cursor.row = cursor.row + 1; return; case 'F': cursor.charset = cursor.charset_save = charset_special; return; case 'G': cursor.charset = cursor.charset_save = Null(); return; case 'H': if (!mode_decanm) { cursor.col = 0; cursor.row = (cursor.mode_decom) ? int(scroll_begin) : 0; } else if (cursor.col >= 0 && cursor.col < int(tabs.size())) // HTS tabs[cursor.col] = true; return; case 'J': i = cursor.row; if (cursor.col > 0) { dispatch_csi('K', output); ++i; } output->clear(0, i, cols, rows - i, blank_style); return; case 'K': output->clear(cursor.col, cursor.row, cols - cursor.col, 1, blank_style); return; case 'I': case 'M': // RI if (cursor.row == scroll_begin) scroll(scroll_begin, scroll_end, -1, output); else if (cursor.row > 0) cursor.row = cursor.row - 1; return; case 'N': cursor.charset = charset[2]; return; case 'O': cursor.charset = charset[3]; return; case 'Y': state = vt52_1_state; return; case 'Z': // DECID stuff(L"\e/Z"); return; case 'c': // RIS c = cols; r = rows; *this = Emulator(); set_size(c, r); return; } } else switch (v_collect.front()) { case '#': switch (ch) { case '8': v_chars.resize(cols); fill(v_chars.begin(), v_chars.end(), 'E'); for (int r = 0; r < rows; ++r) output->set_text(0, r, cols, &v_chars[0], cursor.style); return; } break; case '(': // SCS case ')': i = ('(' == v_collect.front()) ? 0 : 1; switch (ch) { case 'A': charset[i] = charset_uk; return; case 'B': charset[i] = NULL; return; case '0': charset[i] = charset_special; return; case '1': charset[i] = NULL; return; case '2': charset[i] = NULL; return; default: fprintf(stderr, "unknown character set: %c\n", ch); return; } } fprintf(stderr, "unknown ESC: "); for (int i = 0; i < int(v_collect.size()); ++i) fprintf(stderr, "%c", v_collect[i]); fprintf(stderr, "%c\n", ch); } void emulate_stuff(wchar_t const * text) { int len = 0; while ('\0' != text[len]) ++len; v_reply.insert(v_reply.end(), text, text + len); } void emulate_stuff(char const * text) { v_reply.insert(v_reply.end(), text, text + strlen(text)); } */ /* void emulate_event(XKeyEvent const &event, Output * output) { if (mode_kam || event.type != KeyPress) return; char buffer[1024]; KeySym keysym; XKeyEvent tmp = event; int len = XLookupString(&tmp, buffer, sizeof(buffer) - 2, &keysym, NULL); if (mode_lnm && len > 0 && buffer[len - 1] == '\r') buffer[len++] = '\n'; buffer[len++] = '\0'; if (mode_decanm) // ANSI switch (keysym) { case XK_Up: strcpy(buffer, mode_decckm ? "\eOA" : "\e[A"); break; case XK_Down: strcpy(buffer, mode_decckm ? "\eOB" : "\e[B"); break; case XK_Right: strcpy(buffer, mode_decckm ? "\eOC" : "\e[C"); break; case XK_Left: strcpy(buffer, mode_decckm ? "\eOD" : "\e[D"); break; case XK_KP_0: if (mode_deckpam) strcpy(buffer, "\eOp"); break; case XK_KP_1: if (mode_deckpam) strcpy(buffer, "\eOq"); break; case XK_KP_2: if (mode_deckpam) strcpy(buffer, "\eOr"); break; case XK_KP_3: if (mode_deckpam) strcpy(buffer, "\eOs"); break; case XK_KP_4: if (mode_deckpam) strcpy(buffer, "\eOt"); break; case XK_KP_5: if (mode_deckpam) strcpy(buffer, "\eOu"); break; case XK_KP_6: if (mode_deckpam) strcpy(buffer, "\eOv"); break; case XK_KP_7: if (mode_deckpam) strcpy(buffer, "\eOw"); break; case XK_KP_8: if (mode_deckpam) strcpy(buffer, "\eOx"); break; case XK_KP_9: if (mode_deckpam) strcpy(buffer, "\eOy"); break; case XK_KP_Separator: if (mode_deckpam) strcpy(buffer, "\eOl"); break; case XK_KP_Subtract: if (mode_deckpam) strcpy(buffer, "\eOm"); break; case XK_KP_Decimal: if (mode_deckpam) strcpy(buffer, "\eOn"); break; case XK_KP_Enter: if (mode_deckpam) strcpy(buffer, "\eOM"); break; case XK_F1: strcpy(buffer, "\eOP"); break; case XK_F2: strcpy(buffer, "\eOQ"); break; case XK_F3: strcpy(buffer, "\eOR"); break; case XK_F4: strcpy(buffer, "\eOS"); break; } else // VT52 switch (keysym) { case XK_Up: strcpy(buffer, "\eA"); break; case XK_Down: strcpy(buffer, "\eB"); break; case XK_Right: strcpy(buffer, "\eC"); break; case XK_Left: strcpy(buffer, "\eD"); break; case XK_KP_0: if (mode_deckpam) strcpy(buffer, "\e?p"); break; case XK_KP_1: if (mode_deckpam) strcpy(buffer, "\e?q"); break; case XK_KP_2: if (mode_deckpam) strcpy(buffer, "\e?r"); break; case XK_KP_3: if (mode_deckpam) strcpy(buffer, "\e?s"); break; case XK_KP_4: if (mode_deckpam) strcpy(buffer, "\e?t"); break; case XK_KP_5: if (mode_deckpam) strcpy(buffer, "\e?u"); break; case XK_KP_6: if (mode_deckpam) strcpy(buffer, "\e?v"); break; case XK_KP_7: if (mode_deckpam) strcpy(buffer, "\e?w"); break; case XK_KP_8: if (mode_deckpam) strcpy(buffer, "\e?x"); break; case XK_KP_9: if (mode_deckpam) strcpy(buffer, "\e?y"); break; case XK_KP_Separator: if (mode_deckpam) strcpy(buffer, "\e?l"); break; case XK_KP_Subtract: if (mode_deckpam) strcpy(buffer, "\e?m"); break; case XK_KP_Decimal: if (mode_deckpam) strcpy(buffer, "\e?n"); break; case XK_KP_Enter: if (mode_deckpam) strcpy(buffer, "\e?M"); break; case XK_F1: strcpy(buffer, "\eP"); break; case XK_F2: strcpy(buffer, "\eQ"); break; case XK_F3: strcpy(buffer, "\eR"); break; case XK_F4: strcpy(buffer, "\eS"); break; } if ('\0' != buffer[0]) { int const old = v_reply.size(); stuff(buffer); if (!mode_srm) data(v_reply.size() - old, &v_reply[old], output); } else fprintf(stderr, "unknown keypress: %s\n", XKeysymToString(keysym)); } int emulate_get_reply(wchar_t * buffer, int length) { length = std::min(length, int(v_reply.size())); copy(v_reply.begin(), v_reply.begin() + length, buffer); v_reply.erase(v_reply.begin(), v_reply.begin() + length); return length; } bool emulate_is_printable(wchar_t ch) { return ch >= 0x20 && ch < 0x7F || ch >= 0xA0; } void emulate_scroll(int begin, int end, int num, Output * output) { if (num > 0) { num = std::min(num, end - begin); output->copy(0, begin + num, 0, begin, cols, end - begin - num); output->clear(0, end - num, cols, num, blank_style); } else { num = std::min(-num, end - begin); output->copy(0, begin, 0, begin + num, cols, end - begin - num); output->clear(0, begin, cols, num, blank_style); } } */