|
@@ -46,14 +46,16 @@
|
|
|
|
|
|
|
|
#define UNICODE_REPLACEMENT_CHARACTER (0xfffd)
|
|
#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_INPUT_BUFFER_LENGTH 8192
|
|
|
#define MAX_CONSOLE_CHAR 8192
|
|
#define MAX_CONSOLE_CHAR 8192
|
|
@@ -62,7 +64,12 @@
|
|
|
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
|
|
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
|
|
|
#endif
|
|
#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 void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info);
|
|
|
static int uv__cancel_read_console(uv_tty_t* handle);
|
|
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 HANDLE uv__tty_console_handle = INVALID_HANDLE_VALUE;
|
|
|
static int uv__tty_console_height = -1;
|
|
static int uv__tty_console_height = -1;
|
|
|
static int uv__tty_console_width = -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 DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param);
|
|
|
static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook,
|
|
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,
|
|
LONG idChild,
|
|
|
DWORD dwEventThread,
|
|
DWORD dwEventThread,
|
|
|
DWORD dwmsEventTime);
|
|
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
|
|
/* 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
|
|
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_bg_bright = 0;
|
|
|
static char uv_tty_default_inverse = 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. */
|
|
/* 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);
|
|
static void uv__determine_vterm_state(HANDLE handle);
|
|
|
|
|
|
|
|
void uv_console_init(void) {
|
|
void uv_console_init(void) {
|
|
@@ -165,9 +174,15 @@ void uv_console_init(void) {
|
|
|
0,
|
|
0,
|
|
|
0);
|
|
0);
|
|
|
if (uv__tty_console_handle != INVALID_HANDLE_VALUE) {
|
|
if (uv__tty_console_handle != INVALID_HANDLE_VALUE) {
|
|
|
|
|
+ CONSOLE_SCREEN_BUFFER_INFO sb_info;
|
|
|
QueueUserWorkItem(uv__tty_console_resize_message_loop_thread,
|
|
QueueUserWorkItem(uv__tty_console_resize_message_loop_thread,
|
|
|
NULL,
|
|
NULL,
|
|
|
WT_EXECUTELONGFUNCTION);
|
|
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;
|
|
DWORD NumberOfEvents;
|
|
|
HANDLE handle;
|
|
HANDLE handle;
|
|
|
CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
|
|
CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
|
|
|
|
|
+ CONSOLE_CURSOR_INFO cursor_info;
|
|
|
(void)unused;
|
|
(void)unused;
|
|
|
|
|
|
|
|
uv__once_init();
|
|
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());
|
|
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
|
|
/* Obtain the tty_output_lock because the virtual window state is shared
|
|
|
* between all uv_tty_t handles. */
|
|
* between all uv_tty_t handles. */
|
|
|
uv_sem_wait(&uv_tty_output_lock);
|
|
uv_sem_wait(&uv_tty_output_lock);
|
|
|
|
|
|
|
|
- if (uv__vterm_state == UV_UNCHECKED)
|
|
|
|
|
|
|
+ if (uv__need_check_vterm_state)
|
|
|
uv__determine_vterm_state(handle);
|
|
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);
|
|
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
|
|
/* Set the default console text attributes based on how the console was
|
|
|
* configured when libuv started.
|
|
* 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;
|
|
static int style_captured = 0;
|
|
|
|
|
|
|
|
/* Only do this once.
|
|
/* Only do this once.
|
|
@@ -277,7 +300,7 @@ static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info) {
|
|
|
return;
|
|
return;
|
|
|
|
|
|
|
|
/* Save raw win32 attributes. */
|
|
/* 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. */
|
|
/* Convert black text on black background to use white text. */
|
|
|
if (uv_tty_default_text_attributes == 0)
|
|
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)
|
|
if (uv_tty_default_text_attributes & COMMON_LVB_REVERSE_VIDEO)
|
|
|
uv_tty_default_inverse = 1;
|
|
uv_tty_default_inverse = 1;
|
|
|
|
|
|
|
|
|
|
+ /* Save the cursor size and the cursor state. */
|
|
|
|
|
+ uv_tty_default_cursor_info = *cursor_info;
|
|
|
|
|
+
|
|
|
style_captured = 1;
|
|
style_captured = 1;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -728,6 +754,12 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
|
|
|
}
|
|
}
|
|
|
records_left--;
|
|
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. */
|
|
/* Ignore other events that are not key events. */
|
|
|
if (handle->tty.rd.last_input_record.EventType != KEY_EVENT) {
|
|
if (handle->tty.rd.last_input_record.EventType != KEY_EVENT) {
|
|
|
continue;
|
|
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) {
|
|
static int uv_tty_reset(uv_tty_t* handle, DWORD* error) {
|
|
|
const COORD origin = {0, 0};
|
|
const COORD origin = {0, 0};
|
|
|
const WORD char_attrs = uv_tty_default_text_attributes;
|
|
const WORD char_attrs = uv_tty_default_text_attributes;
|
|
|
- CONSOLE_SCREEN_BUFFER_INFO info;
|
|
|
|
|
|
|
+ CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
|
|
|
DWORD count, written;
|
|
DWORD count, written;
|
|
|
|
|
|
|
|
if (*error != ERROR_SUCCESS) {
|
|
if (*error != ERROR_SUCCESS) {
|
|
@@ -1239,12 +1271,12 @@ static int uv_tty_reset(uv_tty_t* handle, DWORD* error) {
|
|
|
|
|
|
|
|
/* Clear the screen buffer. */
|
|
/* Clear the screen buffer. */
|
|
|
retry:
|
|
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,
|
|
if (!(FillConsoleOutputCharacterW(handle->handle,
|
|
|
L'\x20',
|
|
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. */
|
|
/* Move the virtual window up to the top. */
|
|
|
uv_tty_virtual_offset = 0;
|
|
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;
|
|
return 0;
|
|
|
}
|
|
}
|
|
@@ -1606,6 +1644,31 @@ static int uv_tty_set_cursor_visibility(uv_tty_t* handle,
|
|
|
return 0;
|
|
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,
|
|
static int uv_tty_write_bufs(uv_tty_t* handle,
|
|
|
const uv_buf_t bufs[],
|
|
const uv_buf_t bufs[],
|
|
|
unsigned int nbufs,
|
|
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
|
|
/* We can only write 8k characters at a time. Windows can't handle much more
|
|
|
* characters in a single console write anyway. */
|
|
* characters in a single console write anyway. */
|
|
|
WCHAR utf16_buf[MAX_CONSOLE_CHAR];
|
|
WCHAR utf16_buf[MAX_CONSOLE_CHAR];
|
|
|
- WCHAR* utf16_buffer;
|
|
|
|
|
DWORD utf16_buf_used = 0;
|
|
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) \
|
|
#define ENSURE_BUFFER_SPACE(wchars_needed) \
|
|
|
if (wchars_needed > ARRAY_SIZE(utf16_buf) - utf16_buf_used) { \
|
|
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 char utf8_bytes_left = handle->tty.wr.utf8_bytes_left;
|
|
|
unsigned int utf8_codepoint = handle->tty.wr.utf8_codepoint;
|
|
unsigned int utf8_codepoint = handle->tty.wr.utf8_codepoint;
|
|
|
unsigned char previous_eol = handle->tty.wr.previous_eol;
|
|
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
|
|
/* 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. */
|
|
* keep parsing the buffer so we leave the parser in a consistent state. */
|
|
|
*error = ERROR_SUCCESS;
|
|
*error = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
- utf16_buffer = utf16_buf;
|
|
|
|
|
-
|
|
|
|
|
uv_sem_wait(&uv_tty_output_lock);
|
|
uv_sem_wait(&uv_tty_output_lock);
|
|
|
|
|
|
|
|
for (i = 0; i < nbufs; i++) {
|
|
for (i = 0; i < nbufs; i++) {
|
|
|
uv_buf_t buf = bufs[i];
|
|
uv_buf_t buf = bufs[i];
|
|
|
unsigned int j;
|
|
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++) {
|
|
for (j = 0; j < buf.len; j++) {
|
|
|
unsigned char c = buf.base[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 */
|
|
/* 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) {
|
|
switch (utf8_codepoint) {
|
|
|
case '\033':
|
|
case '\033':
|
|
|
ansi_parser_state = ANSI_ESCAPE_SEEN;
|
|
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;
|
|
ansi_parser_state = ANSI_NORMAL;
|
|
|
continue;
|
|
continue;
|
|
|
|
|
|
|
|
- case '8':
|
|
|
|
|
|
|
+ case '8':
|
|
|
/* Restore the cursor position and text attributes */
|
|
/* Restore the cursor position and text attributes */
|
|
|
FLUSH_TEXT();
|
|
FLUSH_TEXT();
|
|
|
uv_tty_restore_state(handle, 1, error);
|
|
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) {
|
|
} 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;
|
|
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;
|
|
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;
|
|
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;
|
|
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) {
|
|
switch (utf8_codepoint) {
|
|
|
case 'A':
|
|
case 'A':
|
|
|
/* cursor up */
|
|
/* cursor up */
|
|
|
FLUSH_TEXT();
|
|
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);
|
|
uv_tty_move_caret(handle, 0, 1, y, 1, error);
|
|
|
break;
|
|
break;
|
|
|
|
|
|
|
|
case 'B':
|
|
case 'B':
|
|
|
/* cursor down */
|
|
/* cursor down */
|
|
|
FLUSH_TEXT();
|
|
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);
|
|
uv_tty_move_caret(handle, 0, 1, y, 1, error);
|
|
|
break;
|
|
break;
|
|
|
|
|
|
|
|
case 'C':
|
|
case 'C':
|
|
|
/* cursor forward */
|
|
/* cursor forward */
|
|
|
FLUSH_TEXT();
|
|
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);
|
|
uv_tty_move_caret(handle, x, 1, 0, 1, error);
|
|
|
break;
|
|
break;
|
|
|
|
|
|
|
|
case 'D':
|
|
case 'D':
|
|
|
/* cursor back */
|
|
/* cursor back */
|
|
|
FLUSH_TEXT();
|
|
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);
|
|
uv_tty_move_caret(handle, x, 1, 0, 1, error);
|
|
|
break;
|
|
break;
|
|
|
|
|
|
|
|
case 'E':
|
|
case 'E':
|
|
|
/* cursor next line */
|
|
/* cursor next line */
|
|
|
FLUSH_TEXT();
|
|
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);
|
|
uv_tty_move_caret(handle, 0, 0, y, 1, error);
|
|
|
break;
|
|
break;
|
|
|
|
|
|
|
|
case 'F':
|
|
case 'F':
|
|
|
/* cursor previous line */
|
|
/* cursor previous line */
|
|
|
FLUSH_TEXT();
|
|
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);
|
|
uv_tty_move_caret(handle, 0, 0, y, 1, error);
|
|
|
break;
|
|
break;
|
|
|
|
|
|
|
|
case 'G':
|
|
case 'G':
|
|
|
/* cursor horizontal move absolute */
|
|
/* cursor horizontal move absolute */
|
|
|
FLUSH_TEXT();
|
|
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;
|
|
? handle->tty.wr.ansi_csi_argv[0] - 1 : 0;
|
|
|
uv_tty_move_caret(handle, x, 0, 0, 1, error);
|
|
uv_tty_move_caret(handle, x, 0, 0, 1, error);
|
|
|
break;
|
|
break;
|
|
@@ -1936,9 +2025,11 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
|
|
case 'f':
|
|
case 'f':
|
|
|
/* cursor move absolute */
|
|
/* cursor move absolute */
|
|
|
FLUSH_TEXT();
|
|
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;
|
|
? 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;
|
|
? handle->tty.wr.ansi_csi_argv[1] - 1 : 0;
|
|
|
uv_tty_move_caret(handle, x, 0, y, 0, error);
|
|
uv_tty_move_caret(handle, x, 0, y, 0, error);
|
|
|
break;
|
|
break;
|
|
@@ -1946,7 +2037,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
|
|
case 'J':
|
|
case 'J':
|
|
|
/* Erase screen */
|
|
/* Erase screen */
|
|
|
FLUSH_TEXT();
|
|
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) {
|
|
if (d >= 0 && d <= 2) {
|
|
|
uv_tty_clear(handle, d, 1, error);
|
|
uv_tty_clear(handle, d, 1, error);
|
|
|
}
|
|
}
|
|
@@ -1955,7 +2047,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
|
|
case 'K':
|
|
case 'K':
|
|
|
/* Erase line */
|
|
/* Erase line */
|
|
|
FLUSH_TEXT();
|
|
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) {
|
|
if (d >= 0 && d <= 2) {
|
|
|
uv_tty_clear(handle, d, 0, error);
|
|
uv_tty_clear(handle, d, 0, error);
|
|
|
}
|
|
}
|
|
@@ -1978,41 +2071,17 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
|
|
FLUSH_TEXT();
|
|
FLUSH_TEXT();
|
|
|
uv_tty_restore_state(handle, 0, error);
|
|
uv_tty_restore_state(handle, 0, error);
|
|
|
break;
|
|
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 {
|
|
} 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;
|
|
continue;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -2264,38 +2333,56 @@ int uv_tty_reset_mode(void) {
|
|
|
static void uv__determine_vterm_state(HANDLE handle) {
|
|
static void uv__determine_vterm_state(HANDLE handle) {
|
|
|
DWORD dwMode = 0;
|
|
DWORD dwMode = 0;
|
|
|
|
|
|
|
|
|
|
+ uv__need_check_vterm_state = FALSE;
|
|
|
if (!GetConsoleMode(handle, &dwMode)) {
|
|
if (!GetConsoleMode(handle, &dwMode)) {
|
|
|
- uv__vterm_state = UV_UNSUPPORTED;
|
|
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
|
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
|
|
if (!SetConsoleMode(handle, dwMode)) {
|
|
if (!SetConsoleMode(handle, dwMode)) {
|
|
|
- uv__vterm_state = UV_UNSUPPORTED;
|
|
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- uv__vterm_state = UV_SUPPORTED;
|
|
|
|
|
|
|
+ uv__vterm_state = UV_TTY_SUPPORTED;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param) {
|
|
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;
|
|
MSG msg;
|
|
|
|
|
|
|
|
- if (!GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info))
|
|
|
|
|
|
|
+ if (pSetWinEventHook == NULL || pNtQueryInformationProcess == NULL)
|
|
|
return 0;
|
|
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;
|
|
return 0;
|
|
|
|
|
|
|
|
if (!pSetWinEventHook(EVENT_CONSOLE_LAYOUT,
|
|
if (!pSetWinEventHook(EVENT_CONSOLE_LAYOUT,
|
|
|
EVENT_CONSOLE_LAYOUT,
|
|
EVENT_CONSOLE_LAYOUT,
|
|
|
NULL,
|
|
NULL,
|
|
|
uv__tty_console_resize_event,
|
|
uv__tty_console_resize_event,
|
|
|
- 0,
|
|
|
|
|
|
|
+ (DWORD)conhost_pid,
|
|
|
0,
|
|
0,
|
|
|
WINEVENT_OUTOFCONTEXT))
|
|
WINEVENT_OUTOFCONTEXT))
|
|
|
return 0;
|
|
return 0;
|
|
@@ -2314,6 +2401,20 @@ static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook,
|
|
|
LONG idChild,
|
|
LONG idChild,
|
|
|
DWORD dwEventThread,
|
|
DWORD dwEventThread,
|
|
|
DWORD dwmsEventTime) {
|
|
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;
|
|
CONSOLE_SCREEN_BUFFER_INFO sb_info;
|
|
|
int width, height;
|
|
int width, height;
|
|
|
|
|
|
|
@@ -2323,9 +2424,28 @@ static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook,
|
|
|
width = sb_info.dwSize.X;
|
|
width = sb_info.dwSize.X;
|
|
|
height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1;
|
|
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) {
|
|
if (width != uv__tty_console_width || height != uv__tty_console_height) {
|
|
|
uv__tty_console_width = width;
|
|
uv__tty_console_width = width;
|
|
|
uv__tty_console_height = height;
|
|
uv__tty_console_height = height;
|
|
|
|
|
+ uv_mutex_unlock(&uv__tty_console_resize_mutex);
|
|
|
uv__signal_dispatch(SIGWINCH);
|
|
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;
|
|
|
|
|
+}
|