1e66f31c5Sopenharmony_ci/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. 2e66f31c5Sopenharmony_ci * 3e66f31c5Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 4e66f31c5Sopenharmony_ci * of this software and associated documentation files (the "Software"), to 5e66f31c5Sopenharmony_ci * deal in the Software without restriction, including without limitation the 6e66f31c5Sopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7e66f31c5Sopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is 8e66f31c5Sopenharmony_ci * furnished to do so, subject to the following conditions: 9e66f31c5Sopenharmony_ci * 10e66f31c5Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 11e66f31c5Sopenharmony_ci * all copies or substantial portions of the Software. 12e66f31c5Sopenharmony_ci * 13e66f31c5Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14e66f31c5Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15e66f31c5Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16e66f31c5Sopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17e66f31c5Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18e66f31c5Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19e66f31c5Sopenharmony_ci * IN THE SOFTWARE. 20e66f31c5Sopenharmony_ci */ 21e66f31c5Sopenharmony_ci 22e66f31c5Sopenharmony_ci#include <assert.h> 23e66f31c5Sopenharmony_ci#include <io.h> 24e66f31c5Sopenharmony_ci#include <string.h> 25e66f31c5Sopenharmony_ci#include <stdlib.h> 26e66f31c5Sopenharmony_ci#include <stdint.h> 27e66f31c5Sopenharmony_ci 28e66f31c5Sopenharmony_ci#ifndef COMMON_LVB_REVERSE_VIDEO 29e66f31c5Sopenharmony_ci# define COMMON_LVB_REVERSE_VIDEO 0x4000 30e66f31c5Sopenharmony_ci#endif 31e66f31c5Sopenharmony_ci 32e66f31c5Sopenharmony_ci#include "uv.h" 33e66f31c5Sopenharmony_ci#include "internal.h" 34e66f31c5Sopenharmony_ci#include "handle-inl.h" 35e66f31c5Sopenharmony_ci#include "stream-inl.h" 36e66f31c5Sopenharmony_ci#include "req-inl.h" 37e66f31c5Sopenharmony_ci 38e66f31c5Sopenharmony_ci#ifndef InterlockedOr 39e66f31c5Sopenharmony_ci# define InterlockedOr _InterlockedOr 40e66f31c5Sopenharmony_ci#endif 41e66f31c5Sopenharmony_ci 42e66f31c5Sopenharmony_ci#define UNICODE_REPLACEMENT_CHARACTER (0xfffd) 43e66f31c5Sopenharmony_ci 44e66f31c5Sopenharmony_ci#define ANSI_NORMAL 0x0000 45e66f31c5Sopenharmony_ci#define ANSI_ESCAPE_SEEN 0x0002 46e66f31c5Sopenharmony_ci#define ANSI_CSI 0x0004 47e66f31c5Sopenharmony_ci#define ANSI_ST_CONTROL 0x0008 48e66f31c5Sopenharmony_ci#define ANSI_IGNORE 0x0010 49e66f31c5Sopenharmony_ci#define ANSI_IN_ARG 0x0020 50e66f31c5Sopenharmony_ci#define ANSI_IN_STRING 0x0040 51e66f31c5Sopenharmony_ci#define ANSI_BACKSLASH_SEEN 0x0080 52e66f31c5Sopenharmony_ci#define ANSI_EXTENSION 0x0100 53e66f31c5Sopenharmony_ci#define ANSI_DECSCUSR 0x0200 54e66f31c5Sopenharmony_ci 55e66f31c5Sopenharmony_ci#define MAX_INPUT_BUFFER_LENGTH 8192 56e66f31c5Sopenharmony_ci#define MAX_CONSOLE_CHAR 8192 57e66f31c5Sopenharmony_ci 58e66f31c5Sopenharmony_ci#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING 59e66f31c5Sopenharmony_ci#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 60e66f31c5Sopenharmony_ci#endif 61e66f31c5Sopenharmony_ci 62e66f31c5Sopenharmony_ci#define CURSOR_SIZE_SMALL 25 63e66f31c5Sopenharmony_ci#define CURSOR_SIZE_LARGE 100 64e66f31c5Sopenharmony_ci 65e66f31c5Sopenharmony_cistatic void uv__tty_capture_initial_style( 66e66f31c5Sopenharmony_ci CONSOLE_SCREEN_BUFFER_INFO* screen_buffer_info, 67e66f31c5Sopenharmony_ci CONSOLE_CURSOR_INFO* cursor_info); 68e66f31c5Sopenharmony_cistatic void uv__tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info); 69e66f31c5Sopenharmony_cistatic int uv__cancel_read_console(uv_tty_t* handle); 70e66f31c5Sopenharmony_ci 71e66f31c5Sopenharmony_ci 72e66f31c5Sopenharmony_ci/* Null uv_buf_t */ 73e66f31c5Sopenharmony_cistatic const uv_buf_t uv_null_buf_ = { 0, NULL }; 74e66f31c5Sopenharmony_ci 75e66f31c5Sopenharmony_cienum uv__read_console_status_e { 76e66f31c5Sopenharmony_ci NOT_STARTED, 77e66f31c5Sopenharmony_ci IN_PROGRESS, 78e66f31c5Sopenharmony_ci TRAP_REQUESTED, 79e66f31c5Sopenharmony_ci COMPLETED 80e66f31c5Sopenharmony_ci}; 81e66f31c5Sopenharmony_ci 82e66f31c5Sopenharmony_cistatic volatile LONG uv__read_console_status = NOT_STARTED; 83e66f31c5Sopenharmony_cistatic volatile LONG uv__restore_screen_state; 84e66f31c5Sopenharmony_cistatic CONSOLE_SCREEN_BUFFER_INFO uv__saved_screen_state; 85e66f31c5Sopenharmony_ci 86e66f31c5Sopenharmony_ci 87e66f31c5Sopenharmony_ci/* 88e66f31c5Sopenharmony_ci * The console virtual window. 89e66f31c5Sopenharmony_ci * 90e66f31c5Sopenharmony_ci * Normally cursor movement in windows is relative to the console screen buffer, 91e66f31c5Sopenharmony_ci * e.g. the application is allowed to overwrite the 'history'. This is very 92e66f31c5Sopenharmony_ci * inconvenient, it makes absolute cursor movement pretty useless. There is 93e66f31c5Sopenharmony_ci * also the concept of 'client rect' which is defined by the actual size of 94e66f31c5Sopenharmony_ci * the console window and the scroll position of the screen buffer, but it's 95e66f31c5Sopenharmony_ci * very volatile because it changes when the user scrolls. 96e66f31c5Sopenharmony_ci * 97e66f31c5Sopenharmony_ci * To make cursor movement behave sensibly we define a virtual window to which 98e66f31c5Sopenharmony_ci * cursor movement is confined. The virtual window is always as wide as the 99e66f31c5Sopenharmony_ci * console screen buffer, but it's height is defined by the size of the 100e66f31c5Sopenharmony_ci * console window. The top of the virtual window aligns with the position 101e66f31c5Sopenharmony_ci * of the caret when the first stdout/err handle is created, unless that would 102e66f31c5Sopenharmony_ci * mean that it would extend beyond the bottom of the screen buffer - in that 103e66f31c5Sopenharmony_ci * that case it's located as far down as possible. 104e66f31c5Sopenharmony_ci * 105e66f31c5Sopenharmony_ci * When the user writes a long text or many newlines, such that the output 106e66f31c5Sopenharmony_ci * reaches beyond the bottom of the virtual window, the virtual window is 107e66f31c5Sopenharmony_ci * shifted downwards, but not resized. 108e66f31c5Sopenharmony_ci * 109e66f31c5Sopenharmony_ci * Since all tty i/o happens on the same console, this window is shared 110e66f31c5Sopenharmony_ci * between all stdout/stderr handles. 111e66f31c5Sopenharmony_ci */ 112e66f31c5Sopenharmony_ci 113e66f31c5Sopenharmony_cistatic int uv_tty_virtual_offset = -1; 114e66f31c5Sopenharmony_cistatic int uv_tty_virtual_height = -1; 115e66f31c5Sopenharmony_cistatic int uv_tty_virtual_width = -1; 116e66f31c5Sopenharmony_ci 117e66f31c5Sopenharmony_ci/* The console window size 118e66f31c5Sopenharmony_ci * We keep this separate from uv_tty_virtual_*. We use those values to only 119e66f31c5Sopenharmony_ci * handle signalling SIGWINCH 120e66f31c5Sopenharmony_ci */ 121e66f31c5Sopenharmony_ci 122e66f31c5Sopenharmony_cistatic HANDLE uv__tty_console_handle = INVALID_HANDLE_VALUE; 123e66f31c5Sopenharmony_cistatic int uv__tty_console_height = -1; 124e66f31c5Sopenharmony_cistatic int uv__tty_console_width = -1; 125e66f31c5Sopenharmony_cistatic HANDLE uv__tty_console_resized = INVALID_HANDLE_VALUE; 126e66f31c5Sopenharmony_cistatic uv_mutex_t uv__tty_console_resize_mutex; 127e66f31c5Sopenharmony_ci 128e66f31c5Sopenharmony_cistatic DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param); 129e66f31c5Sopenharmony_cistatic void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook, 130e66f31c5Sopenharmony_ci DWORD event, 131e66f31c5Sopenharmony_ci HWND hwnd, 132e66f31c5Sopenharmony_ci LONG idObject, 133e66f31c5Sopenharmony_ci LONG idChild, 134e66f31c5Sopenharmony_ci DWORD dwEventThread, 135e66f31c5Sopenharmony_ci DWORD dwmsEventTime); 136e66f31c5Sopenharmony_cistatic DWORD WINAPI uv__tty_console_resize_watcher_thread(void* param); 137e66f31c5Sopenharmony_cistatic void uv__tty_console_signal_resize(void); 138e66f31c5Sopenharmony_ci 139e66f31c5Sopenharmony_ci/* We use a semaphore rather than a mutex or critical section because in some 140e66f31c5Sopenharmony_ci cases (uv__cancel_read_console) we need take the lock in the main thread and 141e66f31c5Sopenharmony_ci release it in another thread. Using a semaphore ensures that in such 142e66f31c5Sopenharmony_ci scenario the main thread will still block when trying to acquire the lock. */ 143e66f31c5Sopenharmony_cistatic uv_sem_t uv_tty_output_lock; 144e66f31c5Sopenharmony_ci 145e66f31c5Sopenharmony_cistatic WORD uv_tty_default_text_attributes = 146e66f31c5Sopenharmony_ci FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; 147e66f31c5Sopenharmony_ci 148e66f31c5Sopenharmony_cistatic char uv_tty_default_fg_color = 7; 149e66f31c5Sopenharmony_cistatic char uv_tty_default_bg_color = 0; 150e66f31c5Sopenharmony_cistatic char uv_tty_default_fg_bright = 0; 151e66f31c5Sopenharmony_cistatic char uv_tty_default_bg_bright = 0; 152e66f31c5Sopenharmony_cistatic char uv_tty_default_inverse = 0; 153e66f31c5Sopenharmony_ci 154e66f31c5Sopenharmony_cistatic CONSOLE_CURSOR_INFO uv_tty_default_cursor_info; 155e66f31c5Sopenharmony_ci 156e66f31c5Sopenharmony_ci/* Determine whether or not ANSI support is enabled. */ 157e66f31c5Sopenharmony_cistatic BOOL uv__need_check_vterm_state = TRUE; 158e66f31c5Sopenharmony_cistatic uv_tty_vtermstate_t uv__vterm_state = UV_TTY_UNSUPPORTED; 159e66f31c5Sopenharmony_cistatic void uv__determine_vterm_state(HANDLE handle); 160e66f31c5Sopenharmony_ci 161e66f31c5Sopenharmony_civoid uv__console_init(void) { 162e66f31c5Sopenharmony_ci if (uv_sem_init(&uv_tty_output_lock, 1)) 163e66f31c5Sopenharmony_ci abort(); 164e66f31c5Sopenharmony_ci uv__tty_console_handle = CreateFileW(L"CONOUT$", 165e66f31c5Sopenharmony_ci GENERIC_READ | GENERIC_WRITE, 166e66f31c5Sopenharmony_ci FILE_SHARE_WRITE, 167e66f31c5Sopenharmony_ci 0, 168e66f31c5Sopenharmony_ci OPEN_EXISTING, 169e66f31c5Sopenharmony_ci 0, 170e66f31c5Sopenharmony_ci 0); 171e66f31c5Sopenharmony_ci if (uv__tty_console_handle != INVALID_HANDLE_VALUE) { 172e66f31c5Sopenharmony_ci CONSOLE_SCREEN_BUFFER_INFO sb_info; 173e66f31c5Sopenharmony_ci uv_mutex_init(&uv__tty_console_resize_mutex); 174e66f31c5Sopenharmony_ci if (GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info)) { 175e66f31c5Sopenharmony_ci uv__tty_console_width = sb_info.dwSize.X; 176e66f31c5Sopenharmony_ci uv__tty_console_height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1; 177e66f31c5Sopenharmony_ci } 178e66f31c5Sopenharmony_ci QueueUserWorkItem(uv__tty_console_resize_message_loop_thread, 179e66f31c5Sopenharmony_ci NULL, 180e66f31c5Sopenharmony_ci WT_EXECUTELONGFUNCTION); 181e66f31c5Sopenharmony_ci } 182e66f31c5Sopenharmony_ci} 183e66f31c5Sopenharmony_ci 184e66f31c5Sopenharmony_ci 185e66f31c5Sopenharmony_ciint uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) { 186e66f31c5Sopenharmony_ci BOOL readable; 187e66f31c5Sopenharmony_ci DWORD NumberOfEvents; 188e66f31c5Sopenharmony_ci HANDLE handle; 189e66f31c5Sopenharmony_ci CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info; 190e66f31c5Sopenharmony_ci CONSOLE_CURSOR_INFO cursor_info; 191e66f31c5Sopenharmony_ci (void)unused; 192e66f31c5Sopenharmony_ci 193e66f31c5Sopenharmony_ci uv__once_init(); 194e66f31c5Sopenharmony_ci handle = (HANDLE) uv__get_osfhandle(fd); 195e66f31c5Sopenharmony_ci if (handle == INVALID_HANDLE_VALUE) 196e66f31c5Sopenharmony_ci return UV_EBADF; 197e66f31c5Sopenharmony_ci 198e66f31c5Sopenharmony_ci if (fd <= 2) { 199e66f31c5Sopenharmony_ci /* In order to avoid closing a stdio file descriptor 0-2, duplicate the 200e66f31c5Sopenharmony_ci * underlying OS handle and forget about the original fd. 201e66f31c5Sopenharmony_ci * We could also opt to use the original OS handle and just never close it, 202e66f31c5Sopenharmony_ci * but then there would be no reliable way to cancel pending read operations 203e66f31c5Sopenharmony_ci * upon close. 204e66f31c5Sopenharmony_ci */ 205e66f31c5Sopenharmony_ci if (!DuplicateHandle(INVALID_HANDLE_VALUE, 206e66f31c5Sopenharmony_ci handle, 207e66f31c5Sopenharmony_ci INVALID_HANDLE_VALUE, 208e66f31c5Sopenharmony_ci &handle, 209e66f31c5Sopenharmony_ci 0, 210e66f31c5Sopenharmony_ci FALSE, 211e66f31c5Sopenharmony_ci DUPLICATE_SAME_ACCESS)) 212e66f31c5Sopenharmony_ci return uv_translate_sys_error(GetLastError()); 213e66f31c5Sopenharmony_ci fd = -1; 214e66f31c5Sopenharmony_ci } 215e66f31c5Sopenharmony_ci 216e66f31c5Sopenharmony_ci readable = GetNumberOfConsoleInputEvents(handle, &NumberOfEvents); 217e66f31c5Sopenharmony_ci if (!readable) { 218e66f31c5Sopenharmony_ci /* Obtain the screen buffer info with the output handle. */ 219e66f31c5Sopenharmony_ci if (!GetConsoleScreenBufferInfo(handle, &screen_buffer_info)) { 220e66f31c5Sopenharmony_ci return uv_translate_sys_error(GetLastError()); 221e66f31c5Sopenharmony_ci } 222e66f31c5Sopenharmony_ci 223e66f31c5Sopenharmony_ci /* Obtain the cursor info with the output handle. */ 224e66f31c5Sopenharmony_ci if (!GetConsoleCursorInfo(handle, &cursor_info)) { 225e66f31c5Sopenharmony_ci return uv_translate_sys_error(GetLastError()); 226e66f31c5Sopenharmony_ci } 227e66f31c5Sopenharmony_ci 228e66f31c5Sopenharmony_ci /* Obtain the tty_output_lock because the virtual window state is shared 229e66f31c5Sopenharmony_ci * between all uv_tty_t handles. */ 230e66f31c5Sopenharmony_ci uv_sem_wait(&uv_tty_output_lock); 231e66f31c5Sopenharmony_ci 232e66f31c5Sopenharmony_ci if (uv__need_check_vterm_state) 233e66f31c5Sopenharmony_ci uv__determine_vterm_state(handle); 234e66f31c5Sopenharmony_ci 235e66f31c5Sopenharmony_ci /* Remember the original console text attributes and cursor info. */ 236e66f31c5Sopenharmony_ci uv__tty_capture_initial_style(&screen_buffer_info, &cursor_info); 237e66f31c5Sopenharmony_ci 238e66f31c5Sopenharmony_ci uv__tty_update_virtual_window(&screen_buffer_info); 239e66f31c5Sopenharmony_ci 240e66f31c5Sopenharmony_ci uv_sem_post(&uv_tty_output_lock); 241e66f31c5Sopenharmony_ci } 242e66f31c5Sopenharmony_ci 243e66f31c5Sopenharmony_ci 244e66f31c5Sopenharmony_ci uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY); 245e66f31c5Sopenharmony_ci uv__connection_init((uv_stream_t*) tty); 246e66f31c5Sopenharmony_ci 247e66f31c5Sopenharmony_ci tty->handle = handle; 248e66f31c5Sopenharmony_ci tty->u.fd = fd; 249e66f31c5Sopenharmony_ci tty->reqs_pending = 0; 250e66f31c5Sopenharmony_ci tty->flags |= UV_HANDLE_BOUND; 251e66f31c5Sopenharmony_ci 252e66f31c5Sopenharmony_ci if (readable) { 253e66f31c5Sopenharmony_ci /* Initialize TTY input specific fields. */ 254e66f31c5Sopenharmony_ci tty->flags |= UV_HANDLE_TTY_READABLE | UV_HANDLE_READABLE; 255e66f31c5Sopenharmony_ci /* TODO: remove me in v2.x. */ 256e66f31c5Sopenharmony_ci tty->tty.rd.unused_ = NULL; 257e66f31c5Sopenharmony_ci tty->tty.rd.read_line_buffer = uv_null_buf_; 258e66f31c5Sopenharmony_ci tty->tty.rd.read_raw_wait = NULL; 259e66f31c5Sopenharmony_ci 260e66f31c5Sopenharmony_ci /* Init keycode-to-vt100 mapper state. */ 261e66f31c5Sopenharmony_ci tty->tty.rd.last_key_len = 0; 262e66f31c5Sopenharmony_ci tty->tty.rd.last_key_offset = 0; 263e66f31c5Sopenharmony_ci tty->tty.rd.last_utf16_high_surrogate = 0; 264e66f31c5Sopenharmony_ci memset(&tty->tty.rd.last_input_record, 0, sizeof tty->tty.rd.last_input_record); 265e66f31c5Sopenharmony_ci } else { 266e66f31c5Sopenharmony_ci /* TTY output specific fields. */ 267e66f31c5Sopenharmony_ci tty->flags |= UV_HANDLE_WRITABLE; 268e66f31c5Sopenharmony_ci 269e66f31c5Sopenharmony_ci /* Init utf8-to-utf16 conversion state. */ 270e66f31c5Sopenharmony_ci tty->tty.wr.utf8_bytes_left = 0; 271e66f31c5Sopenharmony_ci tty->tty.wr.utf8_codepoint = 0; 272e66f31c5Sopenharmony_ci 273e66f31c5Sopenharmony_ci /* Initialize eol conversion state */ 274e66f31c5Sopenharmony_ci tty->tty.wr.previous_eol = 0; 275e66f31c5Sopenharmony_ci 276e66f31c5Sopenharmony_ci /* Init ANSI parser state. */ 277e66f31c5Sopenharmony_ci tty->tty.wr.ansi_parser_state = ANSI_NORMAL; 278e66f31c5Sopenharmony_ci } 279e66f31c5Sopenharmony_ci 280e66f31c5Sopenharmony_ci return 0; 281e66f31c5Sopenharmony_ci} 282e66f31c5Sopenharmony_ci 283e66f31c5Sopenharmony_ci 284e66f31c5Sopenharmony_ci/* Set the default console text attributes based on how the console was 285e66f31c5Sopenharmony_ci * configured when libuv started. 286e66f31c5Sopenharmony_ci */ 287e66f31c5Sopenharmony_cistatic void uv__tty_capture_initial_style( 288e66f31c5Sopenharmony_ci CONSOLE_SCREEN_BUFFER_INFO* screen_buffer_info, 289e66f31c5Sopenharmony_ci CONSOLE_CURSOR_INFO* cursor_info) { 290e66f31c5Sopenharmony_ci static int style_captured = 0; 291e66f31c5Sopenharmony_ci 292e66f31c5Sopenharmony_ci /* Only do this once. 293e66f31c5Sopenharmony_ci Assumption: Caller has acquired uv_tty_output_lock. */ 294e66f31c5Sopenharmony_ci if (style_captured) 295e66f31c5Sopenharmony_ci return; 296e66f31c5Sopenharmony_ci 297e66f31c5Sopenharmony_ci /* Save raw win32 attributes. */ 298e66f31c5Sopenharmony_ci uv_tty_default_text_attributes = screen_buffer_info->wAttributes; 299e66f31c5Sopenharmony_ci 300e66f31c5Sopenharmony_ci /* Convert black text on black background to use white text. */ 301e66f31c5Sopenharmony_ci if (uv_tty_default_text_attributes == 0) 302e66f31c5Sopenharmony_ci uv_tty_default_text_attributes = 7; 303e66f31c5Sopenharmony_ci 304e66f31c5Sopenharmony_ci /* Convert Win32 attributes to ANSI colors. */ 305e66f31c5Sopenharmony_ci uv_tty_default_fg_color = 0; 306e66f31c5Sopenharmony_ci uv_tty_default_bg_color = 0; 307e66f31c5Sopenharmony_ci uv_tty_default_fg_bright = 0; 308e66f31c5Sopenharmony_ci uv_tty_default_bg_bright = 0; 309e66f31c5Sopenharmony_ci uv_tty_default_inverse = 0; 310e66f31c5Sopenharmony_ci 311e66f31c5Sopenharmony_ci if (uv_tty_default_text_attributes & FOREGROUND_RED) 312e66f31c5Sopenharmony_ci uv_tty_default_fg_color |= 1; 313e66f31c5Sopenharmony_ci 314e66f31c5Sopenharmony_ci if (uv_tty_default_text_attributes & FOREGROUND_GREEN) 315e66f31c5Sopenharmony_ci uv_tty_default_fg_color |= 2; 316e66f31c5Sopenharmony_ci 317e66f31c5Sopenharmony_ci if (uv_tty_default_text_attributes & FOREGROUND_BLUE) 318e66f31c5Sopenharmony_ci uv_tty_default_fg_color |= 4; 319e66f31c5Sopenharmony_ci 320e66f31c5Sopenharmony_ci if (uv_tty_default_text_attributes & BACKGROUND_RED) 321e66f31c5Sopenharmony_ci uv_tty_default_bg_color |= 1; 322e66f31c5Sopenharmony_ci 323e66f31c5Sopenharmony_ci if (uv_tty_default_text_attributes & BACKGROUND_GREEN) 324e66f31c5Sopenharmony_ci uv_tty_default_bg_color |= 2; 325e66f31c5Sopenharmony_ci 326e66f31c5Sopenharmony_ci if (uv_tty_default_text_attributes & BACKGROUND_BLUE) 327e66f31c5Sopenharmony_ci uv_tty_default_bg_color |= 4; 328e66f31c5Sopenharmony_ci 329e66f31c5Sopenharmony_ci if (uv_tty_default_text_attributes & FOREGROUND_INTENSITY) 330e66f31c5Sopenharmony_ci uv_tty_default_fg_bright = 1; 331e66f31c5Sopenharmony_ci 332e66f31c5Sopenharmony_ci if (uv_tty_default_text_attributes & BACKGROUND_INTENSITY) 333e66f31c5Sopenharmony_ci uv_tty_default_bg_bright = 1; 334e66f31c5Sopenharmony_ci 335e66f31c5Sopenharmony_ci if (uv_tty_default_text_attributes & COMMON_LVB_REVERSE_VIDEO) 336e66f31c5Sopenharmony_ci uv_tty_default_inverse = 1; 337e66f31c5Sopenharmony_ci 338e66f31c5Sopenharmony_ci /* Save the cursor size and the cursor state. */ 339e66f31c5Sopenharmony_ci uv_tty_default_cursor_info = *cursor_info; 340e66f31c5Sopenharmony_ci 341e66f31c5Sopenharmony_ci style_captured = 1; 342e66f31c5Sopenharmony_ci} 343e66f31c5Sopenharmony_ci 344e66f31c5Sopenharmony_ci 345e66f31c5Sopenharmony_ciint uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { 346e66f31c5Sopenharmony_ci DWORD flags; 347e66f31c5Sopenharmony_ci unsigned char was_reading; 348e66f31c5Sopenharmony_ci uv_alloc_cb alloc_cb; 349e66f31c5Sopenharmony_ci uv_read_cb read_cb; 350e66f31c5Sopenharmony_ci int err; 351e66f31c5Sopenharmony_ci 352e66f31c5Sopenharmony_ci if (!(tty->flags & UV_HANDLE_TTY_READABLE)) { 353e66f31c5Sopenharmony_ci return UV_EINVAL; 354e66f31c5Sopenharmony_ci } 355e66f31c5Sopenharmony_ci 356e66f31c5Sopenharmony_ci if (!!mode == !!(tty->flags & UV_HANDLE_TTY_RAW)) { 357e66f31c5Sopenharmony_ci return 0; 358e66f31c5Sopenharmony_ci } 359e66f31c5Sopenharmony_ci 360e66f31c5Sopenharmony_ci switch (mode) { 361e66f31c5Sopenharmony_ci case UV_TTY_MODE_NORMAL: 362e66f31c5Sopenharmony_ci flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT; 363e66f31c5Sopenharmony_ci break; 364e66f31c5Sopenharmony_ci case UV_TTY_MODE_RAW: 365e66f31c5Sopenharmony_ci flags = ENABLE_WINDOW_INPUT; 366e66f31c5Sopenharmony_ci break; 367e66f31c5Sopenharmony_ci case UV_TTY_MODE_IO: 368e66f31c5Sopenharmony_ci return UV_ENOTSUP; 369e66f31c5Sopenharmony_ci default: 370e66f31c5Sopenharmony_ci return UV_EINVAL; 371e66f31c5Sopenharmony_ci } 372e66f31c5Sopenharmony_ci 373e66f31c5Sopenharmony_ci /* If currently reading, stop, and restart reading. */ 374e66f31c5Sopenharmony_ci if (tty->flags & UV_HANDLE_READING) { 375e66f31c5Sopenharmony_ci was_reading = 1; 376e66f31c5Sopenharmony_ci alloc_cb = tty->alloc_cb; 377e66f31c5Sopenharmony_ci read_cb = tty->read_cb; 378e66f31c5Sopenharmony_ci err = uv__tty_read_stop(tty); 379e66f31c5Sopenharmony_ci if (err) { 380e66f31c5Sopenharmony_ci return uv_translate_sys_error(err); 381e66f31c5Sopenharmony_ci } 382e66f31c5Sopenharmony_ci } else { 383e66f31c5Sopenharmony_ci was_reading = 0; 384e66f31c5Sopenharmony_ci alloc_cb = NULL; 385e66f31c5Sopenharmony_ci read_cb = NULL; 386e66f31c5Sopenharmony_ci } 387e66f31c5Sopenharmony_ci 388e66f31c5Sopenharmony_ci uv_sem_wait(&uv_tty_output_lock); 389e66f31c5Sopenharmony_ci if (!SetConsoleMode(tty->handle, flags)) { 390e66f31c5Sopenharmony_ci err = uv_translate_sys_error(GetLastError()); 391e66f31c5Sopenharmony_ci uv_sem_post(&uv_tty_output_lock); 392e66f31c5Sopenharmony_ci return err; 393e66f31c5Sopenharmony_ci } 394e66f31c5Sopenharmony_ci uv_sem_post(&uv_tty_output_lock); 395e66f31c5Sopenharmony_ci 396e66f31c5Sopenharmony_ci /* Update flag. */ 397e66f31c5Sopenharmony_ci tty->flags &= ~UV_HANDLE_TTY_RAW; 398e66f31c5Sopenharmony_ci tty->flags |= mode ? UV_HANDLE_TTY_RAW : 0; 399e66f31c5Sopenharmony_ci 400e66f31c5Sopenharmony_ci /* If we just stopped reading, restart. */ 401e66f31c5Sopenharmony_ci if (was_reading) { 402e66f31c5Sopenharmony_ci err = uv__tty_read_start(tty, alloc_cb, read_cb); 403e66f31c5Sopenharmony_ci if (err) { 404e66f31c5Sopenharmony_ci return uv_translate_sys_error(err); 405e66f31c5Sopenharmony_ci } 406e66f31c5Sopenharmony_ci } 407e66f31c5Sopenharmony_ci 408e66f31c5Sopenharmony_ci return 0; 409e66f31c5Sopenharmony_ci} 410e66f31c5Sopenharmony_ci 411e66f31c5Sopenharmony_ci 412e66f31c5Sopenharmony_ciint uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) { 413e66f31c5Sopenharmony_ci CONSOLE_SCREEN_BUFFER_INFO info; 414e66f31c5Sopenharmony_ci 415e66f31c5Sopenharmony_ci if (!GetConsoleScreenBufferInfo(tty->handle, &info)) { 416e66f31c5Sopenharmony_ci return uv_translate_sys_error(GetLastError()); 417e66f31c5Sopenharmony_ci } 418e66f31c5Sopenharmony_ci 419e66f31c5Sopenharmony_ci uv_sem_wait(&uv_tty_output_lock); 420e66f31c5Sopenharmony_ci uv__tty_update_virtual_window(&info); 421e66f31c5Sopenharmony_ci uv_sem_post(&uv_tty_output_lock); 422e66f31c5Sopenharmony_ci 423e66f31c5Sopenharmony_ci *width = uv_tty_virtual_width; 424e66f31c5Sopenharmony_ci *height = uv_tty_virtual_height; 425e66f31c5Sopenharmony_ci 426e66f31c5Sopenharmony_ci return 0; 427e66f31c5Sopenharmony_ci} 428e66f31c5Sopenharmony_ci 429e66f31c5Sopenharmony_ci 430e66f31c5Sopenharmony_cistatic void CALLBACK uv_tty_post_raw_read(void* data, BOOLEAN didTimeout) { 431e66f31c5Sopenharmony_ci uv_loop_t* loop; 432e66f31c5Sopenharmony_ci uv_tty_t* handle; 433e66f31c5Sopenharmony_ci uv_req_t* req; 434e66f31c5Sopenharmony_ci 435e66f31c5Sopenharmony_ci assert(data); 436e66f31c5Sopenharmony_ci assert(!didTimeout); 437e66f31c5Sopenharmony_ci 438e66f31c5Sopenharmony_ci req = (uv_req_t*) data; 439e66f31c5Sopenharmony_ci handle = (uv_tty_t*) req->data; 440e66f31c5Sopenharmony_ci loop = handle->loop; 441e66f31c5Sopenharmony_ci 442e66f31c5Sopenharmony_ci UnregisterWait(handle->tty.rd.read_raw_wait); 443e66f31c5Sopenharmony_ci handle->tty.rd.read_raw_wait = NULL; 444e66f31c5Sopenharmony_ci 445e66f31c5Sopenharmony_ci SET_REQ_SUCCESS(req); 446e66f31c5Sopenharmony_ci POST_COMPLETION_FOR_REQ(loop, req); 447e66f31c5Sopenharmony_ci} 448e66f31c5Sopenharmony_ci 449e66f31c5Sopenharmony_ci 450e66f31c5Sopenharmony_cistatic void uv__tty_queue_read_raw(uv_loop_t* loop, uv_tty_t* handle) { 451e66f31c5Sopenharmony_ci uv_read_t* req; 452e66f31c5Sopenharmony_ci BOOL r; 453e66f31c5Sopenharmony_ci 454e66f31c5Sopenharmony_ci assert(handle->flags & UV_HANDLE_READING); 455e66f31c5Sopenharmony_ci assert(!(handle->flags & UV_HANDLE_READ_PENDING)); 456e66f31c5Sopenharmony_ci 457e66f31c5Sopenharmony_ci assert(handle->handle && handle->handle != INVALID_HANDLE_VALUE); 458e66f31c5Sopenharmony_ci 459e66f31c5Sopenharmony_ci handle->tty.rd.read_line_buffer = uv_null_buf_; 460e66f31c5Sopenharmony_ci 461e66f31c5Sopenharmony_ci req = &handle->read_req; 462e66f31c5Sopenharmony_ci memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); 463e66f31c5Sopenharmony_ci 464e66f31c5Sopenharmony_ci r = RegisterWaitForSingleObject(&handle->tty.rd.read_raw_wait, 465e66f31c5Sopenharmony_ci handle->handle, 466e66f31c5Sopenharmony_ci uv_tty_post_raw_read, 467e66f31c5Sopenharmony_ci (void*) req, 468e66f31c5Sopenharmony_ci INFINITE, 469e66f31c5Sopenharmony_ci WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE); 470e66f31c5Sopenharmony_ci if (!r) { 471e66f31c5Sopenharmony_ci handle->tty.rd.read_raw_wait = NULL; 472e66f31c5Sopenharmony_ci SET_REQ_ERROR(req, GetLastError()); 473e66f31c5Sopenharmony_ci uv__insert_pending_req(loop, (uv_req_t*)req); 474e66f31c5Sopenharmony_ci } 475e66f31c5Sopenharmony_ci 476e66f31c5Sopenharmony_ci handle->flags |= UV_HANDLE_READ_PENDING; 477e66f31c5Sopenharmony_ci handle->reqs_pending++; 478e66f31c5Sopenharmony_ci} 479e66f31c5Sopenharmony_ci 480e66f31c5Sopenharmony_ci 481e66f31c5Sopenharmony_cistatic DWORD CALLBACK uv_tty_line_read_thread(void* data) { 482e66f31c5Sopenharmony_ci uv_loop_t* loop; 483e66f31c5Sopenharmony_ci uv_tty_t* handle; 484e66f31c5Sopenharmony_ci uv_req_t* req; 485e66f31c5Sopenharmony_ci DWORD bytes; 486e66f31c5Sopenharmony_ci size_t read_bytes; 487e66f31c5Sopenharmony_ci WCHAR utf16[MAX_INPUT_BUFFER_LENGTH / 3]; 488e66f31c5Sopenharmony_ci DWORD chars; 489e66f31c5Sopenharmony_ci DWORD read_chars; 490e66f31c5Sopenharmony_ci LONG status; 491e66f31c5Sopenharmony_ci COORD pos; 492e66f31c5Sopenharmony_ci BOOL read_console_success; 493e66f31c5Sopenharmony_ci 494e66f31c5Sopenharmony_ci assert(data); 495e66f31c5Sopenharmony_ci 496e66f31c5Sopenharmony_ci req = (uv_req_t*) data; 497e66f31c5Sopenharmony_ci handle = (uv_tty_t*) req->data; 498e66f31c5Sopenharmony_ci loop = handle->loop; 499e66f31c5Sopenharmony_ci 500e66f31c5Sopenharmony_ci assert(handle->tty.rd.read_line_buffer.base != NULL); 501e66f31c5Sopenharmony_ci assert(handle->tty.rd.read_line_buffer.len > 0); 502e66f31c5Sopenharmony_ci 503e66f31c5Sopenharmony_ci /* ReadConsole can't handle big buffers. */ 504e66f31c5Sopenharmony_ci if (handle->tty.rd.read_line_buffer.len < MAX_INPUT_BUFFER_LENGTH) { 505e66f31c5Sopenharmony_ci bytes = handle->tty.rd.read_line_buffer.len; 506e66f31c5Sopenharmony_ci } else { 507e66f31c5Sopenharmony_ci bytes = MAX_INPUT_BUFFER_LENGTH; 508e66f31c5Sopenharmony_ci } 509e66f31c5Sopenharmony_ci 510e66f31c5Sopenharmony_ci /* At last, unicode! One utf-16 codeunit never takes more than 3 utf-8 511e66f31c5Sopenharmony_ci * codeunits to encode. */ 512e66f31c5Sopenharmony_ci chars = bytes / 3; 513e66f31c5Sopenharmony_ci 514e66f31c5Sopenharmony_ci status = InterlockedExchange(&uv__read_console_status, IN_PROGRESS); 515e66f31c5Sopenharmony_ci if (status == TRAP_REQUESTED) { 516e66f31c5Sopenharmony_ci SET_REQ_SUCCESS(req); 517e66f31c5Sopenharmony_ci InterlockedExchange(&uv__read_console_status, COMPLETED); 518e66f31c5Sopenharmony_ci req->u.io.overlapped.InternalHigh = 0; 519e66f31c5Sopenharmony_ci POST_COMPLETION_FOR_REQ(loop, req); 520e66f31c5Sopenharmony_ci return 0; 521e66f31c5Sopenharmony_ci } 522e66f31c5Sopenharmony_ci 523e66f31c5Sopenharmony_ci read_console_success = ReadConsoleW(handle->handle, 524e66f31c5Sopenharmony_ci (void*) utf16, 525e66f31c5Sopenharmony_ci chars, 526e66f31c5Sopenharmony_ci &read_chars, 527e66f31c5Sopenharmony_ci NULL); 528e66f31c5Sopenharmony_ci 529e66f31c5Sopenharmony_ci if (read_console_success) { 530e66f31c5Sopenharmony_ci read_bytes = bytes; 531e66f31c5Sopenharmony_ci uv_utf16_to_wtf8(utf16, 532e66f31c5Sopenharmony_ci read_chars, 533e66f31c5Sopenharmony_ci &handle->tty.rd.read_line_buffer.base, 534e66f31c5Sopenharmony_ci &read_bytes); 535e66f31c5Sopenharmony_ci SET_REQ_SUCCESS(req); 536e66f31c5Sopenharmony_ci req->u.io.overlapped.InternalHigh = (DWORD) read_bytes; 537e66f31c5Sopenharmony_ci } else { 538e66f31c5Sopenharmony_ci SET_REQ_ERROR(req, GetLastError()); 539e66f31c5Sopenharmony_ci } 540e66f31c5Sopenharmony_ci 541e66f31c5Sopenharmony_ci status = InterlockedExchange(&uv__read_console_status, COMPLETED); 542e66f31c5Sopenharmony_ci 543e66f31c5Sopenharmony_ci if (status == TRAP_REQUESTED) { 544e66f31c5Sopenharmony_ci /* If we canceled the read by sending a VK_RETURN event, restore the 545e66f31c5Sopenharmony_ci screen state to undo the visual effect of the VK_RETURN */ 546e66f31c5Sopenharmony_ci if (read_console_success && InterlockedOr(&uv__restore_screen_state, 0)) { 547e66f31c5Sopenharmony_ci HANDLE active_screen_buffer; 548e66f31c5Sopenharmony_ci active_screen_buffer = CreateFileA("conout$", 549e66f31c5Sopenharmony_ci GENERIC_READ | GENERIC_WRITE, 550e66f31c5Sopenharmony_ci FILE_SHARE_READ | FILE_SHARE_WRITE, 551e66f31c5Sopenharmony_ci NULL, 552e66f31c5Sopenharmony_ci OPEN_EXISTING, 553e66f31c5Sopenharmony_ci FILE_ATTRIBUTE_NORMAL, 554e66f31c5Sopenharmony_ci NULL); 555e66f31c5Sopenharmony_ci if (active_screen_buffer != INVALID_HANDLE_VALUE) { 556e66f31c5Sopenharmony_ci pos = uv__saved_screen_state.dwCursorPosition; 557e66f31c5Sopenharmony_ci 558e66f31c5Sopenharmony_ci /* If the cursor was at the bottom line of the screen buffer, the 559e66f31c5Sopenharmony_ci VK_RETURN would have caused the buffer contents to scroll up by one 560e66f31c5Sopenharmony_ci line. The right position to reset the cursor to is therefore one line 561e66f31c5Sopenharmony_ci higher */ 562e66f31c5Sopenharmony_ci if (pos.Y == uv__saved_screen_state.dwSize.Y - 1) 563e66f31c5Sopenharmony_ci pos.Y--; 564e66f31c5Sopenharmony_ci 565e66f31c5Sopenharmony_ci SetConsoleCursorPosition(active_screen_buffer, pos); 566e66f31c5Sopenharmony_ci CloseHandle(active_screen_buffer); 567e66f31c5Sopenharmony_ci } 568e66f31c5Sopenharmony_ci } 569e66f31c5Sopenharmony_ci uv_sem_post(&uv_tty_output_lock); 570e66f31c5Sopenharmony_ci } 571e66f31c5Sopenharmony_ci POST_COMPLETION_FOR_REQ(loop, req); 572e66f31c5Sopenharmony_ci return 0; 573e66f31c5Sopenharmony_ci} 574e66f31c5Sopenharmony_ci 575e66f31c5Sopenharmony_ci 576e66f31c5Sopenharmony_cistatic void uv__tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) { 577e66f31c5Sopenharmony_ci uv_read_t* req; 578e66f31c5Sopenharmony_ci BOOL r; 579e66f31c5Sopenharmony_ci 580e66f31c5Sopenharmony_ci assert(handle->flags & UV_HANDLE_READING); 581e66f31c5Sopenharmony_ci assert(!(handle->flags & UV_HANDLE_READ_PENDING)); 582e66f31c5Sopenharmony_ci assert(handle->handle && handle->handle != INVALID_HANDLE_VALUE); 583e66f31c5Sopenharmony_ci 584e66f31c5Sopenharmony_ci req = &handle->read_req; 585e66f31c5Sopenharmony_ci memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); 586e66f31c5Sopenharmony_ci 587e66f31c5Sopenharmony_ci handle->tty.rd.read_line_buffer = uv_buf_init(NULL, 0); 588e66f31c5Sopenharmony_ci handle->alloc_cb((uv_handle_t*) handle, 8192, &handle->tty.rd.read_line_buffer); 589e66f31c5Sopenharmony_ci if (handle->tty.rd.read_line_buffer.base == NULL || 590e66f31c5Sopenharmony_ci handle->tty.rd.read_line_buffer.len == 0) { 591e66f31c5Sopenharmony_ci handle->read_cb((uv_stream_t*) handle, 592e66f31c5Sopenharmony_ci UV_ENOBUFS, 593e66f31c5Sopenharmony_ci &handle->tty.rd.read_line_buffer); 594e66f31c5Sopenharmony_ci return; 595e66f31c5Sopenharmony_ci } 596e66f31c5Sopenharmony_ci assert(handle->tty.rd.read_line_buffer.base != NULL); 597e66f31c5Sopenharmony_ci 598e66f31c5Sopenharmony_ci /* Reset flags No locking is required since there cannot be a line read 599e66f31c5Sopenharmony_ci in progress. We are also relying on the memory barrier provided by 600e66f31c5Sopenharmony_ci QueueUserWorkItem*/ 601e66f31c5Sopenharmony_ci uv__restore_screen_state = FALSE; 602e66f31c5Sopenharmony_ci uv__read_console_status = NOT_STARTED; 603e66f31c5Sopenharmony_ci r = QueueUserWorkItem(uv_tty_line_read_thread, 604e66f31c5Sopenharmony_ci (void*) req, 605e66f31c5Sopenharmony_ci WT_EXECUTELONGFUNCTION); 606e66f31c5Sopenharmony_ci if (!r) { 607e66f31c5Sopenharmony_ci SET_REQ_ERROR(req, GetLastError()); 608e66f31c5Sopenharmony_ci uv__insert_pending_req(loop, (uv_req_t*)req); 609e66f31c5Sopenharmony_ci } 610e66f31c5Sopenharmony_ci 611e66f31c5Sopenharmony_ci handle->flags |= UV_HANDLE_READ_PENDING; 612e66f31c5Sopenharmony_ci handle->reqs_pending++; 613e66f31c5Sopenharmony_ci} 614e66f31c5Sopenharmony_ci 615e66f31c5Sopenharmony_ci 616e66f31c5Sopenharmony_cistatic void uv__tty_queue_read(uv_loop_t* loop, uv_tty_t* handle) { 617e66f31c5Sopenharmony_ci if (handle->flags & UV_HANDLE_TTY_RAW) { 618e66f31c5Sopenharmony_ci uv__tty_queue_read_raw(loop, handle); 619e66f31c5Sopenharmony_ci } else { 620e66f31c5Sopenharmony_ci uv__tty_queue_read_line(loop, handle); 621e66f31c5Sopenharmony_ci } 622e66f31c5Sopenharmony_ci} 623e66f31c5Sopenharmony_ci 624e66f31c5Sopenharmony_ci 625e66f31c5Sopenharmony_cistatic const char* get_vt100_fn_key(DWORD code, char shift, char ctrl, 626e66f31c5Sopenharmony_ci size_t* len) { 627e66f31c5Sopenharmony_ci#define VK_CASE(vk, normal_str, shift_str, ctrl_str, shift_ctrl_str) \ 628e66f31c5Sopenharmony_ci case (vk): \ 629e66f31c5Sopenharmony_ci if (shift && ctrl) { \ 630e66f31c5Sopenharmony_ci *len = sizeof shift_ctrl_str; \ 631e66f31c5Sopenharmony_ci return "\033" shift_ctrl_str; \ 632e66f31c5Sopenharmony_ci } else if (shift) { \ 633e66f31c5Sopenharmony_ci *len = sizeof shift_str ; \ 634e66f31c5Sopenharmony_ci return "\033" shift_str; \ 635e66f31c5Sopenharmony_ci } else if (ctrl) { \ 636e66f31c5Sopenharmony_ci *len = sizeof ctrl_str; \ 637e66f31c5Sopenharmony_ci return "\033" ctrl_str; \ 638e66f31c5Sopenharmony_ci } else { \ 639e66f31c5Sopenharmony_ci *len = sizeof normal_str; \ 640e66f31c5Sopenharmony_ci return "\033" normal_str; \ 641e66f31c5Sopenharmony_ci } 642e66f31c5Sopenharmony_ci 643e66f31c5Sopenharmony_ci switch (code) { 644e66f31c5Sopenharmony_ci /* These mappings are the same as Cygwin's. Unmodified and alt-modified 645e66f31c5Sopenharmony_ci * keypad keys comply with linux console, modifiers comply with xterm 646e66f31c5Sopenharmony_ci * modifier usage. F1. f12 and shift-f1. f10 comply with linux console, f6. 647e66f31c5Sopenharmony_ci * f12 with and without modifiers comply with rxvt. */ 648e66f31c5Sopenharmony_ci VK_CASE(VK_INSERT, "[2~", "[2;2~", "[2;5~", "[2;6~") 649e66f31c5Sopenharmony_ci VK_CASE(VK_END, "[4~", "[4;2~", "[4;5~", "[4;6~") 650e66f31c5Sopenharmony_ci VK_CASE(VK_DOWN, "[B", "[1;2B", "[1;5B", "[1;6B") 651e66f31c5Sopenharmony_ci VK_CASE(VK_NEXT, "[6~", "[6;2~", "[6;5~", "[6;6~") 652e66f31c5Sopenharmony_ci VK_CASE(VK_LEFT, "[D", "[1;2D", "[1;5D", "[1;6D") 653e66f31c5Sopenharmony_ci VK_CASE(VK_CLEAR, "[G", "[1;2G", "[1;5G", "[1;6G") 654e66f31c5Sopenharmony_ci VK_CASE(VK_RIGHT, "[C", "[1;2C", "[1;5C", "[1;6C") 655e66f31c5Sopenharmony_ci VK_CASE(VK_UP, "[A", "[1;2A", "[1;5A", "[1;6A") 656e66f31c5Sopenharmony_ci VK_CASE(VK_HOME, "[1~", "[1;2~", "[1;5~", "[1;6~") 657e66f31c5Sopenharmony_ci VK_CASE(VK_PRIOR, "[5~", "[5;2~", "[5;5~", "[5;6~") 658e66f31c5Sopenharmony_ci VK_CASE(VK_DELETE, "[3~", "[3;2~", "[3;5~", "[3;6~") 659e66f31c5Sopenharmony_ci VK_CASE(VK_NUMPAD0, "[2~", "[2;2~", "[2;5~", "[2;6~") 660e66f31c5Sopenharmony_ci VK_CASE(VK_NUMPAD1, "[4~", "[4;2~", "[4;5~", "[4;6~") 661e66f31c5Sopenharmony_ci VK_CASE(VK_NUMPAD2, "[B", "[1;2B", "[1;5B", "[1;6B") 662e66f31c5Sopenharmony_ci VK_CASE(VK_NUMPAD3, "[6~", "[6;2~", "[6;5~", "[6;6~") 663e66f31c5Sopenharmony_ci VK_CASE(VK_NUMPAD4, "[D", "[1;2D", "[1;5D", "[1;6D") 664e66f31c5Sopenharmony_ci VK_CASE(VK_NUMPAD5, "[G", "[1;2G", "[1;5G", "[1;6G") 665e66f31c5Sopenharmony_ci VK_CASE(VK_NUMPAD6, "[C", "[1;2C", "[1;5C", "[1;6C") 666e66f31c5Sopenharmony_ci VK_CASE(VK_NUMPAD7, "[A", "[1;2A", "[1;5A", "[1;6A") 667e66f31c5Sopenharmony_ci VK_CASE(VK_NUMPAD8, "[1~", "[1;2~", "[1;5~", "[1;6~") 668e66f31c5Sopenharmony_ci VK_CASE(VK_NUMPAD9, "[5~", "[5;2~", "[5;5~", "[5;6~") 669e66f31c5Sopenharmony_ci VK_CASE(VK_DECIMAL, "[3~", "[3;2~", "[3;5~", "[3;6~") 670e66f31c5Sopenharmony_ci VK_CASE(VK_F1, "[[A", "[23~", "[11^", "[23^" ) 671e66f31c5Sopenharmony_ci VK_CASE(VK_F2, "[[B", "[24~", "[12^", "[24^" ) 672e66f31c5Sopenharmony_ci VK_CASE(VK_F3, "[[C", "[25~", "[13^", "[25^" ) 673e66f31c5Sopenharmony_ci VK_CASE(VK_F4, "[[D", "[26~", "[14^", "[26^" ) 674e66f31c5Sopenharmony_ci VK_CASE(VK_F5, "[[E", "[28~", "[15^", "[28^" ) 675e66f31c5Sopenharmony_ci VK_CASE(VK_F6, "[17~", "[29~", "[17^", "[29^" ) 676e66f31c5Sopenharmony_ci VK_CASE(VK_F7, "[18~", "[31~", "[18^", "[31^" ) 677e66f31c5Sopenharmony_ci VK_CASE(VK_F8, "[19~", "[32~", "[19^", "[32^" ) 678e66f31c5Sopenharmony_ci VK_CASE(VK_F9, "[20~", "[33~", "[20^", "[33^" ) 679e66f31c5Sopenharmony_ci VK_CASE(VK_F10, "[21~", "[34~", "[21^", "[34^" ) 680e66f31c5Sopenharmony_ci VK_CASE(VK_F11, "[23~", "[23$", "[23^", "[23@" ) 681e66f31c5Sopenharmony_ci VK_CASE(VK_F12, "[24~", "[24$", "[24^", "[24@" ) 682e66f31c5Sopenharmony_ci 683e66f31c5Sopenharmony_ci default: 684e66f31c5Sopenharmony_ci *len = 0; 685e66f31c5Sopenharmony_ci return NULL; 686e66f31c5Sopenharmony_ci } 687e66f31c5Sopenharmony_ci#undef VK_CASE 688e66f31c5Sopenharmony_ci} 689e66f31c5Sopenharmony_ci 690e66f31c5Sopenharmony_ci 691e66f31c5Sopenharmony_civoid uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, 692e66f31c5Sopenharmony_ci uv_req_t* req) { 693e66f31c5Sopenharmony_ci /* Shortcut for handle->tty.rd.last_input_record.Event.KeyEvent. */ 694e66f31c5Sopenharmony_ci#define KEV handle->tty.rd.last_input_record.Event.KeyEvent 695e66f31c5Sopenharmony_ci 696e66f31c5Sopenharmony_ci DWORD records_left, records_read; 697e66f31c5Sopenharmony_ci uv_buf_t buf; 698e66f31c5Sopenharmony_ci _off_t buf_used; 699e66f31c5Sopenharmony_ci 700e66f31c5Sopenharmony_ci assert(handle->type == UV_TTY); 701e66f31c5Sopenharmony_ci assert(handle->flags & UV_HANDLE_TTY_READABLE); 702e66f31c5Sopenharmony_ci handle->flags &= ~UV_HANDLE_READ_PENDING; 703e66f31c5Sopenharmony_ci 704e66f31c5Sopenharmony_ci if (!(handle->flags & UV_HANDLE_READING) || 705e66f31c5Sopenharmony_ci !(handle->flags & UV_HANDLE_TTY_RAW)) { 706e66f31c5Sopenharmony_ci goto out; 707e66f31c5Sopenharmony_ci } 708e66f31c5Sopenharmony_ci 709e66f31c5Sopenharmony_ci if (!REQ_SUCCESS(req)) { 710e66f31c5Sopenharmony_ci /* An error occurred while waiting for the event. */ 711e66f31c5Sopenharmony_ci if ((handle->flags & UV_HANDLE_READING)) { 712e66f31c5Sopenharmony_ci handle->flags &= ~UV_HANDLE_READING; 713e66f31c5Sopenharmony_ci handle->read_cb((uv_stream_t*)handle, 714e66f31c5Sopenharmony_ci uv_translate_sys_error(GET_REQ_ERROR(req)), 715e66f31c5Sopenharmony_ci &uv_null_buf_); 716e66f31c5Sopenharmony_ci } 717e66f31c5Sopenharmony_ci goto out; 718e66f31c5Sopenharmony_ci } 719e66f31c5Sopenharmony_ci 720e66f31c5Sopenharmony_ci /* Fetch the number of events */ 721e66f31c5Sopenharmony_ci if (!GetNumberOfConsoleInputEvents(handle->handle, &records_left)) { 722e66f31c5Sopenharmony_ci handle->flags &= ~UV_HANDLE_READING; 723e66f31c5Sopenharmony_ci DECREASE_ACTIVE_COUNT(loop, handle); 724e66f31c5Sopenharmony_ci handle->read_cb((uv_stream_t*)handle, 725e66f31c5Sopenharmony_ci uv_translate_sys_error(GetLastError()), 726e66f31c5Sopenharmony_ci &uv_null_buf_); 727e66f31c5Sopenharmony_ci goto out; 728e66f31c5Sopenharmony_ci } 729e66f31c5Sopenharmony_ci 730e66f31c5Sopenharmony_ci /* Windows sends a lot of events that we're not interested in, so buf will be 731e66f31c5Sopenharmony_ci * allocated on demand, when there's actually something to emit. */ 732e66f31c5Sopenharmony_ci buf = uv_null_buf_; 733e66f31c5Sopenharmony_ci buf_used = 0; 734e66f31c5Sopenharmony_ci 735e66f31c5Sopenharmony_ci while ((records_left > 0 || handle->tty.rd.last_key_len > 0) && 736e66f31c5Sopenharmony_ci (handle->flags & UV_HANDLE_READING)) { 737e66f31c5Sopenharmony_ci if (handle->tty.rd.last_key_len == 0) { 738e66f31c5Sopenharmony_ci /* Read the next input record */ 739e66f31c5Sopenharmony_ci if (!ReadConsoleInputW(handle->handle, 740e66f31c5Sopenharmony_ci &handle->tty.rd.last_input_record, 741e66f31c5Sopenharmony_ci 1, 742e66f31c5Sopenharmony_ci &records_read)) { 743e66f31c5Sopenharmony_ci handle->flags &= ~UV_HANDLE_READING; 744e66f31c5Sopenharmony_ci DECREASE_ACTIVE_COUNT(loop, handle); 745e66f31c5Sopenharmony_ci handle->read_cb((uv_stream_t*) handle, 746e66f31c5Sopenharmony_ci uv_translate_sys_error(GetLastError()), 747e66f31c5Sopenharmony_ci &buf); 748e66f31c5Sopenharmony_ci goto out; 749e66f31c5Sopenharmony_ci } 750e66f31c5Sopenharmony_ci records_left--; 751e66f31c5Sopenharmony_ci 752e66f31c5Sopenharmony_ci /* We might be not subscribed to EVENT_CONSOLE_LAYOUT or we might be 753e66f31c5Sopenharmony_ci * running under some TTY emulator that does not send those events. */ 754e66f31c5Sopenharmony_ci if (handle->tty.rd.last_input_record.EventType == WINDOW_BUFFER_SIZE_EVENT) { 755e66f31c5Sopenharmony_ci uv__tty_console_signal_resize(); 756e66f31c5Sopenharmony_ci } 757e66f31c5Sopenharmony_ci 758e66f31c5Sopenharmony_ci /* Ignore other events that are not key events. */ 759e66f31c5Sopenharmony_ci if (handle->tty.rd.last_input_record.EventType != KEY_EVENT) { 760e66f31c5Sopenharmony_ci continue; 761e66f31c5Sopenharmony_ci } 762e66f31c5Sopenharmony_ci 763e66f31c5Sopenharmony_ci /* Ignore keyup events, unless the left alt key was held and a valid 764e66f31c5Sopenharmony_ci * unicode character was emitted. */ 765e66f31c5Sopenharmony_ci if (!KEV.bKeyDown && 766e66f31c5Sopenharmony_ci (KEV.wVirtualKeyCode != VK_MENU || 767e66f31c5Sopenharmony_ci KEV.uChar.UnicodeChar == 0)) { 768e66f31c5Sopenharmony_ci continue; 769e66f31c5Sopenharmony_ci } 770e66f31c5Sopenharmony_ci 771e66f31c5Sopenharmony_ci /* Ignore keypresses to numpad number keys if the left alt is held 772e66f31c5Sopenharmony_ci * because the user is composing a character, or windows simulating this. 773e66f31c5Sopenharmony_ci */ 774e66f31c5Sopenharmony_ci if ((KEV.dwControlKeyState & LEFT_ALT_PRESSED) && 775e66f31c5Sopenharmony_ci !(KEV.dwControlKeyState & ENHANCED_KEY) && 776e66f31c5Sopenharmony_ci (KEV.wVirtualKeyCode == VK_INSERT || 777e66f31c5Sopenharmony_ci KEV.wVirtualKeyCode == VK_END || 778e66f31c5Sopenharmony_ci KEV.wVirtualKeyCode == VK_DOWN || 779e66f31c5Sopenharmony_ci KEV.wVirtualKeyCode == VK_NEXT || 780e66f31c5Sopenharmony_ci KEV.wVirtualKeyCode == VK_LEFT || 781e66f31c5Sopenharmony_ci KEV.wVirtualKeyCode == VK_CLEAR || 782e66f31c5Sopenharmony_ci KEV.wVirtualKeyCode == VK_RIGHT || 783e66f31c5Sopenharmony_ci KEV.wVirtualKeyCode == VK_HOME || 784e66f31c5Sopenharmony_ci KEV.wVirtualKeyCode == VK_UP || 785e66f31c5Sopenharmony_ci KEV.wVirtualKeyCode == VK_PRIOR || 786e66f31c5Sopenharmony_ci KEV.wVirtualKeyCode == VK_NUMPAD0 || 787e66f31c5Sopenharmony_ci KEV.wVirtualKeyCode == VK_NUMPAD1 || 788e66f31c5Sopenharmony_ci KEV.wVirtualKeyCode == VK_NUMPAD2 || 789e66f31c5Sopenharmony_ci KEV.wVirtualKeyCode == VK_NUMPAD3 || 790e66f31c5Sopenharmony_ci KEV.wVirtualKeyCode == VK_NUMPAD4 || 791e66f31c5Sopenharmony_ci KEV.wVirtualKeyCode == VK_NUMPAD5 || 792e66f31c5Sopenharmony_ci KEV.wVirtualKeyCode == VK_NUMPAD6 || 793e66f31c5Sopenharmony_ci KEV.wVirtualKeyCode == VK_NUMPAD7 || 794e66f31c5Sopenharmony_ci KEV.wVirtualKeyCode == VK_NUMPAD8 || 795e66f31c5Sopenharmony_ci KEV.wVirtualKeyCode == VK_NUMPAD9)) { 796e66f31c5Sopenharmony_ci continue; 797e66f31c5Sopenharmony_ci } 798e66f31c5Sopenharmony_ci 799e66f31c5Sopenharmony_ci if (KEV.uChar.UnicodeChar != 0) { 800e66f31c5Sopenharmony_ci int prefix_len; 801e66f31c5Sopenharmony_ci size_t char_len; 802e66f31c5Sopenharmony_ci char* last_key_buf; 803e66f31c5Sopenharmony_ci 804e66f31c5Sopenharmony_ci /* Character key pressed */ 805e66f31c5Sopenharmony_ci if (KEV.uChar.UnicodeChar >= 0xD800 && 806e66f31c5Sopenharmony_ci KEV.uChar.UnicodeChar < 0xDC00) { 807e66f31c5Sopenharmony_ci /* UTF-16 high surrogate */ 808e66f31c5Sopenharmony_ci handle->tty.rd.last_utf16_high_surrogate = KEV.uChar.UnicodeChar; 809e66f31c5Sopenharmony_ci continue; 810e66f31c5Sopenharmony_ci } 811e66f31c5Sopenharmony_ci 812e66f31c5Sopenharmony_ci /* Prefix with \u033 if alt was held, but alt was not used as part a 813e66f31c5Sopenharmony_ci * compose sequence. */ 814e66f31c5Sopenharmony_ci if ((KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) 815e66f31c5Sopenharmony_ci && !(KEV.dwControlKeyState & (LEFT_CTRL_PRESSED | 816e66f31c5Sopenharmony_ci RIGHT_CTRL_PRESSED)) && KEV.bKeyDown) { 817e66f31c5Sopenharmony_ci handle->tty.rd.last_key[0] = '\033'; 818e66f31c5Sopenharmony_ci prefix_len = 1; 819e66f31c5Sopenharmony_ci } else { 820e66f31c5Sopenharmony_ci prefix_len = 0; 821e66f31c5Sopenharmony_ci } 822e66f31c5Sopenharmony_ci 823e66f31c5Sopenharmony_ci char_len = sizeof handle->tty.rd.last_key; 824e66f31c5Sopenharmony_ci last_key_buf = &handle->tty.rd.last_key[prefix_len]; 825e66f31c5Sopenharmony_ci if (handle->tty.rd.last_utf16_high_surrogate) { 826e66f31c5Sopenharmony_ci /* UTF-16 surrogate pair */ 827e66f31c5Sopenharmony_ci WCHAR utf16_buffer[2]; 828e66f31c5Sopenharmony_ci utf16_buffer[0] = handle->tty.rd.last_utf16_high_surrogate; 829e66f31c5Sopenharmony_ci utf16_buffer[1] = KEV.uChar.UnicodeChar; 830e66f31c5Sopenharmony_ci if (uv_utf16_to_wtf8(utf16_buffer, 831e66f31c5Sopenharmony_ci 2, 832e66f31c5Sopenharmony_ci &last_key_buf, 833e66f31c5Sopenharmony_ci &char_len)) 834e66f31c5Sopenharmony_ci char_len = 0; 835e66f31c5Sopenharmony_ci handle->tty.rd.last_utf16_high_surrogate = 0; 836e66f31c5Sopenharmony_ci } else { 837e66f31c5Sopenharmony_ci /* Single UTF-16 character */ 838e66f31c5Sopenharmony_ci if (uv_utf16_to_wtf8(&KEV.uChar.UnicodeChar, 839e66f31c5Sopenharmony_ci 1, 840e66f31c5Sopenharmony_ci &last_key_buf, 841e66f31c5Sopenharmony_ci &char_len)) 842e66f31c5Sopenharmony_ci char_len = 0; 843e66f31c5Sopenharmony_ci } 844e66f31c5Sopenharmony_ci 845e66f31c5Sopenharmony_ci /* If the utf16 character(s) couldn't be converted something must be 846e66f31c5Sopenharmony_ci * wrong. */ 847e66f31c5Sopenharmony_ci if (char_len == 0) { 848e66f31c5Sopenharmony_ci handle->flags &= ~UV_HANDLE_READING; 849e66f31c5Sopenharmony_ci DECREASE_ACTIVE_COUNT(loop, handle); 850e66f31c5Sopenharmony_ci handle->read_cb((uv_stream_t*) handle, 851e66f31c5Sopenharmony_ci uv_translate_sys_error(GetLastError()), 852e66f31c5Sopenharmony_ci &buf); 853e66f31c5Sopenharmony_ci goto out; 854e66f31c5Sopenharmony_ci } 855e66f31c5Sopenharmony_ci 856e66f31c5Sopenharmony_ci handle->tty.rd.last_key_len = (unsigned char) (prefix_len + char_len); 857e66f31c5Sopenharmony_ci handle->tty.rd.last_key_offset = 0; 858e66f31c5Sopenharmony_ci continue; 859e66f31c5Sopenharmony_ci 860e66f31c5Sopenharmony_ci } else { 861e66f31c5Sopenharmony_ci /* Function key pressed */ 862e66f31c5Sopenharmony_ci const char* vt100; 863e66f31c5Sopenharmony_ci size_t prefix_len, vt100_len; 864e66f31c5Sopenharmony_ci 865e66f31c5Sopenharmony_ci vt100 = get_vt100_fn_key(KEV.wVirtualKeyCode, 866e66f31c5Sopenharmony_ci !!(KEV.dwControlKeyState & SHIFT_PRESSED), 867e66f31c5Sopenharmony_ci !!(KEV.dwControlKeyState & ( 868e66f31c5Sopenharmony_ci LEFT_CTRL_PRESSED | 869e66f31c5Sopenharmony_ci RIGHT_CTRL_PRESSED)), 870e66f31c5Sopenharmony_ci &vt100_len); 871e66f31c5Sopenharmony_ci 872e66f31c5Sopenharmony_ci /* If we were unable to map to a vt100 sequence, just ignore. */ 873e66f31c5Sopenharmony_ci if (!vt100) { 874e66f31c5Sopenharmony_ci continue; 875e66f31c5Sopenharmony_ci } 876e66f31c5Sopenharmony_ci 877e66f31c5Sopenharmony_ci /* Prefix with \x033 when the alt key was held. */ 878e66f31c5Sopenharmony_ci if (KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) { 879e66f31c5Sopenharmony_ci handle->tty.rd.last_key[0] = '\033'; 880e66f31c5Sopenharmony_ci prefix_len = 1; 881e66f31c5Sopenharmony_ci } else { 882e66f31c5Sopenharmony_ci prefix_len = 0; 883e66f31c5Sopenharmony_ci } 884e66f31c5Sopenharmony_ci 885e66f31c5Sopenharmony_ci /* Copy the vt100 sequence to the handle buffer. */ 886e66f31c5Sopenharmony_ci assert(prefix_len + vt100_len < sizeof handle->tty.rd.last_key); 887e66f31c5Sopenharmony_ci memcpy(&handle->tty.rd.last_key[prefix_len], vt100, vt100_len); 888e66f31c5Sopenharmony_ci 889e66f31c5Sopenharmony_ci handle->tty.rd.last_key_len = (unsigned char) (prefix_len + vt100_len); 890e66f31c5Sopenharmony_ci handle->tty.rd.last_key_offset = 0; 891e66f31c5Sopenharmony_ci continue; 892e66f31c5Sopenharmony_ci } 893e66f31c5Sopenharmony_ci } else { 894e66f31c5Sopenharmony_ci /* Copy any bytes left from the last keypress to the user buffer. */ 895e66f31c5Sopenharmony_ci if (handle->tty.rd.last_key_offset < handle->tty.rd.last_key_len) { 896e66f31c5Sopenharmony_ci /* Allocate a buffer if needed */ 897e66f31c5Sopenharmony_ci if (buf_used == 0) { 898e66f31c5Sopenharmony_ci buf = uv_buf_init(NULL, 0); 899e66f31c5Sopenharmony_ci handle->alloc_cb((uv_handle_t*) handle, 1024, &buf); 900e66f31c5Sopenharmony_ci if (buf.base == NULL || buf.len == 0) { 901e66f31c5Sopenharmony_ci handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf); 902e66f31c5Sopenharmony_ci goto out; 903e66f31c5Sopenharmony_ci } 904e66f31c5Sopenharmony_ci assert(buf.base != NULL); 905e66f31c5Sopenharmony_ci } 906e66f31c5Sopenharmony_ci 907e66f31c5Sopenharmony_ci buf.base[buf_used++] = handle->tty.rd.last_key[handle->tty.rd.last_key_offset++]; 908e66f31c5Sopenharmony_ci 909e66f31c5Sopenharmony_ci /* If the buffer is full, emit it */ 910e66f31c5Sopenharmony_ci if ((size_t) buf_used == buf.len) { 911e66f31c5Sopenharmony_ci handle->read_cb((uv_stream_t*) handle, buf_used, &buf); 912e66f31c5Sopenharmony_ci buf = uv_null_buf_; 913e66f31c5Sopenharmony_ci buf_used = 0; 914e66f31c5Sopenharmony_ci } 915e66f31c5Sopenharmony_ci 916e66f31c5Sopenharmony_ci continue; 917e66f31c5Sopenharmony_ci } 918e66f31c5Sopenharmony_ci 919e66f31c5Sopenharmony_ci /* Apply dwRepeat from the last input record. */ 920e66f31c5Sopenharmony_ci if (--KEV.wRepeatCount > 0) { 921e66f31c5Sopenharmony_ci handle->tty.rd.last_key_offset = 0; 922e66f31c5Sopenharmony_ci continue; 923e66f31c5Sopenharmony_ci } 924e66f31c5Sopenharmony_ci 925e66f31c5Sopenharmony_ci handle->tty.rd.last_key_len = 0; 926e66f31c5Sopenharmony_ci continue; 927e66f31c5Sopenharmony_ci } 928e66f31c5Sopenharmony_ci } 929e66f31c5Sopenharmony_ci 930e66f31c5Sopenharmony_ci /* Send the buffer back to the user */ 931e66f31c5Sopenharmony_ci if (buf_used > 0) { 932e66f31c5Sopenharmony_ci handle->read_cb((uv_stream_t*) handle, buf_used, &buf); 933e66f31c5Sopenharmony_ci } 934e66f31c5Sopenharmony_ci 935e66f31c5Sopenharmony_ci out: 936e66f31c5Sopenharmony_ci /* Wait for more input events. */ 937e66f31c5Sopenharmony_ci if ((handle->flags & UV_HANDLE_READING) && 938e66f31c5Sopenharmony_ci !(handle->flags & UV_HANDLE_READ_PENDING)) { 939e66f31c5Sopenharmony_ci uv__tty_queue_read(loop, handle); 940e66f31c5Sopenharmony_ci } 941e66f31c5Sopenharmony_ci 942e66f31c5Sopenharmony_ci DECREASE_PENDING_REQ_COUNT(handle); 943e66f31c5Sopenharmony_ci 944e66f31c5Sopenharmony_ci#undef KEV 945e66f31c5Sopenharmony_ci} 946e66f31c5Sopenharmony_ci 947e66f31c5Sopenharmony_ci 948e66f31c5Sopenharmony_ci 949e66f31c5Sopenharmony_civoid uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle, 950e66f31c5Sopenharmony_ci uv_req_t* req) { 951e66f31c5Sopenharmony_ci uv_buf_t buf; 952e66f31c5Sopenharmony_ci 953e66f31c5Sopenharmony_ci assert(handle->type == UV_TTY); 954e66f31c5Sopenharmony_ci assert(handle->flags & UV_HANDLE_TTY_READABLE); 955e66f31c5Sopenharmony_ci 956e66f31c5Sopenharmony_ci buf = handle->tty.rd.read_line_buffer; 957e66f31c5Sopenharmony_ci 958e66f31c5Sopenharmony_ci handle->flags &= ~UV_HANDLE_READ_PENDING; 959e66f31c5Sopenharmony_ci handle->tty.rd.read_line_buffer = uv_null_buf_; 960e66f31c5Sopenharmony_ci 961e66f31c5Sopenharmony_ci if (!REQ_SUCCESS(req)) { 962e66f31c5Sopenharmony_ci /* Read was not successful */ 963e66f31c5Sopenharmony_ci if (handle->flags & UV_HANDLE_READING) { 964e66f31c5Sopenharmony_ci /* Real error */ 965e66f31c5Sopenharmony_ci handle->flags &= ~UV_HANDLE_READING; 966e66f31c5Sopenharmony_ci DECREASE_ACTIVE_COUNT(loop, handle); 967e66f31c5Sopenharmony_ci handle->read_cb((uv_stream_t*) handle, 968e66f31c5Sopenharmony_ci uv_translate_sys_error(GET_REQ_ERROR(req)), 969e66f31c5Sopenharmony_ci &buf); 970e66f31c5Sopenharmony_ci } 971e66f31c5Sopenharmony_ci } else { 972e66f31c5Sopenharmony_ci if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING) && 973e66f31c5Sopenharmony_ci req->u.io.overlapped.InternalHigh != 0) { 974e66f31c5Sopenharmony_ci /* Read successful. TODO: read unicode, convert to utf-8 */ 975e66f31c5Sopenharmony_ci DWORD bytes = req->u.io.overlapped.InternalHigh; 976e66f31c5Sopenharmony_ci handle->read_cb((uv_stream_t*) handle, bytes, &buf); 977e66f31c5Sopenharmony_ci } 978e66f31c5Sopenharmony_ci handle->flags &= ~UV_HANDLE_CANCELLATION_PENDING; 979e66f31c5Sopenharmony_ci } 980e66f31c5Sopenharmony_ci 981e66f31c5Sopenharmony_ci /* Wait for more input events. */ 982e66f31c5Sopenharmony_ci if ((handle->flags & UV_HANDLE_READING) && 983e66f31c5Sopenharmony_ci !(handle->flags & UV_HANDLE_READ_PENDING)) { 984e66f31c5Sopenharmony_ci uv__tty_queue_read(loop, handle); 985e66f31c5Sopenharmony_ci } 986e66f31c5Sopenharmony_ci 987e66f31c5Sopenharmony_ci DECREASE_PENDING_REQ_COUNT(handle); 988e66f31c5Sopenharmony_ci} 989e66f31c5Sopenharmony_ci 990e66f31c5Sopenharmony_ci 991e66f31c5Sopenharmony_civoid uv__process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle, 992e66f31c5Sopenharmony_ci uv_req_t* req) { 993e66f31c5Sopenharmony_ci assert(handle->type == UV_TTY); 994e66f31c5Sopenharmony_ci assert(handle->flags & UV_HANDLE_TTY_READABLE); 995e66f31c5Sopenharmony_ci 996e66f31c5Sopenharmony_ci /* If the read_line_buffer member is zero, it must have been an raw read. 997e66f31c5Sopenharmony_ci * Otherwise it was a line-buffered read. FIXME: This is quite obscure. Use a 998e66f31c5Sopenharmony_ci * flag or something. */ 999e66f31c5Sopenharmony_ci if (handle->tty.rd.read_line_buffer.len == 0) { 1000e66f31c5Sopenharmony_ci uv_process_tty_read_raw_req(loop, handle, req); 1001e66f31c5Sopenharmony_ci } else { 1002e66f31c5Sopenharmony_ci uv_process_tty_read_line_req(loop, handle, req); 1003e66f31c5Sopenharmony_ci } 1004e66f31c5Sopenharmony_ci} 1005e66f31c5Sopenharmony_ci 1006e66f31c5Sopenharmony_ci 1007e66f31c5Sopenharmony_ciint uv__tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb, 1008e66f31c5Sopenharmony_ci uv_read_cb read_cb) { 1009e66f31c5Sopenharmony_ci uv_loop_t* loop = handle->loop; 1010e66f31c5Sopenharmony_ci 1011e66f31c5Sopenharmony_ci if (!(handle->flags & UV_HANDLE_TTY_READABLE)) { 1012e66f31c5Sopenharmony_ci return ERROR_INVALID_PARAMETER; 1013e66f31c5Sopenharmony_ci } 1014e66f31c5Sopenharmony_ci 1015e66f31c5Sopenharmony_ci handle->flags |= UV_HANDLE_READING; 1016e66f31c5Sopenharmony_ci INCREASE_ACTIVE_COUNT(loop, handle); 1017e66f31c5Sopenharmony_ci handle->read_cb = read_cb; 1018e66f31c5Sopenharmony_ci handle->alloc_cb = alloc_cb; 1019e66f31c5Sopenharmony_ci 1020e66f31c5Sopenharmony_ci /* If reading was stopped and then started again, there could still be a read 1021e66f31c5Sopenharmony_ci * request pending. */ 1022e66f31c5Sopenharmony_ci if (handle->flags & UV_HANDLE_READ_PENDING) { 1023e66f31c5Sopenharmony_ci return 0; 1024e66f31c5Sopenharmony_ci } 1025e66f31c5Sopenharmony_ci 1026e66f31c5Sopenharmony_ci /* Maybe the user stopped reading half-way while processing key events. 1027e66f31c5Sopenharmony_ci * Short-circuit if this could be the case. */ 1028e66f31c5Sopenharmony_ci if (handle->tty.rd.last_key_len > 0) { 1029e66f31c5Sopenharmony_ci SET_REQ_SUCCESS(&handle->read_req); 1030e66f31c5Sopenharmony_ci uv__insert_pending_req(handle->loop, (uv_req_t*) &handle->read_req); 1031e66f31c5Sopenharmony_ci /* Make sure no attempt is made to insert it again until it's handled. */ 1032e66f31c5Sopenharmony_ci handle->flags |= UV_HANDLE_READ_PENDING; 1033e66f31c5Sopenharmony_ci handle->reqs_pending++; 1034e66f31c5Sopenharmony_ci return 0; 1035e66f31c5Sopenharmony_ci } 1036e66f31c5Sopenharmony_ci 1037e66f31c5Sopenharmony_ci uv__tty_queue_read(loop, handle); 1038e66f31c5Sopenharmony_ci 1039e66f31c5Sopenharmony_ci return 0; 1040e66f31c5Sopenharmony_ci} 1041e66f31c5Sopenharmony_ci 1042e66f31c5Sopenharmony_ci 1043e66f31c5Sopenharmony_ciint uv__tty_read_stop(uv_tty_t* handle) { 1044e66f31c5Sopenharmony_ci INPUT_RECORD record; 1045e66f31c5Sopenharmony_ci DWORD written, err; 1046e66f31c5Sopenharmony_ci 1047e66f31c5Sopenharmony_ci handle->flags &= ~UV_HANDLE_READING; 1048e66f31c5Sopenharmony_ci DECREASE_ACTIVE_COUNT(handle->loop, handle); 1049e66f31c5Sopenharmony_ci 1050e66f31c5Sopenharmony_ci if (!(handle->flags & UV_HANDLE_READ_PENDING)) 1051e66f31c5Sopenharmony_ci return 0; 1052e66f31c5Sopenharmony_ci 1053e66f31c5Sopenharmony_ci if (handle->flags & UV_HANDLE_TTY_RAW) { 1054e66f31c5Sopenharmony_ci /* Cancel raw read. Write some bullshit event to force the console wait to 1055e66f31c5Sopenharmony_ci * return. */ 1056e66f31c5Sopenharmony_ci memset(&record, 0, sizeof record); 1057e66f31c5Sopenharmony_ci record.EventType = FOCUS_EVENT; 1058e66f31c5Sopenharmony_ci if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) { 1059e66f31c5Sopenharmony_ci return GetLastError(); 1060e66f31c5Sopenharmony_ci } 1061e66f31c5Sopenharmony_ci } else if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) { 1062e66f31c5Sopenharmony_ci /* Cancel line-buffered read if not already pending */ 1063e66f31c5Sopenharmony_ci err = uv__cancel_read_console(handle); 1064e66f31c5Sopenharmony_ci if (err) 1065e66f31c5Sopenharmony_ci return err; 1066e66f31c5Sopenharmony_ci 1067e66f31c5Sopenharmony_ci handle->flags |= UV_HANDLE_CANCELLATION_PENDING; 1068e66f31c5Sopenharmony_ci } 1069e66f31c5Sopenharmony_ci 1070e66f31c5Sopenharmony_ci return 0; 1071e66f31c5Sopenharmony_ci} 1072e66f31c5Sopenharmony_ci 1073e66f31c5Sopenharmony_cistatic int uv__cancel_read_console(uv_tty_t* handle) { 1074e66f31c5Sopenharmony_ci HANDLE active_screen_buffer = INVALID_HANDLE_VALUE; 1075e66f31c5Sopenharmony_ci INPUT_RECORD record; 1076e66f31c5Sopenharmony_ci DWORD written; 1077e66f31c5Sopenharmony_ci DWORD err = 0; 1078e66f31c5Sopenharmony_ci LONG status; 1079e66f31c5Sopenharmony_ci 1080e66f31c5Sopenharmony_ci assert(!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)); 1081e66f31c5Sopenharmony_ci 1082e66f31c5Sopenharmony_ci /* Hold the output lock during the cancellation, to ensure that further 1083e66f31c5Sopenharmony_ci writes don't interfere with the screen state. It will be the ReadConsole 1084e66f31c5Sopenharmony_ci thread's responsibility to release the lock. */ 1085e66f31c5Sopenharmony_ci uv_sem_wait(&uv_tty_output_lock); 1086e66f31c5Sopenharmony_ci status = InterlockedExchange(&uv__read_console_status, TRAP_REQUESTED); 1087e66f31c5Sopenharmony_ci if (status != IN_PROGRESS) { 1088e66f31c5Sopenharmony_ci /* Either we have managed to set a trap for the other thread before 1089e66f31c5Sopenharmony_ci ReadConsole is called, or ReadConsole has returned because the user 1090e66f31c5Sopenharmony_ci has pressed ENTER. In either case, there is nothing else to do. */ 1091e66f31c5Sopenharmony_ci uv_sem_post(&uv_tty_output_lock); 1092e66f31c5Sopenharmony_ci return 0; 1093e66f31c5Sopenharmony_ci } 1094e66f31c5Sopenharmony_ci 1095e66f31c5Sopenharmony_ci /* Save screen state before sending the VK_RETURN event */ 1096e66f31c5Sopenharmony_ci active_screen_buffer = CreateFileA("conout$", 1097e66f31c5Sopenharmony_ci GENERIC_READ | GENERIC_WRITE, 1098e66f31c5Sopenharmony_ci FILE_SHARE_READ | FILE_SHARE_WRITE, 1099e66f31c5Sopenharmony_ci NULL, 1100e66f31c5Sopenharmony_ci OPEN_EXISTING, 1101e66f31c5Sopenharmony_ci FILE_ATTRIBUTE_NORMAL, 1102e66f31c5Sopenharmony_ci NULL); 1103e66f31c5Sopenharmony_ci 1104e66f31c5Sopenharmony_ci if (active_screen_buffer != INVALID_HANDLE_VALUE && 1105e66f31c5Sopenharmony_ci GetConsoleScreenBufferInfo(active_screen_buffer, 1106e66f31c5Sopenharmony_ci &uv__saved_screen_state)) { 1107e66f31c5Sopenharmony_ci InterlockedOr(&uv__restore_screen_state, 1); 1108e66f31c5Sopenharmony_ci } 1109e66f31c5Sopenharmony_ci 1110e66f31c5Sopenharmony_ci /* Write enter key event to force the console wait to return. */ 1111e66f31c5Sopenharmony_ci record.EventType = KEY_EVENT; 1112e66f31c5Sopenharmony_ci record.Event.KeyEvent.bKeyDown = TRUE; 1113e66f31c5Sopenharmony_ci record.Event.KeyEvent.wRepeatCount = 1; 1114e66f31c5Sopenharmony_ci record.Event.KeyEvent.wVirtualKeyCode = VK_RETURN; 1115e66f31c5Sopenharmony_ci record.Event.KeyEvent.wVirtualScanCode = 1116e66f31c5Sopenharmony_ci MapVirtualKeyW(VK_RETURN, MAPVK_VK_TO_VSC); 1117e66f31c5Sopenharmony_ci record.Event.KeyEvent.uChar.UnicodeChar = L'\r'; 1118e66f31c5Sopenharmony_ci record.Event.KeyEvent.dwControlKeyState = 0; 1119e66f31c5Sopenharmony_ci if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) 1120e66f31c5Sopenharmony_ci err = GetLastError(); 1121e66f31c5Sopenharmony_ci 1122e66f31c5Sopenharmony_ci if (active_screen_buffer != INVALID_HANDLE_VALUE) 1123e66f31c5Sopenharmony_ci CloseHandle(active_screen_buffer); 1124e66f31c5Sopenharmony_ci 1125e66f31c5Sopenharmony_ci return err; 1126e66f31c5Sopenharmony_ci} 1127e66f31c5Sopenharmony_ci 1128e66f31c5Sopenharmony_ci 1129e66f31c5Sopenharmony_cistatic void uv__tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) { 1130e66f31c5Sopenharmony_ci uv_tty_virtual_width = info->dwSize.X; 1131e66f31c5Sopenharmony_ci uv_tty_virtual_height = info->srWindow.Bottom - info->srWindow.Top + 1; 1132e66f31c5Sopenharmony_ci 1133e66f31c5Sopenharmony_ci /* Recompute virtual window offset row. */ 1134e66f31c5Sopenharmony_ci if (uv_tty_virtual_offset == -1) { 1135e66f31c5Sopenharmony_ci uv_tty_virtual_offset = info->dwCursorPosition.Y; 1136e66f31c5Sopenharmony_ci } else if (uv_tty_virtual_offset < info->dwCursorPosition.Y - 1137e66f31c5Sopenharmony_ci uv_tty_virtual_height + 1) { 1138e66f31c5Sopenharmony_ci /* If suddenly find the cursor outside of the virtual window, it must have 1139e66f31c5Sopenharmony_ci * somehow scrolled. Update the virtual window offset. */ 1140e66f31c5Sopenharmony_ci uv_tty_virtual_offset = info->dwCursorPosition.Y - 1141e66f31c5Sopenharmony_ci uv_tty_virtual_height + 1; 1142e66f31c5Sopenharmony_ci } 1143e66f31c5Sopenharmony_ci if (uv_tty_virtual_offset + uv_tty_virtual_height > info->dwSize.Y) { 1144e66f31c5Sopenharmony_ci uv_tty_virtual_offset = info->dwSize.Y - uv_tty_virtual_height; 1145e66f31c5Sopenharmony_ci } 1146e66f31c5Sopenharmony_ci if (uv_tty_virtual_offset < 0) { 1147e66f31c5Sopenharmony_ci uv_tty_virtual_offset = 0; 1148e66f31c5Sopenharmony_ci } 1149e66f31c5Sopenharmony_ci} 1150e66f31c5Sopenharmony_ci 1151e66f31c5Sopenharmony_ci 1152e66f31c5Sopenharmony_cistatic COORD uv__tty_make_real_coord(uv_tty_t* handle, 1153e66f31c5Sopenharmony_ci CONSOLE_SCREEN_BUFFER_INFO* info, int x, unsigned char x_relative, int y, 1154e66f31c5Sopenharmony_ci unsigned char y_relative) { 1155e66f31c5Sopenharmony_ci COORD result; 1156e66f31c5Sopenharmony_ci 1157e66f31c5Sopenharmony_ci uv__tty_update_virtual_window(info); 1158e66f31c5Sopenharmony_ci 1159e66f31c5Sopenharmony_ci /* Adjust y position */ 1160e66f31c5Sopenharmony_ci if (y_relative) { 1161e66f31c5Sopenharmony_ci y = info->dwCursorPosition.Y + y; 1162e66f31c5Sopenharmony_ci } else { 1163e66f31c5Sopenharmony_ci y = uv_tty_virtual_offset + y; 1164e66f31c5Sopenharmony_ci } 1165e66f31c5Sopenharmony_ci /* Clip y to virtual client rectangle */ 1166e66f31c5Sopenharmony_ci if (y < uv_tty_virtual_offset) { 1167e66f31c5Sopenharmony_ci y = uv_tty_virtual_offset; 1168e66f31c5Sopenharmony_ci } else if (y >= uv_tty_virtual_offset + uv_tty_virtual_height) { 1169e66f31c5Sopenharmony_ci y = uv_tty_virtual_offset + uv_tty_virtual_height - 1; 1170e66f31c5Sopenharmony_ci } 1171e66f31c5Sopenharmony_ci 1172e66f31c5Sopenharmony_ci /* Adjust x */ 1173e66f31c5Sopenharmony_ci if (x_relative) { 1174e66f31c5Sopenharmony_ci x = info->dwCursorPosition.X + x; 1175e66f31c5Sopenharmony_ci } 1176e66f31c5Sopenharmony_ci /* Clip x */ 1177e66f31c5Sopenharmony_ci if (x < 0) { 1178e66f31c5Sopenharmony_ci x = 0; 1179e66f31c5Sopenharmony_ci } else if (x >= uv_tty_virtual_width) { 1180e66f31c5Sopenharmony_ci x = uv_tty_virtual_width - 1; 1181e66f31c5Sopenharmony_ci } 1182e66f31c5Sopenharmony_ci 1183e66f31c5Sopenharmony_ci result.X = (unsigned short) x; 1184e66f31c5Sopenharmony_ci result.Y = (unsigned short) y; 1185e66f31c5Sopenharmony_ci return result; 1186e66f31c5Sopenharmony_ci} 1187e66f31c5Sopenharmony_ci 1188e66f31c5Sopenharmony_ci 1189e66f31c5Sopenharmony_cistatic int uv__tty_emit_text(uv_tty_t* handle, WCHAR buffer[], DWORD length, 1190e66f31c5Sopenharmony_ci DWORD* error) { 1191e66f31c5Sopenharmony_ci DWORD written; 1192e66f31c5Sopenharmony_ci 1193e66f31c5Sopenharmony_ci if (*error != ERROR_SUCCESS) { 1194e66f31c5Sopenharmony_ci return -1; 1195e66f31c5Sopenharmony_ci } 1196e66f31c5Sopenharmony_ci 1197e66f31c5Sopenharmony_ci if (!WriteConsoleW(handle->handle, 1198e66f31c5Sopenharmony_ci (void*) buffer, 1199e66f31c5Sopenharmony_ci length, 1200e66f31c5Sopenharmony_ci &written, 1201e66f31c5Sopenharmony_ci NULL)) { 1202e66f31c5Sopenharmony_ci *error = GetLastError(); 1203e66f31c5Sopenharmony_ci return -1; 1204e66f31c5Sopenharmony_ci } 1205e66f31c5Sopenharmony_ci 1206e66f31c5Sopenharmony_ci return 0; 1207e66f31c5Sopenharmony_ci} 1208e66f31c5Sopenharmony_ci 1209e66f31c5Sopenharmony_ci 1210e66f31c5Sopenharmony_cistatic int uv__tty_move_caret(uv_tty_t* handle, int x, unsigned char x_relative, 1211e66f31c5Sopenharmony_ci int y, unsigned char y_relative, DWORD* error) { 1212e66f31c5Sopenharmony_ci CONSOLE_SCREEN_BUFFER_INFO info; 1213e66f31c5Sopenharmony_ci COORD pos; 1214e66f31c5Sopenharmony_ci 1215e66f31c5Sopenharmony_ci if (*error != ERROR_SUCCESS) { 1216e66f31c5Sopenharmony_ci return -1; 1217e66f31c5Sopenharmony_ci } 1218e66f31c5Sopenharmony_ci 1219e66f31c5Sopenharmony_ci retry: 1220e66f31c5Sopenharmony_ci if (!GetConsoleScreenBufferInfo(handle->handle, &info)) { 1221e66f31c5Sopenharmony_ci *error = GetLastError(); 1222e66f31c5Sopenharmony_ci } 1223e66f31c5Sopenharmony_ci 1224e66f31c5Sopenharmony_ci pos = uv__tty_make_real_coord(handle, &info, x, x_relative, y, y_relative); 1225e66f31c5Sopenharmony_ci 1226e66f31c5Sopenharmony_ci if (!SetConsoleCursorPosition(handle->handle, pos)) { 1227e66f31c5Sopenharmony_ci if (GetLastError() == ERROR_INVALID_PARAMETER) { 1228e66f31c5Sopenharmony_ci /* The console may be resized - retry */ 1229e66f31c5Sopenharmony_ci goto retry; 1230e66f31c5Sopenharmony_ci } else { 1231e66f31c5Sopenharmony_ci *error = GetLastError(); 1232e66f31c5Sopenharmony_ci return -1; 1233e66f31c5Sopenharmony_ci } 1234e66f31c5Sopenharmony_ci } 1235e66f31c5Sopenharmony_ci 1236e66f31c5Sopenharmony_ci return 0; 1237e66f31c5Sopenharmony_ci} 1238e66f31c5Sopenharmony_ci 1239e66f31c5Sopenharmony_ci 1240e66f31c5Sopenharmony_cistatic int uv__tty_reset(uv_tty_t* handle, DWORD* error) { 1241e66f31c5Sopenharmony_ci const COORD origin = {0, 0}; 1242e66f31c5Sopenharmony_ci const WORD char_attrs = uv_tty_default_text_attributes; 1243e66f31c5Sopenharmony_ci CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info; 1244e66f31c5Sopenharmony_ci DWORD count, written; 1245e66f31c5Sopenharmony_ci 1246e66f31c5Sopenharmony_ci if (*error != ERROR_SUCCESS) { 1247e66f31c5Sopenharmony_ci return -1; 1248e66f31c5Sopenharmony_ci } 1249e66f31c5Sopenharmony_ci 1250e66f31c5Sopenharmony_ci /* Reset original text attributes. */ 1251e66f31c5Sopenharmony_ci if (!SetConsoleTextAttribute(handle->handle, char_attrs)) { 1252e66f31c5Sopenharmony_ci *error = GetLastError(); 1253e66f31c5Sopenharmony_ci return -1; 1254e66f31c5Sopenharmony_ci } 1255e66f31c5Sopenharmony_ci 1256e66f31c5Sopenharmony_ci /* Move the cursor position to (0, 0). */ 1257e66f31c5Sopenharmony_ci if (!SetConsoleCursorPosition(handle->handle, origin)) { 1258e66f31c5Sopenharmony_ci *error = GetLastError(); 1259e66f31c5Sopenharmony_ci return -1; 1260e66f31c5Sopenharmony_ci } 1261e66f31c5Sopenharmony_ci 1262e66f31c5Sopenharmony_ci /* Clear the screen buffer. */ 1263e66f31c5Sopenharmony_ci retry: 1264e66f31c5Sopenharmony_ci if (!GetConsoleScreenBufferInfo(handle->handle, &screen_buffer_info)) { 1265e66f31c5Sopenharmony_ci *error = GetLastError(); 1266e66f31c5Sopenharmony_ci return -1; 1267e66f31c5Sopenharmony_ci } 1268e66f31c5Sopenharmony_ci 1269e66f31c5Sopenharmony_ci count = screen_buffer_info.dwSize.X * screen_buffer_info.dwSize.Y; 1270e66f31c5Sopenharmony_ci 1271e66f31c5Sopenharmony_ci if (!(FillConsoleOutputCharacterW(handle->handle, 1272e66f31c5Sopenharmony_ci L'\x20', 1273e66f31c5Sopenharmony_ci count, 1274e66f31c5Sopenharmony_ci origin, 1275e66f31c5Sopenharmony_ci &written) && 1276e66f31c5Sopenharmony_ci FillConsoleOutputAttribute(handle->handle, 1277e66f31c5Sopenharmony_ci char_attrs, 1278e66f31c5Sopenharmony_ci written, 1279e66f31c5Sopenharmony_ci origin, 1280e66f31c5Sopenharmony_ci &written))) { 1281e66f31c5Sopenharmony_ci if (GetLastError() == ERROR_INVALID_PARAMETER) { 1282e66f31c5Sopenharmony_ci /* The console may be resized - retry */ 1283e66f31c5Sopenharmony_ci goto retry; 1284e66f31c5Sopenharmony_ci } else { 1285e66f31c5Sopenharmony_ci *error = GetLastError(); 1286e66f31c5Sopenharmony_ci return -1; 1287e66f31c5Sopenharmony_ci } 1288e66f31c5Sopenharmony_ci } 1289e66f31c5Sopenharmony_ci 1290e66f31c5Sopenharmony_ci /* Move the virtual window up to the top. */ 1291e66f31c5Sopenharmony_ci uv_tty_virtual_offset = 0; 1292e66f31c5Sopenharmony_ci uv__tty_update_virtual_window(&screen_buffer_info); 1293e66f31c5Sopenharmony_ci 1294e66f31c5Sopenharmony_ci /* Reset the cursor size and the cursor state. */ 1295e66f31c5Sopenharmony_ci if (!SetConsoleCursorInfo(handle->handle, &uv_tty_default_cursor_info)) { 1296e66f31c5Sopenharmony_ci *error = GetLastError(); 1297e66f31c5Sopenharmony_ci return -1; 1298e66f31c5Sopenharmony_ci } 1299e66f31c5Sopenharmony_ci 1300e66f31c5Sopenharmony_ci return 0; 1301e66f31c5Sopenharmony_ci} 1302e66f31c5Sopenharmony_ci 1303e66f31c5Sopenharmony_ci 1304e66f31c5Sopenharmony_cistatic int uv__tty_clear(uv_tty_t* handle, int dir, char entire_screen, 1305e66f31c5Sopenharmony_ci DWORD* error) { 1306e66f31c5Sopenharmony_ci CONSOLE_SCREEN_BUFFER_INFO info; 1307e66f31c5Sopenharmony_ci COORD start, end; 1308e66f31c5Sopenharmony_ci DWORD count, written; 1309e66f31c5Sopenharmony_ci 1310e66f31c5Sopenharmony_ci int x1, x2, y1, y2; 1311e66f31c5Sopenharmony_ci int x1r, x2r, y1r, y2r; 1312e66f31c5Sopenharmony_ci 1313e66f31c5Sopenharmony_ci if (*error != ERROR_SUCCESS) { 1314e66f31c5Sopenharmony_ci return -1; 1315e66f31c5Sopenharmony_ci } 1316e66f31c5Sopenharmony_ci 1317e66f31c5Sopenharmony_ci if (dir == 0) { 1318e66f31c5Sopenharmony_ci /* Clear from current position */ 1319e66f31c5Sopenharmony_ci x1 = 0; 1320e66f31c5Sopenharmony_ci x1r = 1; 1321e66f31c5Sopenharmony_ci } else { 1322e66f31c5Sopenharmony_ci /* Clear from column 0 */ 1323e66f31c5Sopenharmony_ci x1 = 0; 1324e66f31c5Sopenharmony_ci x1r = 0; 1325e66f31c5Sopenharmony_ci } 1326e66f31c5Sopenharmony_ci 1327e66f31c5Sopenharmony_ci if (dir == 1) { 1328e66f31c5Sopenharmony_ci /* Clear to current position */ 1329e66f31c5Sopenharmony_ci x2 = 0; 1330e66f31c5Sopenharmony_ci x2r = 1; 1331e66f31c5Sopenharmony_ci } else { 1332e66f31c5Sopenharmony_ci /* Clear to end of row. We pretend the console is 65536 characters wide, 1333e66f31c5Sopenharmony_ci * uv__tty_make_real_coord will clip it to the actual console width. */ 1334e66f31c5Sopenharmony_ci x2 = 0xffff; 1335e66f31c5Sopenharmony_ci x2r = 0; 1336e66f31c5Sopenharmony_ci } 1337e66f31c5Sopenharmony_ci 1338e66f31c5Sopenharmony_ci if (!entire_screen) { 1339e66f31c5Sopenharmony_ci /* Stay on our own row */ 1340e66f31c5Sopenharmony_ci y1 = y2 = 0; 1341e66f31c5Sopenharmony_ci y1r = y2r = 1; 1342e66f31c5Sopenharmony_ci } else { 1343e66f31c5Sopenharmony_ci /* Apply columns direction to row */ 1344e66f31c5Sopenharmony_ci y1 = x1; 1345e66f31c5Sopenharmony_ci y1r = x1r; 1346e66f31c5Sopenharmony_ci y2 = x2; 1347e66f31c5Sopenharmony_ci y2r = x2r; 1348e66f31c5Sopenharmony_ci } 1349e66f31c5Sopenharmony_ci 1350e66f31c5Sopenharmony_ci retry: 1351e66f31c5Sopenharmony_ci if (!GetConsoleScreenBufferInfo(handle->handle, &info)) { 1352e66f31c5Sopenharmony_ci *error = GetLastError(); 1353e66f31c5Sopenharmony_ci return -1; 1354e66f31c5Sopenharmony_ci } 1355e66f31c5Sopenharmony_ci 1356e66f31c5Sopenharmony_ci start = uv__tty_make_real_coord(handle, &info, x1, x1r, y1, y1r); 1357e66f31c5Sopenharmony_ci end = uv__tty_make_real_coord(handle, &info, x2, x2r, y2, y2r); 1358e66f31c5Sopenharmony_ci count = (end.Y * info.dwSize.X + end.X) - 1359e66f31c5Sopenharmony_ci (start.Y * info.dwSize.X + start.X) + 1; 1360e66f31c5Sopenharmony_ci 1361e66f31c5Sopenharmony_ci if (!(FillConsoleOutputCharacterW(handle->handle, 1362e66f31c5Sopenharmony_ci L'\x20', 1363e66f31c5Sopenharmony_ci count, 1364e66f31c5Sopenharmony_ci start, 1365e66f31c5Sopenharmony_ci &written) && 1366e66f31c5Sopenharmony_ci FillConsoleOutputAttribute(handle->handle, 1367e66f31c5Sopenharmony_ci info.wAttributes, 1368e66f31c5Sopenharmony_ci written, 1369e66f31c5Sopenharmony_ci start, 1370e66f31c5Sopenharmony_ci &written))) { 1371e66f31c5Sopenharmony_ci if (GetLastError() == ERROR_INVALID_PARAMETER) { 1372e66f31c5Sopenharmony_ci /* The console may be resized - retry */ 1373e66f31c5Sopenharmony_ci goto retry; 1374e66f31c5Sopenharmony_ci } else { 1375e66f31c5Sopenharmony_ci *error = GetLastError(); 1376e66f31c5Sopenharmony_ci return -1; 1377e66f31c5Sopenharmony_ci } 1378e66f31c5Sopenharmony_ci } 1379e66f31c5Sopenharmony_ci 1380e66f31c5Sopenharmony_ci return 0; 1381e66f31c5Sopenharmony_ci} 1382e66f31c5Sopenharmony_ci 1383e66f31c5Sopenharmony_ci#define FLIP_FGBG \ 1384e66f31c5Sopenharmony_ci do { \ 1385e66f31c5Sopenharmony_ci WORD fg = info.wAttributes & 0xF; \ 1386e66f31c5Sopenharmony_ci WORD bg = info.wAttributes & 0xF0; \ 1387e66f31c5Sopenharmony_ci info.wAttributes &= 0xFF00; \ 1388e66f31c5Sopenharmony_ci info.wAttributes |= fg << 4; \ 1389e66f31c5Sopenharmony_ci info.wAttributes |= bg >> 4; \ 1390e66f31c5Sopenharmony_ci } while (0) 1391e66f31c5Sopenharmony_ci 1392e66f31c5Sopenharmony_cistatic int uv__tty_set_style(uv_tty_t* handle, DWORD* error) { 1393e66f31c5Sopenharmony_ci unsigned short argc = handle->tty.wr.ansi_csi_argc; 1394e66f31c5Sopenharmony_ci unsigned short* argv = handle->tty.wr.ansi_csi_argv; 1395e66f31c5Sopenharmony_ci int i; 1396e66f31c5Sopenharmony_ci CONSOLE_SCREEN_BUFFER_INFO info; 1397e66f31c5Sopenharmony_ci 1398e66f31c5Sopenharmony_ci char fg_color = -1, bg_color = -1; 1399e66f31c5Sopenharmony_ci char fg_bright = -1, bg_bright = -1; 1400e66f31c5Sopenharmony_ci char inverse = -1; 1401e66f31c5Sopenharmony_ci 1402e66f31c5Sopenharmony_ci if (argc == 0) { 1403e66f31c5Sopenharmony_ci /* Reset mode */ 1404e66f31c5Sopenharmony_ci fg_color = uv_tty_default_fg_color; 1405e66f31c5Sopenharmony_ci bg_color = uv_tty_default_bg_color; 1406e66f31c5Sopenharmony_ci fg_bright = uv_tty_default_fg_bright; 1407e66f31c5Sopenharmony_ci bg_bright = uv_tty_default_bg_bright; 1408e66f31c5Sopenharmony_ci inverse = uv_tty_default_inverse; 1409e66f31c5Sopenharmony_ci } 1410e66f31c5Sopenharmony_ci 1411e66f31c5Sopenharmony_ci for (i = 0; i < argc; i++) { 1412e66f31c5Sopenharmony_ci short arg = argv[i]; 1413e66f31c5Sopenharmony_ci 1414e66f31c5Sopenharmony_ci if (arg == 0) { 1415e66f31c5Sopenharmony_ci /* Reset mode */ 1416e66f31c5Sopenharmony_ci fg_color = uv_tty_default_fg_color; 1417e66f31c5Sopenharmony_ci bg_color = uv_tty_default_bg_color; 1418e66f31c5Sopenharmony_ci fg_bright = uv_tty_default_fg_bright; 1419e66f31c5Sopenharmony_ci bg_bright = uv_tty_default_bg_bright; 1420e66f31c5Sopenharmony_ci inverse = uv_tty_default_inverse; 1421e66f31c5Sopenharmony_ci 1422e66f31c5Sopenharmony_ci } else if (arg == 1) { 1423e66f31c5Sopenharmony_ci /* Foreground bright on */ 1424e66f31c5Sopenharmony_ci fg_bright = 1; 1425e66f31c5Sopenharmony_ci 1426e66f31c5Sopenharmony_ci } else if (arg == 2) { 1427e66f31c5Sopenharmony_ci /* Both bright off */ 1428e66f31c5Sopenharmony_ci fg_bright = 0; 1429e66f31c5Sopenharmony_ci bg_bright = 0; 1430e66f31c5Sopenharmony_ci 1431e66f31c5Sopenharmony_ci } else if (arg == 5) { 1432e66f31c5Sopenharmony_ci /* Background bright on */ 1433e66f31c5Sopenharmony_ci bg_bright = 1; 1434e66f31c5Sopenharmony_ci 1435e66f31c5Sopenharmony_ci } else if (arg == 7) { 1436e66f31c5Sopenharmony_ci /* Inverse: on */ 1437e66f31c5Sopenharmony_ci inverse = 1; 1438e66f31c5Sopenharmony_ci 1439e66f31c5Sopenharmony_ci } else if (arg == 21 || arg == 22) { 1440e66f31c5Sopenharmony_ci /* Foreground bright off */ 1441e66f31c5Sopenharmony_ci fg_bright = 0; 1442e66f31c5Sopenharmony_ci 1443e66f31c5Sopenharmony_ci } else if (arg == 25) { 1444e66f31c5Sopenharmony_ci /* Background bright off */ 1445e66f31c5Sopenharmony_ci bg_bright = 0; 1446e66f31c5Sopenharmony_ci 1447e66f31c5Sopenharmony_ci } else if (arg == 27) { 1448e66f31c5Sopenharmony_ci /* Inverse: off */ 1449e66f31c5Sopenharmony_ci inverse = 0; 1450e66f31c5Sopenharmony_ci 1451e66f31c5Sopenharmony_ci } else if (arg >= 30 && arg <= 37) { 1452e66f31c5Sopenharmony_ci /* Set foreground color */ 1453e66f31c5Sopenharmony_ci fg_color = arg - 30; 1454e66f31c5Sopenharmony_ci 1455e66f31c5Sopenharmony_ci } else if (arg == 39) { 1456e66f31c5Sopenharmony_ci /* Default text color */ 1457e66f31c5Sopenharmony_ci fg_color = uv_tty_default_fg_color; 1458e66f31c5Sopenharmony_ci fg_bright = uv_tty_default_fg_bright; 1459e66f31c5Sopenharmony_ci 1460e66f31c5Sopenharmony_ci } else if (arg >= 40 && arg <= 47) { 1461e66f31c5Sopenharmony_ci /* Set background color */ 1462e66f31c5Sopenharmony_ci bg_color = arg - 40; 1463e66f31c5Sopenharmony_ci 1464e66f31c5Sopenharmony_ci } else if (arg == 49) { 1465e66f31c5Sopenharmony_ci /* Default background color */ 1466e66f31c5Sopenharmony_ci bg_color = uv_tty_default_bg_color; 1467e66f31c5Sopenharmony_ci bg_bright = uv_tty_default_bg_bright; 1468e66f31c5Sopenharmony_ci 1469e66f31c5Sopenharmony_ci } else if (arg >= 90 && arg <= 97) { 1470e66f31c5Sopenharmony_ci /* Set bold foreground color */ 1471e66f31c5Sopenharmony_ci fg_bright = 1; 1472e66f31c5Sopenharmony_ci fg_color = arg - 90; 1473e66f31c5Sopenharmony_ci 1474e66f31c5Sopenharmony_ci } else if (arg >= 100 && arg <= 107) { 1475e66f31c5Sopenharmony_ci /* Set bold background color */ 1476e66f31c5Sopenharmony_ci bg_bright = 1; 1477e66f31c5Sopenharmony_ci bg_color = arg - 100; 1478e66f31c5Sopenharmony_ci 1479e66f31c5Sopenharmony_ci } 1480e66f31c5Sopenharmony_ci } 1481e66f31c5Sopenharmony_ci 1482e66f31c5Sopenharmony_ci if (fg_color == -1 && bg_color == -1 && fg_bright == -1 && 1483e66f31c5Sopenharmony_ci bg_bright == -1 && inverse == -1) { 1484e66f31c5Sopenharmony_ci /* Nothing changed */ 1485e66f31c5Sopenharmony_ci return 0; 1486e66f31c5Sopenharmony_ci } 1487e66f31c5Sopenharmony_ci 1488e66f31c5Sopenharmony_ci if (!GetConsoleScreenBufferInfo(handle->handle, &info)) { 1489e66f31c5Sopenharmony_ci *error = GetLastError(); 1490e66f31c5Sopenharmony_ci return -1; 1491e66f31c5Sopenharmony_ci } 1492e66f31c5Sopenharmony_ci 1493e66f31c5Sopenharmony_ci if ((info.wAttributes & COMMON_LVB_REVERSE_VIDEO) > 0) { 1494e66f31c5Sopenharmony_ci FLIP_FGBG; 1495e66f31c5Sopenharmony_ci } 1496e66f31c5Sopenharmony_ci 1497e66f31c5Sopenharmony_ci if (fg_color != -1) { 1498e66f31c5Sopenharmony_ci info.wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); 1499e66f31c5Sopenharmony_ci if (fg_color & 1) info.wAttributes |= FOREGROUND_RED; 1500e66f31c5Sopenharmony_ci if (fg_color & 2) info.wAttributes |= FOREGROUND_GREEN; 1501e66f31c5Sopenharmony_ci if (fg_color & 4) info.wAttributes |= FOREGROUND_BLUE; 1502e66f31c5Sopenharmony_ci } 1503e66f31c5Sopenharmony_ci 1504e66f31c5Sopenharmony_ci if (fg_bright != -1) { 1505e66f31c5Sopenharmony_ci if (fg_bright) { 1506e66f31c5Sopenharmony_ci info.wAttributes |= FOREGROUND_INTENSITY; 1507e66f31c5Sopenharmony_ci } else { 1508e66f31c5Sopenharmony_ci info.wAttributes &= ~FOREGROUND_INTENSITY; 1509e66f31c5Sopenharmony_ci } 1510e66f31c5Sopenharmony_ci } 1511e66f31c5Sopenharmony_ci 1512e66f31c5Sopenharmony_ci if (bg_color != -1) { 1513e66f31c5Sopenharmony_ci info.wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); 1514e66f31c5Sopenharmony_ci if (bg_color & 1) info.wAttributes |= BACKGROUND_RED; 1515e66f31c5Sopenharmony_ci if (bg_color & 2) info.wAttributes |= BACKGROUND_GREEN; 1516e66f31c5Sopenharmony_ci if (bg_color & 4) info.wAttributes |= BACKGROUND_BLUE; 1517e66f31c5Sopenharmony_ci } 1518e66f31c5Sopenharmony_ci 1519e66f31c5Sopenharmony_ci if (bg_bright != -1) { 1520e66f31c5Sopenharmony_ci if (bg_bright) { 1521e66f31c5Sopenharmony_ci info.wAttributes |= BACKGROUND_INTENSITY; 1522e66f31c5Sopenharmony_ci } else { 1523e66f31c5Sopenharmony_ci info.wAttributes &= ~BACKGROUND_INTENSITY; 1524e66f31c5Sopenharmony_ci } 1525e66f31c5Sopenharmony_ci } 1526e66f31c5Sopenharmony_ci 1527e66f31c5Sopenharmony_ci if (inverse != -1) { 1528e66f31c5Sopenharmony_ci if (inverse) { 1529e66f31c5Sopenharmony_ci info.wAttributes |= COMMON_LVB_REVERSE_VIDEO; 1530e66f31c5Sopenharmony_ci } else { 1531e66f31c5Sopenharmony_ci info.wAttributes &= ~COMMON_LVB_REVERSE_VIDEO; 1532e66f31c5Sopenharmony_ci } 1533e66f31c5Sopenharmony_ci } 1534e66f31c5Sopenharmony_ci 1535e66f31c5Sopenharmony_ci if ((info.wAttributes & COMMON_LVB_REVERSE_VIDEO) > 0) { 1536e66f31c5Sopenharmony_ci FLIP_FGBG; 1537e66f31c5Sopenharmony_ci } 1538e66f31c5Sopenharmony_ci 1539e66f31c5Sopenharmony_ci if (!SetConsoleTextAttribute(handle->handle, info.wAttributes)) { 1540e66f31c5Sopenharmony_ci *error = GetLastError(); 1541e66f31c5Sopenharmony_ci return -1; 1542e66f31c5Sopenharmony_ci } 1543e66f31c5Sopenharmony_ci 1544e66f31c5Sopenharmony_ci return 0; 1545e66f31c5Sopenharmony_ci} 1546e66f31c5Sopenharmony_ci 1547e66f31c5Sopenharmony_ci 1548e66f31c5Sopenharmony_cistatic int uv__tty_save_state(uv_tty_t* handle, unsigned char save_attributes, 1549e66f31c5Sopenharmony_ci DWORD* error) { 1550e66f31c5Sopenharmony_ci CONSOLE_SCREEN_BUFFER_INFO info; 1551e66f31c5Sopenharmony_ci 1552e66f31c5Sopenharmony_ci if (*error != ERROR_SUCCESS) { 1553e66f31c5Sopenharmony_ci return -1; 1554e66f31c5Sopenharmony_ci } 1555e66f31c5Sopenharmony_ci 1556e66f31c5Sopenharmony_ci if (!GetConsoleScreenBufferInfo(handle->handle, &info)) { 1557e66f31c5Sopenharmony_ci *error = GetLastError(); 1558e66f31c5Sopenharmony_ci return -1; 1559e66f31c5Sopenharmony_ci } 1560e66f31c5Sopenharmony_ci 1561e66f31c5Sopenharmony_ci uv__tty_update_virtual_window(&info); 1562e66f31c5Sopenharmony_ci 1563e66f31c5Sopenharmony_ci handle->tty.wr.saved_position.X = info.dwCursorPosition.X; 1564e66f31c5Sopenharmony_ci handle->tty.wr.saved_position.Y = info.dwCursorPosition.Y - 1565e66f31c5Sopenharmony_ci uv_tty_virtual_offset; 1566e66f31c5Sopenharmony_ci handle->flags |= UV_HANDLE_TTY_SAVED_POSITION; 1567e66f31c5Sopenharmony_ci 1568e66f31c5Sopenharmony_ci if (save_attributes) { 1569e66f31c5Sopenharmony_ci handle->tty.wr.saved_attributes = info.wAttributes & 1570e66f31c5Sopenharmony_ci (FOREGROUND_INTENSITY | BACKGROUND_INTENSITY); 1571e66f31c5Sopenharmony_ci handle->flags |= UV_HANDLE_TTY_SAVED_ATTRIBUTES; 1572e66f31c5Sopenharmony_ci } 1573e66f31c5Sopenharmony_ci 1574e66f31c5Sopenharmony_ci return 0; 1575e66f31c5Sopenharmony_ci} 1576e66f31c5Sopenharmony_ci 1577e66f31c5Sopenharmony_ci 1578e66f31c5Sopenharmony_cistatic int uv__tty_restore_state(uv_tty_t* handle, 1579e66f31c5Sopenharmony_ci unsigned char restore_attributes, DWORD* error) { 1580e66f31c5Sopenharmony_ci CONSOLE_SCREEN_BUFFER_INFO info; 1581e66f31c5Sopenharmony_ci WORD new_attributes; 1582e66f31c5Sopenharmony_ci 1583e66f31c5Sopenharmony_ci if (*error != ERROR_SUCCESS) { 1584e66f31c5Sopenharmony_ci return -1; 1585e66f31c5Sopenharmony_ci } 1586e66f31c5Sopenharmony_ci 1587e66f31c5Sopenharmony_ci if (handle->flags & UV_HANDLE_TTY_SAVED_POSITION) { 1588e66f31c5Sopenharmony_ci if (uv__tty_move_caret(handle, 1589e66f31c5Sopenharmony_ci handle->tty.wr.saved_position.X, 1590e66f31c5Sopenharmony_ci 0, 1591e66f31c5Sopenharmony_ci handle->tty.wr.saved_position.Y, 1592e66f31c5Sopenharmony_ci 0, 1593e66f31c5Sopenharmony_ci error) != 0) { 1594e66f31c5Sopenharmony_ci return -1; 1595e66f31c5Sopenharmony_ci } 1596e66f31c5Sopenharmony_ci } 1597e66f31c5Sopenharmony_ci 1598e66f31c5Sopenharmony_ci if (restore_attributes && 1599e66f31c5Sopenharmony_ci (handle->flags & UV_HANDLE_TTY_SAVED_ATTRIBUTES)) { 1600e66f31c5Sopenharmony_ci if (!GetConsoleScreenBufferInfo(handle->handle, &info)) { 1601e66f31c5Sopenharmony_ci *error = GetLastError(); 1602e66f31c5Sopenharmony_ci return -1; 1603e66f31c5Sopenharmony_ci } 1604e66f31c5Sopenharmony_ci 1605e66f31c5Sopenharmony_ci new_attributes = info.wAttributes; 1606e66f31c5Sopenharmony_ci new_attributes &= ~(FOREGROUND_INTENSITY | BACKGROUND_INTENSITY); 1607e66f31c5Sopenharmony_ci new_attributes |= handle->tty.wr.saved_attributes; 1608e66f31c5Sopenharmony_ci 1609e66f31c5Sopenharmony_ci if (!SetConsoleTextAttribute(handle->handle, new_attributes)) { 1610e66f31c5Sopenharmony_ci *error = GetLastError(); 1611e66f31c5Sopenharmony_ci return -1; 1612e66f31c5Sopenharmony_ci } 1613e66f31c5Sopenharmony_ci } 1614e66f31c5Sopenharmony_ci 1615e66f31c5Sopenharmony_ci return 0; 1616e66f31c5Sopenharmony_ci} 1617e66f31c5Sopenharmony_ci 1618e66f31c5Sopenharmony_cistatic int uv__tty_set_cursor_visibility(uv_tty_t* handle, 1619e66f31c5Sopenharmony_ci BOOL visible, 1620e66f31c5Sopenharmony_ci DWORD* error) { 1621e66f31c5Sopenharmony_ci CONSOLE_CURSOR_INFO cursor_info; 1622e66f31c5Sopenharmony_ci 1623e66f31c5Sopenharmony_ci if (!GetConsoleCursorInfo(handle->handle, &cursor_info)) { 1624e66f31c5Sopenharmony_ci *error = GetLastError(); 1625e66f31c5Sopenharmony_ci return -1; 1626e66f31c5Sopenharmony_ci } 1627e66f31c5Sopenharmony_ci 1628e66f31c5Sopenharmony_ci cursor_info.bVisible = visible; 1629e66f31c5Sopenharmony_ci 1630e66f31c5Sopenharmony_ci if (!SetConsoleCursorInfo(handle->handle, &cursor_info)) { 1631e66f31c5Sopenharmony_ci *error = GetLastError(); 1632e66f31c5Sopenharmony_ci return -1; 1633e66f31c5Sopenharmony_ci } 1634e66f31c5Sopenharmony_ci 1635e66f31c5Sopenharmony_ci return 0; 1636e66f31c5Sopenharmony_ci} 1637e66f31c5Sopenharmony_ci 1638e66f31c5Sopenharmony_cistatic int uv__tty_set_cursor_shape(uv_tty_t* handle, int style, DWORD* error) { 1639e66f31c5Sopenharmony_ci CONSOLE_CURSOR_INFO cursor_info; 1640e66f31c5Sopenharmony_ci 1641e66f31c5Sopenharmony_ci if (!GetConsoleCursorInfo(handle->handle, &cursor_info)) { 1642e66f31c5Sopenharmony_ci *error = GetLastError(); 1643e66f31c5Sopenharmony_ci return -1; 1644e66f31c5Sopenharmony_ci } 1645e66f31c5Sopenharmony_ci 1646e66f31c5Sopenharmony_ci if (style == 0) { 1647e66f31c5Sopenharmony_ci cursor_info.dwSize = uv_tty_default_cursor_info.dwSize; 1648e66f31c5Sopenharmony_ci } else if (style <= 2) { 1649e66f31c5Sopenharmony_ci cursor_info.dwSize = CURSOR_SIZE_LARGE; 1650e66f31c5Sopenharmony_ci } else { 1651e66f31c5Sopenharmony_ci cursor_info.dwSize = CURSOR_SIZE_SMALL; 1652e66f31c5Sopenharmony_ci } 1653e66f31c5Sopenharmony_ci 1654e66f31c5Sopenharmony_ci if (!SetConsoleCursorInfo(handle->handle, &cursor_info)) { 1655e66f31c5Sopenharmony_ci *error = GetLastError(); 1656e66f31c5Sopenharmony_ci return -1; 1657e66f31c5Sopenharmony_ci } 1658e66f31c5Sopenharmony_ci 1659e66f31c5Sopenharmony_ci return 0; 1660e66f31c5Sopenharmony_ci} 1661e66f31c5Sopenharmony_ci 1662e66f31c5Sopenharmony_ci 1663e66f31c5Sopenharmony_cistatic int uv__tty_write_bufs(uv_tty_t* handle, 1664e66f31c5Sopenharmony_ci const uv_buf_t bufs[], 1665e66f31c5Sopenharmony_ci unsigned int nbufs, 1666e66f31c5Sopenharmony_ci DWORD* error) { 1667e66f31c5Sopenharmony_ci /* We can only write 8k characters at a time. Windows can't handle much more 1668e66f31c5Sopenharmony_ci * characters in a single console write anyway. */ 1669e66f31c5Sopenharmony_ci WCHAR utf16_buf[MAX_CONSOLE_CHAR]; 1670e66f31c5Sopenharmony_ci DWORD utf16_buf_used = 0; 1671e66f31c5Sopenharmony_ci unsigned int i; 1672e66f31c5Sopenharmony_ci 1673e66f31c5Sopenharmony_ci#define FLUSH_TEXT() \ 1674e66f31c5Sopenharmony_ci do { \ 1675e66f31c5Sopenharmony_ci if (utf16_buf_used > 0) { \ 1676e66f31c5Sopenharmony_ci uv__tty_emit_text(handle, utf16_buf, utf16_buf_used, error); \ 1677e66f31c5Sopenharmony_ci utf16_buf_used = 0; \ 1678e66f31c5Sopenharmony_ci } \ 1679e66f31c5Sopenharmony_ci } while (0) 1680e66f31c5Sopenharmony_ci 1681e66f31c5Sopenharmony_ci#define ENSURE_BUFFER_SPACE(wchars_needed) \ 1682e66f31c5Sopenharmony_ci if (wchars_needed > ARRAY_SIZE(utf16_buf) - utf16_buf_used) { \ 1683e66f31c5Sopenharmony_ci FLUSH_TEXT(); \ 1684e66f31c5Sopenharmony_ci } 1685e66f31c5Sopenharmony_ci 1686e66f31c5Sopenharmony_ci /* Cache for fast access */ 1687e66f31c5Sopenharmony_ci unsigned char utf8_bytes_left = handle->tty.wr.utf8_bytes_left; 1688e66f31c5Sopenharmony_ci unsigned int utf8_codepoint = handle->tty.wr.utf8_codepoint; 1689e66f31c5Sopenharmony_ci unsigned char previous_eol = handle->tty.wr.previous_eol; 1690e66f31c5Sopenharmony_ci unsigned short ansi_parser_state = handle->tty.wr.ansi_parser_state; 1691e66f31c5Sopenharmony_ci 1692e66f31c5Sopenharmony_ci /* Store the error here. If we encounter an error, stop trying to do i/o but 1693e66f31c5Sopenharmony_ci * keep parsing the buffer so we leave the parser in a consistent state. */ 1694e66f31c5Sopenharmony_ci *error = ERROR_SUCCESS; 1695e66f31c5Sopenharmony_ci 1696e66f31c5Sopenharmony_ci uv_sem_wait(&uv_tty_output_lock); 1697e66f31c5Sopenharmony_ci 1698e66f31c5Sopenharmony_ci for (i = 0; i < nbufs; i++) { 1699e66f31c5Sopenharmony_ci uv_buf_t buf = bufs[i]; 1700e66f31c5Sopenharmony_ci unsigned int j; 1701e66f31c5Sopenharmony_ci 1702e66f31c5Sopenharmony_ci for (j = 0; j < buf.len; j++) { 1703e66f31c5Sopenharmony_ci unsigned char c = buf.base[j]; 1704e66f31c5Sopenharmony_ci 1705e66f31c5Sopenharmony_ci /* Run the character through the utf8 decoder We happily accept non 1706e66f31c5Sopenharmony_ci * shortest form encodings and invalid code points - there's no real harm 1707e66f31c5Sopenharmony_ci * that can be done. */ 1708e66f31c5Sopenharmony_ci if (utf8_bytes_left == 0) { 1709e66f31c5Sopenharmony_ci /* Read utf-8 start byte */ 1710e66f31c5Sopenharmony_ci DWORD first_zero_bit; 1711e66f31c5Sopenharmony_ci unsigned char not_c = ~c; 1712e66f31c5Sopenharmony_ci#ifdef _MSC_VER /* msvc */ 1713e66f31c5Sopenharmony_ci if (_BitScanReverse(&first_zero_bit, not_c)) { 1714e66f31c5Sopenharmony_ci#else /* assume gcc */ 1715e66f31c5Sopenharmony_ci if (c != 0) { 1716e66f31c5Sopenharmony_ci first_zero_bit = (sizeof(int) * 8) - 1 - __builtin_clz(not_c); 1717e66f31c5Sopenharmony_ci#endif 1718e66f31c5Sopenharmony_ci if (first_zero_bit == 7) { 1719e66f31c5Sopenharmony_ci /* Ascii - pass right through */ 1720e66f31c5Sopenharmony_ci utf8_codepoint = (unsigned int) c; 1721e66f31c5Sopenharmony_ci 1722e66f31c5Sopenharmony_ci } else if (first_zero_bit <= 5) { 1723e66f31c5Sopenharmony_ci /* Multibyte sequence */ 1724e66f31c5Sopenharmony_ci utf8_codepoint = (0xff >> (8 - first_zero_bit)) & c; 1725e66f31c5Sopenharmony_ci utf8_bytes_left = (char) (6 - first_zero_bit); 1726e66f31c5Sopenharmony_ci 1727e66f31c5Sopenharmony_ci } else { 1728e66f31c5Sopenharmony_ci /* Invalid continuation */ 1729e66f31c5Sopenharmony_ci utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER; 1730e66f31c5Sopenharmony_ci } 1731e66f31c5Sopenharmony_ci 1732e66f31c5Sopenharmony_ci } else { 1733e66f31c5Sopenharmony_ci /* 0xff -- invalid */ 1734e66f31c5Sopenharmony_ci utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER; 1735e66f31c5Sopenharmony_ci } 1736e66f31c5Sopenharmony_ci 1737e66f31c5Sopenharmony_ci } else if ((c & 0xc0) == 0x80) { 1738e66f31c5Sopenharmony_ci /* Valid continuation of utf-8 multibyte sequence */ 1739e66f31c5Sopenharmony_ci utf8_bytes_left--; 1740e66f31c5Sopenharmony_ci utf8_codepoint <<= 6; 1741e66f31c5Sopenharmony_ci utf8_codepoint |= ((unsigned int) c & 0x3f); 1742e66f31c5Sopenharmony_ci 1743e66f31c5Sopenharmony_ci } else { 1744e66f31c5Sopenharmony_ci /* Start byte where continuation was expected. */ 1745e66f31c5Sopenharmony_ci utf8_bytes_left = 0; 1746e66f31c5Sopenharmony_ci utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER; 1747e66f31c5Sopenharmony_ci /* Patch buf offset so this character will be parsed again as a start 1748e66f31c5Sopenharmony_ci * byte. */ 1749e66f31c5Sopenharmony_ci j--; 1750e66f31c5Sopenharmony_ci } 1751e66f31c5Sopenharmony_ci 1752e66f31c5Sopenharmony_ci /* Maybe we need to parse more bytes to find a character. */ 1753e66f31c5Sopenharmony_ci if (utf8_bytes_left != 0) { 1754e66f31c5Sopenharmony_ci continue; 1755e66f31c5Sopenharmony_ci } 1756e66f31c5Sopenharmony_ci 1757e66f31c5Sopenharmony_ci /* Parse vt100/ansi escape codes */ 1758e66f31c5Sopenharmony_ci if (uv__vterm_state == UV_TTY_SUPPORTED) { 1759e66f31c5Sopenharmony_ci /* Pass through escape codes if conhost supports them. */ 1760e66f31c5Sopenharmony_ci } else if (ansi_parser_state == ANSI_NORMAL) { 1761e66f31c5Sopenharmony_ci switch (utf8_codepoint) { 1762e66f31c5Sopenharmony_ci case '\033': 1763e66f31c5Sopenharmony_ci ansi_parser_state = ANSI_ESCAPE_SEEN; 1764e66f31c5Sopenharmony_ci continue; 1765e66f31c5Sopenharmony_ci 1766e66f31c5Sopenharmony_ci case 0233: 1767e66f31c5Sopenharmony_ci ansi_parser_state = ANSI_CSI; 1768e66f31c5Sopenharmony_ci handle->tty.wr.ansi_csi_argc = 0; 1769e66f31c5Sopenharmony_ci continue; 1770e66f31c5Sopenharmony_ci } 1771e66f31c5Sopenharmony_ci 1772e66f31c5Sopenharmony_ci } else if (ansi_parser_state == ANSI_ESCAPE_SEEN) { 1773e66f31c5Sopenharmony_ci switch (utf8_codepoint) { 1774e66f31c5Sopenharmony_ci case '[': 1775e66f31c5Sopenharmony_ci ansi_parser_state = ANSI_CSI; 1776e66f31c5Sopenharmony_ci handle->tty.wr.ansi_csi_argc = 0; 1777e66f31c5Sopenharmony_ci continue; 1778e66f31c5Sopenharmony_ci 1779e66f31c5Sopenharmony_ci case '^': 1780e66f31c5Sopenharmony_ci case '_': 1781e66f31c5Sopenharmony_ci case 'P': 1782e66f31c5Sopenharmony_ci case ']': 1783e66f31c5Sopenharmony_ci /* Not supported, but we'll have to parse until we see a stop code, 1784e66f31c5Sopenharmony_ci * e. g. ESC \ or BEL. */ 1785e66f31c5Sopenharmony_ci ansi_parser_state = ANSI_ST_CONTROL; 1786e66f31c5Sopenharmony_ci continue; 1787e66f31c5Sopenharmony_ci 1788e66f31c5Sopenharmony_ci case '\033': 1789e66f31c5Sopenharmony_ci /* Ignore double escape. */ 1790e66f31c5Sopenharmony_ci continue; 1791e66f31c5Sopenharmony_ci 1792e66f31c5Sopenharmony_ci case 'c': 1793e66f31c5Sopenharmony_ci /* Full console reset. */ 1794e66f31c5Sopenharmony_ci FLUSH_TEXT(); 1795e66f31c5Sopenharmony_ci uv__tty_reset(handle, error); 1796e66f31c5Sopenharmony_ci ansi_parser_state = ANSI_NORMAL; 1797e66f31c5Sopenharmony_ci continue; 1798e66f31c5Sopenharmony_ci 1799e66f31c5Sopenharmony_ci case '7': 1800e66f31c5Sopenharmony_ci /* Save the cursor position and text attributes. */ 1801e66f31c5Sopenharmony_ci FLUSH_TEXT(); 1802e66f31c5Sopenharmony_ci uv__tty_save_state(handle, 1, error); 1803e66f31c5Sopenharmony_ci ansi_parser_state = ANSI_NORMAL; 1804e66f31c5Sopenharmony_ci continue; 1805e66f31c5Sopenharmony_ci 1806e66f31c5Sopenharmony_ci case '8': 1807e66f31c5Sopenharmony_ci /* Restore the cursor position and text attributes */ 1808e66f31c5Sopenharmony_ci FLUSH_TEXT(); 1809e66f31c5Sopenharmony_ci uv__tty_restore_state(handle, 1, error); 1810e66f31c5Sopenharmony_ci ansi_parser_state = ANSI_NORMAL; 1811e66f31c5Sopenharmony_ci continue; 1812e66f31c5Sopenharmony_ci 1813e66f31c5Sopenharmony_ci default: 1814e66f31c5Sopenharmony_ci if (utf8_codepoint >= '@' && utf8_codepoint <= '_') { 1815e66f31c5Sopenharmony_ci /* Single-char control. */ 1816e66f31c5Sopenharmony_ci ansi_parser_state = ANSI_NORMAL; 1817e66f31c5Sopenharmony_ci continue; 1818e66f31c5Sopenharmony_ci } else { 1819e66f31c5Sopenharmony_ci /* Invalid - proceed as normal, */ 1820e66f31c5Sopenharmony_ci ansi_parser_state = ANSI_NORMAL; 1821e66f31c5Sopenharmony_ci } 1822e66f31c5Sopenharmony_ci } 1823e66f31c5Sopenharmony_ci 1824e66f31c5Sopenharmony_ci } else if (ansi_parser_state == ANSI_IGNORE) { 1825e66f31c5Sopenharmony_ci /* We're ignoring this command. Stop only on command character. */ 1826e66f31c5Sopenharmony_ci if (utf8_codepoint >= '@' && utf8_codepoint <= '~') { 1827e66f31c5Sopenharmony_ci ansi_parser_state = ANSI_NORMAL; 1828e66f31c5Sopenharmony_ci } 1829e66f31c5Sopenharmony_ci continue; 1830e66f31c5Sopenharmony_ci 1831e66f31c5Sopenharmony_ci } else if (ansi_parser_state == ANSI_DECSCUSR) { 1832e66f31c5Sopenharmony_ci /* So far we've the sequence `ESC [ arg space`, and we're waiting for 1833e66f31c5Sopenharmony_ci * the final command byte. */ 1834e66f31c5Sopenharmony_ci if (utf8_codepoint >= '@' && utf8_codepoint <= '~') { 1835e66f31c5Sopenharmony_ci /* Command byte */ 1836e66f31c5Sopenharmony_ci if (utf8_codepoint == 'q') { 1837e66f31c5Sopenharmony_ci /* Change the cursor shape */ 1838e66f31c5Sopenharmony_ci int style = handle->tty.wr.ansi_csi_argc 1839e66f31c5Sopenharmony_ci ? handle->tty.wr.ansi_csi_argv[0] : 1; 1840e66f31c5Sopenharmony_ci if (style >= 0 && style <= 6) { 1841e66f31c5Sopenharmony_ci FLUSH_TEXT(); 1842e66f31c5Sopenharmony_ci uv__tty_set_cursor_shape(handle, style, error); 1843e66f31c5Sopenharmony_ci } 1844e66f31c5Sopenharmony_ci } 1845e66f31c5Sopenharmony_ci 1846e66f31c5Sopenharmony_ci /* Sequence ended - go back to normal state. */ 1847e66f31c5Sopenharmony_ci ansi_parser_state = ANSI_NORMAL; 1848e66f31c5Sopenharmony_ci continue; 1849e66f31c5Sopenharmony_ci } 1850e66f31c5Sopenharmony_ci /* Unexpected character, but sequence hasn't ended yet. Ignore the rest 1851e66f31c5Sopenharmony_ci * of the sequence. */ 1852e66f31c5Sopenharmony_ci ansi_parser_state = ANSI_IGNORE; 1853e66f31c5Sopenharmony_ci 1854e66f31c5Sopenharmony_ci } else if (ansi_parser_state & ANSI_CSI) { 1855e66f31c5Sopenharmony_ci /* So far we've seen `ESC [`, and we may or may not have already parsed 1856e66f31c5Sopenharmony_ci * some of the arguments that follow. */ 1857e66f31c5Sopenharmony_ci 1858e66f31c5Sopenharmony_ci if (utf8_codepoint >= '0' && utf8_codepoint <= '9') { 1859e66f31c5Sopenharmony_ci /* Parse a numerical argument. */ 1860e66f31c5Sopenharmony_ci if (!(ansi_parser_state & ANSI_IN_ARG)) { 1861e66f31c5Sopenharmony_ci /* We were not currently parsing a number, add a new one. */ 1862e66f31c5Sopenharmony_ci /* Check for that there are too many arguments. */ 1863e66f31c5Sopenharmony_ci if (handle->tty.wr.ansi_csi_argc >= 1864e66f31c5Sopenharmony_ci ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) { 1865e66f31c5Sopenharmony_ci ansi_parser_state = ANSI_IGNORE; 1866e66f31c5Sopenharmony_ci continue; 1867e66f31c5Sopenharmony_ci } 1868e66f31c5Sopenharmony_ci ansi_parser_state |= ANSI_IN_ARG; 1869e66f31c5Sopenharmony_ci handle->tty.wr.ansi_csi_argc++; 1870e66f31c5Sopenharmony_ci handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] = 1871e66f31c5Sopenharmony_ci (unsigned short) utf8_codepoint - '0'; 1872e66f31c5Sopenharmony_ci continue; 1873e66f31c5Sopenharmony_ci 1874e66f31c5Sopenharmony_ci } else { 1875e66f31c5Sopenharmony_ci /* We were already parsing a number. Parse next digit. */ 1876e66f31c5Sopenharmony_ci uint32_t value = 10 * 1877e66f31c5Sopenharmony_ci handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1]; 1878e66f31c5Sopenharmony_ci 1879e66f31c5Sopenharmony_ci /* Check for overflow. */ 1880e66f31c5Sopenharmony_ci if (value > UINT16_MAX) { 1881e66f31c5Sopenharmony_ci ansi_parser_state = ANSI_IGNORE; 1882e66f31c5Sopenharmony_ci continue; 1883e66f31c5Sopenharmony_ci } 1884e66f31c5Sopenharmony_ci 1885e66f31c5Sopenharmony_ci handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] = 1886e66f31c5Sopenharmony_ci (unsigned short) value + (utf8_codepoint - '0'); 1887e66f31c5Sopenharmony_ci continue; 1888e66f31c5Sopenharmony_ci } 1889e66f31c5Sopenharmony_ci 1890e66f31c5Sopenharmony_ci } else if (utf8_codepoint == ';') { 1891e66f31c5Sopenharmony_ci /* Denotes the end of an argument. */ 1892e66f31c5Sopenharmony_ci if (ansi_parser_state & ANSI_IN_ARG) { 1893e66f31c5Sopenharmony_ci ansi_parser_state &= ~ANSI_IN_ARG; 1894e66f31c5Sopenharmony_ci continue; 1895e66f31c5Sopenharmony_ci 1896e66f31c5Sopenharmony_ci } else { 1897e66f31c5Sopenharmony_ci /* If ANSI_IN_ARG is not set, add another argument and default 1898e66f31c5Sopenharmony_ci * it to 0. */ 1899e66f31c5Sopenharmony_ci 1900e66f31c5Sopenharmony_ci /* Check for too many arguments */ 1901e66f31c5Sopenharmony_ci if (handle->tty.wr.ansi_csi_argc >= 1902e66f31c5Sopenharmony_ci 1903e66f31c5Sopenharmony_ci ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) { 1904e66f31c5Sopenharmony_ci ansi_parser_state = ANSI_IGNORE; 1905e66f31c5Sopenharmony_ci continue; 1906e66f31c5Sopenharmony_ci } 1907e66f31c5Sopenharmony_ci 1908e66f31c5Sopenharmony_ci handle->tty.wr.ansi_csi_argc++; 1909e66f31c5Sopenharmony_ci handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] = 0; 1910e66f31c5Sopenharmony_ci continue; 1911e66f31c5Sopenharmony_ci } 1912e66f31c5Sopenharmony_ci 1913e66f31c5Sopenharmony_ci } else if (utf8_codepoint == '?' && 1914e66f31c5Sopenharmony_ci !(ansi_parser_state & ANSI_IN_ARG) && 1915e66f31c5Sopenharmony_ci !(ansi_parser_state & ANSI_EXTENSION) && 1916e66f31c5Sopenharmony_ci handle->tty.wr.ansi_csi_argc == 0) { 1917e66f31c5Sopenharmony_ci /* Pass through '?' if it is the first character after CSI */ 1918e66f31c5Sopenharmony_ci /* This is an extension character from the VT100 codeset */ 1919e66f31c5Sopenharmony_ci /* that is supported and used by most ANSI terminals today. */ 1920e66f31c5Sopenharmony_ci ansi_parser_state |= ANSI_EXTENSION; 1921e66f31c5Sopenharmony_ci continue; 1922e66f31c5Sopenharmony_ci 1923e66f31c5Sopenharmony_ci } else if (utf8_codepoint == ' ' && 1924e66f31c5Sopenharmony_ci !(ansi_parser_state & ANSI_EXTENSION)) { 1925e66f31c5Sopenharmony_ci /* We expect a command byte to follow after this space. The only 1926e66f31c5Sopenharmony_ci * command that we current support is 'set cursor style'. */ 1927e66f31c5Sopenharmony_ci ansi_parser_state = ANSI_DECSCUSR; 1928e66f31c5Sopenharmony_ci continue; 1929e66f31c5Sopenharmony_ci 1930e66f31c5Sopenharmony_ci } else if (utf8_codepoint >= '@' && utf8_codepoint <= '~') { 1931e66f31c5Sopenharmony_ci /* Command byte */ 1932e66f31c5Sopenharmony_ci if (ansi_parser_state & ANSI_EXTENSION) { 1933e66f31c5Sopenharmony_ci /* Sequence is `ESC [ ? args command`. */ 1934e66f31c5Sopenharmony_ci switch (utf8_codepoint) { 1935e66f31c5Sopenharmony_ci case 'l': 1936e66f31c5Sopenharmony_ci /* Hide the cursor */ 1937e66f31c5Sopenharmony_ci if (handle->tty.wr.ansi_csi_argc == 1 && 1938e66f31c5Sopenharmony_ci handle->tty.wr.ansi_csi_argv[0] == 25) { 1939e66f31c5Sopenharmony_ci FLUSH_TEXT(); 1940e66f31c5Sopenharmony_ci uv__tty_set_cursor_visibility(handle, 0, error); 1941e66f31c5Sopenharmony_ci } 1942e66f31c5Sopenharmony_ci break; 1943e66f31c5Sopenharmony_ci 1944e66f31c5Sopenharmony_ci case 'h': 1945e66f31c5Sopenharmony_ci /* Show the cursor */ 1946e66f31c5Sopenharmony_ci if (handle->tty.wr.ansi_csi_argc == 1 && 1947e66f31c5Sopenharmony_ci handle->tty.wr.ansi_csi_argv[0] == 25) { 1948e66f31c5Sopenharmony_ci FLUSH_TEXT(); 1949e66f31c5Sopenharmony_ci uv__tty_set_cursor_visibility(handle, 1, error); 1950e66f31c5Sopenharmony_ci } 1951e66f31c5Sopenharmony_ci break; 1952e66f31c5Sopenharmony_ci } 1953e66f31c5Sopenharmony_ci 1954e66f31c5Sopenharmony_ci } else { 1955e66f31c5Sopenharmony_ci /* Sequence is `ESC [ args command`. */ 1956e66f31c5Sopenharmony_ci int x, y, d; 1957e66f31c5Sopenharmony_ci switch (utf8_codepoint) { 1958e66f31c5Sopenharmony_ci case 'A': 1959e66f31c5Sopenharmony_ci /* cursor up */ 1960e66f31c5Sopenharmony_ci FLUSH_TEXT(); 1961e66f31c5Sopenharmony_ci y = -(handle->tty.wr.ansi_csi_argc 1962e66f31c5Sopenharmony_ci ? handle->tty.wr.ansi_csi_argv[0] : 1); 1963e66f31c5Sopenharmony_ci uv__tty_move_caret(handle, 0, 1, y, 1, error); 1964e66f31c5Sopenharmony_ci break; 1965e66f31c5Sopenharmony_ci 1966e66f31c5Sopenharmony_ci case 'B': 1967e66f31c5Sopenharmony_ci /* cursor down */ 1968e66f31c5Sopenharmony_ci FLUSH_TEXT(); 1969e66f31c5Sopenharmony_ci y = handle->tty.wr.ansi_csi_argc 1970e66f31c5Sopenharmony_ci ? handle->tty.wr.ansi_csi_argv[0] : 1; 1971e66f31c5Sopenharmony_ci uv__tty_move_caret(handle, 0, 1, y, 1, error); 1972e66f31c5Sopenharmony_ci break; 1973e66f31c5Sopenharmony_ci 1974e66f31c5Sopenharmony_ci case 'C': 1975e66f31c5Sopenharmony_ci /* cursor forward */ 1976e66f31c5Sopenharmony_ci FLUSH_TEXT(); 1977e66f31c5Sopenharmony_ci x = handle->tty.wr.ansi_csi_argc 1978e66f31c5Sopenharmony_ci ? handle->tty.wr.ansi_csi_argv[0] : 1; 1979e66f31c5Sopenharmony_ci uv__tty_move_caret(handle, x, 1, 0, 1, error); 1980e66f31c5Sopenharmony_ci break; 1981e66f31c5Sopenharmony_ci 1982e66f31c5Sopenharmony_ci case 'D': 1983e66f31c5Sopenharmony_ci /* cursor back */ 1984e66f31c5Sopenharmony_ci FLUSH_TEXT(); 1985e66f31c5Sopenharmony_ci x = -(handle->tty.wr.ansi_csi_argc 1986e66f31c5Sopenharmony_ci ? handle->tty.wr.ansi_csi_argv[0] : 1); 1987e66f31c5Sopenharmony_ci uv__tty_move_caret(handle, x, 1, 0, 1, error); 1988e66f31c5Sopenharmony_ci break; 1989e66f31c5Sopenharmony_ci 1990e66f31c5Sopenharmony_ci case 'E': 1991e66f31c5Sopenharmony_ci /* cursor next line */ 1992e66f31c5Sopenharmony_ci FLUSH_TEXT(); 1993e66f31c5Sopenharmony_ci y = handle->tty.wr.ansi_csi_argc 1994e66f31c5Sopenharmony_ci ? handle->tty.wr.ansi_csi_argv[0] : 1; 1995e66f31c5Sopenharmony_ci uv__tty_move_caret(handle, 0, 0, y, 1, error); 1996e66f31c5Sopenharmony_ci break; 1997e66f31c5Sopenharmony_ci 1998e66f31c5Sopenharmony_ci case 'F': 1999e66f31c5Sopenharmony_ci /* cursor previous line */ 2000e66f31c5Sopenharmony_ci FLUSH_TEXT(); 2001e66f31c5Sopenharmony_ci y = -(handle->tty.wr.ansi_csi_argc 2002e66f31c5Sopenharmony_ci ? handle->tty.wr.ansi_csi_argv[0] : 1); 2003e66f31c5Sopenharmony_ci uv__tty_move_caret(handle, 0, 0, y, 1, error); 2004e66f31c5Sopenharmony_ci break; 2005e66f31c5Sopenharmony_ci 2006e66f31c5Sopenharmony_ci case 'G': 2007e66f31c5Sopenharmony_ci /* cursor horizontal move absolute */ 2008e66f31c5Sopenharmony_ci FLUSH_TEXT(); 2009e66f31c5Sopenharmony_ci x = (handle->tty.wr.ansi_csi_argc >= 1 && 2010e66f31c5Sopenharmony_ci handle->tty.wr.ansi_csi_argv[0]) 2011e66f31c5Sopenharmony_ci ? handle->tty.wr.ansi_csi_argv[0] - 1 : 0; 2012e66f31c5Sopenharmony_ci uv__tty_move_caret(handle, x, 0, 0, 1, error); 2013e66f31c5Sopenharmony_ci break; 2014e66f31c5Sopenharmony_ci 2015e66f31c5Sopenharmony_ci case 'H': 2016e66f31c5Sopenharmony_ci case 'f': 2017e66f31c5Sopenharmony_ci /* cursor move absolute */ 2018e66f31c5Sopenharmony_ci FLUSH_TEXT(); 2019e66f31c5Sopenharmony_ci y = (handle->tty.wr.ansi_csi_argc >= 1 && 2020e66f31c5Sopenharmony_ci handle->tty.wr.ansi_csi_argv[0]) 2021e66f31c5Sopenharmony_ci ? handle->tty.wr.ansi_csi_argv[0] - 1 : 0; 2022e66f31c5Sopenharmony_ci x = (handle->tty.wr.ansi_csi_argc >= 2 && 2023e66f31c5Sopenharmony_ci handle->tty.wr.ansi_csi_argv[1]) 2024e66f31c5Sopenharmony_ci ? handle->tty.wr.ansi_csi_argv[1] - 1 : 0; 2025e66f31c5Sopenharmony_ci uv__tty_move_caret(handle, x, 0, y, 0, error); 2026e66f31c5Sopenharmony_ci break; 2027e66f31c5Sopenharmony_ci 2028e66f31c5Sopenharmony_ci case 'J': 2029e66f31c5Sopenharmony_ci /* Erase screen */ 2030e66f31c5Sopenharmony_ci FLUSH_TEXT(); 2031e66f31c5Sopenharmony_ci d = handle->tty.wr.ansi_csi_argc 2032e66f31c5Sopenharmony_ci ? handle->tty.wr.ansi_csi_argv[0] : 0; 2033e66f31c5Sopenharmony_ci if (d >= 0 && d <= 2) { 2034e66f31c5Sopenharmony_ci uv__tty_clear(handle, d, 1, error); 2035e66f31c5Sopenharmony_ci } 2036e66f31c5Sopenharmony_ci break; 2037e66f31c5Sopenharmony_ci 2038e66f31c5Sopenharmony_ci case 'K': 2039e66f31c5Sopenharmony_ci /* Erase line */ 2040e66f31c5Sopenharmony_ci FLUSH_TEXT(); 2041e66f31c5Sopenharmony_ci d = handle->tty.wr.ansi_csi_argc 2042e66f31c5Sopenharmony_ci ? handle->tty.wr.ansi_csi_argv[0] : 0; 2043e66f31c5Sopenharmony_ci if (d >= 0 && d <= 2) { 2044e66f31c5Sopenharmony_ci uv__tty_clear(handle, d, 0, error); 2045e66f31c5Sopenharmony_ci } 2046e66f31c5Sopenharmony_ci break; 2047e66f31c5Sopenharmony_ci 2048e66f31c5Sopenharmony_ci case 'm': 2049e66f31c5Sopenharmony_ci /* Set style */ 2050e66f31c5Sopenharmony_ci FLUSH_TEXT(); 2051e66f31c5Sopenharmony_ci uv__tty_set_style(handle, error); 2052e66f31c5Sopenharmony_ci break; 2053e66f31c5Sopenharmony_ci 2054e66f31c5Sopenharmony_ci case 's': 2055e66f31c5Sopenharmony_ci /* Save the cursor position. */ 2056e66f31c5Sopenharmony_ci FLUSH_TEXT(); 2057e66f31c5Sopenharmony_ci uv__tty_save_state(handle, 0, error); 2058e66f31c5Sopenharmony_ci break; 2059e66f31c5Sopenharmony_ci 2060e66f31c5Sopenharmony_ci case 'u': 2061e66f31c5Sopenharmony_ci /* Restore the cursor position */ 2062e66f31c5Sopenharmony_ci FLUSH_TEXT(); 2063e66f31c5Sopenharmony_ci uv__tty_restore_state(handle, 0, error); 2064e66f31c5Sopenharmony_ci break; 2065e66f31c5Sopenharmony_ci } 2066e66f31c5Sopenharmony_ci } 2067e66f31c5Sopenharmony_ci 2068e66f31c5Sopenharmony_ci /* Sequence ended - go back to normal state. */ 2069e66f31c5Sopenharmony_ci ansi_parser_state = ANSI_NORMAL; 2070e66f31c5Sopenharmony_ci continue; 2071e66f31c5Sopenharmony_ci 2072e66f31c5Sopenharmony_ci } else { 2073e66f31c5Sopenharmony_ci /* We don't support commands that use private mode characters or 2074e66f31c5Sopenharmony_ci * intermediaries. Ignore the rest of the sequence. */ 2075e66f31c5Sopenharmony_ci ansi_parser_state = ANSI_IGNORE; 2076e66f31c5Sopenharmony_ci continue; 2077e66f31c5Sopenharmony_ci } 2078e66f31c5Sopenharmony_ci 2079e66f31c5Sopenharmony_ci } else if (ansi_parser_state & ANSI_ST_CONTROL) { 2080e66f31c5Sopenharmony_ci /* Unsupported control code. 2081e66f31c5Sopenharmony_ci * Ignore everything until we see `BEL` or `ESC \`. */ 2082e66f31c5Sopenharmony_ci if (ansi_parser_state & ANSI_IN_STRING) { 2083e66f31c5Sopenharmony_ci if (!(ansi_parser_state & ANSI_BACKSLASH_SEEN)) { 2084e66f31c5Sopenharmony_ci if (utf8_codepoint == '"') { 2085e66f31c5Sopenharmony_ci ansi_parser_state &= ~ANSI_IN_STRING; 2086e66f31c5Sopenharmony_ci } else if (utf8_codepoint == '\\') { 2087e66f31c5Sopenharmony_ci ansi_parser_state |= ANSI_BACKSLASH_SEEN; 2088e66f31c5Sopenharmony_ci } 2089e66f31c5Sopenharmony_ci } else { 2090e66f31c5Sopenharmony_ci ansi_parser_state &= ~ANSI_BACKSLASH_SEEN; 2091e66f31c5Sopenharmony_ci } 2092e66f31c5Sopenharmony_ci } else { 2093e66f31c5Sopenharmony_ci if (utf8_codepoint == '\007' || (utf8_codepoint == '\\' && 2094e66f31c5Sopenharmony_ci (ansi_parser_state & ANSI_ESCAPE_SEEN))) { 2095e66f31c5Sopenharmony_ci /* End of sequence */ 2096e66f31c5Sopenharmony_ci ansi_parser_state = ANSI_NORMAL; 2097e66f31c5Sopenharmony_ci } else if (utf8_codepoint == '\033') { 2098e66f31c5Sopenharmony_ci /* Escape character */ 2099e66f31c5Sopenharmony_ci ansi_parser_state |= ANSI_ESCAPE_SEEN; 2100e66f31c5Sopenharmony_ci } else if (utf8_codepoint == '"') { 2101e66f31c5Sopenharmony_ci /* String starting */ 2102e66f31c5Sopenharmony_ci ansi_parser_state |= ANSI_IN_STRING; 2103e66f31c5Sopenharmony_ci ansi_parser_state &= ~ANSI_ESCAPE_SEEN; 2104e66f31c5Sopenharmony_ci ansi_parser_state &= ~ANSI_BACKSLASH_SEEN; 2105e66f31c5Sopenharmony_ci } else { 2106e66f31c5Sopenharmony_ci ansi_parser_state &= ~ANSI_ESCAPE_SEEN; 2107e66f31c5Sopenharmony_ci } 2108e66f31c5Sopenharmony_ci } 2109e66f31c5Sopenharmony_ci continue; 2110e66f31c5Sopenharmony_ci } else { 2111e66f31c5Sopenharmony_ci /* Inconsistent state */ 2112e66f31c5Sopenharmony_ci abort(); 2113e66f31c5Sopenharmony_ci } 2114e66f31c5Sopenharmony_ci 2115e66f31c5Sopenharmony_ci if (utf8_codepoint == 0x0a || utf8_codepoint == 0x0d) { 2116e66f31c5Sopenharmony_ci /* EOL conversion - emit \r\n when we see \n. */ 2117e66f31c5Sopenharmony_ci 2118e66f31c5Sopenharmony_ci if (utf8_codepoint == 0x0a && previous_eol != 0x0d) { 2119e66f31c5Sopenharmony_ci /* \n was not preceded by \r; print \r\n. */ 2120e66f31c5Sopenharmony_ci ENSURE_BUFFER_SPACE(2); 2121e66f31c5Sopenharmony_ci utf16_buf[utf16_buf_used++] = L'\r'; 2122e66f31c5Sopenharmony_ci utf16_buf[utf16_buf_used++] = L'\n'; 2123e66f31c5Sopenharmony_ci } else if (utf8_codepoint == 0x0d && previous_eol == 0x0a) { 2124e66f31c5Sopenharmony_ci /* \n was followed by \r; do not print the \r, since the source was 2125e66f31c5Sopenharmony_ci * either \r\n\r (so the second \r is redundant) or was \n\r (so the 2126e66f31c5Sopenharmony_ci * \n was processed by the last case and an \r automatically 2127e66f31c5Sopenharmony_ci * inserted). */ 2128e66f31c5Sopenharmony_ci } else { 2129e66f31c5Sopenharmony_ci /* \r without \n; print \r as-is. */ 2130e66f31c5Sopenharmony_ci ENSURE_BUFFER_SPACE(1); 2131e66f31c5Sopenharmony_ci utf16_buf[utf16_buf_used++] = (WCHAR) utf8_codepoint; 2132e66f31c5Sopenharmony_ci } 2133e66f31c5Sopenharmony_ci 2134e66f31c5Sopenharmony_ci previous_eol = (char) utf8_codepoint; 2135e66f31c5Sopenharmony_ci 2136e66f31c5Sopenharmony_ci } else if (utf8_codepoint <= 0xffff) { 2137e66f31c5Sopenharmony_ci /* Encode character into utf-16 buffer. */ 2138e66f31c5Sopenharmony_ci ENSURE_BUFFER_SPACE(1); 2139e66f31c5Sopenharmony_ci utf16_buf[utf16_buf_used++] = (WCHAR) utf8_codepoint; 2140e66f31c5Sopenharmony_ci previous_eol = 0; 2141e66f31c5Sopenharmony_ci } else { 2142e66f31c5Sopenharmony_ci ENSURE_BUFFER_SPACE(2); 2143e66f31c5Sopenharmony_ci utf8_codepoint -= 0x10000; 2144e66f31c5Sopenharmony_ci utf16_buf[utf16_buf_used++] = (WCHAR) (utf8_codepoint / 0x400 + 0xD800); 2145e66f31c5Sopenharmony_ci utf16_buf[utf16_buf_used++] = (WCHAR) (utf8_codepoint % 0x400 + 0xDC00); 2146e66f31c5Sopenharmony_ci previous_eol = 0; 2147e66f31c5Sopenharmony_ci } 2148e66f31c5Sopenharmony_ci } 2149e66f31c5Sopenharmony_ci } 2150e66f31c5Sopenharmony_ci 2151e66f31c5Sopenharmony_ci /* Flush remaining characters */ 2152e66f31c5Sopenharmony_ci FLUSH_TEXT(); 2153e66f31c5Sopenharmony_ci 2154e66f31c5Sopenharmony_ci /* Copy cached values back to struct. */ 2155e66f31c5Sopenharmony_ci handle->tty.wr.utf8_bytes_left = utf8_bytes_left; 2156e66f31c5Sopenharmony_ci handle->tty.wr.utf8_codepoint = utf8_codepoint; 2157e66f31c5Sopenharmony_ci handle->tty.wr.previous_eol = previous_eol; 2158e66f31c5Sopenharmony_ci handle->tty.wr.ansi_parser_state = ansi_parser_state; 2159e66f31c5Sopenharmony_ci 2160e66f31c5Sopenharmony_ci uv_sem_post(&uv_tty_output_lock); 2161e66f31c5Sopenharmony_ci 2162e66f31c5Sopenharmony_ci if (*error == STATUS_SUCCESS) { 2163e66f31c5Sopenharmony_ci return 0; 2164e66f31c5Sopenharmony_ci } else { 2165e66f31c5Sopenharmony_ci return -1; 2166e66f31c5Sopenharmony_ci } 2167e66f31c5Sopenharmony_ci 2168e66f31c5Sopenharmony_ci#undef FLUSH_TEXT 2169e66f31c5Sopenharmony_ci} 2170e66f31c5Sopenharmony_ci 2171e66f31c5Sopenharmony_ci 2172e66f31c5Sopenharmony_ciint uv__tty_write(uv_loop_t* loop, 2173e66f31c5Sopenharmony_ci uv_write_t* req, 2174e66f31c5Sopenharmony_ci uv_tty_t* handle, 2175e66f31c5Sopenharmony_ci const uv_buf_t bufs[], 2176e66f31c5Sopenharmony_ci unsigned int nbufs, 2177e66f31c5Sopenharmony_ci uv_write_cb cb) { 2178e66f31c5Sopenharmony_ci DWORD error; 2179e66f31c5Sopenharmony_ci 2180e66f31c5Sopenharmony_ci UV_REQ_INIT(req, UV_WRITE); 2181e66f31c5Sopenharmony_ci req->handle = (uv_stream_t*) handle; 2182e66f31c5Sopenharmony_ci req->cb = cb; 2183e66f31c5Sopenharmony_ci 2184e66f31c5Sopenharmony_ci handle->reqs_pending++; 2185e66f31c5Sopenharmony_ci handle->stream.conn.write_reqs_pending++; 2186e66f31c5Sopenharmony_ci REGISTER_HANDLE_REQ(loop, handle, req); 2187e66f31c5Sopenharmony_ci 2188e66f31c5Sopenharmony_ci req->u.io.queued_bytes = 0; 2189e66f31c5Sopenharmony_ci 2190e66f31c5Sopenharmony_ci if (!uv__tty_write_bufs(handle, bufs, nbufs, &error)) { 2191e66f31c5Sopenharmony_ci SET_REQ_SUCCESS(req); 2192e66f31c5Sopenharmony_ci } else { 2193e66f31c5Sopenharmony_ci SET_REQ_ERROR(req, error); 2194e66f31c5Sopenharmony_ci } 2195e66f31c5Sopenharmony_ci 2196e66f31c5Sopenharmony_ci uv__insert_pending_req(loop, (uv_req_t*) req); 2197e66f31c5Sopenharmony_ci 2198e66f31c5Sopenharmony_ci return 0; 2199e66f31c5Sopenharmony_ci} 2200e66f31c5Sopenharmony_ci 2201e66f31c5Sopenharmony_ci 2202e66f31c5Sopenharmony_ciint uv__tty_try_write(uv_tty_t* handle, 2203e66f31c5Sopenharmony_ci const uv_buf_t bufs[], 2204e66f31c5Sopenharmony_ci unsigned int nbufs) { 2205e66f31c5Sopenharmony_ci DWORD error; 2206e66f31c5Sopenharmony_ci 2207e66f31c5Sopenharmony_ci if (handle->stream.conn.write_reqs_pending > 0) 2208e66f31c5Sopenharmony_ci return UV_EAGAIN; 2209e66f31c5Sopenharmony_ci 2210e66f31c5Sopenharmony_ci if (uv__tty_write_bufs(handle, bufs, nbufs, &error)) 2211e66f31c5Sopenharmony_ci return uv_translate_sys_error(error); 2212e66f31c5Sopenharmony_ci 2213e66f31c5Sopenharmony_ci return uv__count_bufs(bufs, nbufs); 2214e66f31c5Sopenharmony_ci} 2215e66f31c5Sopenharmony_ci 2216e66f31c5Sopenharmony_ci 2217e66f31c5Sopenharmony_civoid uv__process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle, 2218e66f31c5Sopenharmony_ci uv_write_t* req) { 2219e66f31c5Sopenharmony_ci int err; 2220e66f31c5Sopenharmony_ci 2221e66f31c5Sopenharmony_ci handle->write_queue_size -= req->u.io.queued_bytes; 2222e66f31c5Sopenharmony_ci UNREGISTER_HANDLE_REQ(loop, handle, req); 2223e66f31c5Sopenharmony_ci 2224e66f31c5Sopenharmony_ci if (req->cb) { 2225e66f31c5Sopenharmony_ci err = GET_REQ_ERROR(req); 2226e66f31c5Sopenharmony_ci req->cb(req, uv_translate_sys_error(err)); 2227e66f31c5Sopenharmony_ci } 2228e66f31c5Sopenharmony_ci 2229e66f31c5Sopenharmony_ci 2230e66f31c5Sopenharmony_ci handle->stream.conn.write_reqs_pending--; 2231e66f31c5Sopenharmony_ci if (handle->stream.conn.write_reqs_pending == 0 && 2232e66f31c5Sopenharmony_ci uv__is_stream_shutting(handle)) 2233e66f31c5Sopenharmony_ci uv__process_tty_shutdown_req(loop, 2234e66f31c5Sopenharmony_ci handle, 2235e66f31c5Sopenharmony_ci handle->stream.conn.shutdown_req); 2236e66f31c5Sopenharmony_ci 2237e66f31c5Sopenharmony_ci DECREASE_PENDING_REQ_COUNT(handle); 2238e66f31c5Sopenharmony_ci} 2239e66f31c5Sopenharmony_ci 2240e66f31c5Sopenharmony_ci 2241e66f31c5Sopenharmony_civoid uv__tty_close(uv_tty_t* handle) { 2242e66f31c5Sopenharmony_ci assert(handle->u.fd == -1 || handle->u.fd > 2); 2243e66f31c5Sopenharmony_ci if (handle->flags & UV_HANDLE_READING) 2244e66f31c5Sopenharmony_ci uv__tty_read_stop(handle); 2245e66f31c5Sopenharmony_ci 2246e66f31c5Sopenharmony_ci if (handle->u.fd == -1) 2247e66f31c5Sopenharmony_ci CloseHandle(handle->handle); 2248e66f31c5Sopenharmony_ci else 2249e66f31c5Sopenharmony_ci _close(handle->u.fd); 2250e66f31c5Sopenharmony_ci 2251e66f31c5Sopenharmony_ci handle->u.fd = -1; 2252e66f31c5Sopenharmony_ci handle->handle = INVALID_HANDLE_VALUE; 2253e66f31c5Sopenharmony_ci handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); 2254e66f31c5Sopenharmony_ci uv__handle_closing(handle); 2255e66f31c5Sopenharmony_ci 2256e66f31c5Sopenharmony_ci if (handle->reqs_pending == 0) 2257e66f31c5Sopenharmony_ci uv__want_endgame(handle->loop, (uv_handle_t*) handle); 2258e66f31c5Sopenharmony_ci} 2259e66f31c5Sopenharmony_ci 2260e66f31c5Sopenharmony_ci 2261e66f31c5Sopenharmony_civoid uv__process_tty_shutdown_req(uv_loop_t* loop, uv_tty_t* stream, uv_shutdown_t* req) { 2262e66f31c5Sopenharmony_ci assert(stream->stream.conn.write_reqs_pending == 0); 2263e66f31c5Sopenharmony_ci assert(req); 2264e66f31c5Sopenharmony_ci 2265e66f31c5Sopenharmony_ci stream->stream.conn.shutdown_req = NULL; 2266e66f31c5Sopenharmony_ci UNREGISTER_HANDLE_REQ(loop, stream, req); 2267e66f31c5Sopenharmony_ci 2268e66f31c5Sopenharmony_ci /* TTY shutdown is really just a no-op */ 2269e66f31c5Sopenharmony_ci if (req->cb) { 2270e66f31c5Sopenharmony_ci if (stream->flags & UV_HANDLE_CLOSING) { 2271e66f31c5Sopenharmony_ci req->cb(req, UV_ECANCELED); 2272e66f31c5Sopenharmony_ci } else { 2273e66f31c5Sopenharmony_ci req->cb(req, 0); 2274e66f31c5Sopenharmony_ci } 2275e66f31c5Sopenharmony_ci } 2276e66f31c5Sopenharmony_ci 2277e66f31c5Sopenharmony_ci DECREASE_PENDING_REQ_COUNT(stream); 2278e66f31c5Sopenharmony_ci} 2279e66f31c5Sopenharmony_ci 2280e66f31c5Sopenharmony_ci 2281e66f31c5Sopenharmony_civoid uv__tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { 2282e66f31c5Sopenharmony_ci assert(handle->flags & UV_HANDLE_CLOSING); 2283e66f31c5Sopenharmony_ci assert(handle->reqs_pending == 0); 2284e66f31c5Sopenharmony_ci 2285e66f31c5Sopenharmony_ci /* The wait handle used for raw reading should be unregistered when the 2286e66f31c5Sopenharmony_ci * wait callback runs. */ 2287e66f31c5Sopenharmony_ci assert(!(handle->flags & UV_HANDLE_TTY_READABLE) || 2288e66f31c5Sopenharmony_ci handle->tty.rd.read_raw_wait == NULL); 2289e66f31c5Sopenharmony_ci 2290e66f31c5Sopenharmony_ci assert(!(handle->flags & UV_HANDLE_CLOSED)); 2291e66f31c5Sopenharmony_ci uv__handle_close(handle); 2292e66f31c5Sopenharmony_ci} 2293e66f31c5Sopenharmony_ci 2294e66f31c5Sopenharmony_ci 2295e66f31c5Sopenharmony_ciint uv_tty_reset_mode(void) { 2296e66f31c5Sopenharmony_ci /* Not necessary to do anything. */ 2297e66f31c5Sopenharmony_ci return 0; 2298e66f31c5Sopenharmony_ci} 2299e66f31c5Sopenharmony_ci 2300e66f31c5Sopenharmony_ci/* Determine whether or not this version of windows supports 2301e66f31c5Sopenharmony_ci * proper ANSI color codes. Should be supported as of windows 2302e66f31c5Sopenharmony_ci * 10 version 1511, build number 10.0.10586. 2303e66f31c5Sopenharmony_ci */ 2304e66f31c5Sopenharmony_cistatic void uv__determine_vterm_state(HANDLE handle) { 2305e66f31c5Sopenharmony_ci DWORD dwMode = 0; 2306e66f31c5Sopenharmony_ci 2307e66f31c5Sopenharmony_ci uv__need_check_vterm_state = FALSE; 2308e66f31c5Sopenharmony_ci if (!GetConsoleMode(handle, &dwMode)) { 2309e66f31c5Sopenharmony_ci return; 2310e66f31c5Sopenharmony_ci } 2311e66f31c5Sopenharmony_ci 2312e66f31c5Sopenharmony_ci dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; 2313e66f31c5Sopenharmony_ci if (!SetConsoleMode(handle, dwMode)) { 2314e66f31c5Sopenharmony_ci return; 2315e66f31c5Sopenharmony_ci } 2316e66f31c5Sopenharmony_ci 2317e66f31c5Sopenharmony_ci uv__vterm_state = UV_TTY_SUPPORTED; 2318e66f31c5Sopenharmony_ci} 2319e66f31c5Sopenharmony_ci 2320e66f31c5Sopenharmony_cistatic DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param) { 2321e66f31c5Sopenharmony_ci NTSTATUS status; 2322e66f31c5Sopenharmony_ci ULONG_PTR conhost_pid; 2323e66f31c5Sopenharmony_ci MSG msg; 2324e66f31c5Sopenharmony_ci 2325e66f31c5Sopenharmony_ci if (pSetWinEventHook == NULL || pNtQueryInformationProcess == NULL) 2326e66f31c5Sopenharmony_ci return 0; 2327e66f31c5Sopenharmony_ci 2328e66f31c5Sopenharmony_ci status = pNtQueryInformationProcess(GetCurrentProcess(), 2329e66f31c5Sopenharmony_ci ProcessConsoleHostProcess, 2330e66f31c5Sopenharmony_ci &conhost_pid, 2331e66f31c5Sopenharmony_ci sizeof(conhost_pid), 2332e66f31c5Sopenharmony_ci NULL); 2333e66f31c5Sopenharmony_ci 2334e66f31c5Sopenharmony_ci if (!NT_SUCCESS(status)) { 2335e66f31c5Sopenharmony_ci /* We couldn't retrieve our console host process, probably because this 2336e66f31c5Sopenharmony_ci * is a 32-bit process running on 64-bit Windows. Fall back to receiving 2337e66f31c5Sopenharmony_ci * console events from the input stream only. */ 2338e66f31c5Sopenharmony_ci return 0; 2339e66f31c5Sopenharmony_ci } 2340e66f31c5Sopenharmony_ci 2341e66f31c5Sopenharmony_ci /* Ensure the PID is a multiple of 4, which is required by SetWinEventHook */ 2342e66f31c5Sopenharmony_ci conhost_pid &= ~(ULONG_PTR)0x3; 2343e66f31c5Sopenharmony_ci 2344e66f31c5Sopenharmony_ci uv__tty_console_resized = CreateEvent(NULL, TRUE, FALSE, NULL); 2345e66f31c5Sopenharmony_ci if (uv__tty_console_resized == NULL) 2346e66f31c5Sopenharmony_ci return 0; 2347e66f31c5Sopenharmony_ci if (QueueUserWorkItem(uv__tty_console_resize_watcher_thread, 2348e66f31c5Sopenharmony_ci NULL, 2349e66f31c5Sopenharmony_ci WT_EXECUTELONGFUNCTION) == 0) 2350e66f31c5Sopenharmony_ci return 0; 2351e66f31c5Sopenharmony_ci 2352e66f31c5Sopenharmony_ci if (!pSetWinEventHook(EVENT_CONSOLE_LAYOUT, 2353e66f31c5Sopenharmony_ci EVENT_CONSOLE_LAYOUT, 2354e66f31c5Sopenharmony_ci NULL, 2355e66f31c5Sopenharmony_ci uv__tty_console_resize_event, 2356e66f31c5Sopenharmony_ci (DWORD)conhost_pid, 2357e66f31c5Sopenharmony_ci 0, 2358e66f31c5Sopenharmony_ci WINEVENT_OUTOFCONTEXT)) 2359e66f31c5Sopenharmony_ci return 0; 2360e66f31c5Sopenharmony_ci 2361e66f31c5Sopenharmony_ci while (GetMessage(&msg, NULL, 0, 0)) { 2362e66f31c5Sopenharmony_ci TranslateMessage(&msg); 2363e66f31c5Sopenharmony_ci DispatchMessage(&msg); 2364e66f31c5Sopenharmony_ci } 2365e66f31c5Sopenharmony_ci return 0; 2366e66f31c5Sopenharmony_ci} 2367e66f31c5Sopenharmony_ci 2368e66f31c5Sopenharmony_cistatic void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook, 2369e66f31c5Sopenharmony_ci DWORD event, 2370e66f31c5Sopenharmony_ci HWND hwnd, 2371e66f31c5Sopenharmony_ci LONG idObject, 2372e66f31c5Sopenharmony_ci LONG idChild, 2373e66f31c5Sopenharmony_ci DWORD dwEventThread, 2374e66f31c5Sopenharmony_ci DWORD dwmsEventTime) { 2375e66f31c5Sopenharmony_ci SetEvent(uv__tty_console_resized); 2376e66f31c5Sopenharmony_ci} 2377e66f31c5Sopenharmony_ci 2378e66f31c5Sopenharmony_cistatic DWORD WINAPI uv__tty_console_resize_watcher_thread(void* param) { 2379e66f31c5Sopenharmony_ci for (;;) { 2380e66f31c5Sopenharmony_ci /* Make sure to not overwhelm the system with resize events */ 2381e66f31c5Sopenharmony_ci Sleep(33); 2382e66f31c5Sopenharmony_ci WaitForSingleObject(uv__tty_console_resized, INFINITE); 2383e66f31c5Sopenharmony_ci uv__tty_console_signal_resize(); 2384e66f31c5Sopenharmony_ci ResetEvent(uv__tty_console_resized); 2385e66f31c5Sopenharmony_ci } 2386e66f31c5Sopenharmony_ci return 0; 2387e66f31c5Sopenharmony_ci} 2388e66f31c5Sopenharmony_ci 2389e66f31c5Sopenharmony_cistatic void uv__tty_console_signal_resize(void) { 2390e66f31c5Sopenharmony_ci CONSOLE_SCREEN_BUFFER_INFO sb_info; 2391e66f31c5Sopenharmony_ci int width, height; 2392e66f31c5Sopenharmony_ci 2393e66f31c5Sopenharmony_ci if (!GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info)) 2394e66f31c5Sopenharmony_ci return; 2395e66f31c5Sopenharmony_ci 2396e66f31c5Sopenharmony_ci width = sb_info.dwSize.X; 2397e66f31c5Sopenharmony_ci height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1; 2398e66f31c5Sopenharmony_ci 2399e66f31c5Sopenharmony_ci uv_mutex_lock(&uv__tty_console_resize_mutex); 2400e66f31c5Sopenharmony_ci if (width != uv__tty_console_width || height != uv__tty_console_height) { 2401e66f31c5Sopenharmony_ci uv__tty_console_width = width; 2402e66f31c5Sopenharmony_ci uv__tty_console_height = height; 2403e66f31c5Sopenharmony_ci uv_mutex_unlock(&uv__tty_console_resize_mutex); 2404e66f31c5Sopenharmony_ci uv__signal_dispatch(SIGWINCH); 2405e66f31c5Sopenharmony_ci } else { 2406e66f31c5Sopenharmony_ci uv_mutex_unlock(&uv__tty_console_resize_mutex); 2407e66f31c5Sopenharmony_ci } 2408e66f31c5Sopenharmony_ci} 2409e66f31c5Sopenharmony_ci 2410e66f31c5Sopenharmony_civoid uv_tty_set_vterm_state(uv_tty_vtermstate_t state) { 2411e66f31c5Sopenharmony_ci uv_sem_wait(&uv_tty_output_lock); 2412e66f31c5Sopenharmony_ci uv__need_check_vterm_state = FALSE; 2413e66f31c5Sopenharmony_ci uv__vterm_state = state; 2414e66f31c5Sopenharmony_ci uv_sem_post(&uv_tty_output_lock); 2415e66f31c5Sopenharmony_ci} 2416e66f31c5Sopenharmony_ci 2417e66f31c5Sopenharmony_ciint uv_tty_get_vterm_state(uv_tty_vtermstate_t* state) { 2418e66f31c5Sopenharmony_ci uv_sem_wait(&uv_tty_output_lock); 2419e66f31c5Sopenharmony_ci *state = uv__vterm_state; 2420e66f31c5Sopenharmony_ci uv_sem_post(&uv_tty_output_lock); 2421e66f31c5Sopenharmony_ci return 0; 2422e66f31c5Sopenharmony_ci} 2423