1+ diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h
2+ index 02397dd0fdd4..3971dc869c99 100644
3+ --- a/deps/uv/include/uv.h
4+ +++ b/deps/uv/include/uv.h
5+ @@ -770,10 +770,15 @@ struct uv_tty_s {
6+ typedef enum {
7+ /* Initial/normal terminal mode */
8+ UV_TTY_MODE_NORMAL,
9+ - /* Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled) */
10+ + /*
11+ + * Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled).
12+ + * May become equivalent to UV_TTY_MODE_RAW_VT in future libuv versions.
13+ + */
14+ UV_TTY_MODE_RAW,
15+ /* Binary-safe I/O mode for IPC (Unix-only) */
16+ - UV_TTY_MODE_IO
17+ + UV_TTY_MODE_IO,
18+ + /* Raw input mode. On Windows ENABLE_VIRTUAL_TERMINAL_INPUT is also set. */
19+ + UV_TTY_MODE_RAW_VT
20+ } uv_tty_mode_t;
21+
22+ typedef enum {
23+ diff --git a/deps/uv/include/uv/win.h b/deps/uv/include/uv/win.h
24+ index 6f8c47298e40..2b29325c520c 100644
25+ --- a/deps/uv/include/uv/win.h
26+ +++ b/deps/uv/include/uv/win.h
27+ @@ -507,8 +507,11 @@ typedef struct {
28+ union { \
29+ struct { \
30+ /* Used for readable TTY handles */ \
31+ - /* TODO: remove me in v2.x. */ \
32+ - HANDLE unused_; \
33+ + union { \
34+ + /* TODO: remove me in v2.x. */ \
35+ + HANDLE unused_; \
36+ + int mode; \
37+ + } mode; \
38+ uv_buf_t read_line_buffer; \
39+ HANDLE read_raw_wait; \
40+ /* Fields used for translating win keystrokes into vt100 characters */ \
41+ diff --git a/deps/uv/src/unix/tty.c b/deps/uv/src/unix/tty.c
42+ index d099bdb3b677..19aabc84935f 100644
43+ --- a/deps/uv/src/unix/tty.c
44+ +++ b/deps/uv/src/unix/tty.c
45+ @@ -284,6 +284,11 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
46+ int fd;
47+ int rc;
48+
49+ + if (uv__is_raw_tty_mode(mode)) {
50+ + /* There is only a single raw TTY mode on UNIX. */
51+ + mode = UV_TTY_MODE_RAW;
52+ + }
53+ +
54+ if (tty->mode == (int) mode)
55+ return 0;
56+
57+ @@ -324,6 +329,8 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
58+ case UV_TTY_MODE_IO:
59+ uv__tty_make_raw(&tmp);
60+ break;
61+ + default:
62+ + UNREACHABLE();
63+ }
64+
65+ /* Apply changes after draining */
66+ diff --git a/deps/uv/src/uv-common.h b/deps/uv/src/uv-common.h
67+ index cd57e5a35153..6ba8399bf873 100644
68+ --- a/deps/uv/src/uv-common.h
69+ +++ b/deps/uv/src/uv-common.h
70+ @@ -125,7 +125,7 @@ enum {
71+
72+ /* Only used by uv_tty_t handles. */
73+ UV_HANDLE_TTY_READABLE = 0x01000000,
74+ - UV_HANDLE_TTY_RAW = 0x02000000,
75+ + UV_HANDLE_UNUSED0 = 0x02000000,
76+ UV_HANDLE_TTY_SAVED_POSITION = 0x04000000,
77+ UV_HANDLE_TTY_SAVED_ATTRIBUTES = 0x08000000,
78+
79+ @@ -140,6 +140,10 @@ enum {
80+ UV_HANDLE_REAP = 0x10000000
81+ };
82+
83+ + static inline int uv__is_raw_tty_mode(uv_tty_mode_t m) {
84+ + return m == UV_TTY_MODE_RAW || m == UV_TTY_MODE_RAW_VT;
85+ + }
86+ +
87+ int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap);
88+
89+ void uv__loop_close(uv_loop_t* loop);
190diff --git a/deps/uv/src/win/tty.c b/deps/uv/src/win/tty.c
2- index 7e1f15544b17..37bc2c4ace57 100644
91+ index 7e1f15544b17..26b9d0deced5 100644
392--- a/deps/uv/src/win/tty.c
493+++ b/deps/uv/src/win/tty.c
594@@ -58,6 +58,9 @@
@@ -9,38 +98,199 @@ index 7e1f15544b17..37bc2c4ace57 100644
998+ #ifndef ENABLE_VIRTUAL_TERMINAL_INPUT
1099+ #define ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200
11100+ #endif
12-
101+
13102 #define CURSOR_SIZE_SMALL 25
14103 #define CURSOR_SIZE_LARGE 100
15- @@ -344,6 +347,7 @@ static void uv__tty_capture_initial_style(
16-
104+ @@ -119,7 +122,10 @@ static int uv_tty_virtual_width = -1;
105+ * handle signalling SIGWINCH
106+ */
107+
108+ - static HANDLE uv__tty_console_handle = INVALID_HANDLE_VALUE;
109+ + static HANDLE uv__tty_console_handle_out = INVALID_HANDLE_VALUE;
110+ + static HANDLE uv__tty_console_handle_in = INVALID_HANDLE_VALUE;
111+ + static DWORD uv__tty_console_in_original_mode = (DWORD)-1;
112+ + static volatile LONG uv__tty_console_in_need_mode_reset = 0;
113+ static int uv__tty_console_height = -1;
114+ static int uv__tty_console_width = -1;
115+ static HANDLE uv__tty_console_resized = INVALID_HANDLE_VALUE;
116+ @@ -159,19 +165,21 @@ static uv_tty_vtermstate_t uv__vterm_state = UV_TTY_UNSUPPORTED;
117+ static void uv__determine_vterm_state(HANDLE handle);
118+
119+ void uv__console_init(void) {
120+ + DWORD dwMode;
121+ +
122+ if (uv_sem_init(&uv_tty_output_lock, 1))
123+ abort();
124+ - uv__tty_console_handle = CreateFileW(L"CONOUT$",
125+ - GENERIC_READ | GENERIC_WRITE,
126+ - FILE_SHARE_WRITE,
127+ - 0,
128+ - OPEN_EXISTING,
129+ - 0,
130+ - 0);
131+ - if (uv__tty_console_handle != INVALID_HANDLE_VALUE) {
132+ + uv__tty_console_handle_out = CreateFileW(L"CONOUT$",
133+ + GENERIC_READ | GENERIC_WRITE,
134+ + FILE_SHARE_WRITE,
135+ + 0,
136+ + OPEN_EXISTING,
137+ + 0,
138+ + 0);
139+ + if (uv__tty_console_handle_out != INVALID_HANDLE_VALUE) {
140+ CONSOLE_SCREEN_BUFFER_INFO sb_info;
141+ uv_mutex_init(&uv__tty_console_resize_mutex);
142+ - if (GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info)) {
143+ + if (GetConsoleScreenBufferInfo(uv__tty_console_handle_out, &sb_info)) {
144+ uv__tty_console_width = sb_info.dwSize.X;
145+ uv__tty_console_height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1;
146+ }
147+ @@ -179,6 +187,18 @@ void uv__console_init(void) {
148+ NULL,
149+ WT_EXECUTELONGFUNCTION);
150+ }
151+ + uv__tty_console_handle_in = CreateFileW(L"CONIN$",
152+ + GENERIC_READ | GENERIC_WRITE,
153+ + FILE_SHARE_READ,
154+ + 0,
155+ + OPEN_EXISTING,
156+ + 0,
157+ + 0);
158+ + if (uv__tty_console_handle_in != INVALID_HANDLE_VALUE) {
159+ + if (GetConsoleMode(uv__tty_console_handle_in, &dwMode)) {
160+ + uv__tty_console_in_original_mode = dwMode;
161+ + }
162+ + }
163+ }
164+
165+
166+ @@ -253,7 +273,9 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) {
167+ /* Initialize TTY input specific fields. */
168+ tty->flags |= UV_HANDLE_TTY_READABLE | UV_HANDLE_READABLE;
169+ /* TODO: remove me in v2.x. */
170+ - tty->tty.rd.unused_ = NULL;
171+ + tty->tty.rd.mode.unused_ = NULL;
172+ + /* Partially overwrites unused_ again. */
173+ + tty->tty.rd.mode.mode = 0;
174+ tty->tty.rd.read_line_buffer = uv_null_buf_;
175+ tty->tty.rd.read_raw_wait = NULL;
176+
177+ @@ -344,6 +366,7 @@ static void uv__tty_capture_initial_style(
178+
17179 int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
18180 DWORD flags;
19181+ DWORD try_set_flags;
20182 unsigned char was_reading;
21183 uv_alloc_cb alloc_cb;
22184 uv_read_cb read_cb;
23- @@ -360,9 +364,11 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
185+ @@ -353,14 +376,19 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
186+ return UV_EINVAL;
187+ }
188+
189+ - if (!!mode == !!(tty->flags & UV_HANDLE_TTY_RAW)) {
190+ + if ((int)mode == tty->tty.rd.mode.mode) {
191+ return 0;
192+ }
193+
194+ + try_set_flags = 0;
24195 switch (mode) {
25196 case UV_TTY_MODE_NORMAL:
26197 flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
27- + try_set_flags = 0;
28198 break;
199+ + case UV_TTY_MODE_RAW_VT:
200+ + try_set_flags = ENABLE_VIRTUAL_TERMINAL_INPUT;
201+ + InterlockedExchange(&uv__tty_console_in_need_mode_reset, 1);
202+ + /* fallthrough */
29203 case UV_TTY_MODE_RAW:
30204 flags = ENABLE_WINDOW_INPUT;
31- + try_set_flags = ENABLE_VIRTUAL_TERMINAL_INPUT;
32205 break;
33- case UV_TTY_MODE_IO:
34- return UV_ENOTSUP;
35- @@ -386,7 +392,10 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
206+ @@ -386,16 +414,16 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
36207 }
37-
208+
38209 uv_sem_wait(&uv_tty_output_lock);
39210- if (!SetConsoleMode(tty->handle, flags)) {
40- + if (
41- + !SetConsoleMode(tty->handle, flags | try_set_flags) &&
42- + !SetConsoleMode(tty->handle, flags)
43- + ) {
211+ + if (!SetConsoleMode(tty->handle, flags | try_set_flags) &&
212+ + !SetConsoleMode(tty->handle, flags)) {
44213 err = uv_translate_sys_error(GetLastError());
45214 uv_sem_post(&uv_tty_output_lock);
46215 return err;
216+ }
217+ uv_sem_post(&uv_tty_output_lock);
218+
219+ - /* Update flag. */
220+ - tty->flags &= ~UV_HANDLE_TTY_RAW;
221+ - tty->flags |= mode ? UV_HANDLE_TTY_RAW : 0;
222+ + /* Update mode. */
223+ + tty->tty.rd.mode.mode = mode;
224+
225+ /* If we just stopped reading, restart. */
226+ if (was_reading) {
227+ @@ -615,7 +643,7 @@ static void uv__tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) {
228+
229+
230+ static void uv__tty_queue_read(uv_loop_t* loop, uv_tty_t* handle) {
231+ - if (handle->flags & UV_HANDLE_TTY_RAW) {
232+ + if (uv__is_raw_tty_mode(handle->tty.rd.mode.mode)) {
233+ uv__tty_queue_read_raw(loop, handle);
234+ } else {
235+ uv__tty_queue_read_line(loop, handle);
236+ @@ -703,7 +731,7 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
237+ handle->flags &= ~UV_HANDLE_READ_PENDING;
238+
239+ if (!(handle->flags & UV_HANDLE_READING) ||
240+ - !(handle->flags & UV_HANDLE_TTY_RAW)) {
241+ + !(uv__is_raw_tty_mode(handle->tty.rd.mode.mode))) {
242+ goto out;
243+ }
244+
245+ @@ -1056,7 +1084,7 @@ int uv__tty_read_stop(uv_tty_t* handle) {
246+ if (!(handle->flags & UV_HANDLE_READ_PENDING))
247+ return 0;
248+
249+ - if (handle->flags & UV_HANDLE_TTY_RAW) {
250+ + if (uv__is_raw_tty_mode(handle->tty.rd.mode.mode)) {
251+ /* Cancel raw read. Write some bullshit event to force the console wait to
252+ * return. */
253+ memset(&record, 0, sizeof record);
254+ @@ -2299,7 +2327,17 @@ void uv__tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
255+
256+
257+ int uv_tty_reset_mode(void) {
258+ - /* Not necessary to do anything. */
259+ + /**
260+ + * Shells on Windows do know to reset output flags after a program exits,
261+ + * but not necessarily input flags, so we do that for them.
262+ + */
263+ + if (
264+ + uv__tty_console_handle_in != INVALID_HANDLE_VALUE &&
265+ + uv__tty_console_in_original_mode != (DWORD)-1 &&
266+ + InterlockedExchange(&uv__tty_console_in_need_mode_reset, 0) != 0
267+ + ) {
268+ + SetConsoleMode(uv__tty_console_handle_in, uv__tty_console_in_original_mode);
269+ + }
270+ return 0;
271+ }
272+
273+ @@ -2396,7 +2434,7 @@ static void uv__tty_console_signal_resize(void) {
274+ CONSOLE_SCREEN_BUFFER_INFO sb_info;
275+ int width, height;
276+
277+ - if (!GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info))
278+ + if (!GetConsoleScreenBufferInfo(uv__tty_console_handle_out, &sb_info))
279+ return;
280+
281+ width = sb_info.dwSize.X;
282+ diff --git a/src/tty_wrap.cc b/src/tty_wrap.cc
283+ index d2bd9c383abe..bbc3fd37f992 100644
284+ --- a/src/tty_wrap.cc
285+ +++ b/src/tty_wrap.cc
286+ @@ -112,7 +112,9 @@ void TTYWrap::SetRawMode(const FunctionCallbackInfo<Value>& args) {
287+ TTYWrap* wrap;
288+ ASSIGN_OR_RETURN_UNWRAP(
289+ &wrap, args.This(), args.GetReturnValue().Set(UV_EBADF));
290+ - int err = uv_tty_set_mode(&wrap->handle_, args[0]->IsTrue());
291+ + int err = uv_tty_set_mode(
292+ + &wrap->handle_,
293+ + args[0]->IsTrue() ? UV_TTY_MODE_RAW_VT : UV_TTY_MODE_NORMAL);
294+ args.GetReturnValue().Set(err);
295+ }
296+
0 commit comments