test-tty-duplicate-key.c
Go to the documentation of this file.
1 /* Copyright libuv project 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 #ifdef _WIN32
23 
24 #include "uv.h"
25 #include "task.h"
26 
27 #include <errno.h>
28 #include <io.h>
29 #include <string.h>
30 #include <windows.h>
31 
32 #define ESC "\x1b"
33 #define EUR_UTF8 "\xe2\x82\xac"
34 #define EUR_UNICODE 0x20AC
35 
36 
37 const char* expect_str = NULL;
38 ssize_t expect_nread = 0;
39 
40 static void dump_str(const char* str, ssize_t len) {
41  ssize_t i;
42  for (i = 0; i < len; i++) {
43  fprintf(stderr, "%#02x ", *(str + i));
44  }
45 }
46 
47 static void print_err_msg(const char* expect, ssize_t expect_len,
48  const char* found, ssize_t found_len) {
49  fprintf(stderr, "expect ");
50  dump_str(expect, expect_len);
51  fprintf(stderr, ", but found ");
52  dump_str(found, found_len);
53  fprintf(stderr, "\n");
54 }
55 
56 static void tty_alloc(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
57  buf->base = malloc(size);
58  ASSERT(buf->base != NULL);
59  buf->len = size;
60 }
61 
62 static void tty_read(uv_stream_t* tty_in, ssize_t nread, const uv_buf_t* buf) {
63  if (nread > 0) {
64  if (nread != expect_nread) {
65  fprintf(stderr, "expected nread %ld, but found %ld\n",
66  (long)expect_nread, (long)nread);
67  print_err_msg(expect_str, expect_nread, buf->base, nread);
68  ASSERT(FALSE);
69  }
70  if (strncmp(buf->base, expect_str, nread) != 0) {
71  print_err_msg(expect_str, expect_nread, buf->base, nread);
72  ASSERT(FALSE);
73  }
74  uv_close((uv_handle_t*) tty_in, NULL);
75  } else {
76  ASSERT(nread == 0);
77  }
78 }
79 
80 static void make_key_event_records(WORD virt_key, DWORD ctr_key_state,
81  BOOL is_wsl, INPUT_RECORD* records) {
82 # define KEV(I) records[(I)].Event.KeyEvent
83  BYTE kb_state[256] = {0};
84  WCHAR buf[2];
85  int ret;
86 
87  records[0].EventType = records[1].EventType = KEY_EVENT;
88  KEV(0).bKeyDown = TRUE;
89  KEV(1).bKeyDown = FALSE;
90  KEV(0).wVirtualKeyCode = KEV(1).wVirtualKeyCode = virt_key;
91  KEV(0).wRepeatCount = KEV(1).wRepeatCount = 1;
92  KEV(0).wVirtualScanCode = KEV(1).wVirtualScanCode =
93  MapVirtualKeyW(virt_key, MAPVK_VK_TO_VSC);
94  KEV(0).dwControlKeyState = KEV(1).dwControlKeyState = ctr_key_state;
95  if (ctr_key_state & LEFT_ALT_PRESSED) {
96  kb_state[VK_LMENU] = 0x01;
97  }
98  if (ctr_key_state & RIGHT_ALT_PRESSED) {
99  kb_state[VK_RMENU] = 0x01;
100  }
101  if (ctr_key_state & LEFT_CTRL_PRESSED) {
102  kb_state[VK_LCONTROL] = 0x01;
103  }
104  if (ctr_key_state & RIGHT_CTRL_PRESSED) {
105  kb_state[VK_RCONTROL] = 0x01;
106  }
107  if (ctr_key_state & SHIFT_PRESSED) {
108  kb_state[VK_SHIFT] = 0x01;
109  }
110  ret = ToUnicode(virt_key, KEV(0).wVirtualScanCode, kb_state, buf, 2, 0);
111  if (ret == 1) {
112  if(!is_wsl &&
113  ((ctr_key_state & LEFT_ALT_PRESSED) ||
114  (ctr_key_state & RIGHT_ALT_PRESSED))) {
115  /*
116  * If ALT key is pressed, the UnicodeChar value of the keyup event is
117  * set to 0 on nomal console. Emulate this behavior.
118  * See https://github.com/Microsoft/console/issues/320
119  */
120  KEV(0).uChar.UnicodeChar = buf[0];
121  KEV(1).uChar.UnicodeChar = 0;
122  } else{
123  /*
124  * In WSL UnicodeChar is normally set. This behavior cause #2111.
125  */
126  KEV(0).uChar.UnicodeChar = KEV(1).uChar.UnicodeChar = buf[0];
127  }
128  } else {
129  KEV(0).uChar.UnicodeChar = KEV(1).uChar.UnicodeChar = 0;
130  }
131 # undef KEV
132 }
133 
134 TEST_IMPL(tty_duplicate_vt100_fn_key) {
135  int r;
136  int ttyin_fd;
137  uv_tty_t tty_in;
138  uv_loop_t* loop;
139  HANDLE handle;
140  INPUT_RECORD records[2];
141  DWORD written;
142 
143  loop = uv_default_loop();
144 
145  /* Make sure we have an FD that refers to a tty */
146  handle = CreateFileA("conin$",
147  GENERIC_READ | GENERIC_WRITE,
148  FILE_SHARE_READ | FILE_SHARE_WRITE,
149  NULL,
150  OPEN_EXISTING,
151  FILE_ATTRIBUTE_NORMAL,
152  NULL);
154  ttyin_fd = _open_osfhandle((intptr_t) handle, 0);
155  ASSERT(ttyin_fd >= 0);
156  ASSERT(UV_TTY == uv_guess_handle(ttyin_fd));
157 
158  r = uv_tty_init(uv_default_loop(), &tty_in, ttyin_fd, 1); /* Readable. */
159  ASSERT(r == 0);
160  ASSERT(uv_is_readable((uv_stream_t*) &tty_in));
161  ASSERT(!uv_is_writable((uv_stream_t*) &tty_in));
162 
163  r = uv_read_start((uv_stream_t*)&tty_in, tty_alloc, tty_read);
164  ASSERT(r == 0);
165 
166  expect_str = ESC"[[A";
167  expect_nread = strlen(expect_str);
168 
169  /* Turn on raw mode. */
170  r = uv_tty_set_mode(&tty_in, UV_TTY_MODE_RAW);
171  ASSERT(r == 0);
172 
173  /*
174  * Send F1 keystrokes. Test of issue cause by #2114 that vt100 fn key
175  * duplicate.
176  */
177  make_key_event_records(VK_F1, 0, TRUE, records);
178  WriteConsoleInputW(handle, records, ARRAY_SIZE(records), &written);
179  ASSERT(written == ARRAY_SIZE(records));
180 
182 
184  return 0;
185 }
186 
187 TEST_IMPL(tty_duplicate_alt_modifier_key) {
188  int r;
189  int ttyin_fd;
190  uv_tty_t tty_in;
191  uv_loop_t* loop;
192  HANDLE handle;
193  INPUT_RECORD records[2];
194  INPUT_RECORD alt_records[2];
195  DWORD written;
196 
197  loop = uv_default_loop();
198 
199  /* Make sure we have an FD that refers to a tty */
200  handle = CreateFileA("conin$",
201  GENERIC_READ | GENERIC_WRITE,
202  FILE_SHARE_READ | FILE_SHARE_WRITE,
203  NULL,
204  OPEN_EXISTING,
205  FILE_ATTRIBUTE_NORMAL,
206  NULL);
208  ttyin_fd = _open_osfhandle((intptr_t) handle, 0);
209  ASSERT(ttyin_fd >= 0);
210  ASSERT(UV_TTY == uv_guess_handle(ttyin_fd));
211 
212  r = uv_tty_init(uv_default_loop(), &tty_in, ttyin_fd, 1); /* Readable. */
213  ASSERT(r == 0);
214  ASSERT(uv_is_readable((uv_stream_t*) &tty_in));
215  ASSERT(!uv_is_writable((uv_stream_t*) &tty_in));
216 
217  r = uv_read_start((uv_stream_t*)&tty_in, tty_alloc, tty_read);
218  ASSERT(r == 0);
219 
220  expect_str = ESC"a"ESC"a";
221  expect_nread = strlen(expect_str);
222 
223  /* Turn on raw mode. */
224  r = uv_tty_set_mode(&tty_in, UV_TTY_MODE_RAW);
225  ASSERT(r == 0);
226 
227  /* Emulate transmission of M-a at normal console */
228  make_key_event_records(VK_MENU, 0, TRUE, alt_records);
229  WriteConsoleInputW(handle, &alt_records[0], 1, &written);
230  ASSERT(written == 1);
231  make_key_event_records(L'A', LEFT_ALT_PRESSED, FALSE, records);
232  WriteConsoleInputW(handle, records, ARRAY_SIZE(records), &written);
233  ASSERT(written == 2);
234  WriteConsoleInputW(handle, &alt_records[1], 1, &written);
235  ASSERT(written == 1);
236 
237  /* Emulate transmission of M-a at WSL(#2111) */
238  make_key_event_records(VK_MENU, 0, TRUE, alt_records);
239  WriteConsoleInputW(handle, &alt_records[0], 1, &written);
240  ASSERT(written == 1);
241  make_key_event_records(L'A', LEFT_ALT_PRESSED, TRUE, records);
242  WriteConsoleInputW(handle, records, ARRAY_SIZE(records), &written);
243  ASSERT(written == 2);
244  WriteConsoleInputW(handle, &alt_records[1], 1, &written);
245  ASSERT(written == 1);
246 
248 
250  return 0;
251 }
252 
253 TEST_IMPL(tty_composing_character) {
254  int r;
255  int ttyin_fd;
256  uv_tty_t tty_in;
257  uv_loop_t* loop;
258  HANDLE handle;
259  INPUT_RECORD records[2];
260  INPUT_RECORD alt_records[2];
261  DWORD written;
262 
263  loop = uv_default_loop();
264 
265  /* Make sure we have an FD that refers to a tty */
266  handle = CreateFileA("conin$",
267  GENERIC_READ | GENERIC_WRITE,
268  FILE_SHARE_READ | FILE_SHARE_WRITE,
269  NULL,
270  OPEN_EXISTING,
271  FILE_ATTRIBUTE_NORMAL,
272  NULL);
274  ttyin_fd = _open_osfhandle((intptr_t) handle, 0);
275  ASSERT(ttyin_fd >= 0);
276  ASSERT(UV_TTY == uv_guess_handle(ttyin_fd));
277 
278  r = uv_tty_init(uv_default_loop(), &tty_in, ttyin_fd, 1); /* Readable. */
279  ASSERT(r == 0);
280  ASSERT(uv_is_readable((uv_stream_t*) &tty_in));
281  ASSERT(!uv_is_writable((uv_stream_t*) &tty_in));
282 
283  r = uv_read_start((uv_stream_t*)&tty_in, tty_alloc, tty_read);
284  ASSERT(r == 0);
285 
286  expect_str = EUR_UTF8;
287  expect_nread = strlen(expect_str);
288 
289  /* Turn on raw mode. */
290  r = uv_tty_set_mode(&tty_in, UV_TTY_MODE_RAW);
291  ASSERT(r == 0);
292 
293  /* Emulate EUR inputs by LEFT ALT+NUMPAD ASCII KeyComos */
294  make_key_event_records(VK_MENU, 0, FALSE, alt_records);
295  alt_records[1].Event.KeyEvent.uChar.UnicodeChar = EUR_UNICODE;
296  WriteConsoleInputW(handle, &alt_records[0], 1, &written);
297  make_key_event_records(VK_NUMPAD0, LEFT_ALT_PRESSED, FALSE, records);
298  WriteConsoleInputW(handle, records, ARRAY_SIZE(records), &written);
299  ASSERT(written == ARRAY_SIZE(records));
300  make_key_event_records(VK_NUMPAD1, LEFT_ALT_PRESSED, FALSE, records);
301  WriteConsoleInputW(handle, records, ARRAY_SIZE(records), &written);
302  ASSERT(written == ARRAY_SIZE(records));
303  make_key_event_records(VK_NUMPAD2, LEFT_ALT_PRESSED, FALSE, records);
304  WriteConsoleInputW(handle, records, ARRAY_SIZE(records), &written);
305  ASSERT(written == ARRAY_SIZE(records));
306  make_key_event_records(VK_NUMPAD8, LEFT_ALT_PRESSED, FALSE, records);
307  WriteConsoleInputW(handle, records, ARRAY_SIZE(records), &written);
308  ASSERT(written == ARRAY_SIZE(records));
309  WriteConsoleInputW(handle, &alt_records[1], 1, &written);
310 
312 
314  return 0;
315 }
316 
317 #else
318 
319 typedef int file_has_no_tests; /* ISO C forbids an empty translation unit. */
320 
321 #endif /* ifndef _WIN32 */
xds_interop_client.str
str
Definition: xds_interop_client.py:487
TRUE
const BOOL TRUE
Definition: undname.c:48
async_greeter_server_with_graceful_shutdown.loop
loop
Definition: async_greeter_server_with_graceful_shutdown.py:59
uv_guess_handle
UV_EXTERN uv_handle_type uv_guess_handle(uv_file file)
Definition: unix/tty.c:315
ARRAY_SIZE
#define ARRAY_SIZE(array)
Definition: bloaty.cc:101
task.h
TEST_IMPL
#define TEST_IMPL(name)
Definition: task.h:236
KEV
#define KEV
UV_TTY_MODE_RAW
@ UV_TTY_MODE_RAW
Definition: uv.h:714
string.h
uv_tty_s
Definition: uv.h:704
buf
voidpf void * buf
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
ASSERT
#define ASSERT(expr)
Definition: task.h:102
uv_run
UV_EXTERN int uv_run(uv_loop_t *, uv_run_mode mode)
Definition: unix/core.c:361
BOOL
int BOOL
Definition: undname.c:46
python_utils.port_server.stderr
stderr
Definition: port_server.py:51
uv_close
UV_EXTERN void uv_close(uv_handle_t *handle, uv_close_cb close_cb)
Definition: unix/core.c:112
uv_stream_s
Definition: uv.h:491
uv_default_loop
UV_EXTERN uv_loop_t * uv_default_loop(void)
Definition: uv-common.c:733
ssize_t
intptr_t ssize_t
Definition: win.h:27
gen_stats_data.found
bool found
Definition: gen_stats_data.py:61
uv_is_readable
UV_EXTERN int uv_is_readable(const uv_stream_t *handle)
Definition: unix/stream.c:1606
UV_RUN_DEFAULT
@ UV_RUN_DEFAULT
Definition: uv.h:254
uv_read_start
UV_EXTERN int uv_read_start(uv_stream_t *, uv_alloc_cb alloc_cb, uv_read_cb read_cb)
Definition: unix/stream.c:1555
google::protobuf::python::cmessage::ToUnicode
PyObject * ToUnicode(CMessage *self)
Definition: bloaty/third_party/protobuf/python/google/protobuf/pyext/message.cc:2407
intptr_t
_W64 signed int intptr_t
Definition: stdint-msvc2008.h:118
uv.h
MAKE_VALGRIND_HAPPY
#define MAKE_VALGRIND_HAPPY()
Definition: task.h:229
file_has_no_tests
int file_has_no_tests
Definition: test-tty-duplicate-key.c:319
uv_buf_t
Definition: unix.h:121
FALSE
const BOOL FALSE
Definition: undname.c:47
ret
UniquePtr< SSL_SESSION > ret
Definition: ssl_x509.cc:1029
L
lua_State * L
Definition: upb/upb/bindings/lua/main.c:35
fix_build_deps.r
r
Definition: fix_build_deps.py:491
uv_tty_init
UV_EXTERN int uv_tty_init(uv_loop_t *, uv_tty_t *, uv_file fd, int readable)
Definition: unix/tty.c:123
uv_tty_set_mode
UV_EXTERN int uv_tty_set_mode(uv_tty_t *, uv_tty_mode_t mode)
Definition: unix/tty.c:250
INVALID_HANDLE_VALUE
#define INVALID_HANDLE_VALUE
Definition: bloaty/third_party/zlib/contrib/minizip/iowin32.c:21
handle
static csh handle
Definition: test_arm_regression.c:16
uv_handle_s
Definition: uv.h:441
uv_loop_s
Definition: uv.h:1767
len
int len
Definition: abseil-cpp/absl/base/internal/low_level_alloc_test.cc:46
uv_is_writable
UV_EXTERN int uv_is_writable(const uv_stream_t *handle)
Definition: unix/stream.c:1611
size
voidpf void uLong size
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
errno.h
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230


grpc
Author(s):
autogenerated on Thu Mar 13 2025 03:01:30