From cc4874f90a98c410b32b8a6a6589eb36b3b5185e Mon Sep 17 00:00:00 2001 From: "K. Lange" Date: Fri, 26 Oct 2018 10:15:16 +0900 Subject: [PATCH] tty: improvements (^V, fix nlcr behaviors, enter sends ^M) --- apps/stty.c | 3 ++ apps/terminal-vga.c | 7 +++ apps/terminal.c | 6 +++ base/usr/include/kernel/pty.h | 2 + base/usr/include/sys/termios.h | 1 + kernel/fs/tty.c | 92 +++++++++++++++++++++++----------- 6 files changed, 83 insertions(+), 28 deletions(-) diff --git a/apps/stty.c b/apps/stty.c index 4648568a..dd373ffc 100644 --- a/apps/stty.c +++ b/apps/stty.c @@ -108,6 +108,7 @@ static int show_settings(int all) { print_cc(&t, "kill", VKILL, 21); print_cc(&t, "eof", VEOF, 4); print_cc(&t, "eol", VEOL, 0); + print_cc(&t, "lnext", VLNEXT, 22); if (printed) { fprintf(stdout, "\n"); printed = 0; } print_cc(&t, "start", VSTART, 17); @@ -241,6 +242,7 @@ int main(int argc, char * argv[]) { t.c_cc[VSTOP] = 19; /* ^S */ t.c_cc[VSUSP] = 26; /* ^Z */ t.c_cc[VTIME] = 0; + t.c_cc[VLNEXT] = 22; /* ^V */ } set_char("eof", VEOF); @@ -252,6 +254,7 @@ int main(int argc, char * argv[]) { set_char("start", VSTART); set_char("stop", VSTOP); set_char("susp", VSUSP); + set_char("lnext", VLNEXT); set_cflag("parenb", PARENB); diff --git a/apps/terminal-vga.c b/apps/terminal-vga.c index 0119a523..c2aa1c76 100644 --- a/apps/terminal-vga.c +++ b/apps/terminal-vga.c @@ -881,6 +881,13 @@ void key_event(int ret, key_event_t * event) { handle_input_s("\033[Z"); return; } + + /* ENTER = reads as linefeed, should be carriage return */ + if (event->keycode == 10) { + handle_input('\r'); + return; + } + handle_input(event->key); } else { if (event->action == KEY_ACTION_UP) return; diff --git a/apps/terminal.c b/apps/terminal.c index 4231dc60..8ccabbf5 100644 --- a/apps/terminal.c +++ b/apps/terminal.c @@ -1654,6 +1654,12 @@ static void key_event(int ret, key_event_t * event) { return; } + /* ENTER = reads as linefeed, should be carriage return */ + if (event->keycode == 10) { + handle_input('\r'); + return; + } + /* Pass key value to PTY */ handle_input(event->key); } else { diff --git a/base/usr/include/kernel/pty.h b/base/usr/include/kernel/pty.h index b5709643..c722e7bf 100644 --- a/base/usr/include/kernel/pty.h +++ b/base/usr/include/kernel/pty.h @@ -33,6 +33,8 @@ typedef struct pty { void (*write_in)(struct pty *, uint8_t); void (*write_out)(struct pty *, uint8_t); + int next_is_verbatim; + } pty_t; void tty_output_process_slave(pty_t * pty, uint8_t c); diff --git a/base/usr/include/sys/termios.h b/base/usr/include/sys/termios.h index 72816eeb..5b3e6d37 100644 --- a/base/usr/include/sys/termios.h +++ b/base/usr/include/sys/termios.h @@ -34,6 +34,7 @@ typedef unsigned char cc_t; #define VSTOP 9 /* ^S stop input */ #define VSUSP 10 /* ^Z suspend foreground applicatioan (send SIGTSTP) */ #define VTIME 11 /* Timeout for non-canonical read, deciseconds */ +#define VLNEXT 12 /* ^V literal next */ /* flags for input modes */ #define BRKINT 0000001 diff --git a/kernel/fs/tty.c b/kernel/fs/tty.c index 265efda8..89e53f95 100644 --- a/kernel/fs/tty.c +++ b/kernel/fs/tty.c @@ -78,7 +78,7 @@ void tty_output_process(pty_t * pty, uint8_t c) { output_process_slave(pty, c); } -static void erase_one(pty_t * pty) { +static void erase_one(pty_t * pty, int erase) { if (pty->canon_buflen > 0) { /* How many do we backspace? */ int vwidth = 1; @@ -88,17 +88,35 @@ static void erase_one(pty_t * pty) { vwidth = 2; } pty->canon_buffer[pty->canon_buflen] = '\0'; - if ((pty->tios.c_lflag & ECHO) && (pty->tios.c_lflag & ECHOE)) { - for (int i = 0; i < vwidth; ++i) { - output_process(pty, '\010'); - output_process(pty, ' '); - output_process(pty, '\010'); + if (pty->tios.c_lflag & ECHO) { + if (erase) { + for (int i = 0; i < vwidth; ++i) { + output_process(pty, '\010'); + output_process(pty, ' '); + output_process(pty, '\010'); + } } } } } void tty_input_process(pty_t * pty, uint8_t c) { + if (pty->next_is_verbatim) { + pty->next_is_verbatim = 0; + if (pty->canon_buflen < pty->canon_bufsize) { + pty->canon_buffer[pty->canon_buflen] = c; + pty->canon_buflen++; + } + if (pty->tios.c_lflag & ECHO) { + if (c < ' ') { + output_process(pty, '^'); + output_process(pty, '@'+c); + } else { + output_process(pty, c); + } + } + return; + } if (pty->tios.c_lflag & ISIG) { if (c == pty->tios.c_cc[VINTR]) { if (pty->tios.c_lflag & ECHO) { @@ -131,16 +149,51 @@ void tty_input_process(pty_t * pty, uint8_t c) { /* VSTOP, VSTART */ } #endif + + /* ISTRIP: Strip eighth bit */ + if (pty->tios.c_iflag & ISTRIP) { + c &= 0x7F; + } + + /* IGNCR: Ignore carriage return. */ + if ((pty->tios.c_iflag & IGNCR) && c == '\r') { + return; + } + + if ((pty->tios.c_iflag & INLCR) && c == '\n') { + /* INLCR: Translate NL to CR. */ + c = '\r'; + } else if ((pty->tios.c_iflag & ICRNL) && c == '\r') { + /* ICRNL: Convert carriage return. */ + c = '\n'; + } + if (pty->tios.c_lflag & ICANON) { + + if (c == pty->tios.c_cc[VLNEXT] && (pty->tios.c_lflag & IEXTEN)) { + pty->next_is_verbatim = 1; + output_process(pty, '^'); + output_process(pty, '\010'); + return; + } + if (c == pty->tios.c_cc[VKILL]) { while (pty->canon_buflen > 0) { - erase_one(pty); + erase_one(pty, pty->tios.c_lflag & ECHOK); + } + if ((pty->tios.c_lflag & ECHO) && ! (pty->tios.c_lflag & ECHOK)) { + output_process(pty, '^'); + output_process(pty, '@' + c); } return; } if (c == pty->tios.c_cc[VERASE]) { /* Backspace */ - erase_one(pty); + erase_one(pty, pty->tios.c_lflag & ECHOE); + if ((pty->tios.c_lflag & ECHO) && ! (pty->tios.c_lflag & ECHOE)) { + output_process(pty, '^'); + output_process(pty, '@' + c); + } return; } if (c == pty->tios.c_cc[VEOF]) { @@ -152,26 +205,6 @@ void tty_input_process(pty_t * pty, uint8_t c) { return; } - /* ISTRIP: Strip eighth bit */ - if (pty->tios.c_iflag & ISTRIP) { - c &= 0x7F; - } - - /* IGNCR: Ignore carriage return. */ - if ((pty->tios.c_iflag & IGNCR) && c == '\r') { - return; - } - - /* INLCR: Translate NL to CR. */ - if ((pty->tios.c_iflag & INLCR) && c == '\n') { - c = '\r'; - } - - /* ICRNL: Convert carriage return. */ - if ((pty->tios.c_iflag & ICRNL) && c == '\r') { - c = '\n'; - } - if (pty->canon_buflen < pty->canon_bufsize) { pty->canon_buffer[pty->canon_buflen] = c; pty->canon_buflen++; @@ -593,6 +626,8 @@ pty_t * pty_new(struct winsize * size) { pty_t * pty = malloc(sizeof(pty_t)); + pty->next_is_verbatim = 0; + /* stdin linkage; characters from terminal → PTY slave */ pty->in = ring_buffer_create(TTY_BUFFER_SIZE); pty->out = ring_buffer_create(TTY_BUFFER_SIZE); @@ -640,6 +675,7 @@ pty_t * pty_new(struct winsize * size) { pty->tios.c_cc[VSTOP] = 19; /* ^S */ pty->tios.c_cc[VSUSP] = 26; /* ^Z */ pty->tios.c_cc[VTIME] = 0; + pty->tios.c_cc[VLNEXT] = 22; /* ^V */ pty->canon_buffer = malloc(TTY_BUFFER_SIZE); pty->canon_bufsize = TTY_BUFFER_SIZE-2;