wined3d: Use wined3d_uint32_compare() in compare_sig().
[wine.git] / programs / conhost / tests / tty.c
blob0e459ef36545ede8ced4be409e0b46a84165f825
1 /*
2 * 2020 Jacek Caban for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "wine/test.h"
21 #include <windows.h>
23 static HRESULT (WINAPI *pCreatePseudoConsole)(COORD,HANDLE,HANDLE,DWORD,HPCON*);
24 static void (WINAPI *pClosePseudoConsole)(HPCON);
26 static char console_output[4096];
27 static unsigned int console_output_count;
28 static HANDLE console_pipe;
29 static HANDLE child_pipe;
31 #define fetch_console_output() fetch_console_output_(__LINE__)
32 static void fetch_console_output_(unsigned int line)
34 OVERLAPPED o;
35 DWORD count;
36 BOOL ret;
38 if (console_output_count == sizeof(console_output)) return;
40 memset(&o, 0, sizeof(o));
41 o.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
42 ret = ReadFile(console_pipe, console_output + console_output_count,
43 sizeof(console_output) - console_output_count, NULL, &o);
44 if (!ret)
46 ok_(__FILE__,line)(GetLastError() == ERROR_IO_PENDING, "read failed: %u\n", GetLastError());
47 if (GetLastError() != ERROR_IO_PENDING) return;
48 WaitForSingleObject(o.hEvent, 5000);
50 ret = GetOverlappedResult(console_pipe, &o, &count, FALSE);
51 if (!ret && GetLastError() == ERROR_IO_INCOMPLETE)
52 CancelIoEx(console_pipe, &o);
54 ok_(__FILE__,line)(ret, "Read file failed: %u\n", GetLastError());
55 CloseHandle(o.hEvent);
56 if (ret) console_output_count += count;
59 #define expect_empty_output() expect_empty_output_(__LINE__)
60 static void expect_empty_output_(unsigned int line)
62 DWORD avail;
63 BOOL ret;
65 ret = PeekNamedPipe(console_pipe, NULL, 0, NULL, &avail, NULL);
66 ok_(__FILE__,line)(ret, "PeekNamedPipe failed: %u\n", GetLastError());
67 ok_(__FILE__,line)(!avail, "avail = %u\n", avail);
68 if (avail) fetch_console_output_(line);
69 ok_(__FILE__,line)(!console_output_count, "expected empty buffer, got %s\n",
70 wine_dbgstr_an(console_output, console_output_count));
71 console_output_count = 0;
74 #define expect_output_sequence(a) expect_output_sequence_(__LINE__,0,a)
75 #define expect_output_sequence_ctx(a,b) expect_output_sequence_(__LINE__,a,b)
76 static void expect_output_sequence_(unsigned int line, unsigned ctx, const char *expect)
78 size_t len = strlen(expect);
79 if (console_output_count < len) fetch_console_output_(line);
80 if (len <= console_output_count && !memcmp(console_output, expect, len))
82 console_output_count -= len;
83 memmove(console_output, console_output + len, console_output_count);
85 else ok_(__FILE__,line)(0, "%x: expected %s got %s\n", ctx, wine_dbgstr_a(expect),
86 wine_dbgstr_an(console_output, console_output_count));
89 #define skip_sequence(a) skip_sequence_(__LINE__,a)
90 static BOOL skip_sequence_(unsigned int line, const char *expect)
92 size_t len = strlen(expect);
93 DWORD avail;
94 BOOL r;
96 r = PeekNamedPipe(console_pipe, NULL, 0, NULL, &avail, NULL);
97 if (!console_output_count && r && !avail)
99 Sleep(50);
100 r = PeekNamedPipe(console_pipe, NULL, 0, NULL, &avail, NULL);
102 if (r && avail) fetch_console_output_(line);
104 if (len > console_output_count || memcmp(console_output, expect, len)) return FALSE;
105 console_output_count -= len;
106 memmove(console_output, console_output + len, console_output_count);
107 return TRUE;
110 #define skip_byte(a) skip_byte_(__LINE__,a)
111 static BOOL skip_byte_(unsigned int line, char ch)
113 if (!console_output_count || console_output[0] != ch) return FALSE;
114 console_output_count--;
115 memmove(console_output, console_output + 1, console_output_count);
116 return TRUE;
119 #define expect_hide_cursor() expect_hide_cursor_(__LINE__)
120 static void expect_hide_cursor_(unsigned int line)
122 if (!console_output_count) fetch_console_output_(line);
123 ok_(__FILE__,line)(skip_sequence_(line, "\x1b[?25l") || broken(skip_sequence_(line, "\x1b[25l")),
124 "expected hide cursor escape\n");
127 #define skip_hide_cursor() skip_hide_cursor_(__LINE__)
128 static BOOL skip_hide_cursor_(unsigned int line)
130 if (!console_output_count) fetch_console_output_(line);
131 return skip_sequence_(line, "\x1b[25l") || broken(skip_sequence_(line, "\x1b[?25l"));
134 #define expect_erase_line(a) expect_erase_line_(__LINE__,a)
135 static BOOL expect_erase_line_(unsigned line, unsigned int cnt)
137 char buf[16];
138 if (skip_sequence("\x1b[K")) return FALSE;
139 ok(broken(1), "expected erase line\n");
140 sprintf(buf, "\x1b[%uX", cnt);
141 expect_output_sequence_(line, cnt, buf); /* erase the rest of the line */
142 sprintf(buf, "\x1b[%uC", cnt);
143 expect_output_sequence_(line, cnt, buf); /* move cursor to the end of the line */
144 return TRUE;
147 enum req_type
149 REQ_CREATE_SCREEN_BUFFER,
150 REQ_FILL_CHAR,
151 REQ_GET_INPUT,
152 REQ_GET_SB_INFO,
153 REQ_READ_CONSOLE,
154 REQ_READ_CONSOLE_A,
155 REQ_READ_CONSOLE_FILE,
156 REQ_SCROLL,
157 REQ_SET_ACTIVE,
158 REQ_SET_CURSOR,
159 REQ_SET_INPUT_CP,
160 REQ_SET_INPUT_MODE,
161 REQ_SET_OUTPUT_MODE,
162 REQ_SET_TITLE,
163 REQ_WRITE_CHARACTERS,
164 REQ_WRITE_CONSOLE,
165 REQ_WRITE_OUTPUT,
168 struct pseudoconsole_req
170 enum req_type type;
171 union
173 WCHAR string[1];
174 COORD coord;
175 HANDLE handle;
176 DWORD mode;
177 int cp;
178 size_t size;
179 struct
181 COORD coord;
182 unsigned int len;
183 WCHAR buf[1];
184 } write_characters;
185 struct
187 COORD size;
188 COORD coord;
189 SMALL_RECT region;
190 CHAR_INFO buf[1];
191 } write_output;
192 struct
194 SMALL_RECT rect;
195 COORD dst;
196 CHAR_INFO fill;
197 } scroll;
198 struct
200 WCHAR ch;
201 DWORD count;
202 COORD coord;
203 } fill;
204 } u;
207 static void child_string_request(enum req_type type, const WCHAR *title)
209 char buf[4096];
210 struct pseudoconsole_req *req = (void *)buf;
211 size_t len = lstrlenW(title) + 1;
212 DWORD count;
213 BOOL ret;
215 req->type = type;
216 memcpy(req->u.string, title, len * sizeof(WCHAR));
217 ret = WriteFile(child_pipe, req, FIELD_OFFSET(struct pseudoconsole_req, u.string[len]),
218 &count, NULL);
219 ok(ret, "WriteFile failed: %u\n", GetLastError());
222 static void child_write_characters(const WCHAR *buf, unsigned int x, unsigned int y)
224 char req_buf[4096];
225 struct pseudoconsole_req *req = (void *)req_buf;
226 size_t len = lstrlenW(buf);
227 DWORD count;
228 BOOL ret;
230 req->type = REQ_WRITE_CHARACTERS;
231 req->u.write_characters.coord.X = x;
232 req->u.write_characters.coord.Y = y;
233 req->u.write_characters.len = len;
234 memcpy(req->u.write_characters.buf, buf, len * sizeof(WCHAR));
235 ret = WriteFile(child_pipe, req, FIELD_OFFSET(struct pseudoconsole_req, u.write_characters.buf[len + 1]),
236 &count, NULL);
237 ok(ret, "WriteFile failed: %u\n", GetLastError());
240 static void child_set_cursor(const unsigned int x, unsigned int y)
242 struct pseudoconsole_req req;
243 DWORD count;
244 BOOL ret;
246 req.type = REQ_SET_CURSOR;
247 req.u.coord.X = x;
248 req.u.coord.Y = y;
249 ret = WriteFile(child_pipe, &req, sizeof(req), &count, NULL);
250 ok(ret, "WriteFile failed: %u\n", GetLastError());
253 static HANDLE child_create_screen_buffer(void)
255 struct pseudoconsole_req req;
256 HANDLE handle;
257 DWORD count;
258 BOOL ret;
260 req.type = REQ_CREATE_SCREEN_BUFFER;
261 ret = WriteFile(child_pipe, &req, sizeof(req), &count, NULL);
262 ok(ret, "WriteFile failed: %u\n", GetLastError());
263 ret = ReadFile(child_pipe, &handle, sizeof(handle), &count, NULL);
264 ok(ret, "ReadFile failed: %u\n", GetLastError());
265 return handle;
268 static void child_set_active(HANDLE handle)
270 struct pseudoconsole_req req;
271 DWORD count;
272 BOOL ret;
274 req.type = REQ_SET_ACTIVE;
275 req.u.handle = handle;
276 ret = WriteFile(child_pipe, &req, sizeof(req), &count, NULL);
277 ok(ret, "WriteFile failed: %u\n", GetLastError());
280 #define child_write_output(a,b,c,d,e,f,g,h,j,k,l,m,n) child_write_output_(__LINE__,a,b,c,d,e,f,g,h,j,k,l,m,n)
281 static void child_write_output_(unsigned int line, CHAR_INFO *buf, unsigned int size_x, unsigned int size_y,
282 unsigned int coord_x, unsigned int coord_y, unsigned int left,
283 unsigned int top, unsigned int right, unsigned int bottom, unsigned int out_left,
284 unsigned int out_top, unsigned int out_right, unsigned int out_bottom)
286 char req_buf[4096];
287 struct pseudoconsole_req *req = (void *)req_buf;
288 SMALL_RECT region;
289 DWORD count;
290 BOOL ret;
292 req->type = REQ_WRITE_OUTPUT;
293 req->u.write_output.size.X = size_x;
294 req->u.write_output.size.Y = size_y;
295 req->u.write_output.coord.X = coord_x;
296 req->u.write_output.coord.Y = coord_y;
297 req->u.write_output.region.Left = left;
298 req->u.write_output.region.Top = top;
299 req->u.write_output.region.Right = right;
300 req->u.write_output.region.Bottom = bottom;
301 memcpy(req->u.write_output.buf, buf, size_x * size_y * sizeof(*buf));
302 ret = WriteFile(child_pipe, req, FIELD_OFFSET(struct pseudoconsole_req, u.write_output.buf[size_x * size_y]), &count, NULL);
303 ok_(__FILE__,line)(ret, "WriteFile failed: %u\n", GetLastError());
304 ret = ReadFile(child_pipe, &region, sizeof(region), &count, NULL);
305 ok_(__FILE__,line)(ret, "WriteFile failed: %u\n", GetLastError());
306 ok_(__FILE__,line)(region.Left == out_left, "Left = %u\n", region.Left);
307 ok_(__FILE__,line)(region.Top == out_top, "Top = %u\n", region.Top);
308 ok_(__FILE__,line)(region.Right == out_right, "Right = %u\n", region.Right);
309 ok_(__FILE__,line)(region.Bottom == out_bottom, "Bottom = %u\n", region.Bottom);
312 static void child_scroll(unsigned int src_left, unsigned int src_top, unsigned int src_right,
313 unsigned int src_bottom, unsigned int dst_x, unsigned int dst_y, WCHAR fill)
315 struct pseudoconsole_req req;
316 DWORD count;
317 BOOL ret;
319 req.type = REQ_SCROLL;
320 req.u.scroll.rect.Left = src_left;
321 req.u.scroll.rect.Top = src_top;
322 req.u.scroll.rect.Right = src_right;
323 req.u.scroll.rect.Bottom = src_bottom;
324 req.u.scroll.dst.X = dst_x;
325 req.u.scroll.dst.Y = dst_y;
326 req.u.scroll.fill.Char.UnicodeChar = fill;
327 req.u.scroll.fill.Attributes = 0;
328 ret = WriteFile(child_pipe, &req, sizeof(req), &count, NULL);
329 ok(ret, "WriteFile failed: %u\n", GetLastError());
332 static void child_fill_character(WCHAR ch, DWORD count, int x, int y)
334 struct pseudoconsole_req req;
335 BOOL ret;
337 req.type = REQ_FILL_CHAR;
338 req.u.fill.ch = ch;
339 req.u.fill.count = count;
340 req.u.fill.coord.X = x;
341 req.u.fill.coord.Y = y;
342 ret = WriteFile(child_pipe, &req, sizeof(req), &count, NULL);
343 ok(ret, "WriteFile failed: %u\n", GetLastError());
346 static void child_set_input_mode(HANDLE pipe, DWORD mode)
348 struct pseudoconsole_req req;
349 DWORD count;
350 BOOL ret;
352 req.type = REQ_SET_INPUT_MODE;
353 req.u.mode = mode;
354 ret = WriteFile(pipe, &req, sizeof(req), &count, NULL);
355 ok(ret, "WriteFile failed: %u\n", GetLastError());
358 static void child_set_output_mode(DWORD mode)
360 struct pseudoconsole_req req;
361 DWORD count;
362 BOOL ret;
364 req.type = REQ_SET_OUTPUT_MODE;
365 req.u.mode = mode;
366 ret = WriteFile(child_pipe, &req, sizeof(req), &count, NULL);
367 ok(ret, "WriteFile failed: %u\n", GetLastError());
370 static void child_set_input_cp(int cp)
372 struct pseudoconsole_req req;
373 DWORD count;
374 BOOL ret;
376 req.type = REQ_SET_INPUT_CP;
377 req.u.cp = cp;
378 ret = WriteFile(child_pipe, &req, sizeof(req), &count, NULL);
379 ok(ret, "WriteFile failed: %u\n", GetLastError());
382 static void child_read_console(HANDLE pipe, size_t size)
384 struct pseudoconsole_req req;
385 DWORD count;
386 BOOL ret;
388 req.type = REQ_READ_CONSOLE;
389 req.u.size = size;
390 ret = WriteFile(pipe, &req, sizeof(req), &count, NULL);
391 ok(ret, "WriteFile failed: %u\n", GetLastError());
394 static void child_read_console_a(HANDLE pipe, size_t size)
396 struct pseudoconsole_req req;
397 DWORD count;
398 BOOL ret;
400 req.type = REQ_READ_CONSOLE_A;
401 req.u.size = size;
402 ret = WriteFile(pipe, &req, sizeof(req), &count, NULL);
403 ok(ret, "WriteFile failed: %u\n", GetLastError());
406 static void child_read_console_file(HANDLE pipe, size_t size)
408 struct pseudoconsole_req req;
409 DWORD count;
410 BOOL ret;
412 req.type = REQ_READ_CONSOLE_FILE;
413 req.u.size = size;
414 ret = WriteFile(pipe, &req, sizeof(req), &count, NULL);
415 ok(ret, "WriteFile failed: %u\n", GetLastError());
418 #define child_expect_read_result(a,b) child_expect_read_result_(__LINE__,a,b)
419 static void child_expect_read_result_(unsigned int line, HANDLE pipe, const WCHAR *expect)
421 size_t exlen = wcslen(expect);
422 WCHAR buf[4096];
423 DWORD count;
424 BOOL ret;
426 ret = ReadFile(pipe, buf, sizeof(buf), &count, NULL);
427 ok_(__FILE__,line)(ret, "ReadFile failed: %u\n", GetLastError());
428 ok_(__FILE__,line)(count == exlen * sizeof(WCHAR), "got %u, expected %u\n",
429 count, exlen * sizeof(WCHAR));
430 buf[count / sizeof(WCHAR)] = 0;
431 ok_(__FILE__,line)(!memcmp(expect, buf, count), "unexpected data %s\n", wine_dbgstr_w(buf));
434 #define child_expect_read_result_a(a,b) child_expect_read_result_a_(__LINE__,a,b)
435 static void child_expect_read_result_a_(unsigned int line, HANDLE pipe, const char *expect)
437 size_t exlen = strlen(expect);
438 char buf[4096];
439 DWORD count;
440 BOOL ret;
442 ret = ReadFile(pipe, buf, sizeof(buf), &count, NULL);
443 ok_(__FILE__,line)(ret, "ReadFile failed: %u\n", GetLastError());
444 todo_wine_if(exlen && expect[exlen - 1] == '\xcc')
445 ok_(__FILE__,line)(count == exlen, "got %u, expected %u\n", count, exlen);
446 buf[count] = 0;
447 ok_(__FILE__,line)(!memcmp(expect, buf, count), "unexpected data %s\n", wine_dbgstr_a(buf));
450 static void expect_input(unsigned int event_type, INPUT_RECORD *record)
452 struct pseudoconsole_req req = { REQ_GET_INPUT };
453 INPUT_RECORD input;
454 DWORD read;
455 BOOL ret;
457 ret = WriteFile(child_pipe, &req, sizeof(req), &read, NULL);
458 ok(ret, "WriteFile failed: %u\n", GetLastError());
460 ret = ReadFile(child_pipe, &input, sizeof(input), &read, NULL);
461 ok(ret, "ReadFile failed: %u\n", GetLastError());
463 ok(input.EventType == event_type, "EventType = %u, expected %u\n", input.EventType, event_type);
464 if (record) *record = input;
467 static BOOL get_key_input(unsigned int vt, INPUT_RECORD *record)
469 static INPUT_RECORD prev_record;
470 static BOOL have_prev_record;
472 if (!have_prev_record)
474 expect_input(KEY_EVENT, &prev_record);
475 have_prev_record = TRUE;
478 if (vt && prev_record.Event.KeyEvent.wVirtualKeyCode != vt) return FALSE;
479 *record = prev_record;
480 have_prev_record = FALSE;
481 return TRUE;
484 #define expect_key_input(a,b,c,d) expect_key_input_(__LINE__,0,a,b,c,d)
485 static void expect_key_input_(unsigned int line, unsigned int ctx, WCHAR ch, unsigned int vk,
486 BOOL down, unsigned int ctrl_state)
488 unsigned int vs = MapVirtualKeyW(vk, MAPVK_VK_TO_VSC);
489 INPUT_RECORD record;
491 get_key_input(0, &record);
492 ok_(__FILE__,line)(record.Event.KeyEvent.bKeyDown == down, "%x: bKeyDown = %x\n",
493 ctx, record.Event.KeyEvent.bKeyDown);
494 ok_(__FILE__,line)(record.Event.KeyEvent.wRepeatCount == 1, "%x: wRepeatCount = %x\n",
495 ctx, record.Event.KeyEvent.wRepeatCount);
496 ok_(__FILE__,line)(record.Event.KeyEvent.uChar.UnicodeChar == ch, "%x: UnicodeChar = %x\n",
497 ctx, record.Event.KeyEvent.uChar.UnicodeChar);
498 ok_(__FILE__,line)(record.Event.KeyEvent.wVirtualKeyCode == vk,
499 "%x: wVirtualKeyCode = %x, expected %x\n", ctx,
500 record.Event.KeyEvent.wVirtualKeyCode, vk);
501 ok_(__FILE__,line)(record.Event.KeyEvent.wVirtualScanCode == vs,
502 "%x: wVirtualScanCode = %x expected %x\n", ctx,
503 record.Event.KeyEvent.wVirtualScanCode, vs);
504 ok_(__FILE__,line)(record.Event.KeyEvent.dwControlKeyState == ctrl_state,
505 "%x: dwControlKeyState = %x\n", ctx, record.Event.KeyEvent.dwControlKeyState);
508 #define get_input_key_vt() get_input_key_vt_(__LINE__)
509 static unsigned int get_input_key_vt_(unsigned int line)
511 INPUT_RECORD record;
513 get_key_input(0, &record);
514 ok_(__FILE__,line)(record.Event.KeyEvent.wRepeatCount == 1, "wRepeatCount = %x\n",
515 record.Event.KeyEvent.wRepeatCount);
516 return record.Event.KeyEvent.wVirtualKeyCode;
519 #define expect_key_pressed(a,b,c) expect_key_pressed_(__LINE__,0,a,b,c)
520 #define expect_key_pressed_ctx(a,b,c,d) expect_key_pressed_(__LINE__,a,b,c,d)
521 static void expect_key_pressed_(unsigned int line, unsigned int ctx, WCHAR ch, unsigned int vk,
522 unsigned int ctrl_state)
524 if (ctrl_state & SHIFT_PRESSED)
525 expect_key_input_(line, ctx, 0, VK_SHIFT, TRUE, SHIFT_PRESSED);
526 if (ctrl_state & LEFT_ALT_PRESSED)
527 expect_key_input_(line, ctx, 0, VK_MENU, TRUE,
528 LEFT_ALT_PRESSED | (ctrl_state & SHIFT_PRESSED));
529 if (ctrl_state & LEFT_CTRL_PRESSED)
530 expect_key_input_(line, ctx, 0, VK_CONTROL, TRUE,
531 LEFT_CTRL_PRESSED | (ctrl_state & (SHIFT_PRESSED | LEFT_ALT_PRESSED)));
532 expect_key_input_(line, ctx, ch, vk, TRUE, ctrl_state);
533 expect_key_input_(line, ctx, ch, vk, FALSE, ctrl_state);
534 if (ctrl_state & LEFT_CTRL_PRESSED)
535 expect_key_input_(line, ctx, 0, VK_CONTROL, FALSE,
536 ctrl_state & (SHIFT_PRESSED | LEFT_ALT_PRESSED));
537 if (ctrl_state & LEFT_ALT_PRESSED)
538 expect_key_input_(line, ctx, 0, VK_MENU, FALSE, ctrl_state & SHIFT_PRESSED);
539 if (ctrl_state & SHIFT_PRESSED)
540 expect_key_input_(line, ctx, 0, VK_SHIFT, FALSE, 0);
543 #define expect_char_key(a) expect_char_key_(__LINE__,a)
544 static void expect_char_key_(unsigned int line, WCHAR ch)
546 unsigned int ctrl = 0, vk;
547 vk = VkKeyScanW(ch);
548 if (vk == ~0) vk = 0;
549 if (vk & 0x0100) ctrl |= SHIFT_PRESSED;
550 if (vk & 0x0200) ctrl |= LEFT_CTRL_PRESSED;
551 vk &= 0xff;
552 expect_key_pressed_(line, ch, ch, vk, ctrl);
555 #define test_cursor_pos(a,b) _test_cursor_pos(__LINE__,a,b)
556 static void _test_cursor_pos(unsigned line, int expect_x, int expect_y)
558 struct pseudoconsole_req req = { REQ_GET_SB_INFO };
559 CONSOLE_SCREEN_BUFFER_INFO info;
560 DWORD read;
561 BOOL ret;
563 ret = WriteFile(child_pipe, &req, sizeof(req), &read, NULL);
564 ok(ret, "WriteFile failed: %u\n", GetLastError());
566 ret = ReadFile(child_pipe, &info, sizeof(info), &read, NULL);
567 ok(ret, "ReadFile failed: %u\n", GetLastError());
569 ok_(__FILE__,line)(info.dwCursorPosition.X == expect_x, "dwCursorPosition.X = %u, expected %u\n",
570 info.dwCursorPosition.X, expect_x);
571 ok_(__FILE__,line)(info.dwCursorPosition.Y == expect_y, "dwCursorPosition.Y = %u, expected %u\n",
572 info.dwCursorPosition.Y, expect_y);
575 static void test_write_console(void)
577 child_set_output_mode(ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
579 child_string_request(REQ_WRITE_CONSOLE, L"abc");
580 skip_hide_cursor();
581 expect_output_sequence("abc");
582 skip_sequence("\x1b[?25h"); /* show cursor */
584 child_string_request(REQ_WRITE_CONSOLE, L"\tt");
585 skip_hide_cursor();
586 if (!skip_sequence("\x1b[3C")) expect_output_sequence(" ");
587 expect_output_sequence("t");
588 skip_sequence("\x1b[?25h"); /* show cursor */
589 expect_empty_output();
591 child_string_request(REQ_WRITE_CONSOLE, L"x\rr");
592 expect_hide_cursor();
593 expect_output_sequence("\rr abc tx");
594 if (!skip_sequence("\x1b[9D"))
595 expect_output_sequence("\x1b[4;2H"); /* set cursor */
596 expect_output_sequence("\x1b[?25h"); /* show cursor */
597 expect_empty_output();
599 child_string_request(REQ_WRITE_CONSOLE, L"yz\r\n");
600 skip_hide_cursor();
601 expect_output_sequence("yz\r\n");
602 skip_sequence("\x1b[?25h"); /* show cursor */
603 expect_empty_output();
605 child_string_request(REQ_WRITE_CONSOLE, L"abc\r\n123\r\ncde\r");
606 skip_hide_cursor();
607 expect_output_sequence("abc\r\n123\r\ncde\r");
608 skip_sequence("\x1b[?25h"); /* show cursor */
609 expect_empty_output();
611 child_set_cursor(0, 39);
612 expect_hide_cursor();
613 expect_output_sequence("\x1b[40;1H"); /* set cursor */
614 expect_output_sequence("\x1b[?25h"); /* show cursor */
615 expect_empty_output();
617 child_string_request(REQ_WRITE_CONSOLE, L"yz\r\n");
618 skip_hide_cursor();
619 expect_output_sequence("yz\r");
620 if (skip_sequence("\x1b[?25h")) /* show cursor */
621 expect_output_sequence("\x1b[?25l"); /* hide cursor */
622 expect_output_sequence("\n"); /* next line */
623 if (skip_sequence("\x1b[30X")) /* erase the line */
625 expect_output_sequence("\x1b[30C"); /* move cursor to the end of the line */
626 expect_output_sequence("\r");
628 skip_sequence("\x1b[?25h"); /* show cursor */
629 expect_empty_output();
631 child_string_request(REQ_WRITE_CONSOLE, L"");
632 expect_empty_output();
634 child_string_request(REQ_WRITE_CONSOLE, L"ab\n");
635 skip_hide_cursor();
636 expect_output_sequence("ab");
637 if (skip_sequence("\x1b[?25h")) /* show cursor */
638 expect_output_sequence("\x1b[?25l"); /* hide cursor */
639 expect_output_sequence("\r\n"); /* next line */
640 if (skip_sequence("\x1b[30X")) /* erase the line */
642 expect_output_sequence("\x1b[30C"); /* move cursor to the end of the line */
643 expect_output_sequence("\r");
645 skip_sequence("\x1b[?25h"); /* show cursor */
646 expect_empty_output();
648 child_set_cursor(28, 10);
649 expect_hide_cursor();
650 expect_output_sequence("\x1b[11;29H"); /* set cursor */
651 expect_output_sequence("\x1b[?25h"); /* show cursor */
652 expect_empty_output();
654 child_string_request(REQ_WRITE_CONSOLE, L"xy");
655 skip_hide_cursor();
656 expect_output_sequence("xy");
657 if (!skip_sequence("\b")) skip_sequence("\r\n");
658 skip_sequence("\x1b[?25h"); /* show cursor */
659 expect_empty_output();
661 child_set_cursor(28, 10);
662 fetch_console_output();
663 if (!skip_sequence("\b"))
665 expect_hide_cursor();
666 expect_output_sequence("\x1b[11;29H"); /* set cursor */
667 expect_output_sequence("\x1b[?25h"); /* show cursor */
669 expect_empty_output();
671 child_string_request(REQ_WRITE_CONSOLE, L"abc");
672 skip_hide_cursor();
673 expect_output_sequence("\r ab");
674 expect_output_sequence("\r\nc");
675 if (expect_erase_line(29))
676 expect_output_sequence("\x1b[12;2H"); /* set cursor */
677 skip_sequence("\x1b[?25h"); /* show cursor */
678 expect_empty_output();
680 child_set_cursor(28, 39);
681 expect_hide_cursor();
682 expect_output_sequence("\x1b[40;29H"); /* set cursor */
683 expect_output_sequence("\x1b[?25h"); /* show cursor */
684 expect_empty_output();
686 child_string_request(REQ_WRITE_CONSOLE, L"abc");
687 skip_hide_cursor();
688 expect_output_sequence("ab");
689 skip_sequence("\x1b[40;29H"); /* set cursor */
690 if (skip_sequence("\x1b[?25h")) /* show cursor */
691 expect_output_sequence("\x1b[?25l"); /* hide cursor */
692 else
693 skip_sequence("\b");
694 expect_output_sequence("\r\nc");
695 if (skip_sequence("\x1b[29X")) /* erase the line */
697 expect_output_sequence("\x1b[29C"); /* move cursor to the end of the line */
698 expect_output_sequence("\x1b[40;2H"); /* set cursor */
700 skip_sequence("\x1b[?25h"); /* show cursor */
701 expect_empty_output();
703 child_set_cursor(28, 39);
704 skip_hide_cursor();
705 if (!skip_sequence("\x1b[27C"))
706 expect_output_sequence("\x1b[40;29H"); /* set cursor */
707 skip_sequence("\x1b[?25h"); /* show cursor */
708 expect_empty_output();
710 child_string_request(REQ_WRITE_CONSOLE, L"XY");
711 skip_hide_cursor();
712 expect_output_sequence("XY");
713 skip_sequence("\x1b[40;29H"); /* set cursor */
714 if (skip_sequence("\x1b[?25h")) /* show cursor */
715 skip_sequence("\x1b[?25l"); /* hide cursor */
716 if (!skip_sequence("\b") && skip_sequence("\r\n"))
718 expect_output_sequence("\x1b[30X"); /* erase the line */
719 expect_output_sequence("\x1b[30C"); /* move cursor to the end of the line */
720 expect_output_sequence("\r"); /* set cursor */
722 skip_sequence("\x1b[?25h"); /* show cursor */
723 expect_empty_output();
725 child_string_request(REQ_WRITE_CONSOLE, L"\n");
726 skip_hide_cursor();
727 if (!skip_sequence("\r\n"))
729 expect_output_sequence("\n");
730 expect_output_sequence("\x1b[30X"); /* erase the line */
731 expect_output_sequence("\x1b[30C"); /* move cursor to the end of the line */
732 expect_output_sequence("\r"); /* set cursor */
734 skip_sequence("\x1b[?25h"); /* show cursor */
735 expect_empty_output();
737 child_set_output_mode(ENABLE_PROCESSED_OUTPUT);
739 child_set_cursor(28, 11);
740 expect_hide_cursor();
741 expect_output_sequence("\x1b[12;29H"); /* set cursor */
742 skip_sequence("\x1b[?25h"); /* show cursor */
744 child_string_request(REQ_WRITE_CONSOLE, L"xyz1234");
745 skip_hide_cursor();
746 expect_output_sequence("43\b");
747 skip_sequence("\x1b[?25h"); /* show cursor */
748 expect_empty_output();
750 child_set_cursor(28, 11);
751 skip_hide_cursor();
752 expect_output_sequence("\b"); /* backspace */
753 skip_sequence("\x1b[?25h"); /* show cursor */
755 child_string_request(REQ_WRITE_CONSOLE, L"xyz123");
756 expect_hide_cursor();
757 expect_output_sequence("23");
758 if (!skip_sequence("\x1b[2D"))
759 expect_output_sequence("\x1b[12;29H");/* set cursor */
760 expect_output_sequence("\x1b[?25h"); /* show cursor */
761 expect_empty_output();
763 child_set_cursor(28, 11);
764 child_string_request(REQ_WRITE_CONSOLE, L"abcdef\n\r123456789012345678901234567890xyz");
765 expect_hide_cursor();
766 if (skip_sequence("\x1b[?25h")) expect_hide_cursor();
767 expect_output_sequence("\r ef\r\n");
768 expect_output_sequence("xyz456789012345678901234567890");
769 if (!skip_sequence("\x1b[27D"))
770 expect_output_sequence("\x1b[13;4H"); /* set cursor */
771 expect_output_sequence("\x1b[?25h"); /* show cursor */
772 expect_empty_output();
774 child_set_cursor(28, 11);
775 expect_hide_cursor();
776 expect_output_sequence("\x1b[12;29H"); /* set cursor */
777 expect_output_sequence("\x1b[?25h"); /* show cursor */
779 child_string_request(REQ_WRITE_CONSOLE, L"AB\r\n");
780 skip_hide_cursor();
781 expect_output_sequence("AB\r\n");
782 skip_sequence("\x1b[?25h"); /* show cursor */
783 expect_empty_output();
785 child_set_output_mode(ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
787 child_set_cursor(28, 12);
788 skip_hide_cursor();
789 expect_output_sequence("\x1b[28C"); /* move cursor to the end of the line */
790 skip_sequence("\x1b[?25h"); /* show cursor */
791 expect_empty_output();
793 child_string_request(REQ_WRITE_CONSOLE, L"ab");
794 skip_hide_cursor();
795 expect_output_sequence("ab");
796 skip_sequence("\b");
797 skip_sequence("\x1b[?25h"); /* show cursor */
798 expect_empty_output();
799 test_cursor_pos(29, 12);
801 child_string_request(REQ_WRITE_CONSOLE, L"c");
802 skip_hide_cursor();
803 expect_output_sequence("\r\n");
804 expect_output_sequence("c");
805 skip_sequence("\x1b[?25h"); /* show cursor */
806 expect_empty_output();
807 test_cursor_pos(1, 13);
809 child_set_cursor(28, 14);
810 skip_hide_cursor();
811 expect_output_sequence("\x1b[15;29H"); /* set cursor */
812 skip_sequence("\x1b[?25h"); /* show cursor */
813 expect_empty_output();
815 child_string_request(REQ_WRITE_CONSOLE, L"x");
816 skip_hide_cursor();
817 expect_output_sequence("x");
818 skip_sequence("\x1b[?25h"); /* show cursor */
819 expect_empty_output();
820 test_cursor_pos(29, 14);
822 child_string_request(REQ_WRITE_CONSOLE, L"y");
823 skip_hide_cursor();
824 expect_output_sequence("y");
825 skip_sequence("\x1b[?25h"); /* show cursor */
826 expect_empty_output();
827 test_cursor_pos(29, 14);
829 child_string_request(REQ_WRITE_CONSOLE, L"\b");
830 skip_hide_cursor();
831 expect_output_sequence("\b");
832 skip_sequence("\x1b[?25h"); /* show cursor */
833 expect_empty_output();
834 test_cursor_pos(28, 14);
836 child_string_request(REQ_WRITE_CONSOLE, L"z");
837 skip_hide_cursor();
838 expect_output_sequence("z");
839 skip_sequence("\x1b[?25h"); /* show cursor */
840 expect_empty_output();
841 test_cursor_pos(29, 14);
843 child_string_request(REQ_WRITE_CONSOLE, L"w");
844 skip_hide_cursor();
845 expect_output_sequence("w");
846 skip_sequence("\x1b[?25h"); /* show cursor */
847 expect_empty_output();
848 test_cursor_pos(29, 14);
850 child_string_request(REQ_WRITE_CONSOLE, L"X");
851 skip_hide_cursor();
852 expect_output_sequence("\r\n");
853 expect_output_sequence("X");
854 skip_sequence("\x1b[?25h"); /* show cursor */
855 expect_empty_output();
856 test_cursor_pos(1, 15);
858 child_set_output_mode(ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT);
860 child_set_cursor(28, 20);
861 skip_hide_cursor();
862 expect_output_sequence("\x1b[21;29H"); /* set cursor */
863 skip_sequence("\x1b[?25h"); /* show cursor */
864 expect_empty_output();
866 child_string_request(REQ_WRITE_CONSOLE, L"ab");
867 skip_hide_cursor();
868 expect_output_sequence("ab");
869 expect_output_sequence("\r\n");
870 skip_sequence("\x1b[?25h"); /* show cursor */
871 expect_empty_output();
872 test_cursor_pos(0, 21);
874 child_string_request(REQ_WRITE_CONSOLE, L"c");
875 skip_hide_cursor();
876 expect_output_sequence("c");
877 skip_sequence("\x1b[?25h"); /* show cursor */
878 expect_empty_output();
879 test_cursor_pos(1, 21);
881 child_set_cursor(28, 22);
882 skip_hide_cursor();
883 expect_output_sequence("\x1b[23;29H"); /* set cursor */
884 skip_sequence("\x1b[?25h"); /* show cursor */
885 expect_empty_output();
887 child_string_request(REQ_WRITE_CONSOLE, L"x");
888 skip_hide_cursor();
889 expect_output_sequence("x");
890 skip_sequence("\x1b[?25h"); /* show cursor */
891 expect_empty_output();
892 test_cursor_pos(29, 22);
894 child_string_request(REQ_WRITE_CONSOLE, L"y");
895 skip_hide_cursor();
896 expect_output_sequence("y");
897 expect_output_sequence("\r\n");
898 skip_sequence("\x1b[?25h"); /* show cursor */
899 expect_empty_output();
900 test_cursor_pos(0, 23);
902 child_string_request(REQ_WRITE_CONSOLE, L"z");
903 skip_hide_cursor();
904 expect_output_sequence("z");
905 skip_sequence("\x1b[?25h"); /* show cursor */
906 expect_empty_output();
907 test_cursor_pos(1, 23);
910 static void test_tty_output(void)
912 CHAR_INFO char_info_buf[2048], char_info;
913 HANDLE sb, sb2;
914 unsigned int i;
916 /* simple write chars */
917 child_write_characters(L"child", 3, 4);
918 expect_hide_cursor();
919 expect_output_sequence("\x1b[5;4H"); /* set cursor */
920 expect_output_sequence("child");
921 expect_output_sequence("\x1b[H"); /* set cursor */
922 expect_output_sequence("\x1b[?25h"); /* show cursor */
923 expect_empty_output();
925 /* wrapped write chars */
926 child_write_characters(L"bound", 28, 6);
927 expect_hide_cursor();
928 expect_output_sequence("\x1b[7;1H"); /* set cursor */
929 expect_output_sequence(" bo\r\nund");
930 expect_erase_line(27);
931 expect_output_sequence("\x1b[H"); /* set cursor */
932 expect_output_sequence("\x1b[?25h"); /* show cursor */
933 expect_empty_output();
935 /* fill line 4 with a few simple writes */
936 child_write_characters(L"xxx", 13, 4);
937 expect_hide_cursor();
938 expect_output_sequence("\x1b[5;14H"); /* set cursor */
939 expect_output_sequence("xxx");
940 expect_output_sequence("\x1b[H"); /* set cursor */
941 expect_output_sequence("\x1b[?25h"); /* show cursor */
942 expect_empty_output();
944 /* write one char at the end of row */
945 child_write_characters(L"y", 29, 4);
946 expect_hide_cursor();
947 expect_output_sequence("\x1b[5;30H"); /* set cursor */
948 expect_output_sequence("y");
949 expect_output_sequence("\x1b[H"); /* set cursor */
950 expect_output_sequence("\x1b[?25h"); /* show cursor */
951 expect_empty_output();
953 /* wrapped write chars */
954 child_write_characters(L"zz", 29, 4);
955 expect_hide_cursor();
956 expect_output_sequence("\x1b[5;1H"); /* set cursor */
957 expect_output_sequence(" child xxx z");
958 expect_output_sequence("\r\nz");
959 expect_erase_line(29);
960 expect_output_sequence("\x1b[H"); /* set cursor */
961 expect_output_sequence("\x1b[?25h"); /* show cursor */
962 expect_empty_output();
964 /* trailing spaces */
965 child_write_characters(L"child ", 3, 4);
966 expect_hide_cursor();
967 expect_output_sequence("\x1b[5;4H"); /* set cursor */
968 expect_output_sequence("child ");
969 expect_output_sequence("\x1b[H"); /* set cursor */
970 expect_output_sequence("\x1b[?25h"); /* show cursor */
971 expect_empty_output();
973 child_set_cursor(2, 3);
974 expect_hide_cursor();
975 expect_output_sequence("\x1b[4;3H"); /* set cursor */
976 expect_output_sequence("\x1b[?25h"); /* show cursor */
977 expect_empty_output();
979 child_string_request(REQ_SET_TITLE, L"new title");
980 fetch_console_output();
981 skip_sequence("\x1b[?25l"); /* hide cursor */
982 expect_output_sequence("\x1b]0;new title\x07"); /* set title */
983 skip_sequence("\x1b[?25h"); /* show cursor */
984 expect_empty_output();
986 for (i = 0; i < ARRAY_SIZE(char_info_buf); i++)
988 char_info_buf[i].Char.UnicodeChar = '0' + i % 10;
989 char_info_buf[i].Attributes = 0;
992 child_write_output(char_info_buf, /* size */ 7, 8, /* coord */ 1, 2,
993 /* region */ 3, 7, 5, 9, /* out region */ 3, 7, 5, 9);
994 expect_hide_cursor();
995 expect_output_sequence("\x1b[30m"); /* foreground black */
996 expect_output_sequence("\x1b[8;4H"); /* set cursor */
997 expect_output_sequence("567");
998 expect_output_sequence("\x1b[9;4H"); /* set cursor */
999 expect_output_sequence("234");
1000 expect_output_sequence("\x1b[10;4H"); /* set cursor */
1001 expect_output_sequence("901");
1002 expect_output_sequence("\x1b[4;3H"); /* set cursor */
1003 expect_output_sequence("\x1b[?25h"); /* show cursor */
1004 expect_empty_output();
1006 child_write_output(char_info_buf, /* size */ 2, 3, /* coord */ 1, 2,
1007 /* region */ 3, 8, 15, 19, /* out region */ 3, 8, 3, 8);
1008 expect_hide_cursor();
1009 if (skip_sequence("\x1b[m")) /* default attr */
1010 expect_output_sequence("\x1b[30m");/* foreground black */
1011 expect_output_sequence("\x1b[9;4H"); /* set cursor */
1012 expect_output_sequence("5");
1013 expect_output_sequence("\x1b[4;3H"); /* set cursor */
1014 expect_output_sequence("\x1b[?25h"); /* show cursor */
1015 expect_empty_output();
1017 child_write_output(char_info_buf, /* size */ 3, 4, /* coord */ 1, 2,
1018 /* region */ 3, 8, 15, 19, /* out region */ 3, 8, 4, 9);
1019 expect_hide_cursor();
1020 if (skip_sequence("\x1b[m")) /* default attr */
1021 expect_output_sequence("\x1b[30m");/* foreground black */
1022 expect_output_sequence("\x1b[9;4H"); /* set cursor */
1023 expect_output_sequence("78");
1024 expect_output_sequence("\x1b[10;4H"); /* set cursor */
1025 expect_output_sequence("01");
1026 expect_output_sequence("\x1b[4;3H"); /* set cursor */
1027 expect_output_sequence("\x1b[?25h"); /* show cursor */
1028 expect_empty_output();
1030 child_write_output(char_info_buf, /* size */ 7, 8, /* coord */ 2, 3,
1031 /* region */ 28, 38, 31, 60, /* out region */ 28, 38, 29, 39);
1032 expect_hide_cursor();
1033 if (skip_sequence("\x1b[m")) /* default attr */
1034 expect_output_sequence("\x1b[30m");/* foreground black */
1035 expect_output_sequence("\x1b[39;29H"); /* set cursor */
1036 expect_output_sequence("34");
1037 expect_output_sequence("\x1b[40;29H"); /* set cursor */
1038 expect_output_sequence("01");
1039 expect_output_sequence("\x1b[4;3H"); /* set cursor */
1040 expect_output_sequence("\x1b[?25h"); /* show cursor */
1041 expect_empty_output();
1043 child_write_output(char_info_buf, /* size */ 7, 8, /* coord */ 1, 2,
1044 /* region */ 0, 7, 5, 9, /* out region */ 0, 7, 5, 9);
1045 expect_hide_cursor();
1046 if (skip_sequence("\x1b[m")) /* default attr */
1047 expect_output_sequence("\x1b[30m");/* foreground black */
1048 expect_output_sequence("\x1b[8;1H"); /* set cursor */
1049 expect_output_sequence("567890\r\n");
1050 expect_output_sequence("234567\r\n");
1051 expect_output_sequence("901234");
1052 expect_output_sequence("\x1b[4;3H"); /* set cursor */
1053 expect_output_sequence("\x1b[?25h"); /* show cursor */
1054 expect_empty_output();
1056 child_scroll(/* scroll rect */ 0, 7, 2, 8, /* destination */ 2, 8, /* fill */ 'x');
1057 expect_hide_cursor();
1058 if (skip_sequence("\x1b[m")) /* default attr */
1059 expect_output_sequence("\x1b[30m");/* foreground black */
1060 expect_output_sequence("\x1b[8;1H"); /* set cursor */
1061 expect_output_sequence("xxx89\r\n");
1062 expect_output_sequence("xx567\r\n");
1063 expect_output_sequence("90234");
1064 expect_output_sequence("\x1b[4;3H"); /* set cursor */
1065 expect_output_sequence("\x1b[?25h"); /* show cursor */
1066 expect_empty_output();
1068 child_write_characters(L"xxx", 3, 10);
1069 expect_hide_cursor();
1070 expect_output_sequence("\x1b[m"); /* default attributes */
1071 expect_output_sequence("\x1b[11;4H"); /* set cursor */
1072 expect_output_sequence("xxx");
1073 expect_output_sequence("\x1b[4;3H"); /* set cursor */
1074 expect_output_sequence("\x1b[?25h"); /* show cursor */
1075 expect_empty_output();
1077 /* test attributes */
1078 for (i = 0; i < 0x100 - 0xff; i++)
1080 unsigned int expect;
1081 char expect_buf[16];
1082 char_info.Char.UnicodeChar = 'a';
1083 char_info.Attributes = i;
1084 child_write_output(&char_info, /* size */ 1, 1, /* coord */ 0, 0,
1085 /* region */ 12, 3, 12, 3, /* out region */ 12, 3, 12, 3);
1086 expect_hide_cursor();
1087 if (i != 0x190 && i && ((i & 0xff) != 8)) expect_output_sequence_ctx(i, "\x1b[m");
1088 if ((i & 0x0f) != 7)
1090 expect = 30;
1091 if (i & FOREGROUND_BLUE) expect += 4;
1092 if (i & FOREGROUND_GREEN) expect += 2;
1093 if (i & FOREGROUND_RED) expect += 1;
1094 if (i & FOREGROUND_INTENSITY) expect += 60;
1095 sprintf(expect_buf, "\x1b[%um", expect);
1096 expect_output_sequence_ctx(i, expect_buf);
1098 if (i & 0xf0)
1100 expect = 40;
1101 if (i & BACKGROUND_BLUE) expect += 4;
1102 if (i & BACKGROUND_GREEN) expect += 2;
1103 if (i & BACKGROUND_RED) expect += 1;
1104 if (i & BACKGROUND_INTENSITY) expect += 60;
1105 sprintf(expect_buf, "\x1b[%um", expect);
1106 expect_output_sequence_ctx(i, expect_buf);
1108 if (!skip_sequence("\x1b[10C"))
1109 expect_output_sequence_ctx(i, "\x1b[4;13H"); /* set cursor */
1110 expect_output_sequence("a");
1111 if (!skip_sequence("\x1b[11D"))
1112 expect_output_sequence("\x1b[4;3H"); /* set cursor */
1113 expect_output_sequence("\x1b[?25h"); /* show cursor */
1114 expect_empty_output();
1117 char_info_buf[0].Attributes = FOREGROUND_GREEN;
1118 char_info_buf[1].Attributes = FOREGROUND_GREEN | BACKGROUND_RED;
1119 char_info_buf[2].Attributes = BACKGROUND_RED;
1120 child_write_output(char_info_buf, /* size */ 7, 8, /* coord */ 0, 0,
1121 /* region */ 7, 0, 9, 0, /* out region */ 7, 0, 9, 0);
1122 expect_hide_cursor();
1123 skip_sequence("\x1b[m"); /* default attr */
1124 expect_output_sequence("\x1b[32m"); /* foreground black */
1125 expect_output_sequence("\x1b[1;8H"); /* set cursor */
1126 expect_output_sequence("0");
1127 expect_output_sequence("\x1b[41m"); /* background red */
1128 expect_output_sequence("1");
1129 expect_output_sequence("\x1b[30m"); /* foreground black */
1130 expect_output_sequence("2");
1131 expect_output_sequence("\x1b[4;3H"); /* set cursor */
1132 expect_output_sequence("\x1b[?25h"); /* show cursor */
1133 expect_empty_output();
1135 child_fill_character('i', 5, 15, 16);
1136 expect_hide_cursor();
1137 expect_output_sequence("\x1b[m"); /* default attributes */
1138 expect_output_sequence("\x1b[17;16H"); /* set cursor */
1139 expect_output_sequence("iiiii");
1140 expect_output_sequence("\x1b[4;3H"); /* set cursor */
1141 expect_output_sequence("\x1b[?25h"); /* show cursor */
1142 expect_empty_output();
1144 test_write_console();
1146 sb = child_create_screen_buffer();
1147 child_set_active(sb);
1148 expect_hide_cursor();
1149 expect_output_sequence("\x1b[H"); /* set cursor */
1150 for (i = 0; i < 40; i++)
1152 expect_erase_line(30);
1153 if (i != 39) expect_output_sequence("\r\n");
1155 expect_output_sequence("\x1b[H"); /* set cursor */
1156 expect_output_sequence("\x1b[?25h"); /* show cursor */
1157 expect_empty_output();
1159 child_write_characters(L"new sb", 0, 0);
1160 skip_hide_cursor();
1161 expect_output_sequence("new sb");
1162 ok(skip_sequence("\x1b[H") || skip_sequence("\r"), "expected set cursor\n");
1163 skip_sequence("\x1b[?25h"); /* show cursor */
1164 expect_empty_output();
1166 sb2 = child_create_screen_buffer();
1167 child_set_active(sb2);
1168 expect_hide_cursor();
1169 for (i = 0; i < 40; i++)
1171 expect_erase_line(30);
1172 if (i != 39) expect_output_sequence("\r\n");
1174 expect_output_sequence("\x1b[H"); /* set cursor */
1175 expect_output_sequence("\x1b[?25h"); /* show cursor */
1176 expect_empty_output();
1178 child_set_active(sb);
1179 expect_hide_cursor();
1180 expect_output_sequence("new sb");
1181 expect_erase_line(24);
1182 expect_output_sequence("\r\n");
1183 for (i = 1; i < 40; i++)
1185 expect_erase_line(30);
1186 if (i != 39) expect_output_sequence("\r\n");
1188 expect_output_sequence("\x1b[H"); /* set cursor */
1189 expect_output_sequence("\x1b[?25h"); /* show cursor */
1190 expect_empty_output();
1193 static void write_console_pipe(const char *buf)
1195 DWORD written;
1196 BOOL res;
1197 res = WriteFile(console_pipe, buf, strlen(buf), &written, NULL);
1198 ok(res, "WriteFile failed: %u\n", GetLastError());
1201 static void test_read_console(void)
1203 child_set_input_mode(child_pipe, ENABLE_PROCESSED_INPUT);
1205 child_read_console(child_pipe, 100);
1206 write_console_pipe("abc");
1207 expect_empty_output();
1208 child_expect_read_result(child_pipe, L"abc");
1209 expect_empty_output();
1211 child_read_console(child_pipe, 1);
1212 write_console_pipe("xyz");
1213 child_expect_read_result(child_pipe, L"x");
1214 child_read_console(child_pipe, 100);
1215 child_expect_read_result(child_pipe, L"yz");
1216 expect_empty_output();
1218 child_set_input_cp(932);
1220 child_read_console_a(child_pipe, 2);
1221 write_console_pipe("\xe3\x81\x81");
1222 child_expect_read_result_a(child_pipe, "\x82\x9f");
1223 expect_empty_output();
1225 child_read_console_a(child_pipe, 1);
1226 write_console_pipe("\xe3\x81\x81""a");
1227 child_expect_read_result_a(child_pipe, "\x82\xcc");
1228 child_read_console_a(child_pipe, 1);
1229 child_expect_read_result_a(child_pipe, "a");
1230 expect_empty_output();
1232 child_read_console_a(child_pipe, 2);
1233 write_console_pipe("a\xe3\x81\x81""b");
1234 child_expect_read_result_a(child_pipe, "a\x82\xcc");
1235 child_read_console_a(child_pipe, 1);
1236 child_expect_read_result_a(child_pipe, "b");
1237 expect_empty_output();
1239 child_read_console_file(child_pipe, 2);
1240 write_console_pipe("\xe3\x81\x81");
1241 child_expect_read_result_a(child_pipe, "\x82\x9f");
1242 expect_empty_output();
1244 child_read_console_file(child_pipe, 1);
1245 write_console_pipe("\xe3\x81\x81""a");
1246 child_expect_read_result_a(child_pipe, "\x82\xcc");
1247 child_read_console_file(child_pipe, 1);
1248 child_expect_read_result_a(child_pipe, "a");
1249 expect_empty_output();
1251 child_read_console_file(child_pipe, 2);
1252 write_console_pipe("a\xe3\x81\x81""b");
1253 child_expect_read_result_a(child_pipe, "a\x82\xcc");
1254 child_read_console_file(child_pipe, 1);
1255 child_expect_read_result_a(child_pipe, "b");
1256 expect_empty_output();
1258 child_set_input_cp(437);
1260 child_set_input_mode(child_pipe, ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
1261 ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT | ENABLE_INSERT_MODE |
1262 ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS | ENABLE_AUTO_POSITION);
1264 child_read_console(child_pipe, 100);
1265 write_console_pipe("xyz");
1266 skip_hide_cursor();
1267 expect_output_sequence("xyz");
1268 skip_sequence("\x1b[?25h"); /* show cursor */
1269 write_console_pipe("ab\r\n");
1270 child_expect_read_result(child_pipe, L"xyzab\r\n");
1271 skip_hide_cursor();
1272 expect_output_sequence("ab\r\n");
1273 skip_sequence("\x1b[?25h"); /* show cursor */
1274 expect_key_input('\r', VK_RETURN, 0, FALSE);
1275 expect_key_pressed('\n', VK_RETURN, LEFT_CTRL_PRESSED);
1276 expect_empty_output();
1279 static void test_tty_input(void)
1281 INPUT_RECORD ir;
1282 unsigned int i;
1283 char buf[8];
1285 static const struct
1287 const char *str;
1288 WCHAR ch;
1289 unsigned int vk;
1290 unsigned int ctrl;
1291 } escape_test[] = {
1292 { "\x1b[A", 0, VK_UP, 0 },
1293 { "\x1b[B", 0, VK_DOWN, 0 },
1294 { "\x1b[C", 0, VK_RIGHT, 0 },
1295 { "\x1b[D", 0, VK_LEFT, 0 },
1296 { "\x1b[H", 0, VK_HOME, 0 },
1297 { "\x1b[F", 0, VK_END, 0 },
1298 { "\x1b[2~", 0, VK_INSERT, 0 },
1299 { "\x1b[3~", 0, VK_DELETE, 0 },
1300 { "\x1b[5~", 0, VK_PRIOR, 0 },
1301 { "\x1b[6~", 0, VK_NEXT, 0 },
1302 { "\x1b[15~", 0, VK_F5, 0 },
1303 { "\x1b[17~", 0, VK_F6, 0 },
1304 { "\x1b[18~", 0, VK_F7, 0 },
1305 { "\x1b[19~", 0, VK_F8, 0 },
1306 { "\x1b[20~", 0, VK_F9, 0 },
1307 { "\x1b[21~", 0, VK_F10, 0 },
1308 /* 0x10 */
1309 { "\x1b[23~", 0, VK_F11, 0 },
1310 { "\x1b[24~", 0, VK_F12, 0 },
1311 { "\x1bOP", 0, VK_F1, 0 },
1312 { "\x1bOQ", 0, VK_F2, 0 },
1313 { "\x1bOR", 0, VK_F3, 0 },
1314 { "\x1bOS", 0, VK_F4, 0 },
1315 { "\x1b[1;1A", 0, VK_UP, 0 },
1316 { "\x1b[1;2A", 0, VK_UP, SHIFT_PRESSED },
1317 { "\x1b[1;3A", 0, VK_UP, LEFT_ALT_PRESSED },
1318 { "\x1b[1;4A", 0, VK_UP, SHIFT_PRESSED | LEFT_ALT_PRESSED },
1319 { "\x1b[1;5A", 0, VK_UP, LEFT_CTRL_PRESSED },
1320 { "\x1b[1;6A", 0, VK_UP, SHIFT_PRESSED | LEFT_CTRL_PRESSED },
1321 { "\x1b[1;7A", 0, VK_UP, LEFT_ALT_PRESSED | LEFT_CTRL_PRESSED },
1322 { "\x1b[1;8A", 0, VK_UP, SHIFT_PRESSED | LEFT_ALT_PRESSED | LEFT_CTRL_PRESSED },
1323 { "\x1b[1;9A", 0, VK_UP, 0 },
1324 { "\x1b[1;10A", 0, VK_UP, SHIFT_PRESSED },
1325 /* 0x20 */
1326 { "\x1b[1;11A", 0, VK_UP, LEFT_ALT_PRESSED },
1327 { "\x1b[1;12A", 0, VK_UP, SHIFT_PRESSED | LEFT_ALT_PRESSED },
1328 { "\x1b[1;13A", 0, VK_UP, LEFT_CTRL_PRESSED },
1329 { "\x1b[1;14A", 0, VK_UP, SHIFT_PRESSED | LEFT_CTRL_PRESSED },
1330 { "\x1b[1;15A", 0, VK_UP, LEFT_ALT_PRESSED | LEFT_CTRL_PRESSED },
1331 { "\x1b[1;16A", 0, VK_UP, SHIFT_PRESSED | LEFT_ALT_PRESSED | LEFT_CTRL_PRESSED },
1332 { "\x1b[1;2P", 0, VK_F1, SHIFT_PRESSED },
1333 { "\x1b[2;3~", 0, VK_INSERT, LEFT_ALT_PRESSED },
1334 { "\x1b[2;3;5;6~", 0, VK_INSERT, 0 },
1335 { "\x1b[6;2;3;5;1~", 0, VK_NEXT, 0 },
1336 { "\xe4\xb8\x80", 0x4e00, 0, 0 },
1337 { "\x1b\x1b", 0x1b, VK_ESCAPE, LEFT_ALT_PRESSED },
1338 { "\x1b""1", '1', '1', LEFT_ALT_PRESSED },
1339 { "\x1b""x", 'x', 'X', LEFT_ALT_PRESSED },
1340 { "\x1b""[", '[', VK_OEM_4, LEFT_ALT_PRESSED },
1341 { "\x7f", '\b', VK_BACK, 0 },
1344 write_console_pipe("x");
1345 if (!get_input_key_vt())
1347 skip("Skipping tests on settings that don't have VT mapping for 'x'\n");
1348 get_input_key_vt();
1349 return;
1351 get_input_key_vt();
1353 write_console_pipe("aBCd");
1354 expect_char_key('a');
1355 expect_char_key('B');
1356 expect_char_key('C');
1357 expect_char_key('d');
1359 for (i = 1; i < 0x7f; i++)
1361 if (i == 3 || i == '\n' || i == 0x1b || i == 0x1f) continue;
1362 buf[0] = i;
1363 buf[1] = 0;
1364 write_console_pipe(buf);
1365 if (i == 8)
1366 expect_key_pressed('\b', 'H', LEFT_CTRL_PRESSED);
1367 else if (i == 0x7f)
1368 expect_char_key(8);
1369 else
1370 expect_char_key(i);
1373 write_console_pipe("\r\n");
1374 expect_key_pressed('\r', VK_RETURN, 0);
1375 expect_key_pressed('\n', VK_RETURN, LEFT_CTRL_PRESSED);
1377 write_console_pipe("\xc4\x85");
1378 if (get_key_input(VK_MENU, &ir))
1380 expect_key_input(0x105, 'A', TRUE, LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED);
1381 expect_key_input(0x105, 'A', FALSE, LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED);
1382 expect_key_input(0, VK_MENU, FALSE, ENHANCED_KEY);
1384 else
1386 expect_key_input(0x105, 0, TRUE, 0);
1387 expect_key_input(0x105, 0, FALSE, 0);
1390 for (i = 0; i < ARRAY_SIZE(escape_test); i++)
1392 write_console_pipe(escape_test[i].str);
1393 expect_key_pressed_ctx(i, escape_test[i].ch, escape_test[i].vk, escape_test[i].ctrl);
1396 for (i = 0x80; i < 0x100; i += 11)
1398 buf[0] = i;
1399 buf[1] = 0;
1400 write_console_pipe(buf);
1401 expect_empty_output();
1405 static void child_process(HANDLE pipe)
1407 HANDLE output, input;
1408 DWORD size, count;
1409 char buf[4096];
1410 BOOL ret;
1412 output = CreateFileA("CONOUT$", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
1413 ok(output != INVALID_HANDLE_VALUE, "could not open console output\n");
1415 input = CreateFileA("CONIN$", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
1416 ok(output != INVALID_HANDLE_VALUE, "could not open console output\n");
1418 while(ReadFile(pipe, buf, sizeof(buf), &size, NULL))
1420 const struct pseudoconsole_req *req = (void *)buf;
1421 switch (req->type)
1423 case REQ_CREATE_SCREEN_BUFFER:
1425 HANDLE handle;
1426 SetLastError(0xdeadbeef);
1427 handle = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
1428 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1429 CONSOLE_TEXTMODE_BUFFER, NULL);
1430 ok(handle != INVALID_HANDLE_VALUE, "CreateConsoleScreenBuffer failed: %u\n", GetLastError());
1431 ret = WriteFile(pipe, &handle, sizeof(handle), &count, NULL);
1432 ok(ret, "WriteFile failed: %u\n", GetLastError());
1433 break;
1436 case REQ_GET_INPUT:
1438 INPUT_RECORD record;
1439 ret = ReadConsoleInputW(input, &record, 1, &count);
1440 ok(ret, "ReadConsoleInputW failed: %u\n", GetLastError());
1441 ok(count == 1, "count = %u\n", count);
1442 ret = WriteFile(pipe, &record, sizeof(record), &count, NULL);
1443 ok(ret, "WriteFile failed: %u\n", GetLastError());
1444 break;
1447 case REQ_GET_SB_INFO:
1449 CONSOLE_SCREEN_BUFFER_INFO info;
1450 ret = GetConsoleScreenBufferInfo(output, &info);
1451 ok(ret, "GetConsoleScreenBufferInfo failed: %u\n", GetLastError());
1452 ret = WriteFile(pipe, &info, sizeof(info), &count, NULL);
1453 ok(ret, "WriteFile failed: %u\n", GetLastError());
1454 break;
1457 case REQ_READ_CONSOLE:
1458 ret = ReadConsoleW(input, buf, req->u.size, &count, NULL );
1459 ok(ret, "ReadConsoleW failed: %u\n", GetLastError());
1460 ret = WriteFile(pipe, buf, count * sizeof(WCHAR), NULL, NULL);
1461 ok(ret, "WriteFile failed: %u\n", GetLastError());
1462 break;
1464 case REQ_READ_CONSOLE_A:
1465 count = req->u.size;
1466 memset(buf, 0xcc, sizeof(buf));
1467 ret = ReadConsoleA(input, buf, count, &count, NULL );
1468 ok(ret, "ReadConsoleA failed: %u\n", GetLastError());
1469 ret = WriteFile(pipe, buf, count, NULL, NULL);
1470 ok(ret, "WriteFile failed: %u\n", GetLastError());
1471 break;
1473 case REQ_READ_CONSOLE_FILE:
1474 count = req->u.size;
1475 memset(buf, 0xcc, sizeof(buf));
1476 ret = ReadFile(input, buf, count, &count, NULL );
1477 ok(ret, "ReadFile failed: %u\n", GetLastError());
1478 ret = WriteFile(pipe, buf, count, NULL, NULL);
1479 ok(ret, "WriteFile failed: %u\n", GetLastError());
1480 break;
1482 case REQ_SCROLL:
1483 ret = ScrollConsoleScreenBufferW(output, &req->u.scroll.rect, NULL, req->u.scroll.dst, &req->u.scroll.fill);
1484 ok(ret, "ScrollConsoleScreenBuffer failed: %u\n", GetLastError());
1485 break;
1487 case REQ_FILL_CHAR:
1488 ret = FillConsoleOutputCharacterW(output, req->u.fill.ch, req->u.fill.count, req->u.fill.coord, &count);
1489 ok(ret, "FillConsoleOutputCharacter failed: %u\n", GetLastError());
1490 ok(count == req->u.fill.count, "count = %u, expected %u\n", count, req->u.fill.count);
1491 break;
1493 case REQ_SET_ACTIVE:
1494 output = req->u.handle;
1495 ret = SetConsoleActiveScreenBuffer(output);
1496 ok(ret, "SetConsoleActiveScreenBuffer failed: %u\n", GetLastError());
1497 break;
1499 case REQ_SET_CURSOR:
1500 ret = SetConsoleCursorPosition(output, req->u.coord);
1501 ok(ret, "SetConsoleCursorPosition failed: %u\n", GetLastError());
1502 break;
1504 case REQ_SET_INPUT_CP:
1505 ret = SetConsoleCP(req->u.cp);
1506 ok(ret, "SetConsoleCP failed: %u\n", GetLastError());
1507 break;
1509 case REQ_SET_INPUT_MODE:
1510 ret = SetConsoleMode(input, req->u.mode);
1511 ok(ret, "SetConsoleMode failed: %u\n", GetLastError());
1512 break;
1514 case REQ_SET_OUTPUT_MODE:
1515 ret = SetConsoleMode(output, req->u.mode);
1516 ok(ret, "SetConsoleMode failed: %u\n", GetLastError());
1517 break;
1519 case REQ_SET_TITLE:
1520 ret = SetConsoleTitleW(req->u.string);
1521 ok(ret, "SetConsoleTitleW failed: %u\n", GetLastError());
1522 break;
1524 case REQ_WRITE_CHARACTERS:
1525 ret = WriteConsoleOutputCharacterW(output, req->u.write_characters.buf,
1526 req->u.write_characters.len,
1527 req->u.write_characters.coord, &count);
1528 ok(ret, "WriteConsoleOutputCharacterW failed: %u\n", GetLastError());
1529 break;
1531 case REQ_WRITE_CONSOLE:
1532 ret = WriteConsoleW(output, req->u.string, lstrlenW(req->u.string), NULL, NULL);
1533 ok(ret, "SetConsoleTitleW failed: %u\n", GetLastError());
1534 break;
1536 case REQ_WRITE_OUTPUT:
1538 SMALL_RECT region = req->u.write_output.region;
1539 ret = WriteConsoleOutputW(output, req->u.write_output.buf, req->u.write_output.size, req->u.write_output.coord, &region);
1540 ok(ret, "WriteConsoleOutput failed: %u\n", GetLastError());
1541 ret = WriteFile(pipe, &region, sizeof(region), &count, NULL);
1542 ok(ret, "WriteFile failed: %u\n", GetLastError());
1543 break;
1546 default:
1547 ok(0, "unexpected request type %u\n", req->type);
1550 ok(GetLastError() == ERROR_BROKEN_PIPE, "ReadFile failed: %u\n", GetLastError());
1551 CloseHandle(output);
1552 CloseHandle(input);
1555 static HANDLE run_child(HANDLE console, HANDLE pipe)
1557 STARTUPINFOEXA startup = {{ sizeof(startup) }};
1558 char **argv, cmdline[MAX_PATH];
1559 PROCESS_INFORMATION info;
1560 SIZE_T size;
1561 BOOL ret;
1563 InitializeProcThreadAttributeList(NULL, 1, 0, &size);
1564 startup.lpAttributeList = HeapAlloc(GetProcessHeap(), 0, size);
1565 InitializeProcThreadAttributeList(startup.lpAttributeList, 1, 0, &size);
1566 UpdateProcThreadAttribute(startup.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, console,
1567 sizeof(console), NULL, NULL);
1569 winetest_get_mainargs(&argv);
1570 sprintf(cmdline, "\"%s\" %s child %p", argv[0], argv[1], pipe);
1571 ret = CreateProcessA(NULL, cmdline, NULL, NULL, TRUE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL,
1572 &startup.StartupInfo, &info);
1573 ok(ret, "CreateProcessW failed: %u\n", GetLastError());
1575 CloseHandle(info.hThread);
1576 HeapFree(GetProcessHeap(), 0, startup.lpAttributeList);
1577 return info.hProcess;
1580 static HPCON create_pseudo_console(HANDLE *console_pipe_end, HANDLE *child_process)
1582 SECURITY_ATTRIBUTES sec_attr = { sizeof(sec_attr), NULL, TRUE };
1583 HANDLE child_pipe_end;
1584 COORD size = { 30, 40 };
1585 DWORD read_mode;
1586 HPCON console;
1587 HRESULT hres;
1588 BOOL r;
1590 console_pipe = CreateNamedPipeW(L"\\\\.\\pipe\\pseudoconsoleconn", PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
1591 PIPE_WAIT | PIPE_TYPE_BYTE, 1, 4096, 4096, NMPWAIT_USE_DEFAULT_WAIT, NULL);
1592 ok(console_pipe != INVALID_HANDLE_VALUE, "CreateNamedPipeW failed: %u\n", GetLastError());
1594 *console_pipe_end = CreateFileW(L"\\\\.\\pipe\\pseudoconsoleconn", GENERIC_READ | GENERIC_WRITE,
1595 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
1596 ok(*console_pipe_end != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError());
1598 child_pipe = CreateNamedPipeW(L"\\\\.\\pipe\\pseudoconsoleserver", PIPE_ACCESS_DUPLEX,
1599 PIPE_WAIT | PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 1, 5000, 6000,
1600 NMPWAIT_USE_DEFAULT_WAIT, NULL);
1601 ok(child_pipe != INVALID_HANDLE_VALUE, "CreateNamedPipeW failed: %u\n", GetLastError());
1603 child_pipe_end = CreateFileW(L"\\\\.\\pipe\\pseudoconsoleserver", GENERIC_READ | GENERIC_WRITE, 0,
1604 &sec_attr, OPEN_EXISTING, 0, NULL);
1605 ok(child_pipe_end != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError());
1607 read_mode = PIPE_READMODE_MESSAGE;
1608 r = SetNamedPipeHandleState(child_pipe_end, &read_mode, NULL, NULL);
1609 ok(r, "SetNamedPipeHandleState failed: %u\n", GetLastError());
1611 hres = pCreatePseudoConsole(size, *console_pipe_end, *console_pipe_end, 0, &console);
1612 ok(hres == S_OK, "CreatePseudoConsole failed: %08x\n", hres);
1614 *child_process = run_child(console, child_pipe_end);
1615 CloseHandle(child_pipe_end);
1616 return console;
1619 static void test_pseudoconsole(void)
1621 HANDLE console_pipe_end, child_process;
1622 BOOL broken_version;
1623 HPCON console;
1625 console = create_pseudo_console(&console_pipe_end, &child_process);
1627 child_string_request(REQ_SET_TITLE, L"test title");
1628 expect_output_sequence("\x1b[2J"); /* erase display */
1629 skip_hide_cursor();
1630 expect_output_sequence("\x1b[m"); /* default attributes */
1631 expect_output_sequence("\x1b[H"); /* set cursor */
1632 skip_sequence("\x1b[H"); /* some windows versions emit it twice */
1633 expect_output_sequence("\x1b]0;test title"); /* set title */
1634 broken_version = skip_byte(0); /* some win versions emit nullbyte */
1635 expect_output_sequence("\x07");
1636 skip_sequence("\x1b[?25h"); /* show cursor */
1637 expect_empty_output();
1639 if (!broken_version)
1641 test_tty_output();
1642 test_read_console();
1643 test_tty_input();
1645 else win_skip("Skipping tty output tests on broken Windows version\n");
1647 CloseHandle(child_pipe);
1648 wait_child_process(child_process);
1649 CloseHandle(child_process);
1651 /* native sometimes clears the screen here */
1652 if (skip_sequence("\x1b[25l"))
1654 unsigned int i;
1655 skip_sequence("\x1b[H");
1656 for (i = 0; i < 40; i++)
1658 expect_output_sequence("\x1b[K");
1659 if (i != 39) expect_output_sequence("\r\n");
1661 skip_sequence("\x1b[H\x1b[?25h");
1663 expect_empty_output();
1665 pClosePseudoConsole(console);
1666 CloseHandle(console_pipe_end);
1667 CloseHandle(console_pipe);
1670 START_TEST(tty)
1672 HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll");
1673 char **argv;
1674 int argc;
1676 argc = winetest_get_mainargs(&argv);
1677 if (argc > 3)
1679 HANDLE pipe;
1680 DWORD mode;
1681 sscanf(argv[3], "%p", &pipe);
1682 /* if std output is console, silence debug output so it does not interfere with tests */
1683 if (GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &mode))
1684 winetest_debug = 0;
1685 child_process(pipe);
1686 return;
1689 pCreatePseudoConsole = (void *)GetProcAddress(kernel32, "CreatePseudoConsole");
1690 pClosePseudoConsole = (void *)GetProcAddress(kernel32, "ClosePseudoConsole");
1691 if (!pCreatePseudoConsole)
1693 win_skip("CreatePseudoConsole is not available\n");
1694 return;
1697 test_pseudoconsole();