diff --git a/docs/src/tty.rst b/docs/src/tty.rst index 8cb00663..8dceb293 100644 --- a/docs/src/tty.rst +++ b/docs/src/tty.rst @@ -16,6 +16,22 @@ Data types TTY handle type. +.. c:type:: uv_tty_mode_t + + TTY mode type: + + :: + + typedef enum { + /* Initial/normal terminal mode */ + UV_TTY_MODE_NORMAL, + /* Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled) */ + UV_TTY_MODE_RAW, + /* Binary-safe I/O mode for IPC (Unix-only) */ + UV_TTY_MODE_IO + } uv_tty_mode_t; + + Public members ^^^^^^^^^^^^^^ @@ -43,9 +59,9 @@ API .. note:: TTY streams which are not readable have blocking writes. -.. c:function:: int uv_tty_set_mode(uv_tty_t*, int mode) +.. c:function:: int uv_tty_set_mode(uv_tty_t*, uv_tty_mode_t mode) - Set the TTY mode. 0 for normal, 1 for raw. + Set the TTY using the specified terminal mode. .. c:function:: int uv_tty_reset_mode(void) diff --git a/include/uv.h b/include/uv.h index 7b3c2522..a2332504 100644 --- a/include/uv.h +++ b/include/uv.h @@ -628,11 +628,30 @@ struct uv_tty_s { UV_TTY_PRIVATE_FIELDS }; +typedef enum { + /* Initial/normal terminal mode */ + UV_TTY_MODE_NORMAL, + /* Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled) */ + UV_TTY_MODE_RAW, + /* Binary-safe I/O mode for IPC (Unix-only) */ + UV_TTY_MODE_IO +} uv_tty_mode_t; + UV_EXTERN int uv_tty_init(uv_loop_t*, uv_tty_t*, uv_file fd, int readable); -UV_EXTERN int uv_tty_set_mode(uv_tty_t*, int mode); +UV_EXTERN int uv_tty_set_mode(uv_tty_t*, uv_tty_mode_t mode); UV_EXTERN int uv_tty_reset_mode(void); UV_EXTERN int uv_tty_get_winsize(uv_tty_t*, int* width, int* height); +#ifdef __cplusplus +} /* extern "C" */ + +inline int uv_tty_set_mode(uv_tty_t* handle, int mode) { + return uv_tty_set_mode(handle, static_cast(mode)); +} + +extern "C" { +#endif + UV_EXTERN uv_handle_type uv_guess_handle(uv_file file); /* diff --git a/src/unix/tty.c b/src/unix/tty.c index 7ae19905..068025ea 100644 --- a/src/unix/tty.c +++ b/src/unix/tty.c @@ -98,19 +98,19 @@ skip: uv__nonblock(fd, 1); uv__stream_open((uv_stream_t*) tty, fd, flags); - tty->mode = 0; + tty->mode = UV_TTY_MODE_NORMAL; return 0; } -int uv_tty_set_mode(uv_tty_t* tty, int mode) { - struct termios raw; +int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { + struct termios tmp; int fd; fd = uv__stream_fd(tty); - if (mode && tty->mode == 0) { /* on */ + if (tty->mode == UV_TTY_MODE_NORMAL && mode != UV_TTY_MODE_NORMAL) { if (tcgetattr(fd, &tty->orig_termios)) return -errno; @@ -121,27 +121,30 @@ int uv_tty_set_mode(uv_tty_t* tty, int mode) { orig_termios_fd = fd; } uv_spinlock_unlock(&termios_spinlock); - - raw = tty->orig_termios; - raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); - raw.c_oflag |= (ONLCR); - raw.c_cflag |= (CS8); - raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); - raw.c_cc[VMIN] = 1; - raw.c_cc[VTIME] = 0; - - /* Put terminal in raw mode after draining */ - if (tcsetattr(fd, TCSADRAIN, &raw)) - return -errno; - - tty->mode = 1; - } else if (mode == 0 && tty->mode) { /* off */ - /* Put terminal in original mode after flushing */ - if (tcsetattr(fd, TCSAFLUSH, &tty->orig_termios)) - return -errno; - tty->mode = 0; } + tmp = tty->orig_termios; + switch (mode) { + case UV_TTY_MODE_NORMAL: + break; + case UV_TTY_MODE_RAW: + tmp.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); + tmp.c_oflag |= (ONLCR); + tmp.c_cflag |= (CS8); + tmp.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); + tmp.c_cc[VMIN] = 1; + tmp.c_cc[VTIME] = 0; + break; + case UV_TTY_MODE_IO: + cfmakeraw(&tmp); + break; + } + + /* Apply changes after draining */ + if (tcsetattr(fd, TCSADRAIN, &tmp)) + return -errno; + + tty->mode = mode; return 0; } diff --git a/src/win/tty.c b/src/win/tty.c index 6d6709f7..be4a8b81 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -170,7 +170,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) { } -int uv_tty_set_mode(uv_tty_t* tty, int mode) { +int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { DWORD flags; unsigned char was_reading; uv_alloc_cb alloc_cb; @@ -185,12 +185,15 @@ int uv_tty_set_mode(uv_tty_t* tty, int mode) { return 0; } - if (mode) { - /* Raw input */ - flags = ENABLE_WINDOW_INPUT; - } else { - /* Line-buffered mode. */ - flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT; + switch (mode) { + case UV_TTY_MODE_NORMAL: + flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT; + break; + case UV_TTY_MODE_RAW: + flags = ENABLE_WINDOW_INPUT; + break; + case UV_TTY_MODE_IO: + return UV_ENOTSUP; } if (!SetConsoleMode(tty->handle, flags)) {