From 7b466345af0d3a7dc5622617ce443a90c64e34a4 Mon Sep 17 00:00:00 2001 From: Alex AUVOLAT Date: Sat, 19 May 2012 09:23:48 +0200 Subject: Added ANSI support, minimal readline-like library. --- src/kernel/ui/vt.cpp | 211 +++++++++++++++++++++++++++++++++++++++++++++------ src/kernel/ui/vt.h | 5 +- 2 files changed, 190 insertions(+), 26 deletions(-) (limited to 'src/kernel/ui') diff --git a/src/kernel/ui/vt.cpp b/src/kernel/ui/vt.cpp index 34dfbe9..9b0bdf0 100644 --- a/src/kernel/ui/vt.cpp +++ b/src/kernel/ui/vt.cpp @@ -3,12 +3,22 @@ vt *ke_vt = 0, *home_vt = 0; +static char *kb_cmd_esc[] = { + /* 00 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 20 */ 0, 0, 0, 0, 0, 0, 0, 0, "\x1b[B", 0, + /* 30 */ "\x1b[D", 0, "\x1b[C", 0, "\x1b[A", 0, 0, 0, 0, 0, + /* 40 */ 0, 0, 0, 0, 0, 0, "\x1b[B", "\x1b[A", "\x1b[D", "\x1b[C", + /* 50 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 60 */ 0, 0, 0, 0 }; + vt::vt(node* parent, int ww, int hh) : node(parent, FT_TERMINAL) { w = ww; h = hh; fgcolor = TC_LIGHTGRAY; bgcolor = TC_BLACK; output = 0; cursor_visible = true; + keyboard_echo = false; csr_l = csr_c = 0; kbd_buffer_filled = 0; @@ -34,6 +44,25 @@ void vt::put_at(int l, int c, int ch) { } } +void vt::scroll(int n) { + if (output != 0 && output->connected_vt == this) { + output->text_scroll(n, fgcolor, bgcolor); + } + if (n > 0) { + for (int j = 0; j < w * (h-n); j++) { + text[j] = text[j + w]; + } + for (int j = w * (h-n); j < w * h; j++) { + text[j].fgcolor = fgcolor; + text[j].bgcolor = bgcolor; + text[j].ch = ' '; + } + } else if (n < 0) { + //TODO + } + csr_l -= n; +} + void vt::put(int c) { if (text == 0) return; @@ -60,18 +89,7 @@ void vt::put(int c) { csr_l++; } if (csr_l == h) { - if (output != 0 && output->connected_vt == this) { - output->text_scroll(1, fgcolor, bgcolor); - } - for (int j = 0; j < w * (h-1); j++) { - text[j] = text[j + w]; - } - for (int j = w * (h-1); j < w * h; j++) { - text[j].fgcolor = fgcolor; - text[j].bgcolor = bgcolor; - text[j].ch = ' '; - } - csr_l--; + scroll(1); } if (output != 0 && output->connected_vt == this) output->text_setcsr(csr_l, csr_c, cursor_visible); } @@ -179,6 +197,11 @@ void vt::keyboardInput(keypress kp, keyboard* from) { } else if (kp.command == KB_CMD_ALT && kp.character >= 64 && kp.character <= 126 && kp.pressed) { b[n++] = 27; b[n++] = kp.character; + } else if (kb_cmd_esc[kp.command & 0x3F] != 0 && kp.pressed) { + int i; + for (i = 0; kb_cmd_esc[kp.command & 0x3F][i] != 0; i++) { + b[n++] = kb_cmd_esc[kp.command & 0x3F][i]; + } } if (n == 0) return; if (kbd_buffer_filled + n > KBD_BUFFER_SIZE) goto wake_up; @@ -200,7 +223,136 @@ int vt::write(size_t offset, size_t len, char* buffer) { // ignore offset // TODO: ANSI escape sequences // todo some day : unicode - for (unsigned i = 0; i < len; i++) put(buffer[i]); + for (unsigned i = 0; i < len; i++) { + if (buffer[i] == 27) { + i++; + if (buffer[i++] == '[') { + int n = -1, m = -1; + while (buffer[i] >= '0' && buffer[i] <= '9') { + if (n == -1) n = 0; + n *= 10; + n += buffer[i] - '0'; + i++; + } + if (buffer[i] == ';') { + i++; + while (buffer[i] >= '0' && buffer[i] <= '9') { + if (m == -1) m = 0; + m *= 10; + m += buffer[i] - '0'; + i++; + } + } + if (buffer[i] == 'A') { // move cursor up + if (n == -1) n = 1; + csr_l -= n; + } else if (buffer[i] == 'B') { // move cursor down + if (n == -1) n = 1; + csr_l += n; + } else if (buffer[i] == 'C') { // move cursor forward + if (n == -1) n = 1; + csr_c += n; + } else if (buffer[i] == 'D') { // move cursor back + if (n == -1) n = 1; + csr_c -= n; + } else if (buffer[i] == 'E') { // move cursor n lines down, to beginning of line + if (n == -1) n = 1; + csr_l += n; + csr_c = 0; + } else if (buffer[i] == 'F') { // move cursor to beginning of line, n lines up + if (n == -1) n = 1; + csr_l -= n; + csr_c = 0; + } else if (buffer[i] == 'H' || buffer[i] == 'f') { // set cursor position + if (n == -1) n = 1; + if (m == -1) m = 1; + csr_l = n - 1; + csr_c = m - 1; + } else if (buffer[i] == 'J' || buffer[i] == 'K') { // erase data / erase line + if (n == -1) n = 0; + int start = 0, end = 0; + if (n == 0) { + start = csr_c; end = w; + } else if (n == 1) { + start = 0; end = csr_c; + } else if (n == 2) { + start = 0; end = w; + } + for (int p = start; p < end; p++) put_at(csr_l, p, ' '); + if (buffer[i] == 'J') { // erase data + if (n == 0) { + start = csr_l + 1; end = h; + } else if (n == 1) { + start = 0; end = csr_l; + } else if (n == 2) { + start = 0; end = h; + } + for (int l = start; l < end; l++) { + for (int c = 0; c < w; c++) put_at(l, c, ' '); + } + } + } else if (buffer[i] == 'S') { // scroll up + if (n == -1) n = 1; + scroll(n); + } else if (buffer[i] == 'T') { // scroll down + if (n == -1) n = 1; + scroll(-n); + } else if (buffer[i] == 'm') { // select graphic rendition + if (n == -1) n = 0; + if (n == 0) { + fgcolor = 7; + bgcolor = 0; + } else if (n == 1) { + fgcolor |= TC_MAKE_LIGHT; + } else if (n == 22) { + fgcolor &= TC_MAKE_DARK; + } else if (n >= 30 && n <= 37) { + fgcolor = (fgcolor & TC_MAKE_LIGHT) | (n - 30); + } else if (n >= 40 && n <= 47) { + bgcolor = (n - 40); + } else { + // others to do. + } + } else if (buffer[i] == 'n') { // device status report + kbd_buffer[kbd_buffer_filled++] = 27; + kbd_buffer[kbd_buffer_filled++] = '['; + if (csr_l >= 100) kbd_buffer[kbd_buffer_filled++] = ((csr_l / 100) % 10) + '0'; + if (csr_l >= 10) kbd_buffer[kbd_buffer_filled++] = ((csr_l / 10) % 10) + '0'; + kbd_buffer[kbd_buffer_filled++] = (csr_l % 10) + '0'; + kbd_buffer[kbd_buffer_filled++] = ';'; + if (csr_c >= 100) kbd_buffer[kbd_buffer_filled++] = ((csr_c / 100) % 10) + '0'; + if (csr_c >= 10) kbd_buffer[kbd_buffer_filled++] = ((csr_c / 10) % 10) + '0'; + kbd_buffer[kbd_buffer_filled++] = (csr_c % 10) + '0'; + kbd_buffer[kbd_buffer_filled++] = 'R'; + } else if (buffer[i] == 's') { // save cursor position + save_csr_l = csr_l; + save_csr_c = csr_c; + } else if (buffer[i] == 'p') { // restore cursor position + csr_l = save_csr_l; + csr_c = save_csr_c; + } else if (buffer[i] == 'e') { // CUSTOM : enable keyboard echo + keyboard_echo = true; + } else if (buffer[i] == 'h') { // CUSTOM : disable keyboard echo + keyboard_echo = false; + } else if (buffer[i] == '?') { + if (buffer[++i] == '2' && buffer[++i] == '5') { + if (buffer[++i] == 'l') cursor_visible = false; + else cursor_visible = true; + } + } else { + } + if (csr_l < 0) csr_l = 0; + if (csr_c < 0) csr_c = 0; + if (csr_l >= h) csr_l = h - 1; + if (csr_c >= w) csr_c = w - 1; + if (output != 0 && output->connected_vt == this) output->text_setcsr(csr_l, csr_c, cursor_visible); + } else { + // ignore it. + } + } else { + put(buffer[i]); + } + } return len; } @@ -212,19 +364,30 @@ int vt::read(size_t offset, size_t len, char* buffer) { bool end = false; if (kbd_buffer_filled > 0) { int r = 0; - for (; r < kbd_buffer_filled; r++) { - if (kbd_buffer[r] == '\b') { - if (c > 0) { - c--; - put('\b'); + if (keyboard_echo) { + for (; r < kbd_buffer_filled; r++) { + if (kbd_buffer[r] == '\b') { + if (c > 0) { + c--; + put('\b'); + } + } else if (kbd_buffer[r] == '\n') { + buffer[c++] = '\n'; + c++; + put('\n'); + end = true; + break; + } else if (kbd_buffer[r] >= ' ') { + buffer[c++] = kbd_buffer[r]; + put(buffer[c]); } - } else { - buffer[c] = kbd_buffer[r]; - put(buffer[c]); - if (buffer[c] == '\n' || buffer[c] == 27) end = true; - c++; + if (c == len) break; + } + } else { + for (; r < kbd_buffer_filled && c < len; r++) { + buffer[c++] = kbd_buffer[r]; } - if (c == len) break; + end = true; } memcpy(kbd_buffer + r, kbd_buffer, (kbd_buffer_filled - r)); kbd_buffer_filled -= r; diff --git a/src/kernel/ui/vt.h b/src/kernel/ui/vt.h index a80452b..a29716f 100644 --- a/src/kernel/ui/vt.h +++ b/src/kernel/ui/vt.h @@ -15,11 +15,11 @@ struct vt_char { class vt : public node { private: display *output; - int w, h, csr_l, csr_c; + int w, h, csr_l, csr_c, save_csr_l, save_csr_c; vt_char *text; void put_at(int l, int c, int ch); - bool cursor_visible; + bool cursor_visible, keyboard_echo; int kbd_buffer_filled; char kbd_buffer[KBD_BUFFER_SIZE]; @@ -35,6 +35,7 @@ class vt : public node { // internal use void put(int c); void clear(); + void scroll(int l); void writeStr(char* str) { write(0, strlen(str), str); } void writeHex(uint32_t v); void writeDec(int v); -- cgit v1.2.3