Rizin
unix-like reverse engineering framework and cli tools
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 
84  COMPLETED
85 };
86 
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. */
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 
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();
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;
353  uv_alloc_cb alloc_cb;
354  uv_read_cb read_cb;
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) {
407  err = uv_tty_read_start(tty, alloc_cb, read_cb);
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 
518  if (status == TRAP_REQUESTED) {
521  req->u.io.overlapped.InternalHigh = 0;
523  return 0;
524  }
525 
526  read_console_success = ReadConsoleW(handle->handle,
527  (void*) utf16,
528  chars,
529  &read_chars,
530  NULL);
531 
532  if (read_console_success) {
533  read_bytes = WideCharToMultiByte(CP_UTF8,
534  0,
535  utf16,
536  read_chars,
537  handle->tty.rd.read_line_buffer.base,
538  bytes,
539  NULL,
540  NULL);
542  req->u.io.overlapped.InternalHigh = read_bytes;
543  } else {
544  SET_REQ_ERROR(req, GetLastError());
545  }
546 
548 
549  if (status == TRAP_REQUESTED) {
550  /* If we canceled the read by sending a VK_RETURN event, restore the
551  screen state to undo the visual effect of the VK_RETURN */
552  if (read_console_success && InterlockedOr(&uv__restore_screen_state, 0)) {
553  HANDLE active_screen_buffer;
554  active_screen_buffer = CreateFileA("conout$",
555  GENERIC_READ | GENERIC_WRITE,
556  FILE_SHARE_READ | FILE_SHARE_WRITE,
557  NULL,
558  OPEN_EXISTING,
559  FILE_ATTRIBUTE_NORMAL,
560  NULL);
561  if (active_screen_buffer != INVALID_HANDLE_VALUE) {
562  pos = uv__saved_screen_state.dwCursorPosition;
563 
564  /* If the cursor was at the bottom line of the screen buffer, the
565  VK_RETURN would have caused the buffer contents to scroll up by one
566  line. The right position to reset the cursor to is therefore one line
567  higher */
568  if (pos.Y == uv__saved_screen_state.dwSize.Y - 1)
569  pos.Y--;
570 
571  SetConsoleCursorPosition(active_screen_buffer, pos);
572  CloseHandle(active_screen_buffer);
573  }
574  }
576  }
578  return 0;
579 }
580 
581 
583  uv_read_t* req;
584  BOOL r;
585 
586  assert(handle->flags & UV_HANDLE_READING);
587  assert(!(handle->flags & UV_HANDLE_READ_PENDING));
588  assert(handle->handle && handle->handle != INVALID_HANDLE_VALUE);
589 
590  req = &handle->read_req;
591  memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
592 
593  handle->tty.rd.read_line_buffer = uv_buf_init(NULL, 0);
594  handle->alloc_cb((uv_handle_t*) handle, 8192, &handle->tty.rd.read_line_buffer);
595  if (handle->tty.rd.read_line_buffer.base == NULL ||
596  handle->tty.rd.read_line_buffer.len == 0) {
597  handle->read_cb((uv_stream_t*) handle,
598  UV_ENOBUFS,
599  &handle->tty.rd.read_line_buffer);
600  return;
601  }
602  assert(handle->tty.rd.read_line_buffer.base != NULL);
603 
604  /* Reset flags No locking is required since there cannot be a line read
605  in progress. We are also relying on the memory barrier provided by
606  QueueUserWorkItem*/
609  r = QueueUserWorkItem(uv_tty_line_read_thread,
610  (void*) req,
611  WT_EXECUTELONGFUNCTION);
612  if (!r) {
613  SET_REQ_ERROR(req, GetLastError());
615  }
616 
617  handle->flags |= UV_HANDLE_READ_PENDING;
618  handle->reqs_pending++;
619 }
620 
621 
623  if (handle->flags & UV_HANDLE_TTY_RAW) {
625  } else {
627  }
628 }
629 
630 
631 static const char* get_vt100_fn_key(DWORD code, char shift, char ctrl,
632  size_t* len) {
633 #define VK_CASE(vk, normal_str, shift_str, ctrl_str, shift_ctrl_str) \
634  case (vk): \
635  if (shift && ctrl) { \
636  *len = sizeof shift_ctrl_str; \
637  return "\033" shift_ctrl_str; \
638  } else if (shift) { \
639  *len = sizeof shift_str ; \
640  return "\033" shift_str; \
641  } else if (ctrl) { \
642  *len = sizeof ctrl_str; \
643  return "\033" ctrl_str; \
644  } else { \
645  *len = sizeof normal_str; \
646  return "\033" normal_str; \
647  }
648 
649  switch (code) {
650  /* These mappings are the same as Cygwin's. Unmodified and alt-modified
651  * keypad keys comply with linux console, modifiers comply with xterm
652  * modifier usage. F1. f12 and shift-f1. f10 comply with linux console, f6.
653  * f12 with and without modifiers comply with rxvt. */
654  VK_CASE(VK_INSERT, "[2~", "[2;2~", "[2;5~", "[2;6~")
655  VK_CASE(VK_END, "[4~", "[4;2~", "[4;5~", "[4;6~")
656  VK_CASE(VK_DOWN, "[B", "[1;2B", "[1;5B", "[1;6B")
657  VK_CASE(VK_NEXT, "[6~", "[6;2~", "[6;5~", "[6;6~")
658  VK_CASE(VK_LEFT, "[D", "[1;2D", "[1;5D", "[1;6D")
659  VK_CASE(VK_CLEAR, "[G", "[1;2G", "[1;5G", "[1;6G")
660  VK_CASE(VK_RIGHT, "[C", "[1;2C", "[1;5C", "[1;6C")
661  VK_CASE(VK_UP, "[A", "[1;2A", "[1;5A", "[1;6A")
662  VK_CASE(VK_HOME, "[1~", "[1;2~", "[1;5~", "[1;6~")
663  VK_CASE(VK_PRIOR, "[5~", "[5;2~", "[5;5~", "[5;6~")
664  VK_CASE(VK_DELETE, "[3~", "[3;2~", "[3;5~", "[3;6~")
665  VK_CASE(VK_NUMPAD0, "[2~", "[2;2~", "[2;5~", "[2;6~")
666  VK_CASE(VK_NUMPAD1, "[4~", "[4;2~", "[4;5~", "[4;6~")
667  VK_CASE(VK_NUMPAD2, "[B", "[1;2B", "[1;5B", "[1;6B")
668  VK_CASE(VK_NUMPAD3, "[6~", "[6;2~", "[6;5~", "[6;6~")
669  VK_CASE(VK_NUMPAD4, "[D", "[1;2D", "[1;5D", "[1;6D")
670  VK_CASE(VK_NUMPAD5, "[G", "[1;2G", "[1;5G", "[1;6G")
671  VK_CASE(VK_NUMPAD6, "[C", "[1;2C", "[1;5C", "[1;6C")
672  VK_CASE(VK_NUMPAD7, "[A", "[1;2A", "[1;5A", "[1;6A")
673  VK_CASE(VK_NUMPAD8, "[1~", "[1;2~", "[1;5~", "[1;6~")
674  VK_CASE(VK_NUMPAD9, "[5~", "[5;2~", "[5;5~", "[5;6~")
675  VK_CASE(VK_DECIMAL, "[3~", "[3;2~", "[3;5~", "[3;6~")
676  VK_CASE(VK_F1, "[[A", "[23~", "[11^", "[23^" )
677  VK_CASE(VK_F2, "[[B", "[24~", "[12^", "[24^" )
678  VK_CASE(VK_F3, "[[C", "[25~", "[13^", "[25^" )
679  VK_CASE(VK_F4, "[[D", "[26~", "[14^", "[26^" )
680  VK_CASE(VK_F5, "[[E", "[28~", "[15^", "[28^" )
681  VK_CASE(VK_F6, "[17~", "[29~", "[17^", "[29^" )
682  VK_CASE(VK_F7, "[18~", "[31~", "[18^", "[31^" )
683  VK_CASE(VK_F8, "[19~", "[32~", "[19^", "[32^" )
684  VK_CASE(VK_F9, "[20~", "[33~", "[20^", "[33^" )
685  VK_CASE(VK_F10, "[21~", "[34~", "[21^", "[34^" )
686  VK_CASE(VK_F11, "[23~", "[23$", "[23^", "[23@" )
687  VK_CASE(VK_F12, "[24~", "[24$", "[24^", "[24@" )
688 
689  default:
690  *len = 0;
691  return NULL;
692  }
693 #undef VK_CASE
694 }
695 
696 
698  uv_req_t* req) {
699  /* Shortcut for handle->tty.rd.last_input_record.Event.KeyEvent. */
700 #define KEV handle->tty.rd.last_input_record.Event.KeyEvent
701 
702  DWORD records_left, records_read;
703  uv_buf_t buf;
704  off_t buf_used;
705 
706  assert(handle->type == UV_TTY);
708  handle->flags &= ~UV_HANDLE_READ_PENDING;
709 
710  if (!(handle->flags & UV_HANDLE_READING) ||
711  !(handle->flags & UV_HANDLE_TTY_RAW)) {
712  goto out;
713  }
714 
715  if (!REQ_SUCCESS(req)) {
716  /* An error occurred while waiting for the event. */
717  if ((handle->flags & UV_HANDLE_READING)) {
718  handle->flags &= ~UV_HANDLE_READING;
719  handle->read_cb((uv_stream_t*)handle,
721  &uv_null_buf_);
722  }
723  goto out;
724  }
725 
726  /* Fetch the number of events */
727  if (!GetNumberOfConsoleInputEvents(handle->handle, &records_left)) {
728  handle->flags &= ~UV_HANDLE_READING;
730  handle->read_cb((uv_stream_t*)handle,
731  uv_translate_sys_error(GetLastError()),
732  &uv_null_buf_);
733  goto out;
734  }
735 
736  /* Windows sends a lot of events that we're not interested in, so buf will be
737  * allocated on demand, when there's actually something to emit. */
738  buf = uv_null_buf_;
739  buf_used = 0;
740 
741  while ((records_left > 0 || handle->tty.rd.last_key_len > 0) &&
742  (handle->flags & UV_HANDLE_READING)) {
743  if (handle->tty.rd.last_key_len == 0) {
744  /* Read the next input record */
745  if (!ReadConsoleInputW(handle->handle,
746  &handle->tty.rd.last_input_record,
747  1,
748  &records_read)) {
749  handle->flags &= ~UV_HANDLE_READING;
751  handle->read_cb((uv_stream_t*) handle,
752  uv_translate_sys_error(GetLastError()),
753  &buf);
754  goto out;
755  }
756  records_left--;
757 
758  /* We might be not subscribed to EVENT_CONSOLE_LAYOUT or we might be
759  * running under some TTY emulator that does not send those events. */
760  if (handle->tty.rd.last_input_record.EventType == WINDOW_BUFFER_SIZE_EVENT) {
762  }
763 
764  /* Ignore other events that are not key events. */
765  if (handle->tty.rd.last_input_record.EventType != KEY_EVENT) {
766  continue;
767  }
768 
769  /* Ignore keyup events, unless the left alt key was held and a valid
770  * unicode character was emitted. */
771  if (!KEV.bKeyDown &&
772  (KEV.wVirtualKeyCode != VK_MENU ||
773  KEV.uChar.UnicodeChar == 0)) {
774  continue;
775  }
776 
777  /* Ignore keypresses to numpad number keys if the left alt is held
778  * because the user is composing a character, or windows simulating this.
779  */
780  if ((KEV.dwControlKeyState & LEFT_ALT_PRESSED) &&
781  !(KEV.dwControlKeyState & ENHANCED_KEY) &&
782  (KEV.wVirtualKeyCode == VK_INSERT ||
783  KEV.wVirtualKeyCode == VK_END ||
784  KEV.wVirtualKeyCode == VK_DOWN ||
785  KEV.wVirtualKeyCode == VK_NEXT ||
786  KEV.wVirtualKeyCode == VK_LEFT ||
787  KEV.wVirtualKeyCode == VK_CLEAR ||
788  KEV.wVirtualKeyCode == VK_RIGHT ||
789  KEV.wVirtualKeyCode == VK_HOME ||
790  KEV.wVirtualKeyCode == VK_UP ||
791  KEV.wVirtualKeyCode == VK_PRIOR ||
792  KEV.wVirtualKeyCode == VK_NUMPAD0 ||
793  KEV.wVirtualKeyCode == VK_NUMPAD1 ||
794  KEV.wVirtualKeyCode == VK_NUMPAD2 ||
795  KEV.wVirtualKeyCode == VK_NUMPAD3 ||
796  KEV.wVirtualKeyCode == VK_NUMPAD4 ||
797  KEV.wVirtualKeyCode == VK_NUMPAD5 ||
798  KEV.wVirtualKeyCode == VK_NUMPAD6 ||
799  KEV.wVirtualKeyCode == VK_NUMPAD7 ||
800  KEV.wVirtualKeyCode == VK_NUMPAD8 ||
801  KEV.wVirtualKeyCode == VK_NUMPAD9)) {
802  continue;
803  }
804 
805  if (KEV.uChar.UnicodeChar != 0) {
806  int prefix_len, char_len;
807 
808  /* Character key pressed */
809  if (KEV.uChar.UnicodeChar >= 0xD800 &&
810  KEV.uChar.UnicodeChar < 0xDC00) {
811  /* UTF-16 high surrogate */
812  handle->tty.rd.last_utf16_high_surrogate = KEV.uChar.UnicodeChar;
813  continue;
814  }
815 
816  /* Prefix with \u033 if alt was held, but alt was not used as part a
817  * compose sequence. */
818  if ((KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
819  && !(KEV.dwControlKeyState & (LEFT_CTRL_PRESSED |
820  RIGHT_CTRL_PRESSED)) && KEV.bKeyDown) {
821  handle->tty.rd.last_key[0] = '\033';
822  prefix_len = 1;
823  } else {
824  prefix_len = 0;
825  }
826 
827  if (KEV.uChar.UnicodeChar >= 0xDC00 &&
828  KEV.uChar.UnicodeChar < 0xE000) {
829  /* UTF-16 surrogate pair */
830  WCHAR utf16_buffer[2];
831  utf16_buffer[0] = handle->tty.rd.last_utf16_high_surrogate;
832  utf16_buffer[1] = KEV.uChar.UnicodeChar;
833  char_len = WideCharToMultiByte(CP_UTF8,
834  0,
835  utf16_buffer,
836  2,
837  &handle->tty.rd.last_key[prefix_len],
838  sizeof handle->tty.rd.last_key,
839  NULL,
840  NULL);
841  } else {
842  /* Single UTF-16 character */
843  char_len = WideCharToMultiByte(CP_UTF8,
844  0,
845  &KEV.uChar.UnicodeChar,
846  1,
847  &handle->tty.rd.last_key[prefix_len],
848  sizeof handle->tty.rd.last_key,
849  NULL,
850  NULL);
851  }
852 
853  /* Whatever happened, the last character wasn't a high surrogate. */
854  handle->tty.rd.last_utf16_high_surrogate = 0;
855 
856  /* If the utf16 character(s) couldn't be converted something must be
857  * wrong. */
858  if (!char_len) {
859  handle->flags &= ~UV_HANDLE_READING;
861  handle->read_cb((uv_stream_t*) handle,
862  uv_translate_sys_error(GetLastError()),
863  &buf);
864  goto out;
865  }
866 
867  handle->tty.rd.last_key_len = (unsigned char) (prefix_len + char_len);
868  handle->tty.rd.last_key_offset = 0;
869  continue;
870 
871  } else {
872  /* Function key pressed */
873  const char* vt100;
874  size_t prefix_len, vt100_len;
875 
876  vt100 = get_vt100_fn_key(KEV.wVirtualKeyCode,
877  !!(KEV.dwControlKeyState & SHIFT_PRESSED),
878  !!(KEV.dwControlKeyState & (
879  LEFT_CTRL_PRESSED |
880  RIGHT_CTRL_PRESSED)),
881  &vt100_len);
882 
883  /* If we were unable to map to a vt100 sequence, just ignore. */
884  if (!vt100) {
885  continue;
886  }
887 
888  /* Prefix with \x033 when the alt key was held. */
889  if (KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
890  handle->tty.rd.last_key[0] = '\033';
891  prefix_len = 1;
892  } else {
893  prefix_len = 0;
894  }
895 
896  /* Copy the vt100 sequence to the handle buffer. */
897  assert(prefix_len + vt100_len < sizeof handle->tty.rd.last_key);
898  memcpy(&handle->tty.rd.last_key[prefix_len], vt100, vt100_len);
899 
900  handle->tty.rd.last_key_len = (unsigned char) (prefix_len + vt100_len);
901  handle->tty.rd.last_key_offset = 0;
902  continue;
903  }
904  } else {
905  /* Copy any bytes left from the last keypress to the user buffer. */
906  if (handle->tty.rd.last_key_offset < handle->tty.rd.last_key_len) {
907  /* Allocate a buffer if needed */
908  if (buf_used == 0) {
909  buf = uv_buf_init(NULL, 0);
910  handle->alloc_cb((uv_handle_t*) handle, 1024, &buf);
911  if (buf.base == NULL || buf.len == 0) {
912  handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf);
913  goto out;
914  }
915  assert(buf.base != NULL);
916  }
917 
918  buf.base[buf_used++] = handle->tty.rd.last_key[handle->tty.rd.last_key_offset++];
919 
920  /* If the buffer is full, emit it */
921  if ((size_t) buf_used == buf.len) {
922  handle->read_cb((uv_stream_t*) handle, buf_used, &buf);
923  buf = uv_null_buf_;
924  buf_used = 0;
925  }
926 
927  continue;
928  }
929 
930  /* Apply dwRepeat from the last input record. */
931  if (--KEV.wRepeatCount > 0) {
932  handle->tty.rd.last_key_offset = 0;
933  continue;
934  }
935 
936  handle->tty.rd.last_key_len = 0;
937  continue;
938  }
939  }
940 
941  /* Send the buffer back to the user */
942  if (buf_used > 0) {
943  handle->read_cb((uv_stream_t*) handle, buf_used, &buf);
944  }
945 
946  out:
947  /* Wait for more input events. */
948  if ((handle->flags & UV_HANDLE_READING) &&
949  !(handle->flags & UV_HANDLE_READ_PENDING)) {
951  }
952 
954 
955 #undef KEV
956 }
957 
958 
959 
961  uv_req_t* req) {
962  uv_buf_t buf;
963 
964  assert(handle->type == UV_TTY);
966 
967  buf = handle->tty.rd.read_line_buffer;
968 
969  handle->flags &= ~UV_HANDLE_READ_PENDING;
970  handle->tty.rd.read_line_buffer = uv_null_buf_;
971 
972  if (!REQ_SUCCESS(req)) {
973  /* Read was not successful */
974  if (handle->flags & UV_HANDLE_READING) {
975  /* Real error */
976  handle->flags &= ~UV_HANDLE_READING;
978  handle->read_cb((uv_stream_t*) handle,
980  &buf);
981  }
982  } else {
983  if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING) &&
984  req->u.io.overlapped.InternalHigh != 0) {
985  /* Read successful. TODO: read unicode, convert to utf-8 */
986  DWORD bytes = req->u.io.overlapped.InternalHigh;
987  handle->read_cb((uv_stream_t*) handle, bytes, &buf);
988  }
990  }
991 
992  /* Wait for more input events. */
993  if ((handle->flags & UV_HANDLE_READING) &&
994  !(handle->flags & UV_HANDLE_READ_PENDING)) {
996  }
997 
999 }
1000 
1001 
1003  uv_req_t* req) {
1004  assert(handle->type == UV_TTY);
1006 
1007  /* If the read_line_buffer member is zero, it must have been an raw read.
1008  * Otherwise it was a line-buffered read. FIXME: This is quite obscure. Use a
1009  * flag or something. */
1010  if (handle->tty.rd.read_line_buffer.len == 0) {
1012  } else {
1014  }
1015 }
1016 
1017 
1019  uv_read_cb read_cb) {
1020  uv_loop_t* loop = handle->loop;
1021 
1022  if (!(handle->flags & UV_HANDLE_TTY_READABLE)) {
1023  return ERROR_INVALID_PARAMETER;
1024  }
1025 
1026  handle->flags |= UV_HANDLE_READING;
1028  handle->read_cb = read_cb;
1029  handle->alloc_cb = alloc_cb;
1030 
1031  /* If reading was stopped and then started again, there could still be a read
1032  * request pending. */
1033  if (handle->flags & UV_HANDLE_READ_PENDING) {
1034  return 0;
1035  }
1036 
1037  /* Maybe the user stopped reading half-way while processing key events.
1038  * Short-circuit if this could be the case. */
1039  if (handle->tty.rd.last_key_len > 0) {
1040  SET_REQ_SUCCESS(&handle->read_req);
1041  uv_insert_pending_req(handle->loop, (uv_req_t*) &handle->read_req);
1042  /* Make sure no attempt is made to insert it again until it's handled. */
1043  handle->flags |= UV_HANDLE_READ_PENDING;
1044  handle->reqs_pending++;
1045  return 0;
1046  }
1047 
1049 
1050  return 0;
1051 }
1052 
1053 
1055  INPUT_RECORD record;
1056  DWORD written, err;
1057 
1058  handle->flags &= ~UV_HANDLE_READING;
1060 
1061  if (!(handle->flags & UV_HANDLE_READ_PENDING))
1062  return 0;
1063 
1064  if (handle->flags & UV_HANDLE_TTY_RAW) {
1065  /* Cancel raw read. Write some bullshit event to force the console wait to
1066  * return. */
1067  memset(&record, 0, sizeof record);
1068  record.EventType = FOCUS_EVENT;
1069  if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) {
1070  return GetLastError();
1071  }
1072  } else if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) {
1073  /* Cancel line-buffered read if not already pending */
1075  if (err)
1076  return err;
1077 
1079  }
1080 
1081  return 0;
1082 }
1083 
1085  HANDLE active_screen_buffer = INVALID_HANDLE_VALUE;
1086  INPUT_RECORD record;
1087  DWORD written;
1088  DWORD err = 0;
1089  LONG status;
1090 
1092 
1093  /* Hold the output lock during the cancellation, to ensure that further
1094  writes don't interfere with the screen state. It will be the ReadConsole
1095  thread's responsibility to release the lock. */
1098  if (status != IN_PROGRESS) {
1099  /* Either we have managed to set a trap for the other thread before
1100  ReadConsole is called, or ReadConsole has returned because the user
1101  has pressed ENTER. In either case, there is nothing else to do. */
1103  return 0;
1104  }
1105 
1106  /* Save screen state before sending the VK_RETURN event */
1107  active_screen_buffer = CreateFileA("conout$",
1108  GENERIC_READ | GENERIC_WRITE,
1109  FILE_SHARE_READ | FILE_SHARE_WRITE,
1110  NULL,
1111  OPEN_EXISTING,
1112  FILE_ATTRIBUTE_NORMAL,
1113  NULL);
1114 
1115  if (active_screen_buffer != INVALID_HANDLE_VALUE &&
1116  GetConsoleScreenBufferInfo(active_screen_buffer,
1119  }
1120 
1121  /* Write enter key event to force the console wait to return. */
1122  record.EventType = KEY_EVENT;
1123  record.Event.KeyEvent.bKeyDown = TRUE;
1124  record.Event.KeyEvent.wRepeatCount = 1;
1125  record.Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
1126  record.Event.KeyEvent.wVirtualScanCode =
1127  MapVirtualKeyW(VK_RETURN, MAPVK_VK_TO_VSC);
1128  record.Event.KeyEvent.uChar.UnicodeChar = L'\r';
1129  record.Event.KeyEvent.dwControlKeyState = 0;
1130  if (!WriteConsoleInputW(handle->handle, &record, 1, &written))
1131  err = GetLastError();
1132 
1133  if (active_screen_buffer != INVALID_HANDLE_VALUE)
1134  CloseHandle(active_screen_buffer);
1135 
1136  return err;
1137 }
1138 
1139 
1140 static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) {
1141  uv_tty_virtual_width = info->dwSize.X;
1142  uv_tty_virtual_height = info->srWindow.Bottom - info->srWindow.Top + 1;
1143 
1144  /* Recompute virtual window offset row. */
1145  if (uv_tty_virtual_offset == -1) {
1146  uv_tty_virtual_offset = info->dwCursorPosition.Y;
1147  } else if (uv_tty_virtual_offset < info->dwCursorPosition.Y -
1148  uv_tty_virtual_height + 1) {
1149  /* If suddenly find the cursor outside of the virtual window, it must have
1150  * somehow scrolled. Update the virtual window offset. */
1151  uv_tty_virtual_offset = info->dwCursorPosition.Y -
1153  }
1154  if (uv_tty_virtual_offset + uv_tty_virtual_height > info->dwSize.Y) {
1156  }
1157  if (uv_tty_virtual_offset < 0) {
1159  }
1160 }
1161 
1162 
1164  CONSOLE_SCREEN_BUFFER_INFO* info, int x, unsigned char x_relative, int y,
1165  unsigned char y_relative) {
1166  COORD result;
1167 
1169 
1170  /* Adjust y position */
1171  if (y_relative) {
1172  y = info->dwCursorPosition.Y + y;
1173  } else {
1174  y = uv_tty_virtual_offset + y;
1175  }
1176  /* Clip y to virtual client rectangle */
1177  if (y < uv_tty_virtual_offset) {
1179  } else if (y >= uv_tty_virtual_offset + uv_tty_virtual_height) {
1181  }
1182 
1183  /* Adjust x */
1184  if (x_relative) {
1185  x = info->dwCursorPosition.X + x;
1186  }
1187  /* Clip x */
1188  if (x < 0) {
1189  x = 0;
1190  } else if (x >= uv_tty_virtual_width) {
1191  x = uv_tty_virtual_width - 1;
1192  }
1193 
1194  result.X = (unsigned short) x;
1195  result.Y = (unsigned short) y;
1196  return result;
1197 }
1198 
1199 
1201  DWORD* error) {
1202  DWORD written;
1203 
1204  if (*error != ERROR_SUCCESS) {
1205  return -1;
1206  }
1207 
1208  if (!WriteConsoleW(handle->handle,
1209  (void*) buffer,
1210  length,
1211  &written,
1212  NULL)) {
1213  *error = GetLastError();
1214  return -1;
1215  }
1216 
1217  return 0;
1218 }
1219 
1220 
1221 static int uv_tty_move_caret(uv_tty_t* handle, int x, unsigned char x_relative,
1222  int y, unsigned char y_relative, DWORD* error) {
1223  CONSOLE_SCREEN_BUFFER_INFO info;
1224  COORD pos;
1225 
1226  if (*error != ERROR_SUCCESS) {
1227  return -1;
1228  }
1229 
1230  retry:
1231  if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
1232  *error = GetLastError();
1233  }
1234 
1235  pos = uv_tty_make_real_coord(handle, &info, x, x_relative, y, y_relative);
1236 
1237  if (!SetConsoleCursorPosition(handle->handle, pos)) {
1238  if (GetLastError() == ERROR_INVALID_PARAMETER) {
1239  /* The console may be resized - retry */
1240  goto retry;
1241  } else {
1242  *error = GetLastError();
1243  return -1;
1244  }
1245  }
1246 
1247  return 0;
1248 }
1249 
1250 
1252  const COORD origin = {0, 0};
1253  const WORD char_attrs = uv_tty_default_text_attributes;
1254  CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
1255  DWORD count, written;
1256 
1257  if (*error != ERROR_SUCCESS) {
1258  return -1;
1259  }
1260 
1261  /* Reset original text attributes. */
1262  if (!SetConsoleTextAttribute(handle->handle, char_attrs)) {
1263  *error = GetLastError();
1264  return -1;
1265  }
1266 
1267  /* Move the cursor position to (0, 0). */
1268  if (!SetConsoleCursorPosition(handle->handle, origin)) {
1269  *error = GetLastError();
1270  return -1;
1271  }
1272 
1273  /* Clear the screen buffer. */
1274  retry:
1275  if (!GetConsoleScreenBufferInfo(handle->handle, &screen_buffer_info)) {
1276  *error = GetLastError();
1277  return -1;
1278  }
1279 
1280  count = screen_buffer_info.dwSize.X * screen_buffer_info.dwSize.Y;
1281 
1282  if (!(FillConsoleOutputCharacterW(handle->handle,
1283  L'\x20',
1284  count,
1285  origin,
1286  &written) &&
1287  FillConsoleOutputAttribute(handle->handle,
1288  char_attrs,
1289  written,
1290  origin,
1291  &written))) {
1292  if (GetLastError() == ERROR_INVALID_PARAMETER) {
1293  /* The console may be resized - retry */
1294  goto retry;
1295  } else {
1296  *error = GetLastError();
1297  return -1;
1298  }
1299  }
1300 
1301  /* Move the virtual window up to the top. */
1303  uv_tty_update_virtual_window(&screen_buffer_info);
1304 
1305  /* Reset the cursor size and the cursor state. */
1306  if (!SetConsoleCursorInfo(handle->handle, &uv_tty_default_cursor_info)) {
1307  *error = GetLastError();
1308  return -1;
1309  }
1310 
1311  return 0;
1312 }
1313 
1314 
1315 static int uv_tty_clear(uv_tty_t* handle, int dir, char entire_screen,
1316  DWORD* error) {
1317  CONSOLE_SCREEN_BUFFER_INFO info;
1318  COORD start, end;
1319  DWORD count, written;
1320 
1321  int x1, x2, y1, y2;
1322  int x1r, x2r, y1r, y2r;
1323 
1324  if (*error != ERROR_SUCCESS) {
1325  return -1;
1326  }
1327 
1328  if (dir == 0) {
1329  /* Clear from current position */
1330  x1 = 0;
1331  x1r = 1;
1332  } else {
1333  /* Clear from column 0 */
1334  x1 = 0;
1335  x1r = 0;
1336  }
1337 
1338  if (dir == 1) {
1339  /* Clear to current position */
1340  x2 = 0;
1341  x2r = 1;
1342  } else {
1343  /* Clear to end of row. We pretend the console is 65536 characters wide,
1344  * uv_tty_make_real_coord will clip it to the actual console width. */
1345  x2 = 0xffff;
1346  x2r = 0;
1347  }
1348 
1349  if (!entire_screen) {
1350  /* Stay on our own row */
1351  y1 = y2 = 0;
1352  y1r = y2r = 1;
1353  } else {
1354  /* Apply columns direction to row */
1355  y1 = x1;
1356  y1r = x1r;
1357  y2 = x2;
1358  y2r = x2r;
1359  }
1360 
1361  retry:
1362  if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
1363  *error = GetLastError();
1364  return -1;
1365  }
1366 
1367  start = uv_tty_make_real_coord(handle, &info, x1, x1r, y1, y1r);
1368  end = uv_tty_make_real_coord(handle, &info, x2, x2r, y2, y2r);
1369  count = (end.Y * info.dwSize.X + end.X) -
1370  (start.Y * info.dwSize.X + start.X) + 1;
1371 
1372  if (!(FillConsoleOutputCharacterW(handle->handle,
1373  L'\x20',
1374  count,
1375  start,
1376  &written) &&
1377  FillConsoleOutputAttribute(handle->handle,
1378  info.wAttributes,
1379  written,
1380  start,
1381  &written))) {
1382  if (GetLastError() == ERROR_INVALID_PARAMETER) {
1383  /* The console may be resized - retry */
1384  goto retry;
1385  } else {
1386  *error = GetLastError();
1387  return -1;
1388  }
1389  }
1390 
1391  return 0;
1392 }
1393 
1394 #define FLIP_FGBG \
1395  do { \
1396  WORD fg = info.wAttributes & 0xF; \
1397  WORD bg = info.wAttributes & 0xF0; \
1398  info.wAttributes &= 0xFF00; \
1399  info.wAttributes |= fg << 4; \
1400  info.wAttributes |= bg >> 4; \
1401  } while (0)
1402 
1404  unsigned short argc = handle->tty.wr.ansi_csi_argc;
1405  unsigned short* argv = handle->tty.wr.ansi_csi_argv;
1406  int i;
1407  CONSOLE_SCREEN_BUFFER_INFO info;
1408 
1409  char fg_color = -1, bg_color = -1;
1410  char fg_bright = -1, bg_bright = -1;
1411  char inverse = -1;
1412 
1413  if (argc == 0) {
1414  /* Reset mode */
1415  fg_color = uv_tty_default_fg_color;
1416  bg_color = uv_tty_default_bg_color;
1417  fg_bright = uv_tty_default_fg_bright;
1418  bg_bright = uv_tty_default_bg_bright;
1419  inverse = uv_tty_default_inverse;
1420  }
1421 
1422  for (i = 0; i < argc; i++) {
1423  short arg = argv[i];
1424 
1425  if (arg == 0) {
1426  /* Reset mode */
1427  fg_color = uv_tty_default_fg_color;
1428  bg_color = uv_tty_default_bg_color;
1429  fg_bright = uv_tty_default_fg_bright;
1430  bg_bright = uv_tty_default_bg_bright;
1431  inverse = uv_tty_default_inverse;
1432 
1433  } else if (arg == 1) {
1434  /* Foreground bright on */
1435  fg_bright = 1;
1436 
1437  } else if (arg == 2) {
1438  /* Both bright off */
1439  fg_bright = 0;
1440  bg_bright = 0;
1441 
1442  } else if (arg == 5) {
1443  /* Background bright on */
1444  bg_bright = 1;
1445 
1446  } else if (arg == 7) {
1447  /* Inverse: on */
1448  inverse = 1;
1449 
1450  } else if (arg == 21 || arg == 22) {
1451  /* Foreground bright off */
1452  fg_bright = 0;
1453 
1454  } else if (arg == 25) {
1455  /* Background bright off */
1456  bg_bright = 0;
1457 
1458  } else if (arg == 27) {
1459  /* Inverse: off */
1460  inverse = 0;
1461 
1462  } else if (arg >= 30 && arg <= 37) {
1463  /* Set foreground color */
1464  fg_color = arg - 30;
1465 
1466  } else if (arg == 39) {
1467  /* Default text color */
1468  fg_color = uv_tty_default_fg_color;
1469  fg_bright = uv_tty_default_fg_bright;
1470 
1471  } else if (arg >= 40 && arg <= 47) {
1472  /* Set background color */
1473  bg_color = arg - 40;
1474 
1475  } else if (arg == 49) {
1476  /* Default background color */
1477  bg_color = uv_tty_default_bg_color;
1478  bg_bright = uv_tty_default_bg_bright;
1479 
1480  } else if (arg >= 90 && arg <= 97) {
1481  /* Set bold foreground color */
1482  fg_bright = 1;
1483  fg_color = arg - 90;
1484 
1485  } else if (arg >= 100 && arg <= 107) {
1486  /* Set bold background color */
1487  bg_bright = 1;
1488  bg_color = arg - 100;
1489 
1490  }
1491  }
1492 
1493  if (fg_color == -1 && bg_color == -1 && fg_bright == -1 &&
1494  bg_bright == -1 && inverse == -1) {
1495  /* Nothing changed */
1496  return 0;
1497  }
1498 
1499  if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
1500  *error = GetLastError();
1501  return -1;
1502  }
1503 
1504  if ((info.wAttributes & COMMON_LVB_REVERSE_VIDEO) > 0) {
1505  FLIP_FGBG;
1506  }
1507 
1508  if (fg_color != -1) {
1509  info.wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
1510  if (fg_color & 1) info.wAttributes |= FOREGROUND_RED;
1511  if (fg_color & 2) info.wAttributes |= FOREGROUND_GREEN;
1512  if (fg_color & 4) info.wAttributes |= FOREGROUND_BLUE;
1513  }
1514 
1515  if (fg_bright != -1) {
1516  if (fg_bright) {
1517  info.wAttributes |= FOREGROUND_INTENSITY;
1518  } else {
1519  info.wAttributes &= ~FOREGROUND_INTENSITY;
1520  }
1521  }
1522 
1523  if (bg_color != -1) {
1524  info.wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
1525  if (bg_color & 1) info.wAttributes |= BACKGROUND_RED;
1526  if (bg_color & 2) info.wAttributes |= BACKGROUND_GREEN;
1527  if (bg_color & 4) info.wAttributes |= BACKGROUND_BLUE;
1528  }
1529 
1530  if (bg_bright != -1) {
1531  if (bg_bright) {
1532  info.wAttributes |= BACKGROUND_INTENSITY;
1533  } else {
1534  info.wAttributes &= ~BACKGROUND_INTENSITY;
1535  }
1536  }
1537 
1538  if (inverse != -1) {
1539  if (inverse) {
1540  info.wAttributes |= COMMON_LVB_REVERSE_VIDEO;
1541  } else {
1542  info.wAttributes &= ~COMMON_LVB_REVERSE_VIDEO;
1543  }
1544  }
1545 
1546  if ((info.wAttributes & COMMON_LVB_REVERSE_VIDEO) > 0) {
1547  FLIP_FGBG;
1548  }
1549 
1550  if (!SetConsoleTextAttribute(handle->handle, info.wAttributes)) {
1551  *error = GetLastError();
1552  return -1;
1553  }
1554 
1555  return 0;
1556 }
1557 
1558 
1559 static int uv_tty_save_state(uv_tty_t* handle, unsigned char save_attributes,
1560  DWORD* error) {
1561  CONSOLE_SCREEN_BUFFER_INFO info;
1562 
1563  if (*error != ERROR_SUCCESS) {
1564  return -1;
1565  }
1566 
1567  if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
1568  *error = GetLastError();
1569  return -1;
1570  }
1571 
1573 
1574  handle->tty.wr.saved_position.X = info.dwCursorPosition.X;
1575  handle->tty.wr.saved_position.Y = info.dwCursorPosition.Y - uv_tty_virtual_offset;
1577 
1578  if (save_attributes) {
1579  handle->tty.wr.saved_attributes = info.wAttributes &
1580  (FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
1582  }
1583 
1584  return 0;
1585 }
1586 
1587 
1589  unsigned char restore_attributes, DWORD* error) {
1590  CONSOLE_SCREEN_BUFFER_INFO info;
1591  WORD new_attributes;
1592 
1593  if (*error != ERROR_SUCCESS) {
1594  return -1;
1595  }
1596 
1597  if (handle->flags & UV_HANDLE_TTY_SAVED_POSITION) {
1599  handle->tty.wr.saved_position.X,
1600  0,
1601  handle->tty.wr.saved_position.Y,
1602  0,
1603  error) != 0) {
1604  return -1;
1605  }
1606  }
1607 
1608  if (restore_attributes &&
1610  if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
1611  *error = GetLastError();
1612  return -1;
1613  }
1614 
1615  new_attributes = info.wAttributes;
1616  new_attributes &= ~(FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
1617  new_attributes |= handle->tty.wr.saved_attributes;
1618 
1619  if (!SetConsoleTextAttribute(handle->handle, new_attributes)) {
1620  *error = GetLastError();
1621  return -1;
1622  }
1623  }
1624 
1625  return 0;
1626 }
1627 
1629  BOOL visible,
1630  DWORD* error) {
1631  CONSOLE_CURSOR_INFO cursor_info;
1632 
1633  if (!GetConsoleCursorInfo(handle->handle, &cursor_info)) {
1634  *error = GetLastError();
1635  return -1;
1636  }
1637 
1638  cursor_info.bVisible = visible;
1639 
1640  if (!SetConsoleCursorInfo(handle->handle, &cursor_info)) {
1641  *error = GetLastError();
1642  return -1;
1643  }
1644 
1645  return 0;
1646 }
1647 
1649  CONSOLE_CURSOR_INFO cursor_info;
1650 
1651  if (!GetConsoleCursorInfo(handle->handle, &cursor_info)) {
1652  *error = GetLastError();
1653  return -1;
1654  }
1655 
1656  if (style == 0) {
1657  cursor_info.dwSize = uv_tty_default_cursor_info.dwSize;
1658  } else if (style <= 2) {
1659  cursor_info.dwSize = CURSOR_SIZE_LARGE;
1660  } else {
1661  cursor_info.dwSize = CURSOR_SIZE_SMALL;
1662  }
1663 
1664  if (!SetConsoleCursorInfo(handle->handle, &cursor_info)) {
1665  *error = GetLastError();
1666  return -1;
1667  }
1668 
1669  return 0;
1670 }
1671 
1672 
1674  const uv_buf_t bufs[],
1675  unsigned int nbufs,
1676  DWORD* error) {
1677  /* We can only write 8k characters at a time. Windows can't handle much more
1678  * characters in a single console write anyway. */
1679  WCHAR utf16_buf[MAX_CONSOLE_CHAR];
1680  DWORD utf16_buf_used = 0;
1681  unsigned int i;
1682 
1683 #define FLUSH_TEXT() \
1684  do { \
1685  if (utf16_buf_used > 0) { \
1686  uv_tty_emit_text(handle, utf16_buf, utf16_buf_used, error); \
1687  utf16_buf_used = 0; \
1688  } \
1689  } while (0)
1690 
1691 #define ENSURE_BUFFER_SPACE(wchars_needed) \
1692  if (wchars_needed > ARRAY_SIZE(utf16_buf) - utf16_buf_used) { \
1693  FLUSH_TEXT(); \
1694  }
1695 
1696  /* Cache for fast access */
1697  unsigned char utf8_bytes_left = handle->tty.wr.utf8_bytes_left;
1698  unsigned int utf8_codepoint = handle->tty.wr.utf8_codepoint;
1699  unsigned char previous_eol = handle->tty.wr.previous_eol;
1700  unsigned short ansi_parser_state = handle->tty.wr.ansi_parser_state;
1701 
1702  /* Store the error here. If we encounter an error, stop trying to do i/o but
1703  * keep parsing the buffer so we leave the parser in a consistent state. */
1704  *error = ERROR_SUCCESS;
1705 
1707 
1708  for (i = 0; i < nbufs; i++) {
1709  uv_buf_t buf = bufs[i];
1710  unsigned int j;
1711 
1712  for (j = 0; j < buf.len; j++) {
1713  unsigned char c = buf.base[j];
1714 
1715  /* Run the character through the utf8 decoder We happily accept non
1716  * shortest form encodings and invalid code points - there's no real harm
1717  * that can be done. */
1718  if (utf8_bytes_left == 0) {
1719  /* Read utf-8 start byte */
1720  DWORD first_zero_bit;
1721  unsigned char not_c = ~c;
1722 #ifdef _MSC_VER /* msvc */
1723  if (_BitScanReverse(&first_zero_bit, not_c)) {
1724 #else /* assume gcc */
1725  if (c != 0) {
1726  first_zero_bit = (sizeof(int) * 8) - 1 - __builtin_clz(not_c);
1727 #endif
1728  if (first_zero_bit == 7) {
1729  /* Ascii - pass right through */
1730  utf8_codepoint = (unsigned int) c;
1731 
1732  } else if (first_zero_bit <= 5) {
1733  /* Multibyte sequence */
1734  utf8_codepoint = (0xff >> (8 - first_zero_bit)) & c;
1735  utf8_bytes_left = (char) (6 - first_zero_bit);
1736 
1737  } else {
1738  /* Invalid continuation */
1739  utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
1740  }
1741 
1742  } else {
1743  /* 0xff -- invalid */
1744  utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
1745  }
1746 
1747  } else if ((c & 0xc0) == 0x80) {
1748  /* Valid continuation of utf-8 multibyte sequence */
1749  utf8_bytes_left--;
1750  utf8_codepoint <<= 6;
1751  utf8_codepoint |= ((unsigned int) c & 0x3f);
1752 
1753  } else {
1754  /* Start byte where continuation was expected. */
1755  utf8_bytes_left = 0;
1756  utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
1757  /* Patch buf offset so this character will be parsed again as a start
1758  * byte. */
1759  j--;
1760  }
1761 
1762  /* Maybe we need to parse more bytes to find a character. */
1763  if (utf8_bytes_left != 0) {
1764  continue;
1765  }
1766 
1767  /* Parse vt100/ansi escape codes */
1769  /* Pass through escape codes if conhost supports them. */
1770  } else if (ansi_parser_state == ANSI_NORMAL) {
1771  switch (utf8_codepoint) {
1772  case '\033':
1773  ansi_parser_state = ANSI_ESCAPE_SEEN;
1774  continue;
1775 
1776  case 0233:
1777  ansi_parser_state = ANSI_CSI;
1778  handle->tty.wr.ansi_csi_argc = 0;
1779  continue;
1780  }
1781 
1782  } else if (ansi_parser_state == ANSI_ESCAPE_SEEN) {
1783  switch (utf8_codepoint) {
1784  case '[':
1785  ansi_parser_state = ANSI_CSI;
1786  handle->tty.wr.ansi_csi_argc = 0;
1787  continue;
1788 
1789  case '^':
1790  case '_':
1791  case 'P':
1792  case ']':
1793  /* Not supported, but we'll have to parse until we see a stop code,
1794  * e. g. ESC \ or BEL. */
1795  ansi_parser_state = ANSI_ST_CONTROL;
1796  continue;
1797 
1798  case '\033':
1799  /* Ignore double escape. */
1800  continue;
1801 
1802  case 'c':
1803  /* Full console reset. */
1804  FLUSH_TEXT();
1806  ansi_parser_state = ANSI_NORMAL;
1807  continue;
1808 
1809  case '7':
1810  /* Save the cursor position and text attributes. */
1811  FLUSH_TEXT();
1813  ansi_parser_state = ANSI_NORMAL;
1814  continue;
1815 
1816  case '8':
1817  /* Restore the cursor position and text attributes */
1818  FLUSH_TEXT();
1820  ansi_parser_state = ANSI_NORMAL;
1821  continue;
1822 
1823  default:
1824  if (utf8_codepoint >= '@' && utf8_codepoint <= '_') {
1825  /* Single-char control. */
1826  ansi_parser_state = ANSI_NORMAL;
1827  continue;
1828  } else {
1829  /* Invalid - proceed as normal, */
1830  ansi_parser_state = ANSI_NORMAL;
1831  }
1832  }
1833 
1834  } else if (ansi_parser_state == ANSI_IGNORE) {
1835  /* We're ignoring this command. Stop only on command character. */
1836  if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
1837  ansi_parser_state = ANSI_NORMAL;
1838  }
1839  continue;
1840 
1841  } else if (ansi_parser_state == ANSI_DECSCUSR) {
1842  /* So far we've the sequence `ESC [ arg space`, and we're waiting for
1843  * the final command byte. */
1844  if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
1845  /* Command byte */
1846  if (utf8_codepoint == 'q') {
1847  /* Change the cursor shape */
1848  int style = handle->tty.wr.ansi_csi_argc
1849  ? handle->tty.wr.ansi_csi_argv[0] : 1;
1850  if (style >= 0 && style <= 6) {
1851  FLUSH_TEXT();
1853  }
1854  }
1855 
1856  /* Sequence ended - go back to normal state. */
1857  ansi_parser_state = ANSI_NORMAL;
1858  continue;
1859  }
1860  /* Unexpected character, but sequence hasn't ended yet. Ignore the rest
1861  * of the sequence. */
1862  ansi_parser_state = ANSI_IGNORE;
1863 
1864  } else if (ansi_parser_state & ANSI_CSI) {
1865  /* So far we've seen `ESC [`, and we may or may not have already parsed
1866  * some of the arguments that follow. */
1867 
1868  if (utf8_codepoint >= '0' && utf8_codepoint <= '9') {
1869  /* Parse a numerical argument. */
1870  if (!(ansi_parser_state & ANSI_IN_ARG)) {
1871  /* We were not currently parsing a number, add a new one. */
1872  /* Check for that there are too many arguments. */
1873  if (handle->tty.wr.ansi_csi_argc >=
1874  ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
1875  ansi_parser_state = ANSI_IGNORE;
1876  continue;
1877  }
1878  ansi_parser_state |= ANSI_IN_ARG;
1879  handle->tty.wr.ansi_csi_argc++;
1880  handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
1881  (unsigned short) utf8_codepoint - '0';
1882  continue;
1883 
1884  } else {
1885  /* We were already parsing a number. Parse next digit. */
1886  uint32_t value = 10 *
1887  handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1];
1888 
1889  /* Check for overflow. */
1890  if (value > UINT16_MAX) {
1891  ansi_parser_state = ANSI_IGNORE;
1892  continue;
1893  }
1894 
1895  handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
1896  (unsigned short) value + (utf8_codepoint - '0');
1897  continue;
1898  }
1899 
1900  } else if (utf8_codepoint == ';') {
1901  /* Denotes the end of an argument. */
1902  if (ansi_parser_state & ANSI_IN_ARG) {
1903  ansi_parser_state &= ~ANSI_IN_ARG;
1904  continue;
1905 
1906  } else {
1907  /* If ANSI_IN_ARG is not set, add another argument and default
1908  * it to 0. */
1909 
1910  /* Check for too many arguments */
1911  if (handle->tty.wr.ansi_csi_argc >=
1912 
1913  ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
1914  ansi_parser_state = ANSI_IGNORE;
1915  continue;
1916  }
1917 
1918  handle->tty.wr.ansi_csi_argc++;
1919  handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] = 0;
1920  continue;
1921  }
1922 
1923  } else if (utf8_codepoint == '?' &&
1924  !(ansi_parser_state & ANSI_IN_ARG) &&
1925  !(ansi_parser_state & ANSI_EXTENSION) &&
1926  handle->tty.wr.ansi_csi_argc == 0) {
1927  /* Pass through '?' if it is the first character after CSI */
1928  /* This is an extension character from the VT100 codeset */
1929  /* that is supported and used by most ANSI terminals today. */
1930  ansi_parser_state |= ANSI_EXTENSION;
1931  continue;
1932 
1933  } else if (utf8_codepoint == ' ' &&
1934  !(ansi_parser_state & ANSI_EXTENSION)) {
1935  /* We expect a command byte to follow after this space. The only
1936  * command that we current support is 'set cursor style'. */
1937  ansi_parser_state = ANSI_DECSCUSR;
1938  continue;
1939 
1940  } else if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
1941  /* Command byte */
1942  if (ansi_parser_state & ANSI_EXTENSION) {
1943  /* Sequence is `ESC [ ? args command`. */
1944  switch (utf8_codepoint) {
1945  case 'l':
1946  /* Hide the cursor */
1947  if (handle->tty.wr.ansi_csi_argc == 1 &&
1948  handle->tty.wr.ansi_csi_argv[0] == 25) {
1949  FLUSH_TEXT();
1951  }
1952  break;
1953 
1954  case 'h':
1955  /* Show the cursor */
1956  if (handle->tty.wr.ansi_csi_argc == 1 &&
1957  handle->tty.wr.ansi_csi_argv[0] == 25) {
1958  FLUSH_TEXT();
1960  }
1961  break;
1962  }
1963 
1964  } else {
1965  /* Sequence is `ESC [ args command`. */
1966  int x, y, d;
1967  switch (utf8_codepoint) {
1968  case 'A':
1969  /* cursor up */
1970  FLUSH_TEXT();
1971  y = -(handle->tty.wr.ansi_csi_argc
1972  ? handle->tty.wr.ansi_csi_argv[0] : 1);
1973  uv_tty_move_caret(handle, 0, 1, y, 1, error);
1974  break;
1975 
1976  case 'B':
1977  /* cursor down */
1978  FLUSH_TEXT();
1979  y = handle->tty.wr.ansi_csi_argc
1980  ? handle->tty.wr.ansi_csi_argv[0] : 1;
1981  uv_tty_move_caret(handle, 0, 1, y, 1, error);
1982  break;
1983 
1984  case 'C':
1985  /* cursor forward */
1986  FLUSH_TEXT();
1987  x = handle->tty.wr.ansi_csi_argc
1988  ? handle->tty.wr.ansi_csi_argv[0] : 1;
1989  uv_tty_move_caret(handle, x, 1, 0, 1, error);
1990  break;
1991 
1992  case 'D':
1993  /* cursor back */
1994  FLUSH_TEXT();
1995  x = -(handle->tty.wr.ansi_csi_argc
1996  ? handle->tty.wr.ansi_csi_argv[0] : 1);
1997  uv_tty_move_caret(handle, x, 1, 0, 1, error);
1998  break;
1999 
2000  case 'E':
2001  /* cursor next line */
2002  FLUSH_TEXT();
2003  y = handle->tty.wr.ansi_csi_argc
2004  ? handle->tty.wr.ansi_csi_argv[0] : 1;
2005  uv_tty_move_caret(handle, 0, 0, y, 1, error);
2006  break;
2007 
2008  case 'F':
2009  /* cursor previous line */
2010  FLUSH_TEXT();
2011  y = -(handle->tty.wr.ansi_csi_argc
2012  ? handle->tty.wr.ansi_csi_argv[0] : 1);
2013  uv_tty_move_caret(handle, 0, 0, y, 1, error);
2014  break;
2015 
2016  case 'G':
2017  /* cursor horizontal move absolute */
2018  FLUSH_TEXT();
2019  x = (handle->tty.wr.ansi_csi_argc >= 1 &&
2020  handle->tty.wr.ansi_csi_argv[0])
2021  ? handle->tty.wr.ansi_csi_argv[0] - 1 : 0;
2022  uv_tty_move_caret(handle, x, 0, 0, 1, error);
2023  break;
2024 
2025  case 'H':
2026  case 'f':
2027  /* cursor move absolute */
2028  FLUSH_TEXT();
2029  y = (handle->tty.wr.ansi_csi_argc >= 1 &&
2030  handle->tty.wr.ansi_csi_argv[0])
2031  ? handle->tty.wr.ansi_csi_argv[0] - 1 : 0;
2032  x = (handle->tty.wr.ansi_csi_argc >= 2 &&
2033  handle->tty.wr.ansi_csi_argv[1])
2034  ? handle->tty.wr.ansi_csi_argv[1] - 1 : 0;
2035  uv_tty_move_caret(handle, x, 0, y, 0, error);
2036  break;
2037 
2038  case 'J':
2039  /* Erase screen */
2040  FLUSH_TEXT();
2041  d = handle->tty.wr.ansi_csi_argc
2042  ? handle->tty.wr.ansi_csi_argv[0] : 0;
2043  if (d >= 0 && d <= 2) {
2044  uv_tty_clear(handle, d, 1, error);
2045  }
2046  break;
2047 
2048  case 'K':
2049  /* Erase line */
2050  FLUSH_TEXT();
2051  d = handle->tty.wr.ansi_csi_argc
2052  ? handle->tty.wr.ansi_csi_argv[0] : 0;
2053  if (d >= 0 && d <= 2) {
2054  uv_tty_clear(handle, d, 0, error);
2055  }
2056  break;
2057 
2058  case 'm':
2059  /* Set style */
2060  FLUSH_TEXT();
2062  break;
2063 
2064  case 's':
2065  /* Save the cursor position. */
2066  FLUSH_TEXT();
2068  break;
2069 
2070  case 'u':
2071  /* Restore the cursor position */
2072  FLUSH_TEXT();
2074  break;
2075  }
2076  }
2077 
2078  /* Sequence ended - go back to normal state. */
2079  ansi_parser_state = ANSI_NORMAL;
2080  continue;
2081 
2082  } else {
2083  /* We don't support commands that use private mode characters or
2084  * intermediaries. Ignore the rest of the sequence. */
2085  ansi_parser_state = ANSI_IGNORE;
2086  continue;
2087  }
2088 
2089  } else if (ansi_parser_state & ANSI_ST_CONTROL) {
2090  /* Unsupported control code.
2091  * Ignore everything until we see `BEL` or `ESC \`. */
2092  if (ansi_parser_state & ANSI_IN_STRING) {
2093  if (!(ansi_parser_state & ANSI_BACKSLASH_SEEN)) {
2094  if (utf8_codepoint == '"') {
2095  ansi_parser_state &= ~ANSI_IN_STRING;
2096  } else if (utf8_codepoint == '\\') {
2097  ansi_parser_state |= ANSI_BACKSLASH_SEEN;
2098  }
2099  } else {
2100  ansi_parser_state &= ~ANSI_BACKSLASH_SEEN;
2101  }
2102  } else {
2103  if (utf8_codepoint == '\007' || (utf8_codepoint == '\\' &&
2104  (ansi_parser_state & ANSI_ESCAPE_SEEN))) {
2105  /* End of sequence */
2106  ansi_parser_state = ANSI_NORMAL;
2107  } else if (utf8_codepoint == '\033') {
2108  /* Escape character */
2109  ansi_parser_state |= ANSI_ESCAPE_SEEN;
2110  } else if (utf8_codepoint == '"') {
2111  /* String starting */
2112  ansi_parser_state |= ANSI_IN_STRING;
2113  ansi_parser_state &= ~ANSI_ESCAPE_SEEN;
2114  ansi_parser_state &= ~ANSI_BACKSLASH_SEEN;
2115  } else {
2116  ansi_parser_state &= ~ANSI_ESCAPE_SEEN;
2117  }
2118  }
2119  continue;
2120  } else {
2121  /* Inconsistent state */
2122  abort();
2123  }
2124 
2125  if (utf8_codepoint == 0x0a || utf8_codepoint == 0x0d) {
2126  /* EOL conversion - emit \r\n when we see \n. */
2127 
2128  if (utf8_codepoint == 0x0a && previous_eol != 0x0d) {
2129  /* \n was not preceded by \r; print \r\n. */
2131  utf16_buf[utf16_buf_used++] = L'\r';
2132  utf16_buf[utf16_buf_used++] = L'\n';
2133  } else if (utf8_codepoint == 0x0d && previous_eol == 0x0a) {
2134  /* \n was followed by \r; do not print the \r, since the source was
2135  * either \r\n\r (so the second \r is redundant) or was \n\r (so the
2136  * \n was processed by the last case and an \r automatically
2137  * inserted). */
2138  } else {
2139  /* \r without \n; print \r as-is. */
2141  utf16_buf[utf16_buf_used++] = (WCHAR) utf8_codepoint;
2142  }
2143 
2144  previous_eol = (char) utf8_codepoint;
2145 
2146  } else if (utf8_codepoint <= 0xffff) {
2147  /* Encode character into utf-16 buffer. */
2149  utf16_buf[utf16_buf_used++] = (WCHAR) utf8_codepoint;
2150  previous_eol = 0;
2151  } else {
2153  utf8_codepoint -= 0x10000;
2154  utf16_buf[utf16_buf_used++] = (WCHAR) (utf8_codepoint / 0x400 + 0xD800);
2155  utf16_buf[utf16_buf_used++] = (WCHAR) (utf8_codepoint % 0x400 + 0xDC00);
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  */
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 
2350  NTSTATUS status;
2351  ULONG_PTR conhost_pid;
2352  MSG msg;
2353 
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);
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  return 0;
2416 }
2417 
2419  CONSOLE_SCREEN_BUFFER_INFO sb_info;
2420  int width, height;
2421 
2422  if (!GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info))
2423  return;
2424 
2425  width = sb_info.dwSize.X;
2426  height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1;
2427 
2435  } else {
2437  }
2438 }
2439 
2445 }
2446 
2451  return 0;
2452 }
size_t len
Definition: 6502dis.c:15
#define ARRAY_SIZE(a)
lzma_index ** i
Definition: index.h:629
static RZ_NULLABLE RzILOpBitVector * shift(RzILOpBitVector *val, RZ_NULLABLE RzILOpBool **carry_out, arm_shifter type, RZ_OWN RzILOpBitVector *dist)
Definition: arm_il32.c:190
static bool err
Definition: armass.c:435
static ut8 bytes[32]
Definition: asm_arc.c:23
static mcore_handle handle
Definition: asm_mcore.c:8
RzBinInfo * info(RzBinFile *bf)
Definition: bin_ne.c:86
const lzma_allocator const uint8_t size_t uint8_t * out
Definition: block.h:528
static int value
Definition: cmd_api.c:93
#define NULL
Definition: cris-opc.c:27
#define r
Definition: crypto_rc6.c:12
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void static offset struct stat static buf void long static basep static whence static length const void static len static semflg const void static shmflg const struct timespec req
Definition: sflib.h:128
static static fork const void static count close
Definition: sflib.h:33
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void count
Definition: sflib.h:98
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void static offset struct stat static buf void long static basep static whence static length const void static len static semflg const void static shmflg const struct timespec struct timespec static rem const char static group const void start
Definition: sflib.h:133
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void static offset struct stat static buf void long static basep static whence static length const void static len static semflg const void static shmflg const struct timespec struct timespec static rem const char static group const void length
Definition: sflib.h:133
#define DECREASE_ACTIVE_COUNT(loop, handle)
Definition: handle-inl.h:32
static INLINE void uv_want_endgame(uv_loop_t *loop, uv_handle_t *handle)
Definition: handle-inl.h:88
static INLINE HANDLE uv__get_osfhandle(int fd)
Definition: handle-inl.h:166
#define INCREASE_ACTIVE_COUNT(loop, handle)
Definition: handle-inl.h:42
#define uv__handle_close(handle)
Definition: handle-inl.h:76
#define DECREASE_PENDING_REQ_COUNT(handle)
Definition: handle-inl.h:51
#define uv__handle_closing(handle)
Definition: handle-inl.h:63
voidpf uLong int origin
Definition: ioapi.h:144
const char int mode
Definition: ioapi.h:137
voidpf void * buf
Definition: ioapi.h:138
#define INVALID_HANDLE_VALUE
Definition: iowin32.c:21
#define LONG
InterlockedExchange
Definition: kernel.h:57
return memset(p, 0, total)
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
static static fork const void static count static fd const char const char static newpath char char argv
Definition: sflib.h:40
static const char struct stat static buf struct stat static buf static vhangup int status
Definition: sflib.h:145
assert(limit<=UINT32_MAX/2)
int x
Definition: mipsasm.c:20
#define TRUE
Definition: mybfd.h:103
#define FALSE
Definition: mybfd.h:102
#define GET_REQ_ERROR(req)
Definition: req-inl.h:49
static INLINE void uv_insert_pending_req(uv_loop_t *loop, uv_req_t *req)
Definition: req-inl.h:90
#define REQ_SUCCESS(req)
Definition: req-inl.h:46
#define SET_REQ_SUCCESS(req)
Definition: req-inl.h:40
#define UNREGISTER_HANDLE_REQ(loop, handle, req)
Definition: req-inl.h:62
#define REGISTER_HANDLE_REQ(loop, handle, req)
Definition: req-inl.h:56
#define POST_COMPLETION_FOR_REQ(loop, req)
Definition: req-inl.h:76
#define SET_REQ_ERROR(req, error)
Definition: req-inl.h:34
#define MSG(...)
Definition: roundTripTest.c:50
static struct sockaddr static addrlen static backlog const void static flags void flags
Definition: sfsocketcall.h:123
static int
Definition: sfsocketcall.h:114
static struct sockaddr static addrlen static backlog const void msg
Definition: sfsocketcall.h:119
unsigned int uint32_t
Definition: sftypes.h:29
int off_t
Definition: sftypes.h:41
#define d(i)
Definition: sha256.c:44
#define c(i)
Definition: sha256.c:43
#define UINT16_MAX
static INLINE void uv_stream_init(uv_loop_t *loop, uv_stream_t *handle, uv_handle_type type)
Definition: stream-inl.h:33
static INLINE void uv_connection_init(uv_stream_t *handle)
Definition: stream-inl.h:49
Definition: buffer.h:15
Definition: inftree9.h:24
Definition: dis.h:43
Definition: unix.h:123
Definition: uv.h:1780
Definition: uv.h:407
Definition: uv.h:714
Definition: uv.h:525
uv_loop_t * loop
Definition: main.c:7
int pos
Definition: main.c:11
int width
Definition: main.c:10
int height
Definition: main.c:10
uv_tty_t tty
Definition: main.c:7
void uv__once_init(void)
Definition: core.c:329
int uv__signal_dispatch(int signum)
Definition: signal.c:80
static char bufs[4][128]
Buffers for uint64_to_str() and uint64_to_nicestr()
Definition: util.c:18
Definition: tar.h:52
void uv_tty_set_vterm_state(uv_tty_vtermstate_t state)
Definition: tty.c:397
int uv_tty_get_winsize(uv_tty_t *tty, int *width, int *height)
Definition: tty.c:297
int uv_tty_set_mode(uv_tty_t *tty, uv_tty_mode_t mode)
Definition: tty.c:250
int uv_tty_get_vterm_state(uv_tty_vtermstate_t *state)
Definition: tty.c:400
int uv_tty_init(uv_loop_t *loop, uv_tty_t *tty, int fd, int unused)
Definition: tty.c:123
int uv_tty_reset_mode(void)
Definition: tty.c:378
UV_PLATFORM_SEM_T uv_sem_t
Definition: unix.h:139
int uv_file
Definition: unix.h:128
pthread_mutex_t uv_mutex_t
Definition: unix.h:137
void error(const char *msg)
Definition: untgz.c:593
size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs)
Definition: uv-common.c:573
@ UV_HANDLE_TTY_SAVED_POSITION
Definition: uv-common.h:124
@ UV_HANDLE_TTY_SAVED_ATTRIBUTES
Definition: uv-common.h:125
@ UV_HANDLE_CANCELLATION_PENDING
Definition: uv-common.h:99
@ UV_HANDLE_READING
Definition: uv-common.h:90
@ UV_HANDLE_CLOSING
Definition: uv-common.h:74
@ UV_HANDLE_WRITABLE
Definition: uv-common.h:93
@ UV_HANDLE_CLOSED
Definition: uv-common.h:75
@ UV_HANDLE_TTY_RAW
Definition: uv-common.h:123
@ UV_HANDLE_READ_PENDING
Definition: uv-common.h:94
@ UV_HANDLE_BOUND
Definition: uv-common.h:91
@ UV_HANDLE_READABLE
Definition: uv-common.h:92
@ UV_HANDLE_TTY_READABLE
Definition: uv-common.h:122
#define UV_REQ_INIT(req, typ)
Definition: uv-common.h:322
UV_EXTERN void uv_mutex_lock(uv_mutex_t *handle)
Definition: thread.c:330
void(* uv_write_cb)(uv_write_t *req, int status)
Definition: uv.h:315
UV_EXTERN int uv_translate_sys_error(int sys_errno)
Definition: core.c:1249
uv_tty_mode_t
Definition: uv.h:720
@ UV_TTY_MODE_IO
Definition: uv.h:726
@ UV_TTY_MODE_NORMAL
Definition: uv.h:722
@ UV_TTY_MODE_RAW
Definition: uv.h:724
UV_EXTERN uv_buf_t uv_buf_init(char *base, unsigned int len)
Definition: uv-common.c:157
UV_EXTERN void uv_sem_post(uv_sem_t *sem)
Definition: thread.c:670
UV_EXTERN void uv_mutex_unlock(uv_mutex_t *handle)
Definition: thread.c:350
uv_tty_vtermstate_t
Definition: uv.h:729
@ UV_TTY_UNSUPPORTED
Definition: uv.h:738
@ UV_TTY_SUPPORTED
Definition: uv.h:734
void(* uv_read_cb)(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf)
Definition: uv.h:312
void(* uv_alloc_cb)(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf)
Definition: uv.h:309
UV_EXTERN void uv_sem_wait(uv_sem_t *sem)
Definition: thread.c:678
UV_EXTERN int uv_sem_init(uv_sem_t *sem, unsigned int value)
Definition: thread.c:650
UV_EXTERN int uv_mutex_init(uv_mutex_t *handle)
Definition: thread.c:282
static int uv_tty_clear(uv_tty_t *handle, int dir, char entire_screen, DWORD *error)
Definition: tty.c:1315
static uv_sem_t uv_tty_output_lock
Definition: tty.c:148
static int uv_tty_virtual_height
Definition: tty.c:119
static void uv_tty_queue_read_line(uv_loop_t *loop, uv_tty_t *handle)
Definition: tty.c:582
#define FLIP_FGBG
Definition: tty.c:1394
static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO *screen_buffer_info, CONSOLE_CURSOR_INFO *cursor_info)
Definition: tty.c:292
static char uv_tty_default_inverse
Definition: tty.c:157
#define MAX_INPUT_BUFFER_LENGTH
Definition: tty.c:60
#define CURSOR_SIZE_LARGE
Definition: tty.c:68
static int uv_tty_set_style(uv_tty_t *handle, DWORD *error)
Definition: tty.c:1403
static char uv_tty_default_bg_color
Definition: tty.c:154
static void uv_tty_queue_read(uv_loop_t *loop, uv_tty_t *handle)
Definition: tty.c:622
static int uv_tty_save_state(uv_tty_t *handle, unsigned char save_attributes, DWORD *error)
Definition: tty.c:1559
static DWORD CALLBACK uv_tty_line_read_thread(void *data)
Definition: tty.c:486
static int uv__tty_console_height
Definition: tty.c:128
#define InterlockedOr
Definition: tty.c:44
static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook, DWORD event, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime)
Definition: tty.c:2397
#define ANSI_IGNORE
Definition: tty.c:53
static char uv_tty_default_bg_bright
Definition: tty.c:156
static int uv_tty_write_bufs(uv_tty_t *handle, const uv_buf_t bufs[], unsigned int nbufs, DWORD *error)
Definition: tty.c:1673
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: tty.c:2182
#define ANSI_IN_STRING
Definition: tty.c:55
#define VK_CASE(vk, normal_str, shift_str, ctrl_str, shift_ctrl_str)
#define ANSI_ESCAPE_SEEN
Definition: tty.c:50
static char uv_tty_default_fg_color
Definition: tty.c:153
#define UNICODE_REPLACEMENT_CHARACTER
Definition: tty.c:47
static uv_tty_vtermstate_t uv__vterm_state
Definition: tty.c:163
static int uv_tty_virtual_width
Definition: tty.c:120
static const char * get_vt100_fn_key(DWORD code, char shift, char ctrl, size_t *len)
Definition: tty.c:631
#define ANSI_NORMAL
Definition: tty.c:49
int uv_tty_read_stop(uv_tty_t *handle)
Definition: tty.c:1054
static BOOL uv__need_check_vterm_state
Definition: tty.c:162
static HANDLE uv__tty_console_resized
Definition: tty.c:130
static int uv_tty_virtual_offset
Definition: tty.c:118
static void uv__determine_vterm_state(HANDLE handle)
Definition: tty.c:2333
static void uv_tty_queue_read_raw(uv_loop_t *loop, uv_tty_t *handle)
Definition: tty.c:455
#define ENSURE_BUFFER_SPACE(wchars_needed)
static int uv__tty_console_width
Definition: tty.c:129
static CONSOLE_CURSOR_INFO uv_tty_default_cursor_info
Definition: tty.c:159
void uv_tty_endgame(uv_loop_t *loop, uv_tty_t *handle)
Definition: tty.c:2270
static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO *info)
Definition: tty.c:1140
static uv_mutex_t uv__tty_console_resize_mutex
Definition: tty.c:131
static int uv__cancel_read_console(uv_tty_t *handle)
Definition: tty.c:1084
static DWORD WINAPI uv__tty_console_resize_message_loop_thread(void *param)
Definition: tty.c:2349
static int uv_tty_set_cursor_visibility(uv_tty_t *handle, BOOL visible, DWORD *error)
Definition: tty.c:1628
void uv_process_tty_write_req(uv_loop_t *loop, uv_tty_t *handle, uv_write_t *req)
Definition: tty.c:2227
static volatile LONG uv__restore_screen_state
Definition: tty.c:88
static void uv__tty_console_signal_resize(void)
Definition: tty.c:2418
#define KEV
void uv_process_tty_connect_req(uv_loop_t *loop, uv_tty_t *handle, uv_connect_t *req)
Definition: tty.c:2318
#define ANSI_EXTENSION
Definition: tty.c:57
#define ANSI_ST_CONTROL
Definition: tty.c:52
void uv_process_tty_accept_req(uv_loop_t *loop, uv_tty_t *handle, uv_req_t *raw_req)
Definition: tty.c:2308
#define FLUSH_TEXT()
int uv__tty_try_write(uv_tty_t *handle, const uv_buf_t bufs[], unsigned int nbufs)
Definition: tty.c:2212
static CONSOLE_SCREEN_BUFFER_INFO uv__saved_screen_state
Definition: tty.c:89
void uv_process_tty_read_line_req(uv_loop_t *loop, uv_tty_t *handle, uv_req_t *req)
Definition: tty.c:960
static HANDLE uv__tty_console_handle
Definition: tty.c:127
static int uv_tty_set_cursor_shape(uv_tty_t *handle, int style, DWORD *error)
Definition: tty.c:1648
static int uv_tty_reset(uv_tty_t *handle, DWORD *error)
Definition: tty.c:1251
static void CALLBACK uv_tty_post_raw_read(void *data, BOOLEAN didTimeout)
Definition: tty.c:435
void uv_tty_close(uv_tty_t *handle)
Definition: tty.c:2249
static char uv_tty_default_fg_bright
Definition: tty.c:155
#define MAX_CONSOLE_CHAR
Definition: tty.c:61
#define ANSI_DECSCUSR
Definition: tty.c:58
void uv_process_tty_read_raw_req(uv_loop_t *loop, uv_tty_t *handle, uv_req_t *req)
Definition: tty.c:697
int uv_tty_read_start(uv_tty_t *handle, uv_alloc_cb alloc_cb, uv_read_cb read_cb)
Definition: tty.c:1018
static int uv_tty_restore_state(uv_tty_t *handle, unsigned char restore_attributes, DWORD *error)
Definition: tty.c:1588
static int uv_tty_emit_text(uv_tty_t *handle, WCHAR buffer[], DWORD length, DWORD *error)
Definition: tty.c:1200
#define ANSI_BACKSLASH_SEEN
Definition: tty.c:56
static volatile LONG uv__read_console_status
Definition: tty.c:87
uv__read_console_status_e
Definition: tty.c:80
@ COMPLETED
Definition: tty.c:84
@ TRAP_REQUESTED
Definition: tty.c:83
@ IN_PROGRESS
Definition: tty.c:82
@ NOT_STARTED
Definition: tty.c:81
#define ANSI_IN_ARG
Definition: tty.c:54
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING
Definition: tty.c:64
#define ANSI_CSI
Definition: tty.c:51
static WORD uv_tty_default_text_attributes
Definition: tty.c:150
#define COMMON_LVB_REVERSE_VIDEO
Definition: tty.c:34
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: tty.c:1221
void uv_console_init(void)
Definition: tty.c:166
#define CURSOR_SIZE_SMALL
Definition: tty.c:67
static DWORD WINAPI uv__tty_console_resize_watcher_thread(void *param)
Definition: tty.c:2407
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: tty.c:1163
static const uv_buf_t uv_null_buf_
Definition: tty.c:78
void uv_process_tty_read_req(uv_loop_t *loop, uv_tty_t *handle, uv_req_t *req)
Definition: tty.c:1002
LONG NTSTATUS
Definition: win.h:198
#define SIGWINCH
Definition: win.h:88
sNtQueryInformationProcess pNtQueryInformationProcess
Definition: winapi.c:37
sSetWinEventHook pSetWinEventHook
Definition: winapi.c:46
#define ProcessConsoleHostProcess
Definition: winapi.h:4444
#define NT_SUCCESS(status)
Definition: winapi.h:52
#define STATUS_SUCCESS
Definition: winapi.h:68
DWORD * HANDLE
DWORD
static const z80_opcode fd[]
Definition: z80_tab.h:997
static const char * cb[]
Definition: z80_tab.h:176
#define L
Definition: zip_err_str.c:7