visaljs 0.0.3 → 0.0.4

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