summaryrefslogtreecommitdiff
path: root/Utilities/cmlibuv/src/win/tty.c
diff options
context:
space:
mode:
Diffstat (limited to 'Utilities/cmlibuv/src/win/tty.c')
-rw-r--r--Utilities/cmlibuv/src/win/tty.c502
1 files changed, 311 insertions, 191 deletions
diff --git a/Utilities/cmlibuv/src/win/tty.c b/Utilities/cmlibuv/src/win/tty.c
index a98fe2633..488d9b2a1 100644
--- a/Utilities/cmlibuv/src/win/tty.c
+++ b/Utilities/cmlibuv/src/win/tty.c
@@ -46,14 +46,16 @@
#define UNICODE_REPLACEMENT_CHARACTER (0xfffd)
-#define ANSI_NORMAL 0x00
-#define ANSI_ESCAPE_SEEN 0x02
-#define ANSI_CSI 0x04
-#define ANSI_ST_CONTROL 0x08
-#define ANSI_IGNORE 0x10
-#define ANSI_IN_ARG 0x20
-#define ANSI_IN_STRING 0x40
-#define ANSI_BACKSLASH_SEEN 0x80
+#define ANSI_NORMAL 0x0000
+#define ANSI_ESCAPE_SEEN 0x0002
+#define ANSI_CSI 0x0004
+#define ANSI_ST_CONTROL 0x0008
+#define ANSI_IGNORE 0x0010
+#define ANSI_IN_ARG 0x0020
+#define ANSI_IN_STRING 0x0040
+#define ANSI_BACKSLASH_SEEN 0x0080
+#define ANSI_EXTENSION 0x0100
+#define ANSI_DECSCUSR 0x0200
#define MAX_INPUT_BUFFER_LENGTH 8192
#define MAX_CONSOLE_CHAR 8192
@@ -62,7 +64,12 @@
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
#endif
-static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info);
+#define CURSOR_SIZE_SMALL 25
+#define CURSOR_SIZE_LARGE 100
+
+static void uv_tty_capture_initial_style(
+ CONSOLE_SCREEN_BUFFER_INFO* screen_buffer_info,
+ CONSOLE_CURSOR_INFO* cursor_info);
static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info);
static int uv__cancel_read_console(uv_tty_t* handle);
@@ -120,6 +127,8 @@ static int uv_tty_virtual_width = -1;
static HANDLE uv__tty_console_handle = INVALID_HANDLE_VALUE;
static int uv__tty_console_height = -1;
static int uv__tty_console_width = -1;
+static HANDLE uv__tty_console_resized = INVALID_HANDLE_VALUE;
+static uv_mutex_t uv__tty_console_resize_mutex;
static DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param);
static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook,
@@ -129,6 +138,8 @@ static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook,
LONG idChild,
DWORD dwEventThread,
DWORD dwmsEventTime);
+static DWORD WINAPI uv__tty_console_resize_watcher_thread(void* param);
+static void uv__tty_console_signal_resize(void);
/* We use a semaphore rather than a mutex or critical section because in some
cases (uv__cancel_read_console) we need take the lock in the main thread and
@@ -145,13 +156,11 @@ static char uv_tty_default_fg_bright = 0;
static char uv_tty_default_bg_bright = 0;
static char uv_tty_default_inverse = 0;
-typedef enum {
- UV_SUPPORTED,
- UV_UNCHECKED,
- UV_UNSUPPORTED
-} uv_vtermstate_t;
+static CONSOLE_CURSOR_INFO uv_tty_default_cursor_info;
+
/* Determine whether or not ANSI support is enabled. */
-static uv_vtermstate_t uv__vterm_state = UV_UNCHECKED;
+static BOOL uv__need_check_vterm_state = TRUE;
+static uv_tty_vtermstate_t uv__vterm_state = UV_TTY_UNSUPPORTED;
static void uv__determine_vterm_state(HANDLE handle);
void uv_console_init(void) {
@@ -165,9 +174,15 @@ void uv_console_init(void) {
0,
0);
if (uv__tty_console_handle != INVALID_HANDLE_VALUE) {
+ CONSOLE_SCREEN_BUFFER_INFO sb_info;
QueueUserWorkItem(uv__tty_console_resize_message_loop_thread,
NULL,
WT_EXECUTELONGFUNCTION);
+ uv_mutex_init(&uv__tty_console_resize_mutex);
+ if (GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info)) {
+ uv__tty_console_width = sb_info.dwSize.X;
+ uv__tty_console_height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1;
+ }
}
}
@@ -177,6 +192,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) {
DWORD NumberOfEvents;
HANDLE handle;
CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
+ CONSOLE_CURSOR_INFO cursor_info;
(void)unused;
uv__once_init();
@@ -209,15 +225,20 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) {
return uv_translate_sys_error(GetLastError());
}
+ /* Obtain the cursor info with the output handle. */
+ if (!GetConsoleCursorInfo(handle, &cursor_info)) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
/* Obtain the tty_output_lock because the virtual window state is shared
* between all uv_tty_t handles. */
uv_sem_wait(&uv_tty_output_lock);
- if (uv__vterm_state == UV_UNCHECKED)
+ if (uv__need_check_vterm_state)
uv__determine_vterm_state(handle);
- /* Remember the original console text attributes. */
- uv_tty_capture_initial_style(&screen_buffer_info);
+ /* Remember the original console text attributes and cursor info. */
+ uv_tty_capture_initial_style(&screen_buffer_info, &cursor_info);
uv_tty_update_virtual_window(&screen_buffer_info);
@@ -268,7 +289,9 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) {
/* Set the default console text attributes based on how the console was
* configured when libuv started.
*/
-static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info) {
+static void uv_tty_capture_initial_style(
+ CONSOLE_SCREEN_BUFFER_INFO* screen_buffer_info,
+ CONSOLE_CURSOR_INFO* cursor_info) {
static int style_captured = 0;
/* Only do this once.
@@ -277,7 +300,7 @@ static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info) {
return;
/* Save raw win32 attributes. */
- uv_tty_default_text_attributes = info->wAttributes;
+ uv_tty_default_text_attributes = screen_buffer_info->wAttributes;
/* Convert black text on black background to use white text. */
if (uv_tty_default_text_attributes == 0)
@@ -317,6 +340,9 @@ static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info) {
if (uv_tty_default_text_attributes & COMMON_LVB_REVERSE_VIDEO)
uv_tty_default_inverse = 1;
+ /* Save the cursor size and the cursor state. */
+ uv_tty_default_cursor_info = *cursor_info;
+
style_captured = 1;
}
@@ -728,6 +754,12 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
}
records_left--;
+ /* We might be not subscribed to EVENT_CONSOLE_LAYOUT or we might be
+ * running under some TTY emulator that does not send those events. */
+ if (handle->tty.rd.last_input_record.EventType == WINDOW_BUFFER_SIZE_EVENT) {
+ uv__tty_console_signal_resize();
+ }
+
/* Ignore other events that are not key events. */
if (handle->tty.rd.last_input_record.EventType != KEY_EVENT) {
continue;
@@ -1218,7 +1250,7 @@ static int uv_tty_move_caret(uv_tty_t* handle, int x, unsigned char x_relative,
static int uv_tty_reset(uv_tty_t* handle, DWORD* error) {
const COORD origin = {0, 0};
const WORD char_attrs = uv_tty_default_text_attributes;
- CONSOLE_SCREEN_BUFFER_INFO info;
+ CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
DWORD count, written;
if (*error != ERROR_SUCCESS) {
@@ -1239,12 +1271,12 @@ static int uv_tty_reset(uv_tty_t* handle, DWORD* error) {
/* Clear the screen buffer. */
retry:
- if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
- *error = GetLastError();
- return -1;
+ if (!GetConsoleScreenBufferInfo(handle->handle, &screen_buffer_info)) {
+ *error = GetLastError();
+ return -1;
}
- count = info.dwSize.X * info.dwSize.Y;
+ count = screen_buffer_info.dwSize.X * screen_buffer_info.dwSize.Y;
if (!(FillConsoleOutputCharacterW(handle->handle,
L'\x20',
@@ -1267,7 +1299,13 @@ static int uv_tty_reset(uv_tty_t* handle, DWORD* error) {
/* Move the virtual window up to the top. */
uv_tty_virtual_offset = 0;
- uv_tty_update_virtual_window(&info);
+ uv_tty_update_virtual_window(&screen_buffer_info);
+
+ /* Reset the cursor size and the cursor state. */
+ if (!SetConsoleCursorInfo(handle->handle, &uv_tty_default_cursor_info)) {
+ *error = GetLastError();
+ return -1;
+ }
return 0;
}
@@ -1606,6 +1644,31 @@ static int uv_tty_set_cursor_visibility(uv_tty_t* handle,
return 0;
}
+static int uv_tty_set_cursor_shape(uv_tty_t* handle, int style, DWORD* error) {
+ CONSOLE_CURSOR_INFO cursor_info;
+
+ if (!GetConsoleCursorInfo(handle->handle, &cursor_info)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ if (style == 0) {
+ cursor_info.dwSize = uv_tty_default_cursor_info.dwSize;
+ } else if (style <= 2) {
+ cursor_info.dwSize = CURSOR_SIZE_LARGE;
+ } else {
+ cursor_info.dwSize = CURSOR_SIZE_SMALL;
+ }
+
+ if (!SetConsoleCursorInfo(handle->handle, &cursor_info)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ return 0;
+}
+
+
static int uv_tty_write_bufs(uv_tty_t* handle,
const uv_buf_t bufs[],
unsigned int nbufs,
@@ -1613,28 +1676,16 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
/* We can only write 8k characters at a time. Windows can't handle much more
* characters in a single console write anyway. */
WCHAR utf16_buf[MAX_CONSOLE_CHAR];
- WCHAR* utf16_buffer;
DWORD utf16_buf_used = 0;
- unsigned int i, len, max_len, pos;
- int allocate = 0;
-
-#define FLUSH_TEXT() \
- do { \
- pos = 0; \
- do { \
- len = utf16_buf_used - pos; \
- if (len > MAX_CONSOLE_CHAR) \
- len = MAX_CONSOLE_CHAR; \
- uv_tty_emit_text(handle, &utf16_buffer[pos], len, error); \
- pos += len; \
- } while (pos < utf16_buf_used); \
- if (allocate) { \
- uv__free(utf16_buffer); \
- allocate = 0; \
- utf16_buffer = utf16_buf; \
- } \
- utf16_buf_used = 0; \
- } while (0)
+ unsigned int i;
+
+#define FLUSH_TEXT() \
+ do { \
+ if (utf16_buf_used > 0) { \
+ uv_tty_emit_text(handle, utf16_buf, utf16_buf_used, error); \
+ utf16_buf_used = 0; \
+ } \
+ } while (0)
#define ENSURE_BUFFER_SPACE(wchars_needed) \
if (wchars_needed > ARRAY_SIZE(utf16_buf) - utf16_buf_used) { \
@@ -1645,54 +1696,18 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
unsigned char utf8_bytes_left = handle->tty.wr.utf8_bytes_left;
unsigned int utf8_codepoint = handle->tty.wr.utf8_codepoint;
unsigned char previous_eol = handle->tty.wr.previous_eol;
- unsigned char ansi_parser_state = handle->tty.wr.ansi_parser_state;
+ unsigned short ansi_parser_state = handle->tty.wr.ansi_parser_state;
/* Store the error here. If we encounter an error, stop trying to do i/o but
* keep parsing the buffer so we leave the parser in a consistent state. */
*error = ERROR_SUCCESS;
- utf16_buffer = utf16_buf;
-
uv_sem_wait(&uv_tty_output_lock);
for (i = 0; i < nbufs; i++) {
uv_buf_t buf = bufs[i];
unsigned int j;
- if (uv__vterm_state == UV_SUPPORTED && buf.len > 0) {
- utf16_buf_used = MultiByteToWideChar(CP_UTF8,
- 0,
- buf.base,
- buf.len,
- NULL,
- 0);
-
- if (utf16_buf_used == 0) {
- *error = GetLastError();
- break;
- }
-
- max_len = (utf16_buf_used + 1) * sizeof(WCHAR);
- allocate = max_len > MAX_CONSOLE_CHAR;
- if (allocate)
- utf16_buffer = uv__malloc(max_len);
- if (!MultiByteToWideChar(CP_UTF8,
- 0,
- buf.base,
- buf.len,
- utf16_buffer,
- utf16_buf_used)) {
- if (allocate)
- uv__free(utf16_buffer);
- *error = GetLastError();
- break;
- }
-
- FLUSH_TEXT();
-
- continue;
- }
-
for (j = 0; j < buf.len; j++) {
unsigned char c = buf.base[j];
@@ -1749,7 +1764,9 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
}
/* Parse vt100/ansi escape codes */
- if (ansi_parser_state == ANSI_NORMAL) {
+ if (uv__vterm_state == UV_TTY_SUPPORTED) {
+ /* Pass through escape codes if conhost supports them. */
+ } else if (ansi_parser_state == ANSI_NORMAL) {
switch (utf8_codepoint) {
case '\033':
ansi_parser_state = ANSI_ESCAPE_SEEN;
@@ -1795,7 +1812,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
ansi_parser_state = ANSI_NORMAL;
continue;
- case '8':
+ case '8':
/* Restore the cursor position and text attributes */
FLUSH_TEXT();
uv_tty_restore_state(handle, 1, error);
@@ -1813,121 +1830,193 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
}
}
+ } else if (ansi_parser_state == ANSI_IGNORE) {
+ /* We're ignoring this command. Stop only on command character. */
+ if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
+ ansi_parser_state = ANSI_NORMAL;
+ }
+ continue;
+
+ } else if (ansi_parser_state == ANSI_DECSCUSR) {
+ /* So far we've the sequence `ESC [ arg space`, and we're waiting for
+ * the final command byte. */
+ if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
+ /* Command byte */
+ if (utf8_codepoint == 'q') {
+ /* Change the cursor shape */
+ int style = handle->tty.wr.ansi_csi_argc
+ ? handle->tty.wr.ansi_csi_argv[0] : 1;
+ if (style >= 0 && style <= 6) {
+ FLUSH_TEXT();
+ uv_tty_set_cursor_shape(handle, style, error);
+ }
+ }
+
+ /* Sequence ended - go back to normal state. */
+ ansi_parser_state = ANSI_NORMAL;
+ continue;
+ }
+ /* Unexpected character, but sequence hasn't ended yet. Ignore the rest
+ * of the sequence. */
+ ansi_parser_state = ANSI_IGNORE;
+
} else if (ansi_parser_state & ANSI_CSI) {
- if (!(ansi_parser_state & ANSI_IGNORE)) {
- if (utf8_codepoint >= '0' && utf8_codepoint <= '9') {
- /* Parsing a numerical argument */
-
- if (!(ansi_parser_state & ANSI_IN_ARG)) {
- /* We were not currently parsing a number */
-
- /* Check for too many arguments */
- if (handle->tty.wr.ansi_csi_argc >= ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
- ansi_parser_state |= ANSI_IGNORE;
- continue;
- }
-
- ansi_parser_state |= ANSI_IN_ARG;
- handle->tty.wr.ansi_csi_argc++;
- handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
- (unsigned short) utf8_codepoint - '0';
+ /* So far we've seen `ESC [`, and we may or may not have already parsed
+ * some of the arguments that follow. */
+
+ if (utf8_codepoint >= '0' && utf8_codepoint <= '9') {
+ /* Parse a numerical argument. */
+ if (!(ansi_parser_state & ANSI_IN_ARG)) {
+ /* We were not currently parsing a number, add a new one. */
+ /* Check for that there are too many arguments. */
+ if (handle->tty.wr.ansi_csi_argc >=
+ ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
+ ansi_parser_state = ANSI_IGNORE;
continue;
- } else {
- /* We were already parsing a number. Parse next digit. */
- uint32_t value = 10 *
- handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1];
-
- /* Check for overflow. */
- if (value > UINT16_MAX) {
- ansi_parser_state |= ANSI_IGNORE;
- continue;
- }
-
- handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
- (unsigned short) value + (utf8_codepoint - '0');
- continue;
}
+ ansi_parser_state |= ANSI_IN_ARG;
+ handle->tty.wr.ansi_csi_argc++;
+ handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
+ (unsigned short) utf8_codepoint - '0';
+ continue;
+
+ } else {
+ /* We were already parsing a number. Parse next digit. */
+ uint32_t value = 10 *
+ handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1];
- } else if (utf8_codepoint == ';') {
- /* Denotes the end of an argument. */
- if (ansi_parser_state & ANSI_IN_ARG) {
- ansi_parser_state &= ~ANSI_IN_ARG;
+ /* Check for overflow. */
+ if (value > UINT16_MAX) {
+ ansi_parser_state = ANSI_IGNORE;
continue;
+ }
- } else {
- /* If ANSI_IN_ARG is not set, add another argument and default it
- * to 0. */
+ handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
+ (unsigned short) value + (utf8_codepoint - '0');
+ continue;
+ }
- /* Check for too many arguments */
- if (handle->tty.wr.ansi_csi_argc >= ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
- ansi_parser_state |= ANSI_IGNORE;
- continue;
- }
+ } else if (utf8_codepoint == ';') {
+ /* Denotes the end of an argument. */
+ if (ansi_parser_state & ANSI_IN_ARG) {
+ ansi_parser_state &= ~ANSI_IN_ARG;
+ continue;
+
+ } else {
+ /* If ANSI_IN_ARG is not set, add another argument and default
+ * it to 0. */
- handle->tty.wr.ansi_csi_argc++;
- handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] = 0;
+ /* Check for too many arguments */
+ if (handle->tty.wr.ansi_csi_argc >=
+
+ ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
+ ansi_parser_state = ANSI_IGNORE;
continue;
}
- } else if (utf8_codepoint == '?' && !(ansi_parser_state & ANSI_IN_ARG) &&
- handle->tty.wr.ansi_csi_argc == 0) {
- /* Ignores '?' if it is the first character after CSI[. This is an
- * extension character from the VT100 codeset that is supported and
- * used by most ANSI terminals today. */
+ handle->tty.wr.ansi_csi_argc++;
+ handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] = 0;
continue;
+ }
- } else if (utf8_codepoint >= '@' && utf8_codepoint <= '~' &&
- (handle->tty.wr.ansi_csi_argc > 0 || utf8_codepoint != '[')) {
- int x, y, d;
+ } else if (utf8_codepoint == '?' &&
+ !(ansi_parser_state & ANSI_IN_ARG) &&
+ !(ansi_parser_state & ANSI_EXTENSION) &&
+ handle->tty.wr.ansi_csi_argc == 0) {
+ /* Pass through '?' if it is the first character after CSI */
+ /* This is an extension character from the VT100 codeset */
+ /* that is supported and used by most ANSI terminals today. */
+ ansi_parser_state |= ANSI_EXTENSION;
+ continue;
+
+ } else if (utf8_codepoint == ' ' &&
+ !(ansi_parser_state & ANSI_EXTENSION)) {
+ /* We expect a command byte to follow after this space. The only
+ * command that we current support is 'set cursor style'. */
+ ansi_parser_state = ANSI_DECSCUSR;
+ continue;
- /* Command byte */
+ } else if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
+ /* Command byte */
+ if (ansi_parser_state & ANSI_EXTENSION) {
+ /* Sequence is `ESC [ ? args command`. */
+ switch (utf8_codepoint) {
+ case 'l':
+ /* Hide the cursor */
+ if (handle->tty.wr.ansi_csi_argc == 1 &&
+ handle->tty.wr.ansi_csi_argv[0] == 25) {
+ FLUSH_TEXT();
+ uv_tty_set_cursor_visibility(handle, 0, error);
+ }
+ break;
+
+ case 'h':
+ /* Show the cursor */
+ if (handle->tty.wr.ansi_csi_argc == 1 &&
+ handle->tty.wr.ansi_csi_argv[0] == 25) {
+ FLUSH_TEXT();
+ uv_tty_set_cursor_visibility(handle, 1, error);
+ }
+ break;
+ }
+
+ } else {
+ /* Sequence is `ESC [ args command`. */
+ int x, y, d;
switch (utf8_codepoint) {
case 'A':
/* cursor up */
FLUSH_TEXT();
- y = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1);
+ y = -(handle->tty.wr.ansi_csi_argc
+ ? handle->tty.wr.ansi_csi_argv[0] : 1);
uv_tty_move_caret(handle, 0, 1, y, 1, error);
break;
case 'B':
/* cursor down */
FLUSH_TEXT();
- y = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1;
+ y = handle->tty.wr.ansi_csi_argc
+ ? handle->tty.wr.ansi_csi_argv[0] : 1;
uv_tty_move_caret(handle, 0, 1, y, 1, error);
break;
case 'C':
/* cursor forward */
FLUSH_TEXT();
- x = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1;
+ x = handle->tty.wr.ansi_csi_argc
+ ? handle->tty.wr.ansi_csi_argv[0] : 1;
uv_tty_move_caret(handle, x, 1, 0, 1, error);
break;
case 'D':
/* cursor back */
FLUSH_TEXT();
- x = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1);
+ x = -(handle->tty.wr.ansi_csi_argc
+ ? handle->tty.wr.ansi_csi_argv[0] : 1);
uv_tty_move_caret(handle, x, 1, 0, 1, error);
break;
case 'E':
/* cursor next line */
FLUSH_TEXT();
- y = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1;
+ y = handle->tty.wr.ansi_csi_argc
+ ? handle->tty.wr.ansi_csi_argv[0] : 1;
uv_tty_move_caret(handle, 0, 0, y, 1, error);
break;
case 'F':
/* cursor previous line */
FLUSH_TEXT();
- y = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1);
+ y = -(handle->tty.wr.ansi_csi_argc
+ ? handle->tty.wr.ansi_csi_argv[0] : 1);
uv_tty_move_caret(handle, 0, 0, y, 1, error);
break;
case 'G':
/* cursor horizontal move absolute */
FLUSH_TEXT();
- x = (handle->tty.wr.ansi_csi_argc >= 1 && handle->tty.wr.ansi_csi_argv[0])
+ x = (handle->tty.wr.ansi_csi_argc >= 1 &&
+ handle->tty.wr.ansi_csi_argv[0])
? handle->tty.wr.ansi_csi_argv[0] - 1 : 0;
uv_tty_move_caret(handle, x, 0, 0, 1, error);
break;
@@ -1936,9 +2025,11 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
case 'f':
/* cursor move absolute */
FLUSH_TEXT();
- y = (handle->tty.wr.ansi_csi_argc >= 1 && handle->tty.wr.ansi_csi_argv[0])
+ y = (handle->tty.wr.ansi_csi_argc >= 1 &&
+ handle->tty.wr.ansi_csi_argv[0])
? handle->tty.wr.ansi_csi_argv[0] - 1 : 0;
- x = (handle->tty.wr.ansi_csi_argc >= 2 && handle->tty.wr.ansi_csi_argv[1])
+ x = (handle->tty.wr.ansi_csi_argc >= 2 &&
+ handle->tty.wr.ansi_csi_argv[1])
? handle->tty.wr.ansi_csi_argv[1] - 1 : 0;
uv_tty_move_caret(handle, x, 0, y, 0, error);
break;
@@ -1946,7 +2037,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
case 'J':
/* Erase screen */
FLUSH_TEXT();
- d = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 0;
+ d = handle->tty.wr.ansi_csi_argc
+ ? handle->tty.wr.ansi_csi_argv[0] : 0;
if (d >= 0 && d <= 2) {
uv_tty_clear(handle, d, 1, error);
}
@@ -1955,7 +2047,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
case 'K':
/* Erase line */
FLUSH_TEXT();
- d = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 0;
+ d = handle->tty.wr.ansi_csi_argc
+ ? handle->tty.wr.ansi_csi_argv[0] : 0;
if (d >= 0 && d <= 2) {
uv_tty_clear(handle, d, 0, error);
}
@@ -1978,41 +2071,17 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
FLUSH_TEXT();
uv_tty_restore_state(handle, 0, error);
break;
-
- case 'l':
- /* Hide the cursor */
- if (handle->tty.wr.ansi_csi_argc == 1 &&
- handle->tty.wr.ansi_csi_argv[0] == 25) {
- FLUSH_TEXT();
- uv_tty_set_cursor_visibility(handle, 0, error);
- }
- break;
-
- case 'h':
- /* Show the cursor */
- if (handle->tty.wr.ansi_csi_argc == 1 &&
- handle->tty.wr.ansi_csi_argv[0] == 25) {
- FLUSH_TEXT();
- uv_tty_set_cursor_visibility(handle, 1, error);
- }
- break;
}
+ }
- /* Sequence ended - go back to normal state. */
- ansi_parser_state = ANSI_NORMAL;
- continue;
+ /* Sequence ended - go back to normal state. */
+ ansi_parser_state = ANSI_NORMAL;
+ continue;
- } else {
- /* We don't support commands that use private mode characters or
- * intermediaries. Ignore the rest of the sequence. */
- ansi_parser_state |= ANSI_IGNORE;
- continue;
- }
} else {
- /* We're ignoring this command. Stop only on command character. */
- if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
- ansi_parser_state = ANSI_NORMAL;
- }
+ /* We don't support commands that use private mode characters or
+ * intermediaries. Ignore the rest of the sequence. */
+ ansi_parser_state = ANSI_IGNORE;
continue;
}
@@ -2264,38 +2333,56 @@ int uv_tty_reset_mode(void) {
static void uv__determine_vterm_state(HANDLE handle) {
DWORD dwMode = 0;
+ uv__need_check_vterm_state = FALSE;
if (!GetConsoleMode(handle, &dwMode)) {
- uv__vterm_state = UV_UNSUPPORTED;
return;
}
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
if (!SetConsoleMode(handle, dwMode)) {
- uv__vterm_state = UV_UNSUPPORTED;
return;
}
- uv__vterm_state = UV_SUPPORTED;
+ uv__vterm_state = UV_TTY_SUPPORTED;
}
static DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param) {
- CONSOLE_SCREEN_BUFFER_INFO sb_info;
+ NTSTATUS status;
+ ULONG_PTR conhost_pid;
MSG msg;
- if (!GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info))
+ if (pSetWinEventHook == NULL || pNtQueryInformationProcess == NULL)
return 0;
- uv__tty_console_width = sb_info.dwSize.X;
- uv__tty_console_height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1;
+ status = pNtQueryInformationProcess(GetCurrentProcess(),
+ ProcessConsoleHostProcess,
+ &conhost_pid,
+ sizeof(conhost_pid),
+ NULL);
- if (pSetWinEventHook == NULL)
+ if (!NT_SUCCESS(status)) {
+ /* We couldn't retrieve our console host process, probably because this
+ * is a 32-bit process running on 64-bit Windows. Fall back to receiving
+ * console events from the input stream only. */
+ return 0;
+ }
+
+ /* Ensure the PID is a multiple of 4, which is required by SetWinEventHook */
+ conhost_pid &= ~(ULONG_PTR)0x3;
+
+ uv__tty_console_resized = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (uv__tty_console_resized == NULL)
+ return 0;
+ if (QueueUserWorkItem(uv__tty_console_resize_watcher_thread,
+ NULL,
+ WT_EXECUTELONGFUNCTION) == 0)
return 0;
if (!pSetWinEventHook(EVENT_CONSOLE_LAYOUT,
EVENT_CONSOLE_LAYOUT,
NULL,
uv__tty_console_resize_event,
- 0,
+ (DWORD)conhost_pid,
0,
WINEVENT_OUTOFCONTEXT))
return 0;
@@ -2314,6 +2401,20 @@ static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook,
LONG idChild,
DWORD dwEventThread,
DWORD dwmsEventTime) {
+ SetEvent(uv__tty_console_resized);
+}
+
+static DWORD WINAPI uv__tty_console_resize_watcher_thread(void* param) {
+ for (;;) {
+ /* Make sure to not overwhelm the system with resize events */
+ Sleep(33);
+ WaitForSingleObject(uv__tty_console_resized, INFINITE);
+ uv__tty_console_signal_resize();
+ ResetEvent(uv__tty_console_resized);
+ }
+}
+
+static void uv__tty_console_signal_resize(void) {
CONSOLE_SCREEN_BUFFER_INFO sb_info;
int width, height;
@@ -2323,9 +2424,28 @@ static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook,
width = sb_info.dwSize.X;
height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1;
+ uv_mutex_lock(&uv__tty_console_resize_mutex);
+ assert(uv__tty_console_width != -1 && uv__tty_console_height != -1);
if (width != uv__tty_console_width || height != uv__tty_console_height) {
uv__tty_console_width = width;
uv__tty_console_height = height;
+ uv_mutex_unlock(&uv__tty_console_resize_mutex);
uv__signal_dispatch(SIGWINCH);
+ } else {
+ uv_mutex_unlock(&uv__tty_console_resize_mutex);
}
}
+
+void uv_tty_set_vterm_state(uv_tty_vtermstate_t state) {
+ uv_sem_wait(&uv_tty_output_lock);
+ uv__need_check_vterm_state = FALSE;
+ uv__vterm_state = state;
+ uv_sem_post(&uv_tty_output_lock);
+}
+
+int uv_tty_get_vterm_state(uv_tty_vtermstate_t* state) {
+ uv_sem_wait(&uv_tty_output_lock);
+ *state = uv__vterm_state;
+ uv_sem_post(&uv_tty_output_lock);
+ return 0;
+}