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