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


grpc
Author(s):
autogenerated on Fri May 16 2025 03:00:40