Blame src/win/tty.c

Packit b5b901
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
Packit b5b901
 *
Packit b5b901
 * Permission is hereby granted, free of charge, to any person obtaining a copy
Packit b5b901
 * of this software and associated documentation files (the "Software"), to
Packit b5b901
 * deal in the Software without restriction, including without limitation the
Packit b5b901
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
Packit b5b901
 * sell copies of the Software, and to permit persons to whom the Software is
Packit b5b901
 * furnished to do so, subject to the following conditions:
Packit b5b901
 *
Packit b5b901
 * The above copyright notice and this permission notice shall be included in
Packit b5b901
 * all copies or substantial portions of the Software.
Packit b5b901
 *
Packit b5b901
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Packit b5b901
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Packit b5b901
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Packit b5b901
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Packit b5b901
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
Packit b5b901
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
Packit b5b901
 * IN THE SOFTWARE.
Packit b5b901
 */
Packit b5b901
Packit b5b901
#include <assert.h>
Packit b5b901
#include <io.h>
Packit b5b901
#include <string.h>
Packit b5b901
#include <stdlib.h>
Packit b5b901
Packit b5b901
#if defined(_MSC_VER) && _MSC_VER < 1600
Packit b5b901
# include "uv/stdint-msvc2008.h"
Packit b5b901
#else
Packit b5b901
# include <stdint.h>
Packit b5b901
#endif
Packit b5b901
Packit b5b901
#ifndef COMMON_LVB_REVERSE_VIDEO
Packit b5b901
# define COMMON_LVB_REVERSE_VIDEO 0x4000
Packit b5b901
#endif
Packit b5b901
Packit b5b901
#include "uv.h"
Packit b5b901
#include "internal.h"
Packit b5b901
#include "handle-inl.h"
Packit b5b901
#include "stream-inl.h"
Packit b5b901
#include "req-inl.h"
Packit b5b901
Packit b5b901
#ifndef InterlockedOr
Packit b5b901
# define InterlockedOr _InterlockedOr
Packit b5b901
#endif
Packit b5b901
Packit b5b901
#define UNICODE_REPLACEMENT_CHARACTER (0xfffd)
Packit b5b901
Packit Service e08953
#define ANSI_NORMAL           0x0000
Packit Service e08953
#define ANSI_ESCAPE_SEEN      0x0002
Packit Service e08953
#define ANSI_CSI              0x0004
Packit Service e08953
#define ANSI_ST_CONTROL       0x0008
Packit Service e08953
#define ANSI_IGNORE           0x0010
Packit Service e08953
#define ANSI_IN_ARG           0x0020
Packit Service e08953
#define ANSI_IN_STRING        0x0040
Packit Service e08953
#define ANSI_BACKSLASH_SEEN   0x0080
Packit Service e08953
#define ANSI_EXTENSION        0x0100
Packit Service e08953
#define ANSI_DECSCUSR         0x0200
Packit b5b901
Packit b5b901
#define MAX_INPUT_BUFFER_LENGTH 8192
Packit b5b901
#define MAX_CONSOLE_CHAR 8192
Packit b5b901
Packit b5b901
#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
Packit b5b901
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
Packit b5b901
#endif
Packit b5b901
Packit Service e08953
#define CURSOR_SIZE_SMALL     25
Packit Service e08953
#define CURSOR_SIZE_LARGE     100
Packit Service e08953
Packit Service e08953
static void uv_tty_capture_initial_style(
Packit Service e08953
    CONSOLE_SCREEN_BUFFER_INFO* screen_buffer_info,
Packit Service e08953
    CONSOLE_CURSOR_INFO* cursor_info);
Packit b5b901
static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info);
Packit b5b901
static int uv__cancel_read_console(uv_tty_t* handle);
Packit b5b901
Packit b5b901
Packit b5b901
/* Null uv_buf_t */
Packit b5b901
static const uv_buf_t uv_null_buf_ = { 0, NULL };
Packit b5b901
Packit b5b901
enum uv__read_console_status_e {
Packit b5b901
  NOT_STARTED,
Packit b5b901
  IN_PROGRESS,
Packit b5b901
  TRAP_REQUESTED,
Packit b5b901
  COMPLETED
Packit b5b901
};
Packit b5b901
Packit b5b901
static volatile LONG uv__read_console_status = NOT_STARTED;
Packit b5b901
static volatile LONG uv__restore_screen_state;
Packit b5b901
static CONSOLE_SCREEN_BUFFER_INFO uv__saved_screen_state;
Packit b5b901
Packit b5b901
Packit b5b901
/*
Packit b5b901
 * The console virtual window.
Packit b5b901
 *
Packit b5b901
 * Normally cursor movement in windows is relative to the console screen buffer,
Packit b5b901
 * e.g. the application is allowed to overwrite the 'history'. This is very
Packit b5b901
 * inconvenient, it makes absolute cursor movement pretty useless. There is
Packit b5b901
 * also the concept of 'client rect' which is defined by the actual size of
Packit b5b901
 * the console window and the scroll position of the screen buffer, but it's
Packit b5b901
 * very volatile because it changes when the user scrolls.
Packit b5b901
 *
Packit b5b901
 * To make cursor movement behave sensibly we define a virtual window to which
Packit b5b901
 * cursor movement is confined. The virtual window is always as wide as the
Packit b5b901
 * console screen buffer, but it's height is defined by the size of the
Packit b5b901
 * console window. The top of the virtual window aligns with the position
Packit b5b901
 * of the caret when the first stdout/err handle is created, unless that would
Packit b5b901
 * mean that it would extend beyond the bottom of the screen buffer -  in that
Packit b5b901
 * that case it's located as far down as possible.
Packit b5b901
 *
Packit b5b901
 * When the user writes a long text or many newlines, such that the output
Packit b5b901
 * reaches beyond the bottom of the virtual window, the virtual window is
Packit b5b901
 * shifted downwards, but not resized.
Packit b5b901
 *
Packit b5b901
 * Since all tty i/o happens on the same console, this window is shared
Packit b5b901
 * between all stdout/stderr handles.
Packit b5b901
 */
Packit b5b901
Packit b5b901
static int uv_tty_virtual_offset = -1;
Packit b5b901
static int uv_tty_virtual_height = -1;
Packit b5b901
static int uv_tty_virtual_width = -1;
Packit b5b901
Packit b5b901
/* The console window size
Packit b5b901
 * We keep this separate from uv_tty_virtual_*. We use those values to only
Packit b5b901
 * handle signalling SIGWINCH
Packit b5b901
 */
Packit b5b901
Packit b5b901
static HANDLE uv__tty_console_handle = INVALID_HANDLE_VALUE;
Packit b5b901
static int uv__tty_console_height = -1;
Packit b5b901
static int uv__tty_console_width = -1;
Packit Service e08953
static HANDLE uv__tty_console_resized = INVALID_HANDLE_VALUE;
Packit Service e08953
static uv_mutex_t uv__tty_console_resize_mutex;
Packit b5b901
Packit b5b901
static DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param);
Packit b5b901
static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook,
Packit b5b901
                                                  DWORD event,
Packit b5b901
                                                  HWND hwnd,
Packit b5b901
                                                  LONG idObject,
Packit b5b901
                                                  LONG idChild,
Packit b5b901
                                                  DWORD dwEventThread,
Packit b5b901
                                                  DWORD dwmsEventTime);
Packit Service e08953
static DWORD WINAPI uv__tty_console_resize_watcher_thread(void* param);
Packit Service e08953
static void uv__tty_console_signal_resize(void);
Packit b5b901
Packit b5b901
/* We use a semaphore rather than a mutex or critical section because in some
Packit b5b901
   cases (uv__cancel_read_console) we need take the lock in the main thread and
Packit b5b901
   release it in another thread. Using a semaphore ensures that in such
Packit b5b901
   scenario the main thread will still block when trying to acquire the lock. */
Packit b5b901
static uv_sem_t uv_tty_output_lock;
Packit b5b901
Packit b5b901
static WORD uv_tty_default_text_attributes =
Packit b5b901
    FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
Packit b5b901
Packit b5b901
static char uv_tty_default_fg_color = 7;
Packit b5b901
static char uv_tty_default_bg_color = 0;
Packit b5b901
static char uv_tty_default_fg_bright = 0;
Packit b5b901
static char uv_tty_default_bg_bright = 0;
Packit b5b901
static char uv_tty_default_inverse = 0;
Packit b5b901
Packit Service e08953
static CONSOLE_CURSOR_INFO uv_tty_default_cursor_info;
Packit Service e08953
Packit b5b901
/* Determine whether or not ANSI support is enabled. */
Packit Service e08953
static BOOL uv__need_check_vterm_state = TRUE;
Packit Service e08953
static uv_tty_vtermstate_t uv__vterm_state = UV_TTY_UNSUPPORTED;
Packit b5b901
static void uv__determine_vterm_state(HANDLE handle);
Packit b5b901
Packit b5b901
void uv_console_init(void) {
Packit b5b901
  if (uv_sem_init(&uv_tty_output_lock, 1))
Packit b5b901
    abort();
Packit b5b901
  uv__tty_console_handle = CreateFileW(L"CONOUT$",
Packit b5b901
                                       GENERIC_READ | GENERIC_WRITE,
Packit b5b901
                                       FILE_SHARE_WRITE,
Packit b5b901
                                       0,
Packit b5b901
                                       OPEN_EXISTING,
Packit b5b901
                                       0,
Packit b5b901
                                       0);
Packit Service e08953
  if (uv__tty_console_handle != INVALID_HANDLE_VALUE) {
Packit Service e08953
    CONSOLE_SCREEN_BUFFER_INFO sb_info;
Packit b5b901
    QueueUserWorkItem(uv__tty_console_resize_message_loop_thread,
Packit b5b901
                      NULL,
Packit b5b901
                      WT_EXECUTELONGFUNCTION);
Packit Service e08953
    uv_mutex_init(&uv__tty_console_resize_mutex);
Packit Service e08953
    if (GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info)) {
Packit Service e08953
      uv__tty_console_width = sb_info.dwSize.X;
Packit Service e08953
      uv__tty_console_height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1;
Packit Service e08953
    }
Packit b5b901
  }
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) {
Packit b5b901
  BOOL readable;
Packit b5b901
  DWORD NumberOfEvents;
Packit b5b901
  HANDLE handle;
Packit b5b901
  CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
Packit Service e08953
  CONSOLE_CURSOR_INFO cursor_info;
Packit b5b901
  (void)unused;
Packit b5b901
Packit b5b901
  uv__once_init();
Packit b5b901
  handle = (HANDLE) uv__get_osfhandle(fd);
Packit b5b901
  if (handle == INVALID_HANDLE_VALUE)
Packit b5b901
    return UV_EBADF;
Packit b5b901
Packit b5b901
  if (fd <= 2) {
Packit b5b901
    /* In order to avoid closing a stdio file descriptor 0-2, duplicate the
Packit b5b901
     * underlying OS handle and forget about the original fd.
Packit b5b901
     * We could also opt to use the original OS handle and just never close it,
Packit b5b901
     * but then there would be no reliable way to cancel pending read operations
Packit b5b901
     * upon close.
Packit b5b901
     */
Packit b5b901
    if (!DuplicateHandle(INVALID_HANDLE_VALUE,
Packit b5b901
                         handle,
Packit b5b901
                         INVALID_HANDLE_VALUE,
Packit b5b901
                         &handle,
Packit b5b901
                         0,
Packit b5b901
                         FALSE,
Packit b5b901
                         DUPLICATE_SAME_ACCESS))
Packit b5b901
      return uv_translate_sys_error(GetLastError());
Packit b5b901
    fd = -1;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  readable = GetNumberOfConsoleInputEvents(handle, &NumberOfEvents);
Packit b5b901
  if (!readable) {
Packit b5b901
    /* Obtain the screen buffer info with the output handle. */
Packit b5b901
    if (!GetConsoleScreenBufferInfo(handle, &screen_buffer_info)) {
Packit b5b901
      return uv_translate_sys_error(GetLastError());
Packit b5b901
    }
Packit b5b901
Packit Service e08953
    /* Obtain the cursor info with the output handle. */
Packit Service e08953
    if (!GetConsoleCursorInfo(handle, &cursor_info)) {
Packit Service e08953
      return uv_translate_sys_error(GetLastError());
Packit Service e08953
    }
Packit Service e08953
Packit b5b901
    /* Obtain the tty_output_lock because the virtual window state is shared
Packit b5b901
     * between all uv_tty_t handles. */
Packit b5b901
    uv_sem_wait(&uv_tty_output_lock);
Packit b5b901
Packit Service e08953
    if (uv__need_check_vterm_state)
Packit b5b901
      uv__determine_vterm_state(handle);
Packit b5b901
Packit Service e08953
    /* Remember the original console text attributes and cursor info. */
Packit Service e08953
    uv_tty_capture_initial_style(&screen_buffer_info, &cursor_info);
Packit b5b901
Packit b5b901
    uv_tty_update_virtual_window(&screen_buffer_info);
Packit b5b901
Packit b5b901
    uv_sem_post(&uv_tty_output_lock);
Packit b5b901
  }
Packit b5b901
Packit b5b901
Packit b5b901
  uv_stream_init(loop, (uv_stream_t*) tty, UV_TTY);
Packit b5b901
  uv_connection_init((uv_stream_t*) tty);
Packit b5b901
Packit b5b901
  tty->handle = handle;
Packit b5b901
  tty->u.fd = fd;
Packit b5b901
  tty->reqs_pending = 0;
Packit b5b901
  tty->flags |= UV_HANDLE_BOUND;
Packit b5b901
Packit b5b901
  if (readable) {
Packit b5b901
    /* Initialize TTY input specific fields. */
Packit b5b901
    tty->flags |= UV_HANDLE_TTY_READABLE | UV_HANDLE_READABLE;
Packit b5b901
    /* TODO: remove me in v2.x. */
Packit b5b901
    tty->tty.rd.unused_ = NULL;
Packit b5b901
    tty->tty.rd.read_line_buffer = uv_null_buf_;
Packit b5b901
    tty->tty.rd.read_raw_wait = NULL;
Packit b5b901
Packit b5b901
    /* Init keycode-to-vt100 mapper state. */
Packit b5b901
    tty->tty.rd.last_key_len = 0;
Packit b5b901
    tty->tty.rd.last_key_offset = 0;
Packit b5b901
    tty->tty.rd.last_utf16_high_surrogate = 0;
Packit b5b901
    memset(&tty->tty.rd.last_input_record, 0, sizeof tty->tty.rd.last_input_record);
Packit b5b901
  } else {
Packit b5b901
    /* TTY output specific fields. */
Packit b5b901
    tty->flags |= UV_HANDLE_WRITABLE;
Packit b5b901
Packit b5b901
    /* Init utf8-to-utf16 conversion state. */
Packit b5b901
    tty->tty.wr.utf8_bytes_left = 0;
Packit b5b901
    tty->tty.wr.utf8_codepoint = 0;
Packit b5b901
Packit b5b901
    /* Initialize eol conversion state */
Packit b5b901
    tty->tty.wr.previous_eol = 0;
Packit b5b901
Packit b5b901
    /* Init ANSI parser state. */
Packit b5b901
    tty->tty.wr.ansi_parser_state = ANSI_NORMAL;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
/* Set the default console text attributes based on how the console was
Packit b5b901
 * configured when libuv started.
Packit b5b901
 */
Packit Service e08953
static void uv_tty_capture_initial_style(
Packit Service e08953
    CONSOLE_SCREEN_BUFFER_INFO* screen_buffer_info,
Packit Service e08953
    CONSOLE_CURSOR_INFO* cursor_info) {
Packit b5b901
  static int style_captured = 0;
Packit b5b901
Packit b5b901
  /* Only do this once.
Packit b5b901
     Assumption: Caller has acquired uv_tty_output_lock. */
Packit b5b901
  if (style_captured)
Packit b5b901
    return;
Packit b5b901
Packit b5b901
  /* Save raw win32 attributes. */
Packit Service e08953
  uv_tty_default_text_attributes = screen_buffer_info->wAttributes;
Packit b5b901
Packit b5b901
  /* Convert black text on black background to use white text. */
Packit b5b901
  if (uv_tty_default_text_attributes == 0)
Packit b5b901
    uv_tty_default_text_attributes = 7;
Packit b5b901
Packit b5b901
  /* Convert Win32 attributes to ANSI colors. */
Packit b5b901
  uv_tty_default_fg_color = 0;
Packit b5b901
  uv_tty_default_bg_color = 0;
Packit b5b901
  uv_tty_default_fg_bright = 0;
Packit b5b901
  uv_tty_default_bg_bright = 0;
Packit b5b901
  uv_tty_default_inverse = 0;
Packit b5b901
Packit b5b901
  if (uv_tty_default_text_attributes & FOREGROUND_RED)
Packit b5b901
    uv_tty_default_fg_color |= 1;
Packit b5b901
Packit b5b901
  if (uv_tty_default_text_attributes & FOREGROUND_GREEN)
Packit b5b901
    uv_tty_default_fg_color |= 2;
Packit b5b901
Packit b5b901
  if (uv_tty_default_text_attributes & FOREGROUND_BLUE)
Packit b5b901
    uv_tty_default_fg_color |= 4;
Packit b5b901
Packit b5b901
  if (uv_tty_default_text_attributes & BACKGROUND_RED)
Packit b5b901
    uv_tty_default_bg_color |= 1;
Packit b5b901
Packit b5b901
  if (uv_tty_default_text_attributes & BACKGROUND_GREEN)
Packit b5b901
    uv_tty_default_bg_color |= 2;
Packit b5b901
Packit b5b901
  if (uv_tty_default_text_attributes & BACKGROUND_BLUE)
Packit b5b901
    uv_tty_default_bg_color |= 4;
Packit b5b901
Packit b5b901
  if (uv_tty_default_text_attributes & FOREGROUND_INTENSITY)
Packit b5b901
    uv_tty_default_fg_bright = 1;
Packit b5b901
Packit b5b901
  if (uv_tty_default_text_attributes & BACKGROUND_INTENSITY)
Packit b5b901
    uv_tty_default_bg_bright = 1;
Packit b5b901
Packit b5b901
  if (uv_tty_default_text_attributes & COMMON_LVB_REVERSE_VIDEO)
Packit b5b901
    uv_tty_default_inverse = 1;
Packit b5b901
Packit Service e08953
  /* Save the cursor size and the cursor state. */
Packit Service e08953
  uv_tty_default_cursor_info = *cursor_info;
Packit Service e08953
Packit b5b901
  style_captured = 1;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
Packit b5b901
  DWORD flags;
Packit b5b901
  unsigned char was_reading;
Packit b5b901
  uv_alloc_cb alloc_cb;
Packit b5b901
  uv_read_cb read_cb;
Packit b5b901
  int err;
Packit b5b901
Packit b5b901
  if (!(tty->flags & UV_HANDLE_TTY_READABLE)) {
Packit b5b901
    return UV_EINVAL;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (!!mode == !!(tty->flags & UV_HANDLE_TTY_RAW)) {
Packit b5b901
    return 0;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  switch (mode) {
Packit b5b901
    case UV_TTY_MODE_NORMAL:
Packit b5b901
      flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
Packit b5b901
      break;
Packit b5b901
    case UV_TTY_MODE_RAW:
Packit b5b901
      flags = ENABLE_WINDOW_INPUT;
Packit b5b901
      break;
Packit b5b901
    case UV_TTY_MODE_IO:
Packit b5b901
      return UV_ENOTSUP;
Packit b5b901
    default:
Packit b5b901
      return UV_EINVAL;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* If currently reading, stop, and restart reading. */
Packit b5b901
  if (tty->flags & UV_HANDLE_READING) {
Packit b5b901
    was_reading = 1;
Packit b5b901
    alloc_cb = tty->alloc_cb;
Packit b5b901
    read_cb = tty->read_cb;
Packit b5b901
    err = uv_tty_read_stop(tty);
Packit b5b901
    if (err) {
Packit b5b901
      return uv_translate_sys_error(err);
Packit b5b901
    }
Packit b5b901
  } else {
Packit b5b901
    was_reading = 0;
Packit Service e08953
    alloc_cb = NULL;
Packit Service e08953
    read_cb = NULL;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  uv_sem_wait(&uv_tty_output_lock);
Packit b5b901
  if (!SetConsoleMode(tty->handle, flags)) {
Packit b5b901
    err = uv_translate_sys_error(GetLastError());
Packit b5b901
    uv_sem_post(&uv_tty_output_lock);
Packit b5b901
    return err;
Packit b5b901
  }
Packit b5b901
  uv_sem_post(&uv_tty_output_lock);
Packit b5b901
Packit b5b901
  /* Update flag. */
Packit b5b901
  tty->flags &= ~UV_HANDLE_TTY_RAW;
Packit b5b901
  tty->flags |= mode ? UV_HANDLE_TTY_RAW : 0;
Packit b5b901
Packit b5b901
  /* If we just stopped reading, restart. */
Packit b5b901
  if (was_reading) {
Packit b5b901
    err = uv_tty_read_start(tty, alloc_cb, read_cb);
Packit b5b901
    if (err) {
Packit b5b901
      return uv_translate_sys_error(err);
Packit b5b901
    }
Packit b5b901
  }
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
Packit b5b901
  CONSOLE_SCREEN_BUFFER_INFO info;
Packit b5b901
Packit b5b901
  if (!GetConsoleScreenBufferInfo(tty->handle, &info)) {
Packit b5b901
    return uv_translate_sys_error(GetLastError());
Packit b5b901
  }
Packit b5b901
Packit b5b901
  uv_sem_wait(&uv_tty_output_lock);
Packit b5b901
  uv_tty_update_virtual_window(&info;;
Packit b5b901
  uv_sem_post(&uv_tty_output_lock);
Packit b5b901
Packit b5b901
  *width = uv_tty_virtual_width;
Packit b5b901
  *height = uv_tty_virtual_height;
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static void CALLBACK uv_tty_post_raw_read(void* data, BOOLEAN didTimeout) {
Packit b5b901
  uv_loop_t* loop;
Packit b5b901
  uv_tty_t* handle;
Packit b5b901
  uv_req_t* req;
Packit b5b901
Packit b5b901
  assert(data);
Packit b5b901
  assert(!didTimeout);
Packit b5b901
Packit b5b901
  req = (uv_req_t*) data;
Packit b5b901
  handle = (uv_tty_t*) req->data;
Packit b5b901
  loop = handle->loop;
Packit b5b901
Packit b5b901
  UnregisterWait(handle->tty.rd.read_raw_wait);
Packit b5b901
  handle->tty.rd.read_raw_wait = NULL;
Packit b5b901
Packit b5b901
  SET_REQ_SUCCESS(req);
Packit b5b901
  POST_COMPLETION_FOR_REQ(loop, req);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static void uv_tty_queue_read_raw(uv_loop_t* loop, uv_tty_t* handle) {
Packit b5b901
  uv_read_t* req;
Packit b5b901
  BOOL r;
Packit b5b901
Packit b5b901
  assert(handle->flags & UV_HANDLE_READING);
Packit b5b901
  assert(!(handle->flags & UV_HANDLE_READ_PENDING));
Packit b5b901
Packit b5b901
  assert(handle->handle && handle->handle != INVALID_HANDLE_VALUE);
Packit b5b901
Packit b5b901
  handle->tty.rd.read_line_buffer = uv_null_buf_;
Packit b5b901
Packit b5b901
  req = &handle->read_req;
Packit b5b901
  memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
Packit b5b901
Packit b5b901
  r = RegisterWaitForSingleObject(&handle->tty.rd.read_raw_wait,
Packit b5b901
                                  handle->handle,
Packit b5b901
                                  uv_tty_post_raw_read,
Packit b5b901
                                  (void*) req,
Packit b5b901
                                  INFINITE,
Packit b5b901
                                  WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE);
Packit b5b901
  if (!r) {
Packit b5b901
    handle->tty.rd.read_raw_wait = NULL;
Packit b5b901
    SET_REQ_ERROR(req, GetLastError());
Packit b5b901
    uv_insert_pending_req(loop, (uv_req_t*)req);
Packit b5b901
  }
Packit b5b901
Packit b5b901
  handle->flags |= UV_HANDLE_READ_PENDING;
Packit b5b901
  handle->reqs_pending++;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static DWORD CALLBACK uv_tty_line_read_thread(void* data) {
Packit b5b901
  uv_loop_t* loop;
Packit b5b901
  uv_tty_t* handle;
Packit b5b901
  uv_req_t* req;
Packit b5b901
  DWORD bytes, read_bytes;
Packit b5b901
  WCHAR utf16[MAX_INPUT_BUFFER_LENGTH / 3];
Packit b5b901
  DWORD chars, read_chars;
Packit b5b901
  LONG status;
Packit b5b901
  COORD pos;
Packit b5b901
  BOOL read_console_success;
Packit b5b901
Packit b5b901
  assert(data);
Packit b5b901
Packit b5b901
  req = (uv_req_t*) data;
Packit b5b901
  handle = (uv_tty_t*) req->data;
Packit b5b901
  loop = handle->loop;
Packit b5b901
Packit b5b901
  assert(handle->tty.rd.read_line_buffer.base != NULL);
Packit b5b901
  assert(handle->tty.rd.read_line_buffer.len > 0);
Packit b5b901
Packit b5b901
  /* ReadConsole can't handle big buffers. */
Packit b5b901
  if (handle->tty.rd.read_line_buffer.len < MAX_INPUT_BUFFER_LENGTH) {
Packit b5b901
    bytes = handle->tty.rd.read_line_buffer.len;
Packit b5b901
  } else {
Packit b5b901
    bytes = MAX_INPUT_BUFFER_LENGTH;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* At last, unicode! One utf-16 codeunit never takes more than 3 utf-8
Packit b5b901
   * codeunits to encode. */
Packit b5b901
  chars = bytes / 3;
Packit b5b901
Packit b5b901
  status = InterlockedExchange(&uv__read_console_status, IN_PROGRESS);
Packit b5b901
  if (status == TRAP_REQUESTED) {
Packit b5b901
    SET_REQ_SUCCESS(req);
Packit b5b901
    req->u.io.overlapped.InternalHigh = 0;
Packit b5b901
    POST_COMPLETION_FOR_REQ(loop, req);
Packit b5b901
    return 0;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  read_console_success = ReadConsoleW(handle->handle,
Packit b5b901
                                      (void*) utf16,
Packit b5b901
                                      chars,
Packit b5b901
                                      &read_chars,
Packit b5b901
                                      NULL);
Packit b5b901
Packit b5b901
  if (read_console_success) {
Packit b5b901
    read_bytes = WideCharToMultiByte(CP_UTF8,
Packit b5b901
                                     0,
Packit b5b901
                                     utf16,
Packit b5b901
                                     read_chars,
Packit b5b901
                                     handle->tty.rd.read_line_buffer.base,
Packit b5b901
                                     bytes,
Packit b5b901
                                     NULL,
Packit b5b901
                                     NULL);
Packit b5b901
    SET_REQ_SUCCESS(req);
Packit b5b901
    req->u.io.overlapped.InternalHigh = read_bytes;
Packit b5b901
  } else {
Packit b5b901
    SET_REQ_ERROR(req, GetLastError());
Packit b5b901
  }
Packit b5b901
Packit b5b901
  status = InterlockedExchange(&uv__read_console_status, COMPLETED);
Packit b5b901
Packit b5b901
  if (status ==  TRAP_REQUESTED) {
Packit b5b901
    /* If we canceled the read by sending a VK_RETURN event, restore the
Packit b5b901
       screen state to undo the visual effect of the VK_RETURN */
Packit b5b901
    if (read_console_success && InterlockedOr(&uv__restore_screen_state, 0)) {
Packit b5b901
      HANDLE active_screen_buffer;
Packit b5b901
      active_screen_buffer = CreateFileA("conout$",
Packit b5b901
                                         GENERIC_READ | GENERIC_WRITE,
Packit b5b901
                                         FILE_SHARE_READ | FILE_SHARE_WRITE,
Packit b5b901
                                         NULL,
Packit b5b901
                                         OPEN_EXISTING,
Packit b5b901
                                         FILE_ATTRIBUTE_NORMAL,
Packit b5b901
                                         NULL);
Packit b5b901
      if (active_screen_buffer != INVALID_HANDLE_VALUE) {
Packit b5b901
        pos = uv__saved_screen_state.dwCursorPosition;
Packit b5b901
Packit b5b901
        /* If the cursor was at the bottom line of the screen buffer, the
Packit b5b901
           VK_RETURN would have caused the buffer contents to scroll up by one
Packit b5b901
           line. The right position to reset the cursor to is therefore one line
Packit b5b901
           higher */
Packit b5b901
        if (pos.Y == uv__saved_screen_state.dwSize.Y - 1)
Packit b5b901
          pos.Y--;
Packit b5b901
Packit b5b901
        SetConsoleCursorPosition(active_screen_buffer, pos);
Packit b5b901
        CloseHandle(active_screen_buffer);
Packit b5b901
      }
Packit b5b901
    }
Packit b5b901
    uv_sem_post(&uv_tty_output_lock);
Packit b5b901
  }
Packit b5b901
  POST_COMPLETION_FOR_REQ(loop, req);
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) {
Packit b5b901
  uv_read_t* req;
Packit b5b901
  BOOL r;
Packit b5b901
Packit b5b901
  assert(handle->flags & UV_HANDLE_READING);
Packit b5b901
  assert(!(handle->flags & UV_HANDLE_READ_PENDING));
Packit b5b901
  assert(handle->handle && handle->handle != INVALID_HANDLE_VALUE);
Packit b5b901
Packit b5b901
  req = &handle->read_req;
Packit b5b901
  memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
Packit b5b901
Packit b5b901
  handle->tty.rd.read_line_buffer = uv_buf_init(NULL, 0);
Packit b5b901
  handle->alloc_cb((uv_handle_t*) handle, 8192, &handle->tty.rd.read_line_buffer);
Packit b5b901
  if (handle->tty.rd.read_line_buffer.base == NULL ||
Packit b5b901
      handle->tty.rd.read_line_buffer.len == 0) {
Packit b5b901
    handle->read_cb((uv_stream_t*) handle,
Packit b5b901
                    UV_ENOBUFS,
Packit b5b901
                    &handle->tty.rd.read_line_buffer);
Packit b5b901
    return;
Packit b5b901
  }
Packit b5b901
  assert(handle->tty.rd.read_line_buffer.base != NULL);
Packit b5b901
Packit b5b901
  /* Reset flags  No locking is required since there cannot be a line read
Packit b5b901
     in progress. We are also relying on the memory barrier provided by
Packit b5b901
     QueueUserWorkItem*/
Packit b5b901
  uv__restore_screen_state = FALSE;
Packit b5b901
  uv__read_console_status = NOT_STARTED;
Packit b5b901
  r = QueueUserWorkItem(uv_tty_line_read_thread,
Packit b5b901
                        (void*) req,
Packit b5b901
                        WT_EXECUTELONGFUNCTION);
Packit b5b901
  if (!r) {
Packit b5b901
    SET_REQ_ERROR(req, GetLastError());
Packit b5b901
    uv_insert_pending_req(loop, (uv_req_t*)req);
Packit b5b901
  }
Packit b5b901
Packit b5b901
  handle->flags |= UV_HANDLE_READ_PENDING;
Packit b5b901
  handle->reqs_pending++;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static void uv_tty_queue_read(uv_loop_t* loop, uv_tty_t* handle) {
Packit b5b901
  if (handle->flags & UV_HANDLE_TTY_RAW) {
Packit b5b901
    uv_tty_queue_read_raw(loop, handle);
Packit b5b901
  } else {
Packit b5b901
    uv_tty_queue_read_line(loop, handle);
Packit b5b901
  }
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static const char* get_vt100_fn_key(DWORD code, char shift, char ctrl,
Packit b5b901
    size_t* len) {
Packit b5b901
#define VK_CASE(vk, normal_str, shift_str, ctrl_str, shift_ctrl_str)          \
Packit b5b901
    case (vk):                                                                \
Packit b5b901
      if (shift && ctrl) {                                                    \
Packit b5b901
        *len = sizeof shift_ctrl_str;                                         \
Packit b5b901
        return "\033" shift_ctrl_str;                                         \
Packit b5b901
      } else if (shift) {                                                     \
Packit b5b901
        *len = sizeof shift_str ;                                             \
Packit b5b901
        return "\033" shift_str;                                              \
Packit b5b901
      } else if (ctrl) {                                                      \
Packit b5b901
        *len = sizeof ctrl_str;                                               \
Packit b5b901
        return "\033" ctrl_str;                                               \
Packit b5b901
      } else {                                                                \
Packit b5b901
        *len = sizeof normal_str;                                             \
Packit b5b901
        return "\033" normal_str;                                             \
Packit b5b901
      }
Packit b5b901
Packit b5b901
  switch (code) {
Packit b5b901
    /* These mappings are the same as Cygwin's. Unmodified and alt-modified
Packit b5b901
     * keypad keys comply with linux console, modifiers comply with xterm
Packit b5b901
     * modifier usage. F1. f12 and shift-f1. f10 comply with linux console, f6.
Packit b5b901
     * f12 with and without modifiers comply with rxvt. */
Packit b5b901
    VK_CASE(VK_INSERT,  "[2~",  "[2;2~", "[2;5~", "[2;6~")
Packit b5b901
    VK_CASE(VK_END,     "[4~",  "[4;2~", "[4;5~", "[4;6~")
Packit b5b901
    VK_CASE(VK_DOWN,    "[B",   "[1;2B", "[1;5B", "[1;6B")
Packit b5b901
    VK_CASE(VK_NEXT,    "[6~",  "[6;2~", "[6;5~", "[6;6~")
Packit b5b901
    VK_CASE(VK_LEFT,    "[D",   "[1;2D", "[1;5D", "[1;6D")
Packit b5b901
    VK_CASE(VK_CLEAR,   "[G",   "[1;2G", "[1;5G", "[1;6G")
Packit b5b901
    VK_CASE(VK_RIGHT,   "[C",   "[1;2C", "[1;5C", "[1;6C")
Packit b5b901
    VK_CASE(VK_UP,      "[A",   "[1;2A", "[1;5A", "[1;6A")
Packit b5b901
    VK_CASE(VK_HOME,    "[1~",  "[1;2~", "[1;5~", "[1;6~")
Packit b5b901
    VK_CASE(VK_PRIOR,   "[5~",  "[5;2~", "[5;5~", "[5;6~")
Packit b5b901
    VK_CASE(VK_DELETE,  "[3~",  "[3;2~", "[3;5~", "[3;6~")
Packit b5b901
    VK_CASE(VK_NUMPAD0, "[2~",  "[2;2~", "[2;5~", "[2;6~")
Packit b5b901
    VK_CASE(VK_NUMPAD1, "[4~",  "[4;2~", "[4;5~", "[4;6~")
Packit b5b901
    VK_CASE(VK_NUMPAD2, "[B",   "[1;2B", "[1;5B", "[1;6B")
Packit b5b901
    VK_CASE(VK_NUMPAD3, "[6~",  "[6;2~", "[6;5~", "[6;6~")
Packit b5b901
    VK_CASE(VK_NUMPAD4, "[D",   "[1;2D", "[1;5D", "[1;6D")
Packit b5b901
    VK_CASE(VK_NUMPAD5, "[G",   "[1;2G", "[1;5G", "[1;6G")
Packit b5b901
    VK_CASE(VK_NUMPAD6, "[C",   "[1;2C", "[1;5C", "[1;6C")
Packit b5b901
    VK_CASE(VK_NUMPAD7, "[A",   "[1;2A", "[1;5A", "[1;6A")
Packit b5b901
    VK_CASE(VK_NUMPAD8, "[1~",  "[1;2~", "[1;5~", "[1;6~")
Packit b5b901
    VK_CASE(VK_NUMPAD9, "[5~",  "[5;2~", "[5;5~", "[5;6~")
Packit b5b901
    VK_CASE(VK_DECIMAL, "[3~",  "[3;2~", "[3;5~", "[3;6~")
Packit b5b901
    VK_CASE(VK_F1,      "[[A",  "[23~",  "[11^",  "[23^" )
Packit b5b901
    VK_CASE(VK_F2,      "[[B",  "[24~",  "[12^",  "[24^" )
Packit b5b901
    VK_CASE(VK_F3,      "[[C",  "[25~",  "[13^",  "[25^" )
Packit b5b901
    VK_CASE(VK_F4,      "[[D",  "[26~",  "[14^",  "[26^" )
Packit b5b901
    VK_CASE(VK_F5,      "[[E",  "[28~",  "[15^",  "[28^" )
Packit b5b901
    VK_CASE(VK_F6,      "[17~", "[29~",  "[17^",  "[29^" )
Packit b5b901
    VK_CASE(VK_F7,      "[18~", "[31~",  "[18^",  "[31^" )
Packit b5b901
    VK_CASE(VK_F8,      "[19~", "[32~",  "[19^",  "[32^" )
Packit b5b901
    VK_CASE(VK_F9,      "[20~", "[33~",  "[20^",  "[33^" )
Packit b5b901
    VK_CASE(VK_F10,     "[21~", "[34~",  "[21^",  "[34^" )
Packit b5b901
    VK_CASE(VK_F11,     "[23~", "[23$",  "[23^",  "[23@" )
Packit b5b901
    VK_CASE(VK_F12,     "[24~", "[24$",  "[24^",  "[24@" )
Packit b5b901
Packit b5b901
    default:
Packit b5b901
      *len = 0;
Packit b5b901
      return NULL;
Packit b5b901
  }
Packit b5b901
#undef VK_CASE
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
Packit b5b901
    uv_req_t* req) {
Packit b5b901
  /* Shortcut for handle->tty.rd.last_input_record.Event.KeyEvent. */
Packit b5b901
#define KEV handle->tty.rd.last_input_record.Event.KeyEvent
Packit b5b901
Packit b5b901
  DWORD records_left, records_read;
Packit b5b901
  uv_buf_t buf;
Packit b5b901
  off_t buf_used;
Packit b5b901
Packit b5b901
  assert(handle->type == UV_TTY);
Packit b5b901
  assert(handle->flags & UV_HANDLE_TTY_READABLE);
Packit b5b901
  handle->flags &= ~UV_HANDLE_READ_PENDING;
Packit b5b901
Packit b5b901
  if (!(handle->flags & UV_HANDLE_READING) ||
Packit b5b901
      !(handle->flags & UV_HANDLE_TTY_RAW)) {
Packit b5b901
    goto out;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (!REQ_SUCCESS(req)) {
Packit b5b901
    /* An error occurred while waiting for the event. */
Packit b5b901
    if ((handle->flags & UV_HANDLE_READING)) {
Packit b5b901
      handle->flags &= ~UV_HANDLE_READING;
Packit b5b901
      handle->read_cb((uv_stream_t*)handle,
Packit b5b901
                      uv_translate_sys_error(GET_REQ_ERROR(req)),
Packit b5b901
                      &uv_null_buf_);
Packit b5b901
    }
Packit b5b901
    goto out;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* Fetch the number of events  */
Packit b5b901
  if (!GetNumberOfConsoleInputEvents(handle->handle, &records_left)) {
Packit b5b901
    handle->flags &= ~UV_HANDLE_READING;
Packit b5b901
    DECREASE_ACTIVE_COUNT(loop, handle);
Packit b5b901
    handle->read_cb((uv_stream_t*)handle,
Packit b5b901
                    uv_translate_sys_error(GetLastError()),
Packit b5b901
                    &uv_null_buf_);
Packit b5b901
    goto out;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* Windows sends a lot of events that we're not interested in, so buf will be
Packit b5b901
   * allocated on demand, when there's actually something to emit. */
Packit b5b901
  buf = uv_null_buf_;
Packit b5b901
  buf_used = 0;
Packit b5b901
Packit b5b901
  while ((records_left > 0 || handle->tty.rd.last_key_len > 0) &&
Packit b5b901
         (handle->flags & UV_HANDLE_READING)) {
Packit b5b901
    if (handle->tty.rd.last_key_len == 0) {
Packit b5b901
      /* Read the next input record */
Packit b5b901
      if (!ReadConsoleInputW(handle->handle,
Packit b5b901
                             &handle->tty.rd.last_input_record,
Packit b5b901
                             1,
Packit b5b901
                             &records_read)) {
Packit b5b901
        handle->flags &= ~UV_HANDLE_READING;
Packit b5b901
        DECREASE_ACTIVE_COUNT(loop, handle);
Packit b5b901
        handle->read_cb((uv_stream_t*) handle,
Packit b5b901
                        uv_translate_sys_error(GetLastError()),
Packit b5b901
                        &buf;;
Packit b5b901
        goto out;
Packit b5b901
      }
Packit b5b901
      records_left--;
Packit b5b901
Packit Service e08953
      /* We might be not subscribed to EVENT_CONSOLE_LAYOUT or we might be
Packit Service e08953
       * running under some TTY emulator that does not send those events. */
Packit Service e08953
      if (handle->tty.rd.last_input_record.EventType == WINDOW_BUFFER_SIZE_EVENT) {
Packit Service e08953
        uv__tty_console_signal_resize();
Packit Service e08953
      }
Packit Service e08953
Packit b5b901
      /* Ignore other events that are not key events. */
Packit b5b901
      if (handle->tty.rd.last_input_record.EventType != KEY_EVENT) {
Packit b5b901
        continue;
Packit b5b901
      }
Packit b5b901
Packit b5b901
      /* Ignore keyup events, unless the left alt key was held and a valid
Packit b5b901
       * unicode character was emitted. */
Packit Service e08953
      if (!KEV.bKeyDown &&
Packit Service e08953
          (KEV.wVirtualKeyCode != VK_MENU ||
Packit Service e08953
           KEV.uChar.UnicodeChar == 0)) {
Packit b5b901
        continue;
Packit b5b901
      }
Packit b5b901
Packit b5b901
      /* Ignore keypresses to numpad number keys if the left alt is held
Packit b5b901
       * because the user is composing a character, or windows simulating this.
Packit b5b901
       */
Packit b5b901
      if ((KEV.dwControlKeyState & LEFT_ALT_PRESSED) &&
Packit b5b901
          !(KEV.dwControlKeyState & ENHANCED_KEY) &&
Packit b5b901
          (KEV.wVirtualKeyCode == VK_INSERT ||
Packit b5b901
          KEV.wVirtualKeyCode == VK_END ||
Packit b5b901
          KEV.wVirtualKeyCode == VK_DOWN ||
Packit b5b901
          KEV.wVirtualKeyCode == VK_NEXT ||
Packit b5b901
          KEV.wVirtualKeyCode == VK_LEFT ||
Packit b5b901
          KEV.wVirtualKeyCode == VK_CLEAR ||
Packit b5b901
          KEV.wVirtualKeyCode == VK_RIGHT ||
Packit b5b901
          KEV.wVirtualKeyCode == VK_HOME ||
Packit b5b901
          KEV.wVirtualKeyCode == VK_UP ||
Packit b5b901
          KEV.wVirtualKeyCode == VK_PRIOR ||
Packit b5b901
          KEV.wVirtualKeyCode == VK_NUMPAD0 ||
Packit b5b901
          KEV.wVirtualKeyCode == VK_NUMPAD1 ||
Packit b5b901
          KEV.wVirtualKeyCode == VK_NUMPAD2 ||
Packit b5b901
          KEV.wVirtualKeyCode == VK_NUMPAD3 ||
Packit b5b901
          KEV.wVirtualKeyCode == VK_NUMPAD4 ||
Packit b5b901
          KEV.wVirtualKeyCode == VK_NUMPAD5 ||
Packit b5b901
          KEV.wVirtualKeyCode == VK_NUMPAD6 ||
Packit b5b901
          KEV.wVirtualKeyCode == VK_NUMPAD7 ||
Packit b5b901
          KEV.wVirtualKeyCode == VK_NUMPAD8 ||
Packit b5b901
          KEV.wVirtualKeyCode == VK_NUMPAD9)) {
Packit b5b901
        continue;
Packit b5b901
      }
Packit b5b901
Packit b5b901
      if (KEV.uChar.UnicodeChar != 0) {
Packit b5b901
        int prefix_len, char_len;
Packit b5b901
Packit b5b901
        /* Character key pressed */
Packit b5b901
        if (KEV.uChar.UnicodeChar >= 0xD800 &&
Packit b5b901
            KEV.uChar.UnicodeChar < 0xDC00) {
Packit b5b901
          /* UTF-16 high surrogate */
Packit b5b901
          handle->tty.rd.last_utf16_high_surrogate = KEV.uChar.UnicodeChar;
Packit b5b901
          continue;
Packit b5b901
        }
Packit b5b901
Packit b5b901
        /* Prefix with \u033 if alt was held, but alt was not used as part a
Packit b5b901
         * compose sequence. */
Packit b5b901
        if ((KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
Packit b5b901
            && !(KEV.dwControlKeyState & (LEFT_CTRL_PRESSED |
Packit b5b901
            RIGHT_CTRL_PRESSED)) && KEV.bKeyDown) {
Packit b5b901
          handle->tty.rd.last_key[0] = '\033';
Packit b5b901
          prefix_len = 1;
Packit b5b901
        } else {
Packit b5b901
          prefix_len = 0;
Packit b5b901
        }
Packit b5b901
Packit b5b901
        if (KEV.uChar.UnicodeChar >= 0xDC00 &&
Packit b5b901
            KEV.uChar.UnicodeChar < 0xE000) {
Packit b5b901
          /* UTF-16 surrogate pair */
Packit Service e08953
          WCHAR utf16_buffer[2];
Packit Service e08953
          utf16_buffer[0] = handle->tty.rd.last_utf16_high_surrogate;
Packit Service e08953
          utf16_buffer[1] = KEV.uChar.UnicodeChar;
Packit b5b901
          char_len = WideCharToMultiByte(CP_UTF8,
Packit b5b901
                                         0,
Packit b5b901
                                         utf16_buffer,
Packit b5b901
                                         2,
Packit b5b901
                                         &handle->tty.rd.last_key[prefix_len],
Packit b5b901
                                         sizeof handle->tty.rd.last_key,
Packit b5b901
                                         NULL,
Packit b5b901
                                         NULL);
Packit b5b901
        } else {
Packit b5b901
          /* Single UTF-16 character */
Packit b5b901
          char_len = WideCharToMultiByte(CP_UTF8,
Packit b5b901
                                         0,
Packit b5b901
                                         &KEV.uChar.UnicodeChar,
Packit b5b901
                                         1,
Packit b5b901
                                         &handle->tty.rd.last_key[prefix_len],
Packit b5b901
                                         sizeof handle->tty.rd.last_key,
Packit b5b901
                                         NULL,
Packit b5b901
                                         NULL);
Packit b5b901
        }
Packit b5b901
Packit b5b901
        /* Whatever happened, the last character wasn't a high surrogate. */
Packit b5b901
        handle->tty.rd.last_utf16_high_surrogate = 0;
Packit b5b901
Packit b5b901
        /* If the utf16 character(s) couldn't be converted something must be
Packit b5b901
         * wrong. */
Packit b5b901
        if (!char_len) {
Packit b5b901
          handle->flags &= ~UV_HANDLE_READING;
Packit b5b901
          DECREASE_ACTIVE_COUNT(loop, handle);
Packit b5b901
          handle->read_cb((uv_stream_t*) handle,
Packit b5b901
                          uv_translate_sys_error(GetLastError()),
Packit b5b901
                          &buf;;
Packit b5b901
          goto out;
Packit b5b901
        }
Packit b5b901
Packit b5b901
        handle->tty.rd.last_key_len = (unsigned char) (prefix_len + char_len);
Packit b5b901
        handle->tty.rd.last_key_offset = 0;
Packit b5b901
        continue;
Packit b5b901
Packit b5b901
      } else {
Packit b5b901
        /* Function key pressed */
Packit b5b901
        const char* vt100;
Packit b5b901
        size_t prefix_len, vt100_len;
Packit b5b901
Packit b5b901
        vt100 = get_vt100_fn_key(KEV.wVirtualKeyCode,
Packit b5b901
                                  !!(KEV.dwControlKeyState & SHIFT_PRESSED),
Packit b5b901
                                  !!(KEV.dwControlKeyState & (
Packit b5b901
                                    LEFT_CTRL_PRESSED |
Packit b5b901
                                    RIGHT_CTRL_PRESSED)),
Packit b5b901
                                  &vt100_len);
Packit b5b901
Packit b5b901
        /* If we were unable to map to a vt100 sequence, just ignore. */
Packit b5b901
        if (!vt100) {
Packit b5b901
          continue;
Packit b5b901
        }
Packit b5b901
Packit b5b901
        /* Prefix with \x033 when the alt key was held. */
Packit b5b901
        if (KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
Packit b5b901
          handle->tty.rd.last_key[0] = '\033';
Packit b5b901
          prefix_len = 1;
Packit b5b901
        } else {
Packit b5b901
          prefix_len = 0;
Packit b5b901
        }
Packit b5b901
Packit b5b901
        /* Copy the vt100 sequence to the handle buffer. */
Packit b5b901
        assert(prefix_len + vt100_len < sizeof handle->tty.rd.last_key);
Packit b5b901
        memcpy(&handle->tty.rd.last_key[prefix_len], vt100, vt100_len);
Packit b5b901
Packit b5b901
        handle->tty.rd.last_key_len = (unsigned char) (prefix_len + vt100_len);
Packit b5b901
        handle->tty.rd.last_key_offset = 0;
Packit b5b901
        continue;
Packit b5b901
      }
Packit b5b901
    } else {
Packit b5b901
      /* Copy any bytes left from the last keypress to the user buffer. */
Packit b5b901
      if (handle->tty.rd.last_key_offset < handle->tty.rd.last_key_len) {
Packit b5b901
        /* Allocate a buffer if needed */
Packit b5b901
        if (buf_used == 0) {
Packit b5b901
          buf = uv_buf_init(NULL, 0);
Packit b5b901
          handle->alloc_cb((uv_handle_t*) handle, 1024, &buf;;
Packit b5b901
          if (buf.base == NULL || buf.len == 0) {
Packit b5b901
            handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf;;
Packit b5b901
            goto out;
Packit b5b901
          }
Packit b5b901
          assert(buf.base != NULL);
Packit b5b901
        }
Packit b5b901
Packit b5b901
        buf.base[buf_used++] = handle->tty.rd.last_key[handle->tty.rd.last_key_offset++];
Packit b5b901
Packit b5b901
        /* If the buffer is full, emit it */
Packit b5b901
        if ((size_t) buf_used == buf.len) {
Packit b5b901
          handle->read_cb((uv_stream_t*) handle, buf_used, &buf;;
Packit b5b901
          buf = uv_null_buf_;
Packit b5b901
          buf_used = 0;
Packit b5b901
        }
Packit b5b901
Packit b5b901
        continue;
Packit b5b901
      }
Packit b5b901
Packit b5b901
      /* Apply dwRepeat from the last input record. */
Packit b5b901
      if (--KEV.wRepeatCount > 0) {
Packit b5b901
        handle->tty.rd.last_key_offset = 0;
Packit b5b901
        continue;
Packit b5b901
      }
Packit b5b901
Packit b5b901
      handle->tty.rd.last_key_len = 0;
Packit b5b901
      continue;
Packit b5b901
    }
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* Send the buffer back to the user */
Packit b5b901
  if (buf_used > 0) {
Packit b5b901
    handle->read_cb((uv_stream_t*) handle, buf_used, &buf;;
Packit b5b901
  }
Packit b5b901
Packit b5b901
 out:
Packit b5b901
  /* Wait for more input events. */
Packit b5b901
  if ((handle->flags & UV_HANDLE_READING) &&
Packit b5b901
      !(handle->flags & UV_HANDLE_READ_PENDING)) {
Packit b5b901
    uv_tty_queue_read(loop, handle);
Packit b5b901
  }
Packit b5b901
Packit b5b901
  DECREASE_PENDING_REQ_COUNT(handle);
Packit b5b901
Packit b5b901
#undef KEV
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
Packit b5b901
void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle,
Packit b5b901
    uv_req_t* req) {
Packit b5b901
  uv_buf_t buf;
Packit b5b901
Packit b5b901
  assert(handle->type == UV_TTY);
Packit b5b901
  assert(handle->flags & UV_HANDLE_TTY_READABLE);
Packit b5b901
Packit b5b901
  buf = handle->tty.rd.read_line_buffer;
Packit b5b901
Packit b5b901
  handle->flags &= ~UV_HANDLE_READ_PENDING;
Packit b5b901
  handle->tty.rd.read_line_buffer = uv_null_buf_;
Packit b5b901
Packit b5b901
  if (!REQ_SUCCESS(req)) {
Packit b5b901
    /* Read was not successful */
Packit b5b901
    if (handle->flags & UV_HANDLE_READING) {
Packit b5b901
      /* Real error */
Packit b5b901
      handle->flags &= ~UV_HANDLE_READING;
Packit b5b901
      DECREASE_ACTIVE_COUNT(loop, handle);
Packit b5b901
      handle->read_cb((uv_stream_t*) handle,
Packit b5b901
                      uv_translate_sys_error(GET_REQ_ERROR(req)),
Packit b5b901
                      &buf;;
Packit b5b901
    }
Packit b5b901
  } else {
Packit Service e08953
    if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING) &&
Packit Service e08953
        req->u.io.overlapped.InternalHigh != 0) {
Packit b5b901
      /* Read successful. TODO: read unicode, convert to utf-8 */
Packit b5b901
      DWORD bytes = req->u.io.overlapped.InternalHigh;
Packit b5b901
      handle->read_cb((uv_stream_t*) handle, bytes, &buf;;
Packit b5b901
    }
Packit Service e08953
    handle->flags &= ~UV_HANDLE_CANCELLATION_PENDING;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* Wait for more input events. */
Packit b5b901
  if ((handle->flags & UV_HANDLE_READING) &&
Packit b5b901
      !(handle->flags & UV_HANDLE_READ_PENDING)) {
Packit b5b901
    uv_tty_queue_read(loop, handle);
Packit b5b901
  }
Packit b5b901
Packit b5b901
  DECREASE_PENDING_REQ_COUNT(handle);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle,
Packit b5b901
    uv_req_t* req) {
Packit b5b901
  assert(handle->type == UV_TTY);
Packit b5b901
  assert(handle->flags & UV_HANDLE_TTY_READABLE);
Packit b5b901
Packit b5b901
  /* If the read_line_buffer member is zero, it must have been an raw read.
Packit b5b901
   * Otherwise it was a line-buffered read. FIXME: This is quite obscure. Use a
Packit b5b901
   * flag or something. */
Packit b5b901
  if (handle->tty.rd.read_line_buffer.len == 0) {
Packit b5b901
    uv_process_tty_read_raw_req(loop, handle, req);
Packit b5b901
  } else {
Packit b5b901
    uv_process_tty_read_line_req(loop, handle, req);
Packit b5b901
  }
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
Packit b5b901
    uv_read_cb read_cb) {
Packit b5b901
  uv_loop_t* loop = handle->loop;
Packit b5b901
Packit b5b901
  if (!(handle->flags & UV_HANDLE_TTY_READABLE)) {
Packit b5b901
    return ERROR_INVALID_PARAMETER;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  handle->flags |= UV_HANDLE_READING;
Packit b5b901
  INCREASE_ACTIVE_COUNT(loop, handle);
Packit b5b901
  handle->read_cb = read_cb;
Packit b5b901
  handle->alloc_cb = alloc_cb;
Packit b5b901
Packit b5b901
  /* If reading was stopped and then started again, there could still be a read
Packit b5b901
   * request pending. */
Packit b5b901
  if (handle->flags & UV_HANDLE_READ_PENDING) {
Packit b5b901
    return 0;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* Maybe the user stopped reading half-way while processing key events.
Packit b5b901
   * Short-circuit if this could be the case. */
Packit b5b901
  if (handle->tty.rd.last_key_len > 0) {
Packit b5b901
    SET_REQ_SUCCESS(&handle->read_req);
Packit b5b901
    uv_insert_pending_req(handle->loop, (uv_req_t*) &handle->read_req);
Packit b5b901
    /* Make sure no attempt is made to insert it again until it's handled. */
Packit b5b901
    handle->flags |= UV_HANDLE_READ_PENDING;
Packit b5b901
    handle->reqs_pending++;
Packit b5b901
    return 0;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  uv_tty_queue_read(loop, handle);
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_tty_read_stop(uv_tty_t* handle) {
Packit b5b901
  INPUT_RECORD record;
Packit b5b901
  DWORD written, err;
Packit b5b901
Packit b5b901
  handle->flags &= ~UV_HANDLE_READING;
Packit b5b901
  DECREASE_ACTIVE_COUNT(handle->loop, handle);
Packit b5b901
Packit b5b901
  if (!(handle->flags & UV_HANDLE_READ_PENDING))
Packit b5b901
    return 0;
Packit b5b901
Packit b5b901
  if (handle->flags & UV_HANDLE_TTY_RAW) {
Packit b5b901
    /* Cancel raw read. Write some bullshit event to force the console wait to
Packit b5b901
     * return. */
Packit b5b901
    memset(&record, 0, sizeof record);
Packit Service e08953
    record.EventType = FOCUS_EVENT;
Packit b5b901
    if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) {
Packit b5b901
      return GetLastError();
Packit b5b901
    }
Packit b5b901
  } else if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) {
Packit b5b901
    /* Cancel line-buffered read if not already pending */
Packit b5b901
    err = uv__cancel_read_console(handle);
Packit b5b901
    if (err)
Packit b5b901
      return err;
Packit b5b901
Packit b5b901
    handle->flags |= UV_HANDLE_CANCELLATION_PENDING;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
static int uv__cancel_read_console(uv_tty_t* handle) {
Packit b5b901
  HANDLE active_screen_buffer = INVALID_HANDLE_VALUE;
Packit b5b901
  INPUT_RECORD record;
Packit b5b901
  DWORD written;
Packit b5b901
  DWORD err = 0;
Packit b5b901
  LONG status;
Packit b5b901
Packit b5b901
  assert(!(handle->flags & UV_HANDLE_CANCELLATION_PENDING));
Packit b5b901
Packit b5b901
  /* Hold the output lock during the cancellation, to ensure that further
Packit b5b901
     writes don't interfere with the screen state. It will be the ReadConsole
Packit b5b901
     thread's responsibility to release the lock. */
Packit b5b901
  uv_sem_wait(&uv_tty_output_lock);
Packit b5b901
  status = InterlockedExchange(&uv__read_console_status, TRAP_REQUESTED);
Packit b5b901
  if (status != IN_PROGRESS) {
Packit b5b901
    /* Either we have managed to set a trap for the other thread before
Packit b5b901
       ReadConsole is called, or ReadConsole has returned because the user
Packit b5b901
       has pressed ENTER. In either case, there is nothing else to do. */
Packit b5b901
    uv_sem_post(&uv_tty_output_lock);
Packit b5b901
    return 0;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* Save screen state before sending the VK_RETURN event */
Packit b5b901
  active_screen_buffer = CreateFileA("conout$",
Packit b5b901
                                     GENERIC_READ | GENERIC_WRITE,
Packit b5b901
                                     FILE_SHARE_READ | FILE_SHARE_WRITE,
Packit b5b901
                                     NULL,
Packit b5b901
                                     OPEN_EXISTING,
Packit b5b901
                                     FILE_ATTRIBUTE_NORMAL,
Packit b5b901
                                     NULL);
Packit b5b901
Packit b5b901
  if (active_screen_buffer != INVALID_HANDLE_VALUE &&
Packit b5b901
      GetConsoleScreenBufferInfo(active_screen_buffer,
Packit b5b901
                                 &uv__saved_screen_state)) {
Packit b5b901
    InterlockedOr(&uv__restore_screen_state, 1);
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* Write enter key event to force the console wait to return. */
Packit b5b901
  record.EventType = KEY_EVENT;
Packit b5b901
  record.Event.KeyEvent.bKeyDown = TRUE;
Packit b5b901
  record.Event.KeyEvent.wRepeatCount = 1;
Packit b5b901
  record.Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
Packit b5b901
  record.Event.KeyEvent.wVirtualScanCode =
Packit b5b901
    MapVirtualKeyW(VK_RETURN, MAPVK_VK_TO_VSC);
Packit b5b901
  record.Event.KeyEvent.uChar.UnicodeChar = L'\r';
Packit b5b901
  record.Event.KeyEvent.dwControlKeyState = 0;
Packit b5b901
  if (!WriteConsoleInputW(handle->handle, &record, 1, &written))
Packit b5b901
    err = GetLastError();
Packit b5b901
Packit b5b901
  if (active_screen_buffer != INVALID_HANDLE_VALUE)
Packit b5b901
    CloseHandle(active_screen_buffer);
Packit b5b901
Packit b5b901
  return err;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) {
Packit b5b901
  uv_tty_virtual_width = info->dwSize.X;
Packit b5b901
  uv_tty_virtual_height = info->srWindow.Bottom - info->srWindow.Top + 1;
Packit b5b901
Packit b5b901
  /* Recompute virtual window offset row. */
Packit b5b901
  if (uv_tty_virtual_offset == -1) {
Packit b5b901
    uv_tty_virtual_offset = info->dwCursorPosition.Y;
Packit b5b901
  } else if (uv_tty_virtual_offset < info->dwCursorPosition.Y -
Packit b5b901
             uv_tty_virtual_height + 1) {
Packit b5b901
    /* If suddenly find the cursor outside of the virtual window, it must have
Packit b5b901
     * somehow scrolled. Update the virtual window offset. */
Packit b5b901
    uv_tty_virtual_offset = info->dwCursorPosition.Y -
Packit b5b901
                            uv_tty_virtual_height + 1;
Packit b5b901
  }
Packit b5b901
  if (uv_tty_virtual_offset + uv_tty_virtual_height > info->dwSize.Y) {
Packit b5b901
    uv_tty_virtual_offset = info->dwSize.Y - uv_tty_virtual_height;
Packit b5b901
  }
Packit b5b901
  if (uv_tty_virtual_offset < 0) {
Packit b5b901
    uv_tty_virtual_offset = 0;
Packit b5b901
  }
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static COORD uv_tty_make_real_coord(uv_tty_t* handle,
Packit b5b901
    CONSOLE_SCREEN_BUFFER_INFO* info, int x, unsigned char x_relative, int y,
Packit b5b901
    unsigned char y_relative) {
Packit b5b901
  COORD result;
Packit b5b901
Packit b5b901
  uv_tty_update_virtual_window(info);
Packit b5b901
Packit b5b901
  /* Adjust y position */
Packit b5b901
  if (y_relative) {
Packit b5b901
    y = info->dwCursorPosition.Y + y;
Packit b5b901
  } else {
Packit b5b901
    y = uv_tty_virtual_offset + y;
Packit b5b901
  }
Packit b5b901
  /* Clip y to virtual client rectangle */
Packit b5b901
  if (y < uv_tty_virtual_offset) {
Packit b5b901
    y = uv_tty_virtual_offset;
Packit b5b901
  } else if (y >= uv_tty_virtual_offset + uv_tty_virtual_height) {
Packit b5b901
    y = uv_tty_virtual_offset + uv_tty_virtual_height - 1;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* Adjust x */
Packit b5b901
  if (x_relative) {
Packit b5b901
    x = info->dwCursorPosition.X + x;
Packit b5b901
  }
Packit b5b901
  /* Clip x */
Packit b5b901
  if (x < 0) {
Packit b5b901
    x = 0;
Packit b5b901
  } else if (x >= uv_tty_virtual_width) {
Packit b5b901
    x = uv_tty_virtual_width - 1;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  result.X = (unsigned short) x;
Packit b5b901
  result.Y = (unsigned short) y;
Packit b5b901
  return result;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static int uv_tty_emit_text(uv_tty_t* handle, WCHAR buffer[], DWORD length,
Packit b5b901
    DWORD* error) {
Packit b5b901
  DWORD written;
Packit b5b901
Packit b5b901
  if (*error != ERROR_SUCCESS) {
Packit b5b901
    return -1;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (!WriteConsoleW(handle->handle,
Packit b5b901
                     (void*) buffer,
Packit b5b901
                     length,
Packit b5b901
                     &written,
Packit b5b901
                     NULL)) {
Packit b5b901
    *error = GetLastError();
Packit b5b901
    return -1;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static int uv_tty_move_caret(uv_tty_t* handle, int x, unsigned char x_relative,
Packit b5b901
    int y, unsigned char y_relative, DWORD* error) {
Packit b5b901
  CONSOLE_SCREEN_BUFFER_INFO info;
Packit b5b901
  COORD pos;
Packit b5b901
Packit b5b901
  if (*error != ERROR_SUCCESS) {
Packit b5b901
    return -1;
Packit b5b901
  }
Packit b5b901
Packit b5b901
 retry:
Packit b5b901
  if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
Packit b5b901
    *error = GetLastError();
Packit b5b901
  }
Packit b5b901
Packit b5b901
  pos = uv_tty_make_real_coord(handle, &info, x, x_relative, y, y_relative);
Packit b5b901
Packit b5b901
  if (!SetConsoleCursorPosition(handle->handle, pos)) {
Packit b5b901
    if (GetLastError() == ERROR_INVALID_PARAMETER) {
Packit b5b901
      /* The console may be resized - retry */
Packit b5b901
      goto retry;
Packit b5b901
    } else {
Packit b5b901
      *error = GetLastError();
Packit b5b901
      return -1;
Packit b5b901
    }
Packit b5b901
  }
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static int uv_tty_reset(uv_tty_t* handle, DWORD* error) {
Packit b5b901
  const COORD origin = {0, 0};
Packit b5b901
  const WORD char_attrs = uv_tty_default_text_attributes;
Packit Service e08953
  CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
Packit b5b901
  DWORD count, written;
Packit b5b901
Packit b5b901
  if (*error != ERROR_SUCCESS) {
Packit b5b901
    return -1;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* Reset original text attributes. */
Packit b5b901
  if (!SetConsoleTextAttribute(handle->handle, char_attrs)) {
Packit b5b901
    *error = GetLastError();
Packit b5b901
    return -1;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* Move the cursor position to (0, 0). */
Packit b5b901
  if (!SetConsoleCursorPosition(handle->handle, origin)) {
Packit b5b901
    *error = GetLastError();
Packit b5b901
    return -1;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* Clear the screen buffer. */
Packit b5b901
 retry:
Packit Service e08953
   if (!GetConsoleScreenBufferInfo(handle->handle, &screen_buffer_info)) {
Packit Service e08953
     *error = GetLastError();
Packit Service e08953
     return -1;
Packit b5b901
  }
Packit b5b901
Packit Service e08953
  count = screen_buffer_info.dwSize.X * screen_buffer_info.dwSize.Y;
Packit b5b901
Packit b5b901
  if (!(FillConsoleOutputCharacterW(handle->handle,
Packit b5b901
                                    L'\x20',
Packit b5b901
                                    count,
Packit b5b901
                                    origin,
Packit b5b901
                                    &written) &&
Packit b5b901
        FillConsoleOutputAttribute(handle->handle,
Packit b5b901
                                   char_attrs,
Packit b5b901
                                   written,
Packit b5b901
                                   origin,
Packit b5b901
                                   &written))) {
Packit b5b901
    if (GetLastError() == ERROR_INVALID_PARAMETER) {
Packit b5b901
      /* The console may be resized - retry */
Packit b5b901
      goto retry;
Packit b5b901
    } else {
Packit b5b901
      *error = GetLastError();
Packit b5b901
      return -1;
Packit b5b901
    }
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* Move the virtual window up to the top. */
Packit b5b901
  uv_tty_virtual_offset = 0;
Packit Service e08953
  uv_tty_update_virtual_window(&screen_buffer_info);
Packit Service e08953
Packit Service e08953
  /* Reset the cursor size and the cursor state. */
Packit Service e08953
  if (!SetConsoleCursorInfo(handle->handle, &uv_tty_default_cursor_info)) {
Packit Service e08953
    *error = GetLastError();
Packit Service e08953
    return -1;
Packit Service e08953
  }
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static int uv_tty_clear(uv_tty_t* handle, int dir, char entire_screen,
Packit b5b901
    DWORD* error) {
Packit b5b901
  CONSOLE_SCREEN_BUFFER_INFO info;
Packit b5b901
  COORD start, end;
Packit b5b901
  DWORD count, written;
Packit b5b901
Packit b5b901
  int x1, x2, y1, y2;
Packit b5b901
  int x1r, x2r, y1r, y2r;
Packit b5b901
Packit b5b901
  if (*error != ERROR_SUCCESS) {
Packit b5b901
    return -1;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (dir == 0) {
Packit b5b901
    /* Clear from current position */
Packit b5b901
    x1 = 0;
Packit b5b901
    x1r = 1;
Packit b5b901
  } else {
Packit b5b901
    /* Clear from column 0 */
Packit b5b901
    x1 = 0;
Packit b5b901
    x1r = 0;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (dir == 1) {
Packit b5b901
    /* Clear to current position */
Packit b5b901
    x2 = 0;
Packit b5b901
    x2r = 1;
Packit b5b901
  } else {
Packit b5b901
    /* Clear to end of row. We pretend the console is 65536 characters wide,
Packit b5b901
     * uv_tty_make_real_coord will clip it to the actual console width. */
Packit b5b901
    x2 = 0xffff;
Packit b5b901
    x2r = 0;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (!entire_screen) {
Packit b5b901
    /* Stay on our own row */
Packit b5b901
    y1 = y2 = 0;
Packit b5b901
    y1r = y2r = 1;
Packit b5b901
  } else {
Packit b5b901
    /* Apply columns direction to row */
Packit b5b901
    y1 = x1;
Packit b5b901
    y1r = x1r;
Packit b5b901
    y2 = x2;
Packit b5b901
    y2r = x2r;
Packit b5b901
  }
Packit b5b901
Packit b5b901
 retry:
Packit b5b901
  if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
Packit b5b901
    *error = GetLastError();
Packit b5b901
    return -1;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  start = uv_tty_make_real_coord(handle, &info, x1, x1r, y1, y1r);
Packit b5b901
  end = uv_tty_make_real_coord(handle, &info, x2, x2r, y2, y2r);
Packit b5b901
  count = (end.Y * info.dwSize.X + end.X) -
Packit b5b901
          (start.Y * info.dwSize.X + start.X) + 1;
Packit b5b901
Packit b5b901
  if (!(FillConsoleOutputCharacterW(handle->handle,
Packit b5b901
                              L'\x20',
Packit b5b901
                              count,
Packit b5b901
                              start,
Packit b5b901
                              &written) &&
Packit b5b901
        FillConsoleOutputAttribute(handle->handle,
Packit b5b901
                                   info.wAttributes,
Packit b5b901
                                   written,
Packit b5b901
                                   start,
Packit b5b901
                                   &written))) {
Packit b5b901
    if (GetLastError() == ERROR_INVALID_PARAMETER) {
Packit b5b901
      /* The console may be resized - retry */
Packit b5b901
      goto retry;
Packit b5b901
    } else {
Packit b5b901
      *error = GetLastError();
Packit b5b901
      return -1;
Packit b5b901
    }
Packit b5b901
  }
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
#define FLIP_FGBG                                                             \
Packit b5b901
    do {                                                                      \
Packit b5b901
      WORD fg = info.wAttributes & 0xF;                                       \
Packit b5b901
      WORD bg = info.wAttributes & 0xF0;                                      \
Packit b5b901
      info.wAttributes &= 0xFF00;                                             \
Packit b5b901
      info.wAttributes |= fg << 4;                                            \
Packit b5b901
      info.wAttributes |= bg >> 4;                                            \
Packit b5b901
    } while (0)
Packit b5b901
Packit b5b901
static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) {
Packit b5b901
  unsigned short argc = handle->tty.wr.ansi_csi_argc;
Packit b5b901
  unsigned short* argv = handle->tty.wr.ansi_csi_argv;
Packit b5b901
  int i;
Packit b5b901
  CONSOLE_SCREEN_BUFFER_INFO info;
Packit b5b901
Packit b5b901
  char fg_color = -1, bg_color = -1;
Packit b5b901
  char fg_bright = -1, bg_bright = -1;
Packit b5b901
  char inverse = -1;
Packit b5b901
Packit b5b901
  if (argc == 0) {
Packit b5b901
    /* Reset mode */
Packit b5b901
    fg_color = uv_tty_default_fg_color;
Packit b5b901
    bg_color = uv_tty_default_bg_color;
Packit b5b901
    fg_bright = uv_tty_default_fg_bright;
Packit b5b901
    bg_bright = uv_tty_default_bg_bright;
Packit b5b901
    inverse = uv_tty_default_inverse;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  for (i = 0; i < argc; i++) {
Packit b5b901
    short arg = argv[i];
Packit b5b901
Packit b5b901
    if (arg == 0) {
Packit b5b901
      /* Reset mode */
Packit b5b901
      fg_color = uv_tty_default_fg_color;
Packit b5b901
      bg_color = uv_tty_default_bg_color;
Packit b5b901
      fg_bright = uv_tty_default_fg_bright;
Packit b5b901
      bg_bright = uv_tty_default_bg_bright;
Packit b5b901
      inverse = uv_tty_default_inverse;
Packit b5b901
Packit b5b901
    } else if (arg == 1) {
Packit b5b901
      /* Foreground bright on */
Packit b5b901
      fg_bright = 1;
Packit b5b901
Packit b5b901
    } else if (arg == 2) {
Packit b5b901
      /* Both bright off */
Packit b5b901
      fg_bright = 0;
Packit b5b901
      bg_bright = 0;
Packit b5b901
Packit b5b901
    } else if (arg == 5) {
Packit b5b901
      /* Background bright on */
Packit b5b901
      bg_bright = 1;
Packit b5b901
Packit b5b901
    } else if (arg == 7) {
Packit b5b901
      /* Inverse: on */
Packit b5b901
      inverse = 1;
Packit b5b901
Packit b5b901
    } else if (arg == 21 || arg == 22) {
Packit b5b901
      /* Foreground bright off */
Packit b5b901
      fg_bright = 0;
Packit b5b901
Packit b5b901
    } else if (arg == 25) {
Packit b5b901
      /* Background bright off */
Packit b5b901
      bg_bright = 0;
Packit b5b901
Packit b5b901
    } else if (arg == 27) {
Packit b5b901
      /* Inverse: off */
Packit b5b901
      inverse = 0;
Packit b5b901
Packit b5b901
    } else if (arg >= 30 && arg <= 37) {
Packit b5b901
      /* Set foreground color */
Packit b5b901
      fg_color = arg - 30;
Packit b5b901
Packit b5b901
    } else if (arg == 39) {
Packit b5b901
      /* Default text color */
Packit b5b901
      fg_color = uv_tty_default_fg_color;
Packit b5b901
      fg_bright = uv_tty_default_fg_bright;
Packit b5b901
Packit b5b901
    } else if (arg >= 40 && arg <= 47) {
Packit b5b901
      /* Set background color */
Packit b5b901
      bg_color = arg - 40;
Packit b5b901
Packit b5b901
    } else if (arg ==  49) {
Packit b5b901
      /* Default background color */
Packit b5b901
      bg_color = uv_tty_default_bg_color;
Packit b5b901
      bg_bright = uv_tty_default_bg_bright;
Packit b5b901
Packit b5b901
    } else if (arg >= 90 && arg <= 97) {
Packit b5b901
      /* Set bold foreground color */
Packit b5b901
      fg_bright = 1;
Packit b5b901
      fg_color = arg - 90;
Packit b5b901
Packit b5b901
    } else if (arg >= 100 && arg <= 107) {
Packit b5b901
      /* Set bold background color */
Packit b5b901
      bg_bright = 1;
Packit b5b901
      bg_color = arg - 100;
Packit b5b901
Packit b5b901
    }
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (fg_color == -1 && bg_color == -1 && fg_bright == -1 &&
Packit b5b901
      bg_bright == -1 && inverse == -1) {
Packit b5b901
    /* Nothing changed */
Packit b5b901
    return 0;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
Packit b5b901
    *error = GetLastError();
Packit b5b901
    return -1;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if ((info.wAttributes & COMMON_LVB_REVERSE_VIDEO) > 0) {
Packit b5b901
    FLIP_FGBG;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (fg_color != -1) {
Packit b5b901
    info.wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
Packit b5b901
    if (fg_color & 1) info.wAttributes |= FOREGROUND_RED;
Packit b5b901
    if (fg_color & 2) info.wAttributes |= FOREGROUND_GREEN;
Packit b5b901
    if (fg_color & 4) info.wAttributes |= FOREGROUND_BLUE;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (fg_bright != -1) {
Packit b5b901
    if (fg_bright) {
Packit b5b901
      info.wAttributes |= FOREGROUND_INTENSITY;
Packit b5b901
    } else {
Packit b5b901
      info.wAttributes &= ~FOREGROUND_INTENSITY;
Packit b5b901
    }
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (bg_color != -1) {
Packit b5b901
    info.wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
Packit b5b901
    if (bg_color & 1) info.wAttributes |= BACKGROUND_RED;
Packit b5b901
    if (bg_color & 2) info.wAttributes |= BACKGROUND_GREEN;
Packit b5b901
    if (bg_color & 4) info.wAttributes |= BACKGROUND_BLUE;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (bg_bright != -1) {
Packit b5b901
    if (bg_bright) {
Packit b5b901
      info.wAttributes |= BACKGROUND_INTENSITY;
Packit b5b901
    } else {
Packit b5b901
      info.wAttributes &= ~BACKGROUND_INTENSITY;
Packit b5b901
    }
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (inverse != -1) {
Packit b5b901
    if (inverse) {
Packit b5b901
      info.wAttributes |= COMMON_LVB_REVERSE_VIDEO;
Packit b5b901
    } else {
Packit b5b901
      info.wAttributes &= ~COMMON_LVB_REVERSE_VIDEO;
Packit b5b901
    }
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if ((info.wAttributes & COMMON_LVB_REVERSE_VIDEO) > 0) {
Packit b5b901
    FLIP_FGBG;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (!SetConsoleTextAttribute(handle->handle, info.wAttributes)) {
Packit b5b901
    *error = GetLastError();
Packit b5b901
    return -1;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static int uv_tty_save_state(uv_tty_t* handle, unsigned char save_attributes,
Packit b5b901
    DWORD* error) {
Packit b5b901
  CONSOLE_SCREEN_BUFFER_INFO info;
Packit b5b901
Packit b5b901
  if (*error != ERROR_SUCCESS) {
Packit b5b901
    return -1;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
Packit b5b901
    *error = GetLastError();
Packit b5b901
    return -1;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  uv_tty_update_virtual_window(&info;;
Packit b5b901
Packit b5b901
  handle->tty.wr.saved_position.X = info.dwCursorPosition.X;
Packit b5b901
  handle->tty.wr.saved_position.Y = info.dwCursorPosition.Y - uv_tty_virtual_offset;
Packit b5b901
  handle->flags |= UV_HANDLE_TTY_SAVED_POSITION;
Packit b5b901
Packit b5b901
  if (save_attributes) {
Packit b5b901
    handle->tty.wr.saved_attributes = info.wAttributes &
Packit b5b901
        (FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
Packit b5b901
    handle->flags |= UV_HANDLE_TTY_SAVED_ATTRIBUTES;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static int uv_tty_restore_state(uv_tty_t* handle,
Packit b5b901
    unsigned char restore_attributes, DWORD* error) {
Packit b5b901
  CONSOLE_SCREEN_BUFFER_INFO info;
Packit b5b901
  WORD new_attributes;
Packit b5b901
Packit b5b901
  if (*error != ERROR_SUCCESS) {
Packit b5b901
    return -1;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (handle->flags & UV_HANDLE_TTY_SAVED_POSITION) {
Packit b5b901
    if (uv_tty_move_caret(handle,
Packit b5b901
                          handle->tty.wr.saved_position.X,
Packit b5b901
                          0,
Packit b5b901
                          handle->tty.wr.saved_position.Y,
Packit b5b901
                          0,
Packit b5b901
                          error) != 0) {
Packit b5b901
      return -1;
Packit b5b901
    }
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (restore_attributes &&
Packit b5b901
      (handle->flags & UV_HANDLE_TTY_SAVED_ATTRIBUTES)) {
Packit b5b901
    if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
Packit b5b901
      *error = GetLastError();
Packit b5b901
      return -1;
Packit b5b901
    }
Packit b5b901
Packit b5b901
    new_attributes = info.wAttributes;
Packit b5b901
    new_attributes &= ~(FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
Packit b5b901
    new_attributes |= handle->tty.wr.saved_attributes;
Packit b5b901
Packit b5b901
    if (!SetConsoleTextAttribute(handle->handle, new_attributes)) {
Packit b5b901
      *error = GetLastError();
Packit b5b901
      return -1;
Packit b5b901
    }
Packit b5b901
  }
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
static int uv_tty_set_cursor_visibility(uv_tty_t* handle,
Packit b5b901
                                        BOOL visible,
Packit b5b901
                                        DWORD* error) {
Packit b5b901
  CONSOLE_CURSOR_INFO cursor_info;
Packit b5b901
Packit b5b901
  if (!GetConsoleCursorInfo(handle->handle, &cursor_info)) {
Packit b5b901
    *error = GetLastError();
Packit b5b901
    return -1;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  cursor_info.bVisible = visible;
Packit b5b901
Packit b5b901
  if (!SetConsoleCursorInfo(handle->handle, &cursor_info)) {
Packit b5b901
    *error = GetLastError();
Packit b5b901
    return -1;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit Service e08953
static int uv_tty_set_cursor_shape(uv_tty_t* handle, int style, DWORD* error) {
Packit Service e08953
  CONSOLE_CURSOR_INFO cursor_info;
Packit Service e08953
Packit Service e08953
  if (!GetConsoleCursorInfo(handle->handle, &cursor_info)) {
Packit Service e08953
    *error = GetLastError();
Packit Service e08953
    return -1;
Packit Service e08953
  }
Packit Service e08953
Packit Service e08953
  if (style == 0) {
Packit Service e08953
    cursor_info.dwSize = uv_tty_default_cursor_info.dwSize;
Packit Service e08953
  } else if (style <= 2) {
Packit Service e08953
    cursor_info.dwSize = CURSOR_SIZE_LARGE;
Packit Service e08953
  } else {
Packit Service e08953
    cursor_info.dwSize = CURSOR_SIZE_SMALL;
Packit Service e08953
  }
Packit Service e08953
Packit Service e08953
  if (!SetConsoleCursorInfo(handle->handle, &cursor_info)) {
Packit Service e08953
    *error = GetLastError();
Packit Service e08953
    return -1;
Packit Service e08953
  }
Packit Service e08953
Packit Service e08953
  return 0;
Packit Service e08953
}
Packit Service e08953
Packit Service e08953
Packit b5b901
static int uv_tty_write_bufs(uv_tty_t* handle,
Packit b5b901
                             const uv_buf_t bufs[],
Packit b5b901
                             unsigned int nbufs,
Packit b5b901
                             DWORD* error) {
Packit b5b901
  /* We can only write 8k characters at a time. Windows can't handle much more
Packit b5b901
   * characters in a single console write anyway. */
Packit b5b901
  WCHAR utf16_buf[MAX_CONSOLE_CHAR];
Packit b5b901
  DWORD utf16_buf_used = 0;
Packit Service e08953
  unsigned int i;
Packit Service e08953
Packit Service e08953
#define FLUSH_TEXT()                                                \
Packit Service e08953
  do {                                                              \
Packit Service e08953
    if (utf16_buf_used > 0) {                                       \
Packit Service e08953
      uv_tty_emit_text(handle, utf16_buf, utf16_buf_used, error);   \
Packit Service e08953
      utf16_buf_used = 0;                                           \
Packit Service e08953
    }                                                               \
Packit Service e08953
  } while (0)
Packit b5b901
Packit b5b901
#define ENSURE_BUFFER_SPACE(wchars_needed)                          \
Packit b5b901
  if (wchars_needed > ARRAY_SIZE(utf16_buf) - utf16_buf_used) {     \
Packit b5b901
    FLUSH_TEXT();                                                   \
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* Cache for fast access */
Packit b5b901
  unsigned char utf8_bytes_left = handle->tty.wr.utf8_bytes_left;
Packit b5b901
  unsigned int utf8_codepoint = handle->tty.wr.utf8_codepoint;
Packit b5b901
  unsigned char previous_eol = handle->tty.wr.previous_eol;
Packit Service e08953
  unsigned short ansi_parser_state = handle->tty.wr.ansi_parser_state;
Packit b5b901
Packit b5b901
  /* Store the error here. If we encounter an error, stop trying to do i/o but
Packit b5b901
   * keep parsing the buffer so we leave the parser in a consistent state. */
Packit b5b901
  *error = ERROR_SUCCESS;
Packit b5b901
Packit b5b901
  uv_sem_wait(&uv_tty_output_lock);
Packit b5b901
Packit b5b901
  for (i = 0; i < nbufs; i++) {
Packit b5b901
    uv_buf_t buf = bufs[i];
Packit b5b901
    unsigned int j;
Packit b5b901
Packit b5b901
    for (j = 0; j < buf.len; j++) {
Packit b5b901
      unsigned char c = buf.base[j];
Packit b5b901
Packit b5b901
      /* Run the character through the utf8 decoder We happily accept non
Packit b5b901
       * shortest form encodings and invalid code points - there's no real harm
Packit b5b901
       * that can be done. */
Packit b5b901
      if (utf8_bytes_left == 0) {
Packit b5b901
        /* Read utf-8 start byte */
Packit b5b901
        DWORD first_zero_bit;
Packit b5b901
        unsigned char not_c = ~c;
Packit b5b901
#ifdef _MSC_VER /* msvc */
Packit b5b901
        if (_BitScanReverse(&first_zero_bit, not_c)) {
Packit b5b901
#else /* assume gcc */
Packit b5b901
        if (c != 0) {
Packit b5b901
          first_zero_bit = (sizeof(int) * 8) - 1 - __builtin_clz(not_c);
Packit b5b901
#endif
Packit b5b901
          if (first_zero_bit == 7) {
Packit b5b901
            /* Ascii - pass right through */
Packit b5b901
            utf8_codepoint = (unsigned int) c;
Packit b5b901
Packit b5b901
          } else if (first_zero_bit <= 5) {
Packit b5b901
            /* Multibyte sequence */
Packit b5b901
            utf8_codepoint = (0xff >> (8 - first_zero_bit)) & c;
Packit b5b901
            utf8_bytes_left = (char) (6 - first_zero_bit);
Packit b5b901
Packit b5b901
          } else {
Packit b5b901
            /* Invalid continuation */
Packit b5b901
            utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
Packit b5b901
          }
Packit b5b901
Packit b5b901
        } else {
Packit b5b901
          /* 0xff -- invalid */
Packit b5b901
          utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
Packit b5b901
        }
Packit b5b901
Packit b5b901
      } else if ((c & 0xc0) == 0x80) {
Packit b5b901
        /* Valid continuation of utf-8 multibyte sequence */
Packit b5b901
        utf8_bytes_left--;
Packit b5b901
        utf8_codepoint <<= 6;
Packit b5b901
        utf8_codepoint |= ((unsigned int) c & 0x3f);
Packit b5b901
Packit b5b901
      } else {
Packit b5b901
        /* Start byte where continuation was expected. */
Packit b5b901
        utf8_bytes_left = 0;
Packit b5b901
        utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
Packit b5b901
        /* Patch buf offset so this character will be parsed again as a start
Packit b5b901
         * byte. */
Packit b5b901
        j--;
Packit b5b901
      }
Packit b5b901
Packit b5b901
      /* Maybe we need to parse more bytes to find a character. */
Packit b5b901
      if (utf8_bytes_left != 0) {
Packit b5b901
        continue;
Packit b5b901
      }
Packit b5b901
Packit b5b901
      /* Parse vt100/ansi escape codes */
Packit Service e08953
      if (uv__vterm_state == UV_TTY_SUPPORTED) {
Packit Service e08953
        /* Pass through escape codes if conhost supports them. */
Packit Service e08953
      } else if (ansi_parser_state == ANSI_NORMAL) {
Packit b5b901
        switch (utf8_codepoint) {
Packit b5b901
          case '\033':
Packit b5b901
            ansi_parser_state = ANSI_ESCAPE_SEEN;
Packit b5b901
            continue;
Packit b5b901
Packit b5b901
          case 0233:
Packit b5b901
            ansi_parser_state = ANSI_CSI;
Packit b5b901
            handle->tty.wr.ansi_csi_argc = 0;
Packit b5b901
            continue;
Packit b5b901
        }
Packit b5b901
Packit b5b901
      } else if (ansi_parser_state == ANSI_ESCAPE_SEEN) {
Packit b5b901
        switch (utf8_codepoint) {
Packit b5b901
          case '[':
Packit b5b901
            ansi_parser_state = ANSI_CSI;
Packit b5b901
            handle->tty.wr.ansi_csi_argc = 0;
Packit b5b901
            continue;
Packit b5b901
Packit b5b901
          case '^':
Packit b5b901
          case '_':
Packit b5b901
          case 'P':
Packit b5b901
          case ']':
Packit b5b901
            /* Not supported, but we'll have to parse until we see a stop code,
Packit b5b901
             * e. g. ESC \ or BEL. */
Packit b5b901
            ansi_parser_state = ANSI_ST_CONTROL;
Packit b5b901
            continue;
Packit b5b901
Packit b5b901
          case '\033':
Packit b5b901
            /* Ignore double escape. */
Packit b5b901
            continue;
Packit b5b901
Packit b5b901
          case 'c':
Packit b5b901
            /* Full console reset. */
Packit b5b901
            FLUSH_TEXT();
Packit b5b901
            uv_tty_reset(handle, error);
Packit b5b901
            ansi_parser_state = ANSI_NORMAL;
Packit b5b901
            continue;
Packit b5b901
Packit b5b901
          case '7':
Packit b5b901
            /* Save the cursor position and text attributes. */
Packit b5b901
            FLUSH_TEXT();
Packit b5b901
            uv_tty_save_state(handle, 1, error);
Packit b5b901
            ansi_parser_state = ANSI_NORMAL;
Packit b5b901
            continue;
Packit b5b901
Packit Service e08953
          case '8':
Packit b5b901
            /* Restore the cursor position and text attributes */
Packit b5b901
            FLUSH_TEXT();
Packit b5b901
            uv_tty_restore_state(handle, 1, error);
Packit b5b901
            ansi_parser_state = ANSI_NORMAL;
Packit b5b901
            continue;
Packit b5b901
Packit b5b901
          default:
Packit b5b901
            if (utf8_codepoint >= '@' && utf8_codepoint <= '_') {
Packit b5b901
              /* Single-char control. */
Packit b5b901
              ansi_parser_state = ANSI_NORMAL;
Packit b5b901
              continue;
Packit b5b901
            } else {
Packit b5b901
              /* Invalid - proceed as normal, */
Packit b5b901
              ansi_parser_state = ANSI_NORMAL;
Packit b5b901
            }
Packit b5b901
        }
Packit b5b901
Packit Service e08953
      } else if (ansi_parser_state == ANSI_IGNORE) {
Packit Service e08953
        /* We're ignoring this command. Stop only on command character. */
Packit Service e08953
        if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
Packit Service e08953
          ansi_parser_state = ANSI_NORMAL;
Packit Service e08953
        }
Packit Service e08953
        continue;
Packit Service e08953
Packit Service e08953
      } else if (ansi_parser_state == ANSI_DECSCUSR) {
Packit Service e08953
        /* So far we've the sequence `ESC [ arg space`, and we're waiting for
Packit Service e08953
         * the final command byte. */
Packit Service e08953
        if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
Packit Service e08953
          /* Command byte */
Packit Service e08953
          if (utf8_codepoint == 'q') {
Packit Service e08953
            /* Change the cursor shape */
Packit Service e08953
            int style = handle->tty.wr.ansi_csi_argc
Packit Service e08953
              ? handle->tty.wr.ansi_csi_argv[0] : 1;
Packit Service e08953
            if (style >= 0 && style <= 6) {
Packit Service e08953
              FLUSH_TEXT();
Packit Service e08953
              uv_tty_set_cursor_shape(handle, style, error);
Packit Service e08953
            }
Packit Service e08953
          }
Packit Service e08953
Packit Service e08953
          /* Sequence ended - go back to normal state. */
Packit Service e08953
          ansi_parser_state = ANSI_NORMAL;
Packit Service e08953
          continue;
Packit Service e08953
        }
Packit Service e08953
        /* Unexpected character, but sequence hasn't ended yet. Ignore the rest
Packit Service e08953
         * of the sequence. */
Packit Service e08953
        ansi_parser_state = ANSI_IGNORE;
Packit Service e08953
Packit b5b901
      } else if (ansi_parser_state & ANSI_CSI) {
Packit Service e08953
        /* So far we've seen `ESC [`, and we may or may not have already parsed
Packit Service e08953
         * some of the arguments that follow. */
Packit Service e08953
Packit Service e08953
        if (utf8_codepoint >= '0' && utf8_codepoint <= '9') {
Packit Service e08953
          /* Parse a numerical argument. */
Packit Service e08953
          if (!(ansi_parser_state & ANSI_IN_ARG)) {
Packit Service e08953
            /* We were not currently parsing a number, add a new one. */
Packit Service e08953
            /* Check for that there are too many arguments. */
Packit Service e08953
            if (handle->tty.wr.ansi_csi_argc >=
Packit Service e08953
                ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
Packit Service e08953
              ansi_parser_state = ANSI_IGNORE;
Packit b5b901
              continue;
Packit b5b901
            }
Packit Service e08953
            ansi_parser_state |= ANSI_IN_ARG;
Packit Service e08953
            handle->tty.wr.ansi_csi_argc++;
Packit Service e08953
            handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
Packit Service e08953
                (unsigned short) utf8_codepoint - '0';
Packit Service e08953
            continue;
Packit Service e08953
Packit Service e08953
          } else {
Packit Service e08953
            /* We were already parsing a number. Parse next digit. */
Packit Service e08953
            uint32_t value = 10 *
Packit Service e08953
                handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1];
Packit b5b901
Packit Service e08953
            /* Check for overflow. */
Packit Service e08953
            if (value > UINT16_MAX) {
Packit Service e08953
              ansi_parser_state = ANSI_IGNORE;
Packit b5b901
              continue;
Packit Service e08953
            }
Packit b5b901
Packit Service e08953
            handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
Packit Service e08953
                (unsigned short) value + (utf8_codepoint - '0');
Packit Service e08953
            continue;
Packit Service e08953
          }
Packit b5b901
Packit Service e08953
        } else if (utf8_codepoint == ';') {
Packit Service e08953
          /* Denotes the end of an argument. */
Packit Service e08953
          if (ansi_parser_state & ANSI_IN_ARG) {
Packit Service e08953
            ansi_parser_state &= ~ANSI_IN_ARG;
Packit Service e08953
            continue;
Packit b5b901
Packit Service e08953
          } else {
Packit Service e08953
            /* If ANSI_IN_ARG is not set, add another argument and default
Packit Service e08953
             * it to 0. */
Packit Service e08953
Packit Service e08953
            /* Check for too many arguments */
Packit Service e08953
            if (handle->tty.wr.ansi_csi_argc >=
Packit Service e08953
Packit Service e08953
                ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
Packit Service e08953
              ansi_parser_state = ANSI_IGNORE;
Packit b5b901
              continue;
Packit b5b901
            }
Packit b5b901
Packit Service e08953
            handle->tty.wr.ansi_csi_argc++;
Packit Service e08953
            handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] = 0;
Packit b5b901
            continue;
Packit Service e08953
          }
Packit b5b901
Packit Service e08953
        } else if (utf8_codepoint == '?' &&
Packit Service e08953
                   !(ansi_parser_state & ANSI_IN_ARG) &&
Packit Service e08953
                   !(ansi_parser_state & ANSI_EXTENSION) &&
Packit Service e08953
                   handle->tty.wr.ansi_csi_argc == 0) {
Packit Service e08953
          /* Pass through '?' if it is the first character after CSI */
Packit Service e08953
          /* This is an extension character from the VT100 codeset */
Packit Service e08953
          /* that is supported and used by most ANSI terminals today. */
Packit Service e08953
          ansi_parser_state |= ANSI_EXTENSION;
Packit Service e08953
          continue;
Packit Service e08953
Packit Service e08953
        } else if (utf8_codepoint == ' ' &&
Packit Service e08953
                   !(ansi_parser_state & ANSI_EXTENSION)) {
Packit Service e08953
          /* We expect a command byte to follow after this space. The only
Packit Service e08953
           * command that we current support is 'set cursor style'. */
Packit Service e08953
          ansi_parser_state = ANSI_DECSCUSR;
Packit Service e08953
          continue;
Packit Service e08953
Packit Service e08953
        } else if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
Packit Service e08953
          /* Command byte */
Packit Service e08953
          if (ansi_parser_state & ANSI_EXTENSION) {
Packit Service e08953
            /* Sequence is `ESC [ ? args command`. */
Packit Service e08953
            switch (utf8_codepoint) {
Packit Service e08953
              case 'l':
Packit Service e08953
                /* Hide the cursor */
Packit Service e08953
                if (handle->tty.wr.ansi_csi_argc == 1 &&
Packit Service e08953
                    handle->tty.wr.ansi_csi_argv[0] == 25) {
Packit Service e08953
                  FLUSH_TEXT();
Packit Service e08953
                  uv_tty_set_cursor_visibility(handle, 0, error);
Packit Service e08953
                }
Packit Service e08953
                break;
Packit Service e08953
Packit Service e08953
              case 'h':
Packit Service e08953
                /* Show the cursor */
Packit Service e08953
                if (handle->tty.wr.ansi_csi_argc == 1 &&
Packit Service e08953
                    handle->tty.wr.ansi_csi_argv[0] == 25) {
Packit Service e08953
                  FLUSH_TEXT();
Packit Service e08953
                  uv_tty_set_cursor_visibility(handle, 1, error);
Packit Service e08953
                }
Packit Service e08953
                break;
Packit Service e08953
            }
Packit b5b901
Packit Service e08953
          } else {
Packit Service e08953
            /* Sequence is `ESC [ args command`. */
Packit Service e08953
            int x, y, d;
Packit b5b901
            switch (utf8_codepoint) {
Packit b5b901
              case 'A':
Packit b5b901
                /* cursor up */
Packit b5b901
                FLUSH_TEXT();
Packit Service e08953
                y = -(handle->tty.wr.ansi_csi_argc
Packit Service e08953
                  ? handle->tty.wr.ansi_csi_argv[0] : 1);
Packit b5b901
                uv_tty_move_caret(handle, 0, 1, y, 1, error);
Packit b5b901
                break;
Packit b5b901
Packit b5b901
              case 'B':
Packit b5b901
                /* cursor down */
Packit b5b901
                FLUSH_TEXT();
Packit Service e08953
                y = handle->tty.wr.ansi_csi_argc
Packit Service e08953
                  ? handle->tty.wr.ansi_csi_argv[0] : 1;
Packit b5b901
                uv_tty_move_caret(handle, 0, 1, y, 1, error);
Packit b5b901
                break;
Packit b5b901
Packit b5b901
              case 'C':
Packit b5b901
                /* cursor forward */
Packit b5b901
                FLUSH_TEXT();
Packit Service e08953
                x = handle->tty.wr.ansi_csi_argc
Packit Service e08953
                  ? handle->tty.wr.ansi_csi_argv[0] : 1;
Packit b5b901
                uv_tty_move_caret(handle, x, 1, 0, 1, error);
Packit b5b901
                break;
Packit b5b901
Packit b5b901
              case 'D':
Packit b5b901
                /* cursor back */
Packit b5b901
                FLUSH_TEXT();
Packit Service e08953
                x = -(handle->tty.wr.ansi_csi_argc
Packit Service e08953
                  ? handle->tty.wr.ansi_csi_argv[0] : 1);
Packit b5b901
                uv_tty_move_caret(handle, x, 1, 0, 1, error);
Packit b5b901
                break;
Packit b5b901
Packit b5b901
              case 'E':
Packit b5b901
                /* cursor next line */
Packit b5b901
                FLUSH_TEXT();
Packit Service e08953
                y = handle->tty.wr.ansi_csi_argc
Packit Service e08953
                  ? handle->tty.wr.ansi_csi_argv[0] : 1;
Packit b5b901
                uv_tty_move_caret(handle, 0, 0, y, 1, error);
Packit b5b901
                break;
Packit b5b901
Packit b5b901
              case 'F':
Packit b5b901
                /* cursor previous line */
Packit b5b901
                FLUSH_TEXT();
Packit Service e08953
                y = -(handle->tty.wr.ansi_csi_argc
Packit Service e08953
                  ? handle->tty.wr.ansi_csi_argv[0] : 1);
Packit b5b901
                uv_tty_move_caret(handle, 0, 0, y, 1, error);
Packit b5b901
                break;
Packit b5b901
Packit b5b901
              case 'G':
Packit b5b901
                /* cursor horizontal move absolute */
Packit b5b901
                FLUSH_TEXT();
Packit Service e08953
                x = (handle->tty.wr.ansi_csi_argc >= 1 &&
Packit Service e08953
                     handle->tty.wr.ansi_csi_argv[0])
Packit b5b901
                  ? handle->tty.wr.ansi_csi_argv[0] - 1 : 0;
Packit b5b901
                uv_tty_move_caret(handle, x, 0, 0, 1, error);
Packit b5b901
                break;
Packit b5b901
Packit b5b901
              case 'H':
Packit b5b901
              case 'f':
Packit b5b901
                /* cursor move absolute */
Packit b5b901
                FLUSH_TEXT();
Packit Service e08953
                y = (handle->tty.wr.ansi_csi_argc >= 1 &&
Packit Service e08953
                     handle->tty.wr.ansi_csi_argv[0])
Packit b5b901
                  ? handle->tty.wr.ansi_csi_argv[0] - 1 : 0;
Packit Service e08953
                x = (handle->tty.wr.ansi_csi_argc >= 2 &&
Packit Service e08953
                     handle->tty.wr.ansi_csi_argv[1])
Packit b5b901
                  ? handle->tty.wr.ansi_csi_argv[1] - 1 : 0;
Packit b5b901
                uv_tty_move_caret(handle, x, 0, y, 0, error);
Packit b5b901
                break;
Packit b5b901
Packit b5b901
              case 'J':
Packit b5b901
                /* Erase screen */
Packit b5b901
                FLUSH_TEXT();
Packit Service e08953
                d = handle->tty.wr.ansi_csi_argc
Packit Service e08953
                  ? handle->tty.wr.ansi_csi_argv[0] : 0;
Packit b5b901
                if (d >= 0 && d <= 2) {
Packit b5b901
                  uv_tty_clear(handle, d, 1, error);
Packit b5b901
                }
Packit b5b901
                break;
Packit b5b901
Packit b5b901
              case 'K':
Packit b5b901
                /* Erase line */
Packit b5b901
                FLUSH_TEXT();
Packit Service e08953
                d = handle->tty.wr.ansi_csi_argc
Packit Service e08953
                  ? handle->tty.wr.ansi_csi_argv[0] : 0;
Packit b5b901
                if (d >= 0 && d <= 2) {
Packit b5b901
                  uv_tty_clear(handle, d, 0, error);
Packit b5b901
                }
Packit b5b901
                break;
Packit b5b901
Packit b5b901
              case 'm':
Packit b5b901
                /* Set style */
Packit b5b901
                FLUSH_TEXT();
Packit b5b901
                uv_tty_set_style(handle, error);
Packit b5b901
                break;
Packit b5b901
Packit b5b901
              case 's':
Packit b5b901
                /* Save the cursor position. */
Packit b5b901
                FLUSH_TEXT();
Packit b5b901
                uv_tty_save_state(handle, 0, error);
Packit b5b901
                break;
Packit b5b901
Packit b5b901
              case 'u':
Packit b5b901
                /* Restore the cursor position */
Packit b5b901
                FLUSH_TEXT();
Packit b5b901
                uv_tty_restore_state(handle, 0, error);
Packit b5b901
                break;
Packit b5b901
            }
Packit Service e08953
          }
Packit b5b901
Packit Service e08953
          /* Sequence ended - go back to normal state. */
Packit Service e08953
          ansi_parser_state = ANSI_NORMAL;
Packit Service e08953
          continue;
Packit b5b901
Packit b5b901
        } else {
Packit Service e08953
          /* We don't support commands that use private mode characters or
Packit Service e08953
           * intermediaries. Ignore the rest of the sequence. */
Packit Service e08953
          ansi_parser_state = ANSI_IGNORE;
Packit b5b901
          continue;
Packit b5b901
        }
Packit b5b901
Packit b5b901
      } else if (ansi_parser_state & ANSI_ST_CONTROL) {
Packit b5b901
        /* Unsupported control code.
Packit b5b901
         * Ignore everything until we see `BEL` or `ESC \`. */
Packit b5b901
        if (ansi_parser_state & ANSI_IN_STRING) {
Packit b5b901
          if (!(ansi_parser_state & ANSI_BACKSLASH_SEEN)) {
Packit b5b901
            if (utf8_codepoint == '"') {
Packit b5b901
              ansi_parser_state &= ~ANSI_IN_STRING;
Packit b5b901
            } else if (utf8_codepoint == '\\') {
Packit b5b901
              ansi_parser_state |= ANSI_BACKSLASH_SEEN;
Packit b5b901
            }
Packit b5b901
          } else {
Packit b5b901
            ansi_parser_state &= ~ANSI_BACKSLASH_SEEN;
Packit b5b901
          }
Packit b5b901
        } else {
Packit b5b901
          if (utf8_codepoint == '\007' || (utf8_codepoint == '\\' &&
Packit b5b901
              (ansi_parser_state & ANSI_ESCAPE_SEEN))) {
Packit b5b901
            /* End of sequence */
Packit b5b901
            ansi_parser_state = ANSI_NORMAL;
Packit b5b901
          } else if (utf8_codepoint == '\033') {
Packit b5b901
            /* Escape character */
Packit b5b901
            ansi_parser_state |= ANSI_ESCAPE_SEEN;
Packit b5b901
          } else if (utf8_codepoint == '"') {
Packit b5b901
             /* String starting */
Packit b5b901
            ansi_parser_state |= ANSI_IN_STRING;
Packit b5b901
            ansi_parser_state &= ~ANSI_ESCAPE_SEEN;
Packit b5b901
            ansi_parser_state &= ~ANSI_BACKSLASH_SEEN;
Packit b5b901
          } else {
Packit b5b901
            ansi_parser_state &= ~ANSI_ESCAPE_SEEN;
Packit b5b901
          }
Packit b5b901
        }
Packit b5b901
        continue;
Packit b5b901
      } else {
Packit b5b901
        /* Inconsistent state */
Packit b5b901
        abort();
Packit b5b901
      }
Packit b5b901
Packit b5b901
      /* We wouldn't mind emitting utf-16 surrogate pairs. Too bad, the windows
Packit b5b901
       * console doesn't really support UTF-16, so just emit the replacement
Packit b5b901
       * character. */
Packit b5b901
      if (utf8_codepoint > 0xffff) {
Packit b5b901
        utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
Packit b5b901
      }
Packit b5b901
Packit b5b901
      if (utf8_codepoint == 0x0a || utf8_codepoint == 0x0d) {
Packit b5b901
        /* EOL conversion - emit \r\n when we see \n. */
Packit b5b901
Packit b5b901
        if (utf8_codepoint == 0x0a && previous_eol != 0x0d) {
Packit b5b901
          /* \n was not preceded by \r; print \r\n. */
Packit b5b901
          ENSURE_BUFFER_SPACE(2);
Packit b5b901
          utf16_buf[utf16_buf_used++] = L'\r';
Packit b5b901
          utf16_buf[utf16_buf_used++] = L'\n';
Packit b5b901
        } else if (utf8_codepoint == 0x0d && previous_eol == 0x0a) {
Packit b5b901
          /* \n was followed by \r; do not print the \r, since the source was
Packit b5b901
           * either \r\n\r (so the second \r is redundant) or was \n\r (so the
Packit b5b901
           * \n was processed by the last case and an \r automatically
Packit b5b901
           * inserted). */
Packit b5b901
        } else {
Packit b5b901
          /* \r without \n; print \r as-is. */
Packit b5b901
          ENSURE_BUFFER_SPACE(1);
Packit b5b901
          utf16_buf[utf16_buf_used++] = (WCHAR) utf8_codepoint;
Packit b5b901
        }
Packit b5b901
Packit b5b901
        previous_eol = (char) utf8_codepoint;
Packit b5b901
Packit b5b901
      } else if (utf8_codepoint <= 0xffff) {
Packit b5b901
        /* Encode character into utf-16 buffer. */
Packit b5b901
        ENSURE_BUFFER_SPACE(1);
Packit b5b901
        utf16_buf[utf16_buf_used++] = (WCHAR) utf8_codepoint;
Packit b5b901
        previous_eol = 0;
Packit b5b901
      }
Packit b5b901
    }
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* Flush remaining characters */
Packit b5b901
  FLUSH_TEXT();
Packit b5b901
Packit b5b901
  /* Copy cached values back to struct. */
Packit b5b901
  handle->tty.wr.utf8_bytes_left = utf8_bytes_left;
Packit b5b901
  handle->tty.wr.utf8_codepoint = utf8_codepoint;
Packit b5b901
  handle->tty.wr.previous_eol = previous_eol;
Packit b5b901
  handle->tty.wr.ansi_parser_state = ansi_parser_state;
Packit b5b901
Packit b5b901
  uv_sem_post(&uv_tty_output_lock);
Packit b5b901
Packit b5b901
  if (*error == STATUS_SUCCESS) {
Packit b5b901
    return 0;
Packit b5b901
  } else {
Packit b5b901
    return -1;
Packit b5b901
  }
Packit b5b901
Packit b5b901
#undef FLUSH_TEXT
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_tty_write(uv_loop_t* loop,
Packit b5b901
                 uv_write_t* req,
Packit b5b901
                 uv_tty_t* handle,
Packit b5b901
                 const uv_buf_t bufs[],
Packit b5b901
                 unsigned int nbufs,
Packit b5b901
                 uv_write_cb cb) {
Packit b5b901
  DWORD error;
Packit b5b901
Packit b5b901
  UV_REQ_INIT(req, UV_WRITE);
Packit b5b901
  req->handle = (uv_stream_t*) handle;
Packit b5b901
  req->cb = cb;
Packit b5b901
Packit b5b901
  handle->reqs_pending++;
Packit b5b901
  handle->stream.conn.write_reqs_pending++;
Packit b5b901
  REGISTER_HANDLE_REQ(loop, handle, req);
Packit b5b901
Packit b5b901
  req->u.io.queued_bytes = 0;
Packit b5b901
Packit b5b901
  if (!uv_tty_write_bufs(handle, bufs, nbufs, &error)) {
Packit b5b901
    SET_REQ_SUCCESS(req);
Packit b5b901
  } else {
Packit b5b901
    SET_REQ_ERROR(req, error);
Packit b5b901
  }
Packit b5b901
Packit b5b901
  uv_insert_pending_req(loop, (uv_req_t*) req);
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv__tty_try_write(uv_tty_t* handle,
Packit b5b901
                      const uv_buf_t bufs[],
Packit b5b901
                      unsigned int nbufs) {
Packit b5b901
  DWORD error;
Packit b5b901
Packit b5b901
  if (handle->stream.conn.write_reqs_pending > 0)
Packit b5b901
    return UV_EAGAIN;
Packit b5b901
Packit b5b901
  if (uv_tty_write_bufs(handle, bufs, nbufs, &error))
Packit b5b901
    return uv_translate_sys_error(error);
Packit b5b901
Packit b5b901
  return uv__count_bufs(bufs, nbufs);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
Packit b5b901
  uv_write_t* req) {
Packit b5b901
  int err;
Packit b5b901
Packit b5b901
  handle->write_queue_size -= req->u.io.queued_bytes;
Packit b5b901
  UNREGISTER_HANDLE_REQ(loop, handle, req);
Packit b5b901
Packit b5b901
  if (req->cb) {
Packit b5b901
    err = GET_REQ_ERROR(req);
Packit b5b901
    req->cb(req, uv_translate_sys_error(err));
Packit b5b901
  }
Packit b5b901
Packit b5b901
  handle->stream.conn.write_reqs_pending--;
Packit b5b901
  if (handle->stream.conn.shutdown_req != NULL &&
Packit b5b901
      handle->stream.conn.write_reqs_pending == 0) {
Packit b5b901
    uv_want_endgame(loop, (uv_handle_t*)handle);
Packit b5b901
  }
Packit b5b901
Packit b5b901
  DECREASE_PENDING_REQ_COUNT(handle);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
void uv_tty_close(uv_tty_t* handle) {
Packit b5b901
  assert(handle->u.fd == -1 || handle->u.fd > 2);
Packit Service e08953
  if (handle->flags & UV_HANDLE_READING)
Packit Service e08953
    uv_tty_read_stop(handle);
Packit Service e08953
Packit b5b901
  if (handle->u.fd == -1)
Packit b5b901
    CloseHandle(handle->handle);
Packit b5b901
  else
Packit b5b901
    close(handle->u.fd);
Packit b5b901
Packit b5b901
  handle->u.fd = -1;
Packit b5b901
  handle->handle = INVALID_HANDLE_VALUE;
Packit b5b901
  handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
Packit b5b901
  uv__handle_closing(handle);
Packit b5b901
Packit b5b901
  if (handle->reqs_pending == 0) {
Packit b5b901
    uv_want_endgame(handle->loop, (uv_handle_t*) handle);
Packit b5b901
  }
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
Packit b5b901
  if (!(handle->flags & UV_HANDLE_TTY_READABLE) &&
Packit b5b901
      handle->stream.conn.shutdown_req != NULL &&
Packit b5b901
      handle->stream.conn.write_reqs_pending == 0) {
Packit b5b901
    UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req);
Packit b5b901
Packit b5b901
    /* TTY shutdown is really just a no-op */
Packit b5b901
    if (handle->stream.conn.shutdown_req->cb) {
Packit b5b901
      if (handle->flags & UV_HANDLE_CLOSING) {
Packit b5b901
        handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, UV_ECANCELED);
Packit b5b901
      } else {
Packit b5b901
        handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, 0);
Packit b5b901
      }
Packit b5b901
    }
Packit b5b901
Packit b5b901
    handle->stream.conn.shutdown_req = NULL;
Packit b5b901
Packit b5b901
    DECREASE_PENDING_REQ_COUNT(handle);
Packit b5b901
    return;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (handle->flags & UV_HANDLE_CLOSING &&
Packit b5b901
      handle->reqs_pending == 0) {
Packit b5b901
    /* The wait handle used for raw reading should be unregistered when the
Packit b5b901
     * wait callback runs. */
Packit b5b901
    assert(!(handle->flags & UV_HANDLE_TTY_READABLE) ||
Packit b5b901
           handle->tty.rd.read_raw_wait == NULL);
Packit b5b901
Packit b5b901
    assert(!(handle->flags & UV_HANDLE_CLOSED));
Packit b5b901
    uv__handle_close(handle);
Packit b5b901
  }
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
/*
Packit b5b901
 * uv_process_tty_accept_req() is a stub to keep DELEGATE_STREAM_REQ working
Packit b5b901
 * TODO: find a way to remove it
Packit b5b901
 */
Packit b5b901
void uv_process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle,
Packit b5b901
    uv_req_t* raw_req) {
Packit b5b901
  abort();
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
/*
Packit b5b901
 * uv_process_tty_connect_req() is a stub to keep DELEGATE_STREAM_REQ working
Packit b5b901
 * TODO: find a way to remove it
Packit b5b901
 */
Packit b5b901
void uv_process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle,
Packit b5b901
    uv_connect_t* req) {
Packit b5b901
  abort();
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_tty_reset_mode(void) {
Packit b5b901
  /* Not necessary to do anything. */
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
/* Determine whether or not this version of windows supports
Packit b5b901
 * proper ANSI color codes. Should be supported as of windows
Packit b5b901
 * 10 version 1511, build number 10.0.10586.
Packit b5b901
 */
Packit b5b901
static void uv__determine_vterm_state(HANDLE handle) {
Packit b5b901
  DWORD dwMode = 0;
Packit b5b901
Packit Service e08953
  uv__need_check_vterm_state = FALSE;
Packit b5b901
  if (!GetConsoleMode(handle, &dwMode)) {
Packit b5b901
    return;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
Packit b5b901
  if (!SetConsoleMode(handle, dwMode)) {
Packit b5b901
    return;
Packit b5b901
  }
Packit b5b901
Packit Service e08953
  uv__vterm_state = UV_TTY_SUPPORTED;
Packit b5b901
}
Packit b5b901
Packit b5b901
static DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param) {
Packit Service e08953
  NTSTATUS status;
Packit Service e08953
  ULONG_PTR conhost_pid;
Packit b5b901
  MSG msg;
Packit b5b901
Packit Service e08953
  if (pSetWinEventHook == NULL || pNtQueryInformationProcess == NULL)
Packit b5b901
    return 0;
Packit b5b901
Packit Service e08953
  status = pNtQueryInformationProcess(GetCurrentProcess(),
Packit Service e08953
                                      ProcessConsoleHostProcess,
Packit Service e08953
                                      &conhost_pid,
Packit Service e08953
                                      sizeof(conhost_pid),
Packit Service e08953
                                      NULL);
Packit b5b901
Packit Service e08953
  if (!NT_SUCCESS(status)) {
Packit Service e08953
    /* We couldn't retrieve our console host process, probably because this
Packit Service e08953
     * is a 32-bit process running on 64-bit Windows. Fall back to receiving
Packit Service e08953
     * console events from the input stream only. */
Packit Service e08953
    return 0;
Packit Service e08953
  }
Packit Service e08953
Packit Service e08953
  /* Ensure the PID is a multiple of 4, which is required by SetWinEventHook */
Packit Service e08953
  conhost_pid &= ~(ULONG_PTR)0x3;
Packit Service e08953
Packit Service e08953
  uv__tty_console_resized = CreateEvent(NULL, TRUE, FALSE, NULL);
Packit Service e08953
  if (uv__tty_console_resized == NULL)
Packit Service e08953
    return 0;
Packit Service e08953
  if (QueueUserWorkItem(uv__tty_console_resize_watcher_thread,
Packit Service e08953
                        NULL,
Packit Service e08953
                        WT_EXECUTELONGFUNCTION) == 0)
Packit b5b901
    return 0;
Packit b5b901
Packit b5b901
  if (!pSetWinEventHook(EVENT_CONSOLE_LAYOUT,
Packit b5b901
                        EVENT_CONSOLE_LAYOUT,
Packit b5b901
                        NULL,
Packit b5b901
                        uv__tty_console_resize_event,
Packit Service e08953
                        (DWORD)conhost_pid,
Packit b5b901
                        0,
Packit b5b901
                        WINEVENT_OUTOFCONTEXT))
Packit b5b901
    return 0;
Packit b5b901
Packit b5b901
  while (GetMessage(&msg, NULL, 0, 0)) {
Packit b5b901
    TranslateMessage(&msg;;
Packit b5b901
    DispatchMessage(&msg;;
Packit b5b901
  }
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook,
Packit b5b901
                                                  DWORD event,
Packit b5b901
                                                  HWND hwnd,
Packit b5b901
                                                  LONG idObject,
Packit b5b901
                                                  LONG idChild,
Packit b5b901
                                                  DWORD dwEventThread,
Packit b5b901
                                                  DWORD dwmsEventTime) {
Packit Service e08953
  SetEvent(uv__tty_console_resized);
Packit Service e08953
}
Packit Service e08953
Packit Service e08953
static DWORD WINAPI uv__tty_console_resize_watcher_thread(void* param) {
Packit Service e08953
  for (;;) {
Packit Service e08953
    /* Make sure to not overwhelm the system with resize events */
Packit Service e08953
    Sleep(33);
Packit Service e08953
    WaitForSingleObject(uv__tty_console_resized, INFINITE);
Packit Service e08953
    uv__tty_console_signal_resize();
Packit Service e08953
    ResetEvent(uv__tty_console_resized);
Packit Service e08953
  }
Packit Service e08953
}
Packit Service e08953
Packit Service e08953
static void uv__tty_console_signal_resize(void) {
Packit b5b901
  CONSOLE_SCREEN_BUFFER_INFO sb_info;
Packit b5b901
  int width, height;
Packit b5b901
Packit b5b901
  if (!GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info))
Packit b5b901
    return;
Packit b5b901
Packit b5b901
  width = sb_info.dwSize.X;
Packit b5b901
  height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1;
Packit b5b901
Packit Service e08953
  uv_mutex_lock(&uv__tty_console_resize_mutex);
Packit Service e08953
  assert(uv__tty_console_width != -1 && uv__tty_console_height != -1);
Packit b5b901
  if (width != uv__tty_console_width || height != uv__tty_console_height) {
Packit b5b901
    uv__tty_console_width = width;
Packit b5b901
    uv__tty_console_height = height;
Packit Service e08953
    uv_mutex_unlock(&uv__tty_console_resize_mutex);
Packit b5b901
    uv__signal_dispatch(SIGWINCH);
Packit Service e08953
  } else {
Packit Service e08953
    uv_mutex_unlock(&uv__tty_console_resize_mutex);
Packit b5b901
  }
Packit b5b901
}
Packit Service e08953
Packit Service e08953
void uv_tty_set_vterm_state(uv_tty_vtermstate_t state) {
Packit Service e08953
  uv_sem_wait(&uv_tty_output_lock);
Packit Service e08953
  uv__need_check_vterm_state = FALSE;
Packit Service e08953
  uv__vterm_state = state;
Packit Service e08953
  uv_sem_post(&uv_tty_output_lock);
Packit Service e08953
}
Packit Service e08953
Packit Service e08953
int uv_tty_get_vterm_state(uv_tty_vtermstate_t* state) {
Packit Service e08953
  uv_sem_wait(&uv_tty_output_lock);
Packit Service e08953
  *state = uv__vterm_state;
Packit Service e08953
  uv_sem_post(&uv_tty_output_lock);
Packit Service e08953
  return 0;
Packit Service e08953
}