tty.c 62 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698
  1. /*
  2. * 2020 Jacek Caban for CodeWeavers
  3. *
  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.
  8. *
  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.
  13. *
  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
  17. */
  18. #include "wine/test.h"
  19. #include <windows.h>
  20. static HRESULT (WINAPI *pCreatePseudoConsole)(COORD,HANDLE,HANDLE,DWORD,HPCON*);
  21. static void (WINAPI *pClosePseudoConsole)(HPCON);
  22. static char console_output[4096];
  23. static unsigned int console_output_count;
  24. static HANDLE console_pipe;
  25. static HANDLE child_pipe;
  26. #define fetch_console_output() fetch_console_output_(__LINE__)
  27. static void fetch_console_output_(unsigned int line)
  28. {
  29. OVERLAPPED o;
  30. DWORD count;
  31. BOOL ret;
  32. if (console_output_count == sizeof(console_output)) return;
  33. memset(&o, 0, sizeof(o));
  34. o.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
  35. ret = ReadFile(console_pipe, console_output + console_output_count,
  36. sizeof(console_output) - console_output_count, NULL, &o);
  37. if (!ret)
  38. {
  39. ok_(__FILE__,line)(GetLastError() == ERROR_IO_PENDING, "read failed: %u\n", GetLastError());
  40. if (GetLastError() != ERROR_IO_PENDING) return;
  41. WaitForSingleObject(o.hEvent, 5000);
  42. }
  43. ret = GetOverlappedResult(console_pipe, &o, &count, FALSE);
  44. if (!ret && GetLastError() == ERROR_IO_INCOMPLETE)
  45. CancelIoEx(console_pipe, &o);
  46. ok_(__FILE__,line)(ret, "Read file failed: %u\n", GetLastError());
  47. CloseHandle(o.hEvent);
  48. if (ret) console_output_count += count;
  49. }
  50. #define expect_empty_output() expect_empty_output_(__LINE__)
  51. static void expect_empty_output_(unsigned int line)
  52. {
  53. DWORD avail;
  54. BOOL ret;
  55. ret = PeekNamedPipe(console_pipe, NULL, 0, NULL, &avail, NULL);
  56. ok_(__FILE__,line)(ret, "PeekNamedPipe failed: %u\n", GetLastError());
  57. ok_(__FILE__,line)(!avail, "avail = %u\n", avail);
  58. if (avail) fetch_console_output_(line);
  59. ok_(__FILE__,line)(!console_output_count, "expected empty buffer, got %s\n",
  60. wine_dbgstr_an(console_output, console_output_count));
  61. console_output_count = 0;
  62. }
  63. #define expect_output_sequence(a) expect_output_sequence_(__LINE__,0,a)
  64. #define expect_output_sequence_ctx(a,b) expect_output_sequence_(__LINE__,a,b)
  65. static void expect_output_sequence_(unsigned int line, unsigned ctx, const char *expect)
  66. {
  67. size_t len = strlen(expect);
  68. if (console_output_count < len) fetch_console_output_(line);
  69. if (len <= console_output_count && !memcmp(console_output, expect, len))
  70. {
  71. console_output_count -= len;
  72. memmove(console_output, console_output + len, console_output_count);
  73. }
  74. else ok_(__FILE__,line)(0, "%x: expected %s got %s\n", ctx, wine_dbgstr_a(expect),
  75. wine_dbgstr_an(console_output, console_output_count));
  76. }
  77. #define skip_sequence(a) skip_sequence_(__LINE__,a)
  78. static BOOL skip_sequence_(unsigned int line, const char *expect)
  79. {
  80. size_t len = strlen(expect);
  81. DWORD avail;
  82. BOOL r;
  83. r = PeekNamedPipe(console_pipe, NULL, 0, NULL, &avail, NULL);
  84. if (!console_output_count && r && !avail)
  85. {
  86. Sleep(50);
  87. r = PeekNamedPipe(console_pipe, NULL, 0, NULL, &avail, NULL);
  88. }
  89. if (r && avail) fetch_console_output_(line);
  90. if (len > console_output_count || memcmp(console_output, expect, len)) return FALSE;
  91. console_output_count -= len;
  92. memmove(console_output, console_output + len, console_output_count);
  93. return TRUE;
  94. }
  95. #define skip_byte(a) skip_byte_(__LINE__,a)
  96. static BOOL skip_byte_(unsigned int line, char ch)
  97. {
  98. if (!console_output_count || console_output[0] != ch) return FALSE;
  99. console_output_count--;
  100. memmove(console_output, console_output + 1, console_output_count);
  101. return TRUE;
  102. }
  103. #define expect_hide_cursor() expect_hide_cursor_(__LINE__)
  104. static void expect_hide_cursor_(unsigned int line)
  105. {
  106. if (!console_output_count) fetch_console_output_(line);
  107. ok_(__FILE__,line)(skip_sequence_(line, "\x1b[?25l") || broken(skip_sequence_(line, "\x1b[25l")),
  108. "expected hide cursor escape\n");
  109. }
  110. #define skip_hide_cursor() skip_hide_cursor_(__LINE__)
  111. static BOOL skip_hide_cursor_(unsigned int line)
  112. {
  113. if (!console_output_count) fetch_console_output_(line);
  114. return skip_sequence_(line, "\x1b[25l") || broken(skip_sequence_(line, "\x1b[?25l"));
  115. }
  116. #define expect_erase_line(a) expect_erase_line_(__LINE__,a)
  117. static BOOL expect_erase_line_(unsigned line, unsigned int cnt)
  118. {
  119. char buf[16];
  120. if (skip_sequence("\x1b[K")) return FALSE;
  121. ok(broken(1), "expected erase line\n");
  122. sprintf(buf, "\x1b[%uX", cnt);
  123. expect_output_sequence_(line, cnt, buf); /* erase the rest of the line */
  124. sprintf(buf, "\x1b[%uC", cnt);
  125. expect_output_sequence_(line, cnt, buf); /* move cursor to the end of the line */
  126. return TRUE;
  127. }
  128. enum req_type
  129. {
  130. REQ_CREATE_SCREEN_BUFFER,
  131. REQ_FILL_CHAR,
  132. REQ_GET_INPUT,
  133. REQ_GET_SB_INFO,
  134. REQ_READ_CONSOLE,
  135. REQ_READ_CONSOLE_A,
  136. REQ_READ_CONSOLE_FILE,
  137. REQ_SCROLL,
  138. REQ_SET_ACTIVE,
  139. REQ_SET_CURSOR,
  140. REQ_SET_INPUT_CP,
  141. REQ_SET_INPUT_MODE,
  142. REQ_SET_OUTPUT_MODE,
  143. REQ_SET_TITLE,
  144. REQ_WRITE_CHARACTERS,
  145. REQ_WRITE_CONSOLE,
  146. REQ_WRITE_OUTPUT,
  147. };
  148. struct pseudoconsole_req
  149. {
  150. enum req_type type;
  151. union
  152. {
  153. WCHAR string[1];
  154. COORD coord;
  155. HANDLE handle;
  156. DWORD mode;
  157. int cp;
  158. size_t size;
  159. struct
  160. {
  161. COORD coord;
  162. unsigned int len;
  163. WCHAR buf[1];
  164. } write_characters;
  165. struct
  166. {
  167. COORD size;
  168. COORD coord;
  169. SMALL_RECT region;
  170. CHAR_INFO buf[1];
  171. } write_output;
  172. struct
  173. {
  174. SMALL_RECT rect;
  175. COORD dst;
  176. CHAR_INFO fill;
  177. } scroll;
  178. struct
  179. {
  180. WCHAR ch;
  181. DWORD count;
  182. COORD coord;
  183. } fill;
  184. } u;
  185. };
  186. static void child_string_request(enum req_type type, const WCHAR *title)
  187. {
  188. char buf[4096];
  189. struct pseudoconsole_req *req = (void *)buf;
  190. size_t len = lstrlenW(title) + 1;
  191. DWORD count;
  192. BOOL ret;
  193. req->type = type;
  194. memcpy(req->u.string, title, len * sizeof(WCHAR));
  195. ret = WriteFile(child_pipe, req, FIELD_OFFSET(struct pseudoconsole_req, u.string[len]),
  196. &count, NULL);
  197. ok(ret, "WriteFile failed: %u\n", GetLastError());
  198. }
  199. static void child_write_characters(const WCHAR *buf, unsigned int x, unsigned int y)
  200. {
  201. char req_buf[4096];
  202. struct pseudoconsole_req *req = (void *)req_buf;
  203. size_t len = lstrlenW(buf);
  204. DWORD count;
  205. BOOL ret;
  206. req->type = REQ_WRITE_CHARACTERS;
  207. req->u.write_characters.coord.X = x;
  208. req->u.write_characters.coord.Y = y;
  209. req->u.write_characters.len = len;
  210. memcpy(req->u.write_characters.buf, buf, len * sizeof(WCHAR));
  211. ret = WriteFile(child_pipe, req, FIELD_OFFSET(struct pseudoconsole_req, u.write_characters.buf[len + 1]),
  212. &count, NULL);
  213. ok(ret, "WriteFile failed: %u\n", GetLastError());
  214. }
  215. static void child_set_cursor(const unsigned int x, unsigned int y)
  216. {
  217. struct pseudoconsole_req req;
  218. DWORD count;
  219. BOOL ret;
  220. req.type = REQ_SET_CURSOR;
  221. req.u.coord.X = x;
  222. req.u.coord.Y = y;
  223. ret = WriteFile(child_pipe, &req, sizeof(req), &count, NULL);
  224. ok(ret, "WriteFile failed: %u\n", GetLastError());
  225. }
  226. static HANDLE child_create_screen_buffer(void)
  227. {
  228. struct pseudoconsole_req req;
  229. HANDLE handle;
  230. DWORD count;
  231. BOOL ret;
  232. req.type = REQ_CREATE_SCREEN_BUFFER;
  233. ret = WriteFile(child_pipe, &req, sizeof(req), &count, NULL);
  234. ok(ret, "WriteFile failed: %u\n", GetLastError());
  235. ret = ReadFile(child_pipe, &handle, sizeof(handle), &count, NULL);
  236. ok(ret, "ReadFile failed: %u\n", GetLastError());
  237. return handle;
  238. }
  239. static void child_set_active(HANDLE handle)
  240. {
  241. struct pseudoconsole_req req;
  242. DWORD count;
  243. BOOL ret;
  244. req.type = REQ_SET_ACTIVE;
  245. req.u.handle = handle;
  246. ret = WriteFile(child_pipe, &req, sizeof(req), &count, NULL);
  247. ok(ret, "WriteFile failed: %u\n", GetLastError());
  248. }
  249. #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)
  250. static void child_write_output_(unsigned int line, CHAR_INFO *buf, unsigned int size_x, unsigned int size_y,
  251. unsigned int coord_x, unsigned int coord_y, unsigned int left,
  252. unsigned int top, unsigned int right, unsigned int bottom, unsigned int out_left,
  253. unsigned int out_top, unsigned int out_right, unsigned int out_bottom)
  254. {
  255. char req_buf[4096];
  256. struct pseudoconsole_req *req = (void *)req_buf;
  257. SMALL_RECT region;
  258. DWORD count;
  259. BOOL ret;
  260. req->type = REQ_WRITE_OUTPUT;
  261. req->u.write_output.size.X = size_x;
  262. req->u.write_output.size.Y = size_y;
  263. req->u.write_output.coord.X = coord_x;
  264. req->u.write_output.coord.Y = coord_y;
  265. req->u.write_output.region.Left = left;
  266. req->u.write_output.region.Top = top;
  267. req->u.write_output.region.Right = right;
  268. req->u.write_output.region.Bottom = bottom;
  269. memcpy(req->u.write_output.buf, buf, size_x * size_y * sizeof(*buf));
  270. ret = WriteFile(child_pipe, req, FIELD_OFFSET(struct pseudoconsole_req, u.write_output.buf[size_x * size_y]), &count, NULL);
  271. ok_(__FILE__,line)(ret, "WriteFile failed: %u\n", GetLastError());
  272. ret = ReadFile(child_pipe, &region, sizeof(region), &count, NULL);
  273. ok_(__FILE__,line)(ret, "WriteFile failed: %u\n", GetLastError());
  274. ok_(__FILE__,line)(region.Left == out_left, "Left = %u\n", region.Left);
  275. ok_(__FILE__,line)(region.Top == out_top, "Top = %u\n", region.Top);
  276. ok_(__FILE__,line)(region.Right == out_right, "Right = %u\n", region.Right);
  277. ok_(__FILE__,line)(region.Bottom == out_bottom, "Bottom = %u\n", region.Bottom);
  278. }
  279. static void child_scroll(unsigned int src_left, unsigned int src_top, unsigned int src_right,
  280. unsigned int src_bottom, unsigned int dst_x, unsigned int dst_y, WCHAR fill)
  281. {
  282. struct pseudoconsole_req req;
  283. DWORD count;
  284. BOOL ret;
  285. req.type = REQ_SCROLL;
  286. req.u.scroll.rect.Left = src_left;
  287. req.u.scroll.rect.Top = src_top;
  288. req.u.scroll.rect.Right = src_right;
  289. req.u.scroll.rect.Bottom = src_bottom;
  290. req.u.scroll.dst.X = dst_x;
  291. req.u.scroll.dst.Y = dst_y;
  292. req.u.scroll.fill.Char.UnicodeChar = fill;
  293. req.u.scroll.fill.Attributes = 0;
  294. ret = WriteFile(child_pipe, &req, sizeof(req), &count, NULL);
  295. ok(ret, "WriteFile failed: %u\n", GetLastError());
  296. }
  297. static void child_fill_character(WCHAR ch, DWORD count, int x, int y)
  298. {
  299. struct pseudoconsole_req req;
  300. BOOL ret;
  301. req.type = REQ_FILL_CHAR;
  302. req.u.fill.ch = ch;
  303. req.u.fill.count = count;
  304. req.u.fill.coord.X = x;
  305. req.u.fill.coord.Y = y;
  306. ret = WriteFile(child_pipe, &req, sizeof(req), &count, NULL);
  307. ok(ret, "WriteFile failed: %u\n", GetLastError());
  308. }
  309. static void child_set_input_mode(HANDLE pipe, DWORD mode)
  310. {
  311. struct pseudoconsole_req req;
  312. DWORD count;
  313. BOOL ret;
  314. req.type = REQ_SET_INPUT_MODE;
  315. req.u.mode = mode;
  316. ret = WriteFile(pipe, &req, sizeof(req), &count, NULL);
  317. ok(ret, "WriteFile failed: %u\n", GetLastError());
  318. }
  319. static void child_set_output_mode(DWORD mode)
  320. {
  321. struct pseudoconsole_req req;
  322. DWORD count;
  323. BOOL ret;
  324. req.type = REQ_SET_OUTPUT_MODE;
  325. req.u.mode = mode;
  326. ret = WriteFile(child_pipe, &req, sizeof(req), &count, NULL);
  327. ok(ret, "WriteFile failed: %u\n", GetLastError());
  328. }
  329. static void child_set_input_cp(int cp)
  330. {
  331. struct pseudoconsole_req req;
  332. DWORD count;
  333. BOOL ret;
  334. req.type = REQ_SET_INPUT_CP;
  335. req.u.cp = cp;
  336. ret = WriteFile(child_pipe, &req, sizeof(req), &count, NULL);
  337. ok(ret, "WriteFile failed: %u\n", GetLastError());
  338. }
  339. static void child_read_console(HANDLE pipe, size_t size)
  340. {
  341. struct pseudoconsole_req req;
  342. DWORD count;
  343. BOOL ret;
  344. req.type = REQ_READ_CONSOLE;
  345. req.u.size = size;
  346. ret = WriteFile(pipe, &req, sizeof(req), &count, NULL);
  347. ok(ret, "WriteFile failed: %u\n", GetLastError());
  348. }
  349. static void child_read_console_a(HANDLE pipe, size_t size)
  350. {
  351. struct pseudoconsole_req req;
  352. DWORD count;
  353. BOOL ret;
  354. req.type = REQ_READ_CONSOLE_A;
  355. req.u.size = size;
  356. ret = WriteFile(pipe, &req, sizeof(req), &count, NULL);
  357. ok(ret, "WriteFile failed: %u\n", GetLastError());
  358. }
  359. static void child_read_console_file(HANDLE pipe, size_t size)
  360. {
  361. struct pseudoconsole_req req;
  362. DWORD count;
  363. BOOL ret;
  364. req.type = REQ_READ_CONSOLE_FILE;
  365. req.u.size = size;
  366. ret = WriteFile(pipe, &req, sizeof(req), &count, NULL);
  367. ok(ret, "WriteFile failed: %u\n", GetLastError());
  368. }
  369. #define child_expect_read_result(a,b) child_expect_read_result_(__LINE__,a,b)
  370. static void child_expect_read_result_(unsigned int line, HANDLE pipe, const WCHAR *expect)
  371. {
  372. size_t exlen = wcslen(expect);
  373. WCHAR buf[4096];
  374. DWORD count;
  375. BOOL ret;
  376. ret = ReadFile(pipe, buf, sizeof(buf), &count, NULL);
  377. ok_(__FILE__,line)(ret, "ReadFile failed: %u\n", GetLastError());
  378. ok_(__FILE__,line)(count == exlen * sizeof(WCHAR), "got %u, expected %u\n",
  379. count, exlen * sizeof(WCHAR));
  380. buf[count / sizeof(WCHAR)] = 0;
  381. ok_(__FILE__,line)(!memcmp(expect, buf, count), "unexpected data %s\n", wine_dbgstr_w(buf));
  382. }
  383. #define child_expect_read_result_a(a,b) child_expect_read_result_a_(__LINE__,a,b)
  384. static void child_expect_read_result_a_(unsigned int line, HANDLE pipe, const char *expect)
  385. {
  386. size_t exlen = strlen(expect);
  387. char buf[4096];
  388. DWORD count;
  389. BOOL ret;
  390. ret = ReadFile(pipe, buf, sizeof(buf), &count, NULL);
  391. ok_(__FILE__,line)(ret, "ReadFile failed: %u\n", GetLastError());
  392. todo_wine_if(exlen && expect[exlen - 1] == '\xcc')
  393. ok_(__FILE__,line)(count == exlen, "got %u, expected %u\n", count, exlen);
  394. buf[count] = 0;
  395. ok_(__FILE__,line)(!memcmp(expect, buf, count), "unexpected data %s\n", wine_dbgstr_a(buf));
  396. }
  397. static void expect_input(unsigned int event_type, INPUT_RECORD *record)
  398. {
  399. struct pseudoconsole_req req = { REQ_GET_INPUT };
  400. INPUT_RECORD input;
  401. DWORD read;
  402. BOOL ret;
  403. ret = WriteFile(child_pipe, &req, sizeof(req), &read, NULL);
  404. ok(ret, "WriteFile failed: %u\n", GetLastError());
  405. ret = ReadFile(child_pipe, &input, sizeof(input), &read, NULL);
  406. ok(ret, "ReadFile failed: %u\n", GetLastError());
  407. ok(input.EventType == event_type, "EventType = %u, expected %u\n", input.EventType, event_type);
  408. if (record) *record = input;
  409. }
  410. static BOOL get_key_input(unsigned int vt, INPUT_RECORD *record)
  411. {
  412. static INPUT_RECORD prev_record;
  413. static BOOL have_prev_record;
  414. if (!have_prev_record)
  415. {
  416. expect_input(KEY_EVENT, &prev_record);
  417. have_prev_record = TRUE;
  418. }
  419. if (vt && prev_record.Event.KeyEvent.wVirtualKeyCode != vt) return FALSE;
  420. *record = prev_record;
  421. have_prev_record = FALSE;
  422. return TRUE;
  423. }
  424. #define expect_key_input(a,b,c,d) expect_key_input_(__LINE__,0,a,b,c,d)
  425. static void expect_key_input_(unsigned int line, unsigned int ctx, WCHAR ch, unsigned int vk,
  426. BOOL down, unsigned int ctrl_state)
  427. {
  428. unsigned int vs = MapVirtualKeyW(vk, MAPVK_VK_TO_VSC);
  429. INPUT_RECORD record;
  430. get_key_input(0, &record);
  431. ok_(__FILE__,line)(record.Event.KeyEvent.bKeyDown == down, "%x: bKeyDown = %x\n",
  432. ctx, record.Event.KeyEvent.bKeyDown);
  433. ok_(__FILE__,line)(record.Event.KeyEvent.wRepeatCount == 1, "%x: wRepeatCount = %x\n",
  434. ctx, record.Event.KeyEvent.wRepeatCount);
  435. ok_(__FILE__,line)(record.Event.KeyEvent.uChar.UnicodeChar == ch, "%x: UnicodeChar = %x\n",
  436. ctx, record.Event.KeyEvent.uChar.UnicodeChar);
  437. ok_(__FILE__,line)(record.Event.KeyEvent.wVirtualKeyCode == vk,
  438. "%x: wVirtualKeyCode = %x, expected %x\n", ctx,
  439. record.Event.KeyEvent.wVirtualKeyCode, vk);
  440. ok_(__FILE__,line)(record.Event.KeyEvent.wVirtualScanCode == vs,
  441. "%x: wVirtualScanCode = %x expected %x\n", ctx,
  442. record.Event.KeyEvent.wVirtualScanCode, vs);
  443. ok_(__FILE__,line)(record.Event.KeyEvent.dwControlKeyState == ctrl_state,
  444. "%x: dwControlKeyState = %x\n", ctx, record.Event.KeyEvent.dwControlKeyState);
  445. }
  446. #define get_input_key_vt() get_input_key_vt_(__LINE__)
  447. static unsigned int get_input_key_vt_(unsigned int line)
  448. {
  449. INPUT_RECORD record;
  450. get_key_input(0, &record);
  451. ok_(__FILE__,line)(record.Event.KeyEvent.wRepeatCount == 1, "wRepeatCount = %x\n",
  452. record.Event.KeyEvent.wRepeatCount);
  453. return record.Event.KeyEvent.wVirtualKeyCode;
  454. }
  455. #define expect_key_pressed(a,b,c) expect_key_pressed_(__LINE__,0,a,b,c)
  456. #define expect_key_pressed_ctx(a,b,c,d) expect_key_pressed_(__LINE__,a,b,c,d)
  457. static void expect_key_pressed_(unsigned int line, unsigned int ctx, WCHAR ch, unsigned int vk,
  458. unsigned int ctrl_state)
  459. {
  460. if (ctrl_state & SHIFT_PRESSED)
  461. expect_key_input_(line, ctx, 0, VK_SHIFT, TRUE, SHIFT_PRESSED);
  462. if (ctrl_state & LEFT_ALT_PRESSED)
  463. expect_key_input_(line, ctx, 0, VK_MENU, TRUE,
  464. LEFT_ALT_PRESSED | (ctrl_state & SHIFT_PRESSED));
  465. if (ctrl_state & LEFT_CTRL_PRESSED)
  466. expect_key_input_(line, ctx, 0, VK_CONTROL, TRUE,
  467. LEFT_CTRL_PRESSED | (ctrl_state & (SHIFT_PRESSED | LEFT_ALT_PRESSED)));
  468. expect_key_input_(line, ctx, ch, vk, TRUE, ctrl_state);
  469. expect_key_input_(line, ctx, ch, vk, FALSE, ctrl_state);
  470. if (ctrl_state & LEFT_CTRL_PRESSED)
  471. expect_key_input_(line, ctx, 0, VK_CONTROL, FALSE,
  472. ctrl_state & (SHIFT_PRESSED | LEFT_ALT_PRESSED));
  473. if (ctrl_state & LEFT_ALT_PRESSED)
  474. expect_key_input_(line, ctx, 0, VK_MENU, FALSE, ctrl_state & SHIFT_PRESSED);
  475. if (ctrl_state & SHIFT_PRESSED)
  476. expect_key_input_(line, ctx, 0, VK_SHIFT, FALSE, 0);
  477. }
  478. #define expect_char_key(a) expect_char_key_(__LINE__,a)
  479. static void expect_char_key_(unsigned int line, WCHAR ch)
  480. {
  481. unsigned int ctrl = 0, vk;
  482. vk = VkKeyScanW(ch);
  483. if (vk == ~0) vk = 0;
  484. if (vk & 0x0100) ctrl |= SHIFT_PRESSED;
  485. if (vk & 0x0200) ctrl |= LEFT_CTRL_PRESSED;
  486. vk &= 0xff;
  487. expect_key_pressed_(line, ch, ch, vk, ctrl);
  488. }
  489. #define test_cursor_pos(a,b) _test_cursor_pos(__LINE__,a,b)
  490. static void _test_cursor_pos(unsigned line, int expect_x, int expect_y)
  491. {
  492. struct pseudoconsole_req req = { REQ_GET_SB_INFO };
  493. CONSOLE_SCREEN_BUFFER_INFO info;
  494. DWORD read;
  495. BOOL ret;
  496. ret = WriteFile(child_pipe, &req, sizeof(req), &read, NULL);
  497. ok(ret, "WriteFile failed: %u\n", GetLastError());
  498. ret = ReadFile(child_pipe, &info, sizeof(info), &read, NULL);
  499. ok(ret, "ReadFile failed: %u\n", GetLastError());
  500. ok_(__FILE__,line)(info.dwCursorPosition.X == expect_x, "dwCursorPosition.X = %u, expected %u\n",
  501. info.dwCursorPosition.X, expect_x);
  502. ok_(__FILE__,line)(info.dwCursorPosition.Y == expect_y, "dwCursorPosition.Y = %u, expected %u\n",
  503. info.dwCursorPosition.Y, expect_y);
  504. }
  505. static void test_write_console(void)
  506. {
  507. child_set_output_mode(ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
  508. child_string_request(REQ_WRITE_CONSOLE, L"abc");
  509. skip_hide_cursor();
  510. expect_output_sequence("abc");
  511. skip_sequence("\x1b[?25h"); /* show cursor */
  512. child_string_request(REQ_WRITE_CONSOLE, L"\tt");
  513. skip_hide_cursor();
  514. if (!skip_sequence("\x1b[3C")) expect_output_sequence(" ");
  515. expect_output_sequence("t");
  516. skip_sequence("\x1b[?25h"); /* show cursor */
  517. expect_empty_output();
  518. child_string_request(REQ_WRITE_CONSOLE, L"x\rr");
  519. expect_hide_cursor();
  520. expect_output_sequence("\rr abc tx");
  521. if (!skip_sequence("\x1b[9D"))
  522. expect_output_sequence("\x1b[4;2H"); /* set cursor */
  523. expect_output_sequence("\x1b[?25h"); /* show cursor */
  524. expect_empty_output();
  525. child_string_request(REQ_WRITE_CONSOLE, L"yz\r\n");
  526. skip_hide_cursor();
  527. expect_output_sequence("yz\r\n");
  528. skip_sequence("\x1b[?25h"); /* show cursor */
  529. expect_empty_output();
  530. child_string_request(REQ_WRITE_CONSOLE, L"abc\r\n123\r\ncde\r");
  531. skip_hide_cursor();
  532. expect_output_sequence("abc\r\n123\r\ncde\r");
  533. skip_sequence("\x1b[?25h"); /* show cursor */
  534. expect_empty_output();
  535. child_set_cursor(0, 39);
  536. expect_hide_cursor();
  537. expect_output_sequence("\x1b[40;1H"); /* set cursor */
  538. expect_output_sequence("\x1b[?25h"); /* show cursor */
  539. expect_empty_output();
  540. child_string_request(REQ_WRITE_CONSOLE, L"yz\r\n");
  541. skip_hide_cursor();
  542. expect_output_sequence("yz\r");
  543. if (skip_sequence("\x1b[?25h")) /* show cursor */
  544. expect_output_sequence("\x1b[?25l"); /* hide cursor */
  545. expect_output_sequence("\n"); /* next line */
  546. if (skip_sequence("\x1b[30X")) /* erase the line */
  547. {
  548. expect_output_sequence("\x1b[30C"); /* move cursor to the end of the line */
  549. expect_output_sequence("\r");
  550. }
  551. skip_sequence("\x1b[?25h"); /* show cursor */
  552. expect_empty_output();
  553. child_string_request(REQ_WRITE_CONSOLE, L"");
  554. expect_empty_output();
  555. child_string_request(REQ_WRITE_CONSOLE, L"ab\n");
  556. skip_hide_cursor();
  557. expect_output_sequence("ab");
  558. if (skip_sequence("\x1b[?25h")) /* show cursor */
  559. expect_output_sequence("\x1b[?25l"); /* hide cursor */
  560. expect_output_sequence("\r\n"); /* next line */
  561. if (skip_sequence("\x1b[30X")) /* erase the line */
  562. {
  563. expect_output_sequence("\x1b[30C"); /* move cursor to the end of the line */
  564. expect_output_sequence("\r");
  565. }
  566. skip_sequence("\x1b[?25h"); /* show cursor */
  567. expect_empty_output();
  568. child_set_cursor(28, 10);
  569. expect_hide_cursor();
  570. expect_output_sequence("\x1b[11;29H"); /* set cursor */
  571. expect_output_sequence("\x1b[?25h"); /* show cursor */
  572. expect_empty_output();
  573. child_string_request(REQ_WRITE_CONSOLE, L"xy");
  574. skip_hide_cursor();
  575. expect_output_sequence("xy");
  576. if (!skip_sequence("\b")) skip_sequence("\r\n");
  577. skip_sequence("\x1b[?25h"); /* show cursor */
  578. expect_empty_output();
  579. child_set_cursor(28, 10);
  580. fetch_console_output();
  581. if (!skip_sequence("\b"))
  582. {
  583. expect_hide_cursor();
  584. expect_output_sequence("\x1b[11;29H"); /* set cursor */
  585. expect_output_sequence("\x1b[?25h"); /* show cursor */
  586. }
  587. expect_empty_output();
  588. child_string_request(REQ_WRITE_CONSOLE, L"abc");
  589. skip_hide_cursor();
  590. expect_output_sequence("\r ab");
  591. expect_output_sequence("\r\nc");
  592. if (expect_erase_line(29))
  593. expect_output_sequence("\x1b[12;2H"); /* set cursor */
  594. skip_sequence("\x1b[?25h"); /* show cursor */
  595. expect_empty_output();
  596. child_set_cursor(28, 39);
  597. expect_hide_cursor();
  598. expect_output_sequence("\x1b[40;29H"); /* set cursor */
  599. expect_output_sequence("\x1b[?25h"); /* show cursor */
  600. expect_empty_output();
  601. child_string_request(REQ_WRITE_CONSOLE, L"abc");
  602. skip_hide_cursor();
  603. expect_output_sequence("ab");
  604. skip_sequence("\x1b[40;29H"); /* set cursor */
  605. if (skip_sequence("\x1b[?25h")) /* show cursor */
  606. expect_output_sequence("\x1b[?25l"); /* hide cursor */
  607. else
  608. skip_sequence("\b");
  609. expect_output_sequence("\r\nc");
  610. if (skip_sequence("\x1b[29X")) /* erase the line */
  611. {
  612. expect_output_sequence("\x1b[29C"); /* move cursor to the end of the line */
  613. expect_output_sequence("\x1b[40;2H"); /* set cursor */
  614. }
  615. skip_sequence("\x1b[?25h"); /* show cursor */
  616. expect_empty_output();
  617. child_set_cursor(28, 39);
  618. skip_hide_cursor();
  619. if (!skip_sequence("\x1b[27C"))
  620. expect_output_sequence("\x1b[40;29H"); /* set cursor */
  621. skip_sequence("\x1b[?25h"); /* show cursor */
  622. expect_empty_output();
  623. child_string_request(REQ_WRITE_CONSOLE, L"XY");
  624. skip_hide_cursor();
  625. expect_output_sequence("XY");
  626. skip_sequence("\x1b[40;29H"); /* set cursor */
  627. if (skip_sequence("\x1b[?25h")) /* show cursor */
  628. skip_sequence("\x1b[?25l"); /* hide cursor */
  629. if (!skip_sequence("\b") && skip_sequence("\r\n"))
  630. {
  631. expect_output_sequence("\x1b[30X"); /* erase the line */
  632. expect_output_sequence("\x1b[30C"); /* move cursor to the end of the line */
  633. expect_output_sequence("\r"); /* set cursor */
  634. }
  635. skip_sequence("\x1b[?25h"); /* show cursor */
  636. expect_empty_output();
  637. child_string_request(REQ_WRITE_CONSOLE, L"\n");
  638. skip_hide_cursor();
  639. if (!skip_sequence("\r\n"))
  640. {
  641. expect_output_sequence("\n");
  642. expect_output_sequence("\x1b[30X"); /* erase the line */
  643. expect_output_sequence("\x1b[30C"); /* move cursor to the end of the line */
  644. expect_output_sequence("\r"); /* set cursor */
  645. }
  646. skip_sequence("\x1b[?25h"); /* show cursor */
  647. expect_empty_output();
  648. child_set_output_mode(ENABLE_PROCESSED_OUTPUT);
  649. child_set_cursor(28, 11);
  650. expect_hide_cursor();
  651. expect_output_sequence("\x1b[12;29H"); /* set cursor */
  652. skip_sequence("\x1b[?25h"); /* show cursor */
  653. child_string_request(REQ_WRITE_CONSOLE, L"xyz1234");
  654. skip_hide_cursor();
  655. expect_output_sequence("43\b");
  656. skip_sequence("\x1b[?25h"); /* show cursor */
  657. expect_empty_output();
  658. child_set_cursor(28, 11);
  659. skip_hide_cursor();
  660. expect_output_sequence("\b"); /* backspace */
  661. skip_sequence("\x1b[?25h"); /* show cursor */
  662. child_string_request(REQ_WRITE_CONSOLE, L"xyz123");
  663. expect_hide_cursor();
  664. expect_output_sequence("23");
  665. if (!skip_sequence("\x1b[2D"))
  666. expect_output_sequence("\x1b[12;29H");/* set cursor */
  667. expect_output_sequence("\x1b[?25h"); /* show cursor */
  668. expect_empty_output();
  669. child_set_cursor(28, 11);
  670. child_string_request(REQ_WRITE_CONSOLE, L"abcdef\n\r123456789012345678901234567890xyz");
  671. expect_hide_cursor();
  672. if (skip_sequence("\x1b[?25h")) expect_hide_cursor();
  673. expect_output_sequence("\r ef\r\n");
  674. expect_output_sequence("xyz456789012345678901234567890");
  675. if (!skip_sequence("\x1b[27D"))
  676. expect_output_sequence("\x1b[13;4H"); /* set cursor */
  677. expect_output_sequence("\x1b[?25h"); /* show cursor */
  678. expect_empty_output();
  679. child_set_cursor(28, 11);
  680. expect_hide_cursor();
  681. expect_output_sequence("\x1b[12;29H"); /* set cursor */
  682. expect_output_sequence("\x1b[?25h"); /* show cursor */
  683. child_string_request(REQ_WRITE_CONSOLE, L"AB\r\n");
  684. skip_hide_cursor();
  685. expect_output_sequence("AB\r\n");
  686. skip_sequence("\x1b[?25h"); /* show cursor */
  687. expect_empty_output();
  688. child_set_output_mode(ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
  689. child_set_cursor(28, 12);
  690. skip_hide_cursor();
  691. expect_output_sequence("\x1b[28C"); /* move cursor to the end of the line */
  692. skip_sequence("\x1b[?25h"); /* show cursor */
  693. expect_empty_output();
  694. child_string_request(REQ_WRITE_CONSOLE, L"ab");
  695. skip_hide_cursor();
  696. expect_output_sequence("ab");
  697. skip_sequence("\b");
  698. skip_sequence("\x1b[?25h"); /* show cursor */
  699. expect_empty_output();
  700. test_cursor_pos(29, 12);
  701. child_string_request(REQ_WRITE_CONSOLE, L"c");
  702. skip_hide_cursor();
  703. expect_output_sequence("\r\n");
  704. expect_output_sequence("c");
  705. skip_sequence("\x1b[?25h"); /* show cursor */
  706. expect_empty_output();
  707. test_cursor_pos(1, 13);
  708. child_set_cursor(28, 14);
  709. skip_hide_cursor();
  710. expect_output_sequence("\x1b[15;29H"); /* set cursor */
  711. skip_sequence("\x1b[?25h"); /* show cursor */
  712. expect_empty_output();
  713. child_string_request(REQ_WRITE_CONSOLE, L"x");
  714. skip_hide_cursor();
  715. expect_output_sequence("x");
  716. skip_sequence("\x1b[?25h"); /* show cursor */
  717. expect_empty_output();
  718. test_cursor_pos(29, 14);
  719. child_string_request(REQ_WRITE_CONSOLE, L"y");
  720. skip_hide_cursor();
  721. expect_output_sequence("y");
  722. skip_sequence("\x1b[?25h"); /* show cursor */
  723. expect_empty_output();
  724. test_cursor_pos(29, 14);
  725. child_string_request(REQ_WRITE_CONSOLE, L"\b");
  726. skip_hide_cursor();
  727. expect_output_sequence("\b");
  728. skip_sequence("\x1b[?25h"); /* show cursor */
  729. expect_empty_output();
  730. test_cursor_pos(28, 14);
  731. child_string_request(REQ_WRITE_CONSOLE, L"z");
  732. skip_hide_cursor();
  733. expect_output_sequence("z");
  734. skip_sequence("\x1b[?25h"); /* show cursor */
  735. expect_empty_output();
  736. test_cursor_pos(29, 14);
  737. child_string_request(REQ_WRITE_CONSOLE, L"w");
  738. skip_hide_cursor();
  739. expect_output_sequence("w");
  740. skip_sequence("\x1b[?25h"); /* show cursor */
  741. expect_empty_output();
  742. test_cursor_pos(29, 14);
  743. child_string_request(REQ_WRITE_CONSOLE, L"X");
  744. skip_hide_cursor();
  745. expect_output_sequence("\r\n");
  746. expect_output_sequence("X");
  747. skip_sequence("\x1b[?25h"); /* show cursor */
  748. expect_empty_output();
  749. test_cursor_pos(1, 15);
  750. child_set_output_mode(ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT);
  751. child_set_cursor(28, 20);
  752. skip_hide_cursor();
  753. expect_output_sequence("\x1b[21;29H"); /* set cursor */
  754. skip_sequence("\x1b[?25h"); /* show cursor */
  755. expect_empty_output();
  756. child_string_request(REQ_WRITE_CONSOLE, L"ab");
  757. skip_hide_cursor();
  758. expect_output_sequence("ab");
  759. expect_output_sequence("\r\n");
  760. skip_sequence("\x1b[?25h"); /* show cursor */
  761. expect_empty_output();
  762. test_cursor_pos(0, 21);
  763. child_string_request(REQ_WRITE_CONSOLE, L"c");
  764. skip_hide_cursor();
  765. expect_output_sequence("c");
  766. skip_sequence("\x1b[?25h"); /* show cursor */
  767. expect_empty_output();
  768. test_cursor_pos(1, 21);
  769. child_set_cursor(28, 22);
  770. skip_hide_cursor();
  771. expect_output_sequence("\x1b[23;29H"); /* set cursor */
  772. skip_sequence("\x1b[?25h"); /* show cursor */
  773. expect_empty_output();
  774. child_string_request(REQ_WRITE_CONSOLE, L"x");
  775. skip_hide_cursor();
  776. expect_output_sequence("x");
  777. skip_sequence("\x1b[?25h"); /* show cursor */
  778. expect_empty_output();
  779. test_cursor_pos(29, 22);
  780. child_string_request(REQ_WRITE_CONSOLE, L"y");
  781. skip_hide_cursor();
  782. expect_output_sequence("y");
  783. expect_output_sequence("\r\n");
  784. skip_sequence("\x1b[?25h"); /* show cursor */
  785. expect_empty_output();
  786. test_cursor_pos(0, 23);
  787. child_string_request(REQ_WRITE_CONSOLE, L"z");
  788. skip_hide_cursor();
  789. expect_output_sequence("z");
  790. skip_sequence("\x1b[?25h"); /* show cursor */
  791. expect_empty_output();
  792. test_cursor_pos(1, 23);
  793. }
  794. static void test_tty_output(void)
  795. {
  796. CHAR_INFO char_info_buf[2048], char_info;
  797. HANDLE sb, sb2;
  798. unsigned int i;
  799. /* simple write chars */
  800. child_write_characters(L"child", 3, 4);
  801. expect_hide_cursor();
  802. expect_output_sequence("\x1b[5;4H"); /* set cursor */
  803. expect_output_sequence("child");
  804. expect_output_sequence("\x1b[H"); /* set cursor */
  805. expect_output_sequence("\x1b[?25h"); /* show cursor */
  806. expect_empty_output();
  807. /* wrapped write chars */
  808. child_write_characters(L"bound", 28, 6);
  809. expect_hide_cursor();
  810. expect_output_sequence("\x1b[7;1H"); /* set cursor */
  811. expect_output_sequence(" bo\r\nund");
  812. expect_erase_line(27);
  813. expect_output_sequence("\x1b[H"); /* set cursor */
  814. expect_output_sequence("\x1b[?25h"); /* show cursor */
  815. expect_empty_output();
  816. /* fill line 4 with a few simple writes */
  817. child_write_characters(L"xxx", 13, 4);
  818. expect_hide_cursor();
  819. expect_output_sequence("\x1b[5;14H"); /* set cursor */
  820. expect_output_sequence("xxx");
  821. expect_output_sequence("\x1b[H"); /* set cursor */
  822. expect_output_sequence("\x1b[?25h"); /* show cursor */
  823. expect_empty_output();
  824. /* write one char at the end of row */
  825. child_write_characters(L"y", 29, 4);
  826. expect_hide_cursor();
  827. expect_output_sequence("\x1b[5;30H"); /* set cursor */
  828. expect_output_sequence("y");
  829. expect_output_sequence("\x1b[H"); /* set cursor */
  830. expect_output_sequence("\x1b[?25h"); /* show cursor */
  831. expect_empty_output();
  832. /* wrapped write chars */
  833. child_write_characters(L"zz", 29, 4);
  834. expect_hide_cursor();
  835. expect_output_sequence("\x1b[5;1H"); /* set cursor */
  836. expect_output_sequence(" child xxx z");
  837. expect_output_sequence("\r\nz");
  838. expect_erase_line(29);
  839. expect_output_sequence("\x1b[H"); /* set cursor */
  840. expect_output_sequence("\x1b[?25h"); /* show cursor */
  841. expect_empty_output();
  842. /* trailing spaces */
  843. child_write_characters(L"child ", 3, 4);
  844. expect_hide_cursor();
  845. expect_output_sequence("\x1b[5;4H"); /* set cursor */
  846. expect_output_sequence("child ");
  847. expect_output_sequence("\x1b[H"); /* set cursor */
  848. expect_output_sequence("\x1b[?25h"); /* show cursor */
  849. expect_empty_output();
  850. child_set_cursor(2, 3);
  851. expect_hide_cursor();
  852. expect_output_sequence("\x1b[4;3H"); /* set cursor */
  853. expect_output_sequence("\x1b[?25h"); /* show cursor */
  854. expect_empty_output();
  855. child_string_request(REQ_SET_TITLE, L"new title");
  856. fetch_console_output();
  857. skip_sequence("\x1b[?25l"); /* hide cursor */
  858. expect_output_sequence("\x1b]0;new title\x07"); /* set title */
  859. skip_sequence("\x1b[?25h"); /* show cursor */
  860. expect_empty_output();
  861. for (i = 0; i < ARRAY_SIZE(char_info_buf); i++)
  862. {
  863. char_info_buf[i].Char.UnicodeChar = '0' + i % 10;
  864. char_info_buf[i].Attributes = 0;
  865. }
  866. child_write_output(char_info_buf, /* size */ 7, 8, /* coord */ 1, 2,
  867. /* region */ 3, 7, 5, 9, /* out region */ 3, 7, 5, 9);
  868. expect_hide_cursor();
  869. expect_output_sequence("\x1b[30m"); /* foreground black */
  870. expect_output_sequence("\x1b[8;4H"); /* set cursor */
  871. expect_output_sequence("567");
  872. expect_output_sequence("\x1b[9;4H"); /* set cursor */
  873. expect_output_sequence("234");
  874. expect_output_sequence("\x1b[10;4H"); /* set cursor */
  875. expect_output_sequence("901");
  876. expect_output_sequence("\x1b[4;3H"); /* set cursor */
  877. expect_output_sequence("\x1b[?25h"); /* show cursor */
  878. expect_empty_output();
  879. child_write_output(char_info_buf, /* size */ 2, 3, /* coord */ 1, 2,
  880. /* region */ 3, 8, 15, 19, /* out region */ 3, 8, 3, 8);
  881. expect_hide_cursor();
  882. if (skip_sequence("\x1b[m")) /* default attr */
  883. expect_output_sequence("\x1b[30m");/* foreground black */
  884. expect_output_sequence("\x1b[9;4H"); /* set cursor */
  885. expect_output_sequence("5");
  886. expect_output_sequence("\x1b[4;3H"); /* set cursor */
  887. expect_output_sequence("\x1b[?25h"); /* show cursor */
  888. expect_empty_output();
  889. child_write_output(char_info_buf, /* size */ 3, 4, /* coord */ 1, 2,
  890. /* region */ 3, 8, 15, 19, /* out region */ 3, 8, 4, 9);
  891. expect_hide_cursor();
  892. if (skip_sequence("\x1b[m")) /* default attr */
  893. expect_output_sequence("\x1b[30m");/* foreground black */
  894. expect_output_sequence("\x1b[9;4H"); /* set cursor */
  895. expect_output_sequence("78");
  896. expect_output_sequence("\x1b[10;4H"); /* set cursor */
  897. expect_output_sequence("01");
  898. expect_output_sequence("\x1b[4;3H"); /* set cursor */
  899. expect_output_sequence("\x1b[?25h"); /* show cursor */
  900. expect_empty_output();
  901. child_write_output(char_info_buf, /* size */ 7, 8, /* coord */ 2, 3,
  902. /* region */ 28, 38, 31, 60, /* out region */ 28, 38, 29, 39);
  903. expect_hide_cursor();
  904. if (skip_sequence("\x1b[m")) /* default attr */
  905. expect_output_sequence("\x1b[30m");/* foreground black */
  906. expect_output_sequence("\x1b[39;29H"); /* set cursor */
  907. expect_output_sequence("34");
  908. expect_output_sequence("\x1b[40;29H"); /* set cursor */
  909. expect_output_sequence("01");
  910. expect_output_sequence("\x1b[4;3H"); /* set cursor */
  911. expect_output_sequence("\x1b[?25h"); /* show cursor */
  912. expect_empty_output();
  913. child_write_output(char_info_buf, /* size */ 7, 8, /* coord */ 1, 2,
  914. /* region */ 0, 7, 5, 9, /* out region */ 0, 7, 5, 9);
  915. expect_hide_cursor();
  916. if (skip_sequence("\x1b[m")) /* default attr */
  917. expect_output_sequence("\x1b[30m");/* foreground black */
  918. expect_output_sequence("\x1b[8;1H"); /* set cursor */
  919. expect_output_sequence("567890\r\n");
  920. expect_output_sequence("234567\r\n");
  921. expect_output_sequence("901234");
  922. expect_output_sequence("\x1b[4;3H"); /* set cursor */
  923. expect_output_sequence("\x1b[?25h"); /* show cursor */
  924. expect_empty_output();
  925. child_scroll(/* scroll rect */ 0, 7, 2, 8, /* destination */ 2, 8, /* fill */ 'x');
  926. expect_hide_cursor();
  927. if (skip_sequence("\x1b[m")) /* default attr */
  928. expect_output_sequence("\x1b[30m");/* foreground black */
  929. expect_output_sequence("\x1b[8;1H"); /* set cursor */
  930. expect_output_sequence("xxx89\r\n");
  931. expect_output_sequence("xx567\r\n");
  932. expect_output_sequence("90234");
  933. expect_output_sequence("\x1b[4;3H"); /* set cursor */
  934. expect_output_sequence("\x1b[?25h"); /* show cursor */
  935. expect_empty_output();
  936. child_write_characters(L"xxx", 3, 10);
  937. expect_hide_cursor();
  938. expect_output_sequence("\x1b[m"); /* default attributes */
  939. expect_output_sequence("\x1b[11;4H"); /* set cursor */
  940. expect_output_sequence("xxx");
  941. expect_output_sequence("\x1b[4;3H"); /* set cursor */
  942. expect_output_sequence("\x1b[?25h"); /* show cursor */
  943. expect_empty_output();
  944. /* test attributes */
  945. for (i = 0; i < 0x100 - 0xff; i++)
  946. {
  947. unsigned int expect;
  948. char expect_buf[16];
  949. char_info.Char.UnicodeChar = 'a';
  950. char_info.Attributes = i;
  951. child_write_output(&char_info, /* size */ 1, 1, /* coord */ 0, 0,
  952. /* region */ 12, 3, 12, 3, /* out region */ 12, 3, 12, 3);
  953. expect_hide_cursor();
  954. if (i != 0x190 && i && ((i & 0xff) != 8)) expect_output_sequence_ctx(i, "\x1b[m");
  955. if ((i & 0x0f) != 7)
  956. {
  957. expect = 30;
  958. if (i & FOREGROUND_BLUE) expect += 4;
  959. if (i & FOREGROUND_GREEN) expect += 2;
  960. if (i & FOREGROUND_RED) expect += 1;
  961. if (i & FOREGROUND_INTENSITY) expect += 60;
  962. sprintf(expect_buf, "\x1b[%um", expect);
  963. expect_output_sequence_ctx(i, expect_buf);
  964. }
  965. if (i & 0xf0)
  966. {
  967. expect = 40;
  968. if (i & BACKGROUND_BLUE) expect += 4;
  969. if (i & BACKGROUND_GREEN) expect += 2;
  970. if (i & BACKGROUND_RED) expect += 1;
  971. if (i & BACKGROUND_INTENSITY) expect += 60;
  972. sprintf(expect_buf, "\x1b[%um", expect);
  973. expect_output_sequence_ctx(i, expect_buf);
  974. }
  975. if (!skip_sequence("\x1b[10C"))
  976. expect_output_sequence_ctx(i, "\x1b[4;13H"); /* set cursor */
  977. expect_output_sequence("a");
  978. if (!skip_sequence("\x1b[11D"))
  979. expect_output_sequence("\x1b[4;3H"); /* set cursor */
  980. expect_output_sequence("\x1b[?25h"); /* show cursor */
  981. expect_empty_output();
  982. }
  983. char_info_buf[0].Attributes = FOREGROUND_GREEN;
  984. char_info_buf[1].Attributes = FOREGROUND_GREEN | BACKGROUND_RED;
  985. char_info_buf[2].Attributes = BACKGROUND_RED;
  986. child_write_output(char_info_buf, /* size */ 7, 8, /* coord */ 0, 0,
  987. /* region */ 7, 0, 9, 0, /* out region */ 7, 0, 9, 0);
  988. expect_hide_cursor();
  989. skip_sequence("\x1b[m"); /* default attr */
  990. expect_output_sequence("\x1b[32m"); /* foreground black */
  991. expect_output_sequence("\x1b[1;8H"); /* set cursor */
  992. expect_output_sequence("0");
  993. expect_output_sequence("\x1b[41m"); /* background red */
  994. expect_output_sequence("1");
  995. expect_output_sequence("\x1b[30m"); /* foreground black */
  996. expect_output_sequence("2");
  997. expect_output_sequence("\x1b[4;3H"); /* set cursor */
  998. expect_output_sequence("\x1b[?25h"); /* show cursor */
  999. expect_empty_output();
  1000. child_fill_character('i', 5, 15, 16);
  1001. expect_hide_cursor();
  1002. expect_output_sequence("\x1b[m"); /* default attributes */
  1003. expect_output_sequence("\x1b[17;16H"); /* set cursor */
  1004. expect_output_sequence("iiiii");
  1005. expect_output_sequence("\x1b[4;3H"); /* set cursor */
  1006. expect_output_sequence("\x1b[?25h"); /* show cursor */
  1007. expect_empty_output();
  1008. test_write_console();
  1009. sb = child_create_screen_buffer();
  1010. child_set_active(sb);
  1011. expect_hide_cursor();
  1012. expect_output_sequence("\x1b[H"); /* set cursor */
  1013. for (i = 0; i < 40; i++)
  1014. {
  1015. expect_erase_line(30);
  1016. if (i != 39) expect_output_sequence("\r\n");
  1017. }
  1018. expect_output_sequence("\x1b[H"); /* set cursor */
  1019. expect_output_sequence("\x1b[?25h"); /* show cursor */
  1020. expect_empty_output();
  1021. child_write_characters(L"new sb", 0, 0);
  1022. skip_hide_cursor();
  1023. expect_output_sequence("new sb");
  1024. ok(skip_sequence("\x1b[H") || skip_sequence("\r"), "expected set cursor\n");
  1025. skip_sequence("\x1b[?25h"); /* show cursor */
  1026. expect_empty_output();
  1027. sb2 = child_create_screen_buffer();
  1028. child_set_active(sb2);
  1029. expect_hide_cursor();
  1030. for (i = 0; i < 40; i++)
  1031. {
  1032. expect_erase_line(30);
  1033. if (i != 39) expect_output_sequence("\r\n");
  1034. }
  1035. expect_output_sequence("\x1b[H"); /* set cursor */
  1036. expect_output_sequence("\x1b[?25h"); /* show cursor */
  1037. expect_empty_output();
  1038. child_set_active(sb);
  1039. expect_hide_cursor();
  1040. expect_output_sequence("new sb");
  1041. expect_erase_line(24);
  1042. expect_output_sequence("\r\n");
  1043. for (i = 1; i < 40; i++)
  1044. {
  1045. expect_erase_line(30);
  1046. if (i != 39) expect_output_sequence("\r\n");
  1047. }
  1048. expect_output_sequence("\x1b[H"); /* set cursor */
  1049. expect_output_sequence("\x1b[?25h"); /* show cursor */
  1050. expect_empty_output();
  1051. }
  1052. static void write_console_pipe(const char *buf)
  1053. {
  1054. DWORD written;
  1055. BOOL res;
  1056. res = WriteFile(console_pipe, buf, strlen(buf), &written, NULL);
  1057. ok(res, "WriteFile failed: %u\n", GetLastError());
  1058. }
  1059. static void test_read_console(void)
  1060. {
  1061. child_set_input_mode(child_pipe, ENABLE_PROCESSED_INPUT);
  1062. child_read_console(child_pipe, 100);
  1063. write_console_pipe("abc");
  1064. expect_empty_output();
  1065. child_expect_read_result(child_pipe, L"abc");
  1066. expect_empty_output();
  1067. child_read_console(child_pipe, 1);
  1068. write_console_pipe("xyz");
  1069. child_expect_read_result(child_pipe, L"x");
  1070. child_read_console(child_pipe, 100);
  1071. child_expect_read_result(child_pipe, L"yz");
  1072. expect_empty_output();
  1073. child_set_input_cp(932);
  1074. child_read_console_a(child_pipe, 2);
  1075. write_console_pipe("\xe3\x81\x81");
  1076. child_expect_read_result_a(child_pipe, "\x82\x9f");
  1077. expect_empty_output();
  1078. child_read_console_a(child_pipe, 1);
  1079. write_console_pipe("\xe3\x81\x81""a");
  1080. child_expect_read_result_a(child_pipe, "\x82\xcc");
  1081. child_read_console_a(child_pipe, 1);
  1082. child_expect_read_result_a(child_pipe, "a");
  1083. expect_empty_output();
  1084. child_read_console_a(child_pipe, 2);
  1085. write_console_pipe("a\xe3\x81\x81""b");
  1086. child_expect_read_result_a(child_pipe, "a\x82\xcc");
  1087. child_read_console_a(child_pipe, 1);
  1088. child_expect_read_result_a(child_pipe, "b");
  1089. expect_empty_output();
  1090. child_read_console_file(child_pipe, 2);
  1091. write_console_pipe("\xe3\x81\x81");
  1092. child_expect_read_result_a(child_pipe, "\x82\x9f");
  1093. expect_empty_output();
  1094. child_read_console_file(child_pipe, 1);
  1095. write_console_pipe("\xe3\x81\x81""a");
  1096. child_expect_read_result_a(child_pipe, "\x82\xcc");
  1097. child_read_console_file(child_pipe, 1);
  1098. child_expect_read_result_a(child_pipe, "a");
  1099. expect_empty_output();
  1100. child_read_console_file(child_pipe, 2);
  1101. write_console_pipe("a\xe3\x81\x81""b");
  1102. child_expect_read_result_a(child_pipe, "a\x82\xcc");
  1103. child_read_console_file(child_pipe, 1);
  1104. child_expect_read_result_a(child_pipe, "b");
  1105. expect_empty_output();
  1106. child_set_input_cp(437);
  1107. child_set_input_mode(child_pipe, ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
  1108. ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT | ENABLE_INSERT_MODE |
  1109. ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS | ENABLE_AUTO_POSITION);
  1110. child_read_console(child_pipe, 100);
  1111. write_console_pipe("xyz");
  1112. skip_hide_cursor();
  1113. expect_output_sequence("xyz");
  1114. skip_sequence("\x1b[?25h"); /* show cursor */
  1115. write_console_pipe("ab\r\n");
  1116. child_expect_read_result(child_pipe, L"xyzab\r\n");
  1117. skip_hide_cursor();
  1118. expect_output_sequence("ab\r\n");
  1119. skip_sequence("\x1b[?25h"); /* show cursor */
  1120. expect_key_input('\r', VK_RETURN, 0, FALSE);
  1121. expect_key_pressed('\n', VK_RETURN, LEFT_CTRL_PRESSED);
  1122. expect_empty_output();
  1123. }
  1124. static void test_tty_input(void)
  1125. {
  1126. INPUT_RECORD ir;
  1127. unsigned int i;
  1128. char buf[8];
  1129. static const struct
  1130. {
  1131. const char *str;
  1132. WCHAR ch;
  1133. unsigned int vk;
  1134. unsigned int ctrl;
  1135. } escape_test[] = {
  1136. { "\x1b[A", 0, VK_UP, 0 },
  1137. { "\x1b[B", 0, VK_DOWN, 0 },
  1138. { "\x1b[C", 0, VK_RIGHT, 0 },
  1139. { "\x1b[D", 0, VK_LEFT, 0 },
  1140. { "\x1b[H", 0, VK_HOME, 0 },
  1141. { "\x1b[F", 0, VK_END, 0 },
  1142. { "\x1b[2~", 0, VK_INSERT, 0 },
  1143. { "\x1b[3~", 0, VK_DELETE, 0 },
  1144. { "\x1b[5~", 0, VK_PRIOR, 0 },
  1145. { "\x1b[6~", 0, VK_NEXT, 0 },
  1146. { "\x1b[15~", 0, VK_F5, 0 },
  1147. { "\x1b[17~", 0, VK_F6, 0 },
  1148. { "\x1b[18~", 0, VK_F7, 0 },
  1149. { "\x1b[19~", 0, VK_F8, 0 },
  1150. { "\x1b[20~", 0, VK_F9, 0 },
  1151. { "\x1b[21~", 0, VK_F10, 0 },
  1152. /* 0x10 */
  1153. { "\x1b[23~", 0, VK_F11, 0 },
  1154. { "\x1b[24~", 0, VK_F12, 0 },
  1155. { "\x1bOP", 0, VK_F1, 0 },
  1156. { "\x1bOQ", 0, VK_F2, 0 },
  1157. { "\x1bOR", 0, VK_F3, 0 },
  1158. { "\x1bOS", 0, VK_F4, 0 },
  1159. { "\x1b[1;1A", 0, VK_UP, 0 },
  1160. { "\x1b[1;2A", 0, VK_UP, SHIFT_PRESSED },
  1161. { "\x1b[1;3A", 0, VK_UP, LEFT_ALT_PRESSED },
  1162. { "\x1b[1;4A", 0, VK_UP, SHIFT_PRESSED | LEFT_ALT_PRESSED },
  1163. { "\x1b[1;5A", 0, VK_UP, LEFT_CTRL_PRESSED },
  1164. { "\x1b[1;6A", 0, VK_UP, SHIFT_PRESSED | LEFT_CTRL_PRESSED },
  1165. { "\x1b[1;7A", 0, VK_UP, LEFT_ALT_PRESSED | LEFT_CTRL_PRESSED },
  1166. { "\x1b[1;8A", 0, VK_UP, SHIFT_PRESSED | LEFT_ALT_PRESSED | LEFT_CTRL_PRESSED },
  1167. { "\x1b[1;9A", 0, VK_UP, 0 },
  1168. { "\x1b[1;10A", 0, VK_UP, SHIFT_PRESSED },
  1169. /* 0x20 */
  1170. { "\x1b[1;11A", 0, VK_UP, LEFT_ALT_PRESSED },
  1171. { "\x1b[1;12A", 0, VK_UP, SHIFT_PRESSED | LEFT_ALT_PRESSED },
  1172. { "\x1b[1;13A", 0, VK_UP, LEFT_CTRL_PRESSED },
  1173. { "\x1b[1;14A", 0, VK_UP, SHIFT_PRESSED | LEFT_CTRL_PRESSED },
  1174. { "\x1b[1;15A", 0, VK_UP, LEFT_ALT_PRESSED | LEFT_CTRL_PRESSED },
  1175. { "\x1b[1;16A", 0, VK_UP, SHIFT_PRESSED | LEFT_ALT_PRESSED | LEFT_CTRL_PRESSED },
  1176. { "\x1b[1;2P", 0, VK_F1, SHIFT_PRESSED },
  1177. { "\x1b[2;3~", 0, VK_INSERT, LEFT_ALT_PRESSED },
  1178. { "\x1b[2;3;5;6~", 0, VK_INSERT, 0 },
  1179. { "\x1b[6;2;3;5;1~", 0, VK_NEXT, 0 },
  1180. { "\xe4\xb8\x80", 0x4e00, 0, 0 },
  1181. { "\x1b\x1b", 0x1b, VK_ESCAPE, LEFT_ALT_PRESSED },
  1182. { "\x1b""1", '1', '1', LEFT_ALT_PRESSED },
  1183. { "\x1b""x", 'x', 'X', LEFT_ALT_PRESSED },
  1184. { "\x1b""[", '[', VK_OEM_4, LEFT_ALT_PRESSED },
  1185. { "\x7f", '\b', VK_BACK, 0 },
  1186. };
  1187. write_console_pipe("x");
  1188. if (!get_input_key_vt())
  1189. {
  1190. skip("Skipping tests on settings that don't have VT mapping for 'x'\n");
  1191. get_input_key_vt();
  1192. return;
  1193. }
  1194. get_input_key_vt();
  1195. write_console_pipe("aBCd");
  1196. expect_char_key('a');
  1197. expect_char_key('B');
  1198. expect_char_key('C');
  1199. expect_char_key('d');
  1200. for (i = 1; i < 0x7f; i++)
  1201. {
  1202. if (i == 3 || i == '\n' || i == 0x1b || i == 0x1f) continue;
  1203. buf[0] = i;
  1204. buf[1] = 0;
  1205. write_console_pipe(buf);
  1206. if (i == 8)
  1207. expect_key_pressed('\b', 'H', LEFT_CTRL_PRESSED);
  1208. else if (i == 0x7f)
  1209. expect_char_key(8);
  1210. else
  1211. expect_char_key(i);
  1212. }
  1213. write_console_pipe("\r\n");
  1214. expect_key_pressed('\r', VK_RETURN, 0);
  1215. expect_key_pressed('\n', VK_RETURN, LEFT_CTRL_PRESSED);
  1216. write_console_pipe("\xc4\x85");
  1217. if (get_key_input(VK_MENU, &ir))
  1218. {
  1219. expect_key_input(0x105, 'A', TRUE, LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED);
  1220. expect_key_input(0x105, 'A', FALSE, LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED);
  1221. expect_key_input(0, VK_MENU, FALSE, ENHANCED_KEY);
  1222. }
  1223. else
  1224. {
  1225. expect_key_input(0x105, 0, TRUE, 0);
  1226. expect_key_input(0x105, 0, FALSE, 0);
  1227. }
  1228. for (i = 0; i < ARRAY_SIZE(escape_test); i++)
  1229. {
  1230. write_console_pipe(escape_test[i].str);
  1231. expect_key_pressed_ctx(i, escape_test[i].ch, escape_test[i].vk, escape_test[i].ctrl);
  1232. }
  1233. for (i = 0x80; i < 0x100; i += 11)
  1234. {
  1235. buf[0] = i;
  1236. buf[1] = 0;
  1237. write_console_pipe(buf);
  1238. expect_empty_output();
  1239. }
  1240. }
  1241. static void child_process(HANDLE pipe)
  1242. {
  1243. HANDLE output, input;
  1244. DWORD size, count;
  1245. char buf[4096];
  1246. BOOL ret;
  1247. output = CreateFileA("CONOUT$", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
  1248. ok(output != INVALID_HANDLE_VALUE, "could not open console output\n");
  1249. input = CreateFileA("CONIN$", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
  1250. ok(output != INVALID_HANDLE_VALUE, "could not open console output\n");
  1251. while(ReadFile(pipe, buf, sizeof(buf), &size, NULL))
  1252. {
  1253. const struct pseudoconsole_req *req = (void *)buf;
  1254. switch (req->type)
  1255. {
  1256. case REQ_CREATE_SCREEN_BUFFER:
  1257. {
  1258. HANDLE handle;
  1259. SetLastError(0xdeadbeef);
  1260. handle = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
  1261. FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
  1262. CONSOLE_TEXTMODE_BUFFER, NULL);
  1263. ok(handle != INVALID_HANDLE_VALUE, "CreateConsoleScreenBuffer failed: %u\n", GetLastError());
  1264. ret = WriteFile(pipe, &handle, sizeof(handle), &count, NULL);
  1265. ok(ret, "WriteFile failed: %u\n", GetLastError());
  1266. break;
  1267. }
  1268. case REQ_GET_INPUT:
  1269. {
  1270. INPUT_RECORD record;
  1271. ret = ReadConsoleInputW(input, &record, 1, &count);
  1272. ok(ret, "ReadConsoleInputW failed: %u\n", GetLastError());
  1273. ok(count == 1, "count = %u\n", count);
  1274. ret = WriteFile(pipe, &record, sizeof(record), &count, NULL);
  1275. ok(ret, "WriteFile failed: %u\n", GetLastError());
  1276. break;
  1277. }
  1278. case REQ_GET_SB_INFO:
  1279. {
  1280. CONSOLE_SCREEN_BUFFER_INFO info;
  1281. ret = GetConsoleScreenBufferInfo(output, &info);
  1282. ok(ret, "GetConsoleScreenBufferInfo failed: %u\n", GetLastError());
  1283. ret = WriteFile(pipe, &info, sizeof(info), &count, NULL);
  1284. ok(ret, "WriteFile failed: %u\n", GetLastError());
  1285. break;
  1286. }
  1287. case REQ_READ_CONSOLE:
  1288. ret = ReadConsoleW(input, buf, req->u.size, &count, NULL );
  1289. ok(ret, "ReadConsoleW failed: %u\n", GetLastError());
  1290. ret = WriteFile(pipe, buf, count * sizeof(WCHAR), NULL, NULL);
  1291. ok(ret, "WriteFile failed: %u\n", GetLastError());
  1292. break;
  1293. case REQ_READ_CONSOLE_A:
  1294. count = req->u.size;
  1295. memset(buf, 0xcc, sizeof(buf));
  1296. ret = ReadConsoleA(input, buf, count, &count, NULL );
  1297. ok(ret, "ReadConsoleA failed: %u\n", GetLastError());
  1298. ret = WriteFile(pipe, buf, count, NULL, NULL);
  1299. ok(ret, "WriteFile failed: %u\n", GetLastError());
  1300. break;
  1301. case REQ_READ_CONSOLE_FILE:
  1302. count = req->u.size;
  1303. memset(buf, 0xcc, sizeof(buf));
  1304. ret = ReadFile(input, buf, count, &count, NULL );
  1305. ok(ret, "ReadFile failed: %u\n", GetLastError());
  1306. ret = WriteFile(pipe, buf, count, NULL, NULL);
  1307. ok(ret, "WriteFile failed: %u\n", GetLastError());
  1308. break;
  1309. case REQ_SCROLL:
  1310. ret = ScrollConsoleScreenBufferW(output, &req->u.scroll.rect, NULL, req->u.scroll.dst, &req->u.scroll.fill);
  1311. ok(ret, "ScrollConsoleScreenBuffer failed: %u\n", GetLastError());
  1312. break;
  1313. case REQ_FILL_CHAR:
  1314. ret = FillConsoleOutputCharacterW(output, req->u.fill.ch, req->u.fill.count, req->u.fill.coord, &count);
  1315. ok(ret, "FillConsoleOutputCharacter failed: %u\n", GetLastError());
  1316. ok(count == req->u.fill.count, "count = %u, expected %u\n", count, req->u.fill.count);
  1317. break;
  1318. case REQ_SET_ACTIVE:
  1319. output = req->u.handle;
  1320. ret = SetConsoleActiveScreenBuffer(output);
  1321. ok(ret, "SetConsoleActiveScreenBuffer failed: %u\n", GetLastError());
  1322. break;
  1323. case REQ_SET_CURSOR:
  1324. ret = SetConsoleCursorPosition(output, req->u.coord);
  1325. ok(ret, "SetConsoleCursorPosition failed: %u\n", GetLastError());
  1326. break;
  1327. case REQ_SET_INPUT_CP:
  1328. ret = SetConsoleCP(req->u.cp);
  1329. ok(ret, "SetConsoleCP failed: %u\n", GetLastError());
  1330. break;
  1331. case REQ_SET_INPUT_MODE:
  1332. ret = SetConsoleMode(input, req->u.mode);
  1333. ok(ret, "SetConsoleMode failed: %u\n", GetLastError());
  1334. break;
  1335. case REQ_SET_OUTPUT_MODE:
  1336. ret = SetConsoleMode(output, req->u.mode);
  1337. ok(ret, "SetConsoleMode failed: %u\n", GetLastError());
  1338. break;
  1339. case REQ_SET_TITLE:
  1340. ret = SetConsoleTitleW(req->u.string);
  1341. ok(ret, "SetConsoleTitleW failed: %u\n", GetLastError());
  1342. break;
  1343. case REQ_WRITE_CHARACTERS:
  1344. ret = WriteConsoleOutputCharacterW(output, req->u.write_characters.buf,
  1345. req->u.write_characters.len,
  1346. req->u.write_characters.coord, &count);
  1347. ok(ret, "WriteConsoleOutputCharacterW failed: %u\n", GetLastError());
  1348. break;
  1349. case REQ_WRITE_CONSOLE:
  1350. ret = WriteConsoleW(output, req->u.string, lstrlenW(req->u.string), NULL, NULL);
  1351. ok(ret, "SetConsoleTitleW failed: %u\n", GetLastError());
  1352. break;
  1353. case REQ_WRITE_OUTPUT:
  1354. {
  1355. SMALL_RECT region = req->u.write_output.region;
  1356. ret = WriteConsoleOutputW(output, req->u.write_output.buf, req->u.write_output.size, req->u.write_output.coord, &region);
  1357. ok(ret, "WriteConsoleOutput failed: %u\n", GetLastError());
  1358. ret = WriteFile(pipe, &region, sizeof(region), &count, NULL);
  1359. ok(ret, "WriteFile failed: %u\n", GetLastError());
  1360. break;
  1361. }
  1362. default:
  1363. ok(0, "unexpected request type %u\n", req->type);
  1364. };
  1365. }
  1366. ok(GetLastError() == ERROR_BROKEN_PIPE, "ReadFile failed: %u\n", GetLastError());
  1367. CloseHandle(output);
  1368. CloseHandle(input);
  1369. }
  1370. static HANDLE run_child(HANDLE console, HANDLE pipe)
  1371. {
  1372. STARTUPINFOEXA startup = {{ sizeof(startup) }};
  1373. char **argv, cmdline[MAX_PATH];
  1374. PROCESS_INFORMATION info;
  1375. SIZE_T size;
  1376. BOOL ret;
  1377. InitializeProcThreadAttributeList(NULL, 1, 0, &size);
  1378. startup.lpAttributeList = HeapAlloc(GetProcessHeap(), 0, size);
  1379. InitializeProcThreadAttributeList(startup.lpAttributeList, 1, 0, &size);
  1380. UpdateProcThreadAttribute(startup.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, console,
  1381. sizeof(console), NULL, NULL);
  1382. winetest_get_mainargs(&argv);
  1383. sprintf(cmdline, "\"%s\" %s child %p", argv[0], argv[1], pipe);
  1384. ret = CreateProcessA(NULL, cmdline, NULL, NULL, TRUE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL,
  1385. &startup.StartupInfo, &info);
  1386. ok(ret, "CreateProcessW failed: %u\n", GetLastError());
  1387. CloseHandle(info.hThread);
  1388. HeapFree(GetProcessHeap(), 0, startup.lpAttributeList);
  1389. return info.hProcess;
  1390. }
  1391. static HPCON create_pseudo_console(HANDLE *console_pipe_end, HANDLE *child_process)
  1392. {
  1393. SECURITY_ATTRIBUTES sec_attr = { sizeof(sec_attr), NULL, TRUE };
  1394. HANDLE child_pipe_end;
  1395. COORD size = { 30, 40 };
  1396. DWORD read_mode;
  1397. HPCON console;
  1398. HRESULT hres;
  1399. BOOL r;
  1400. console_pipe = CreateNamedPipeW(L"\\\\.\\pipe\\pseudoconsoleconn", PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
  1401. PIPE_WAIT | PIPE_TYPE_BYTE, 1, 4096, 4096, NMPWAIT_USE_DEFAULT_WAIT, NULL);
  1402. ok(console_pipe != INVALID_HANDLE_VALUE, "CreateNamedPipeW failed: %u\n", GetLastError());
  1403. *console_pipe_end = CreateFileW(L"\\\\.\\pipe\\pseudoconsoleconn", GENERIC_READ | GENERIC_WRITE,
  1404. 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
  1405. ok(*console_pipe_end != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError());
  1406. child_pipe = CreateNamedPipeW(L"\\\\.\\pipe\\pseudoconsoleserver", PIPE_ACCESS_DUPLEX,
  1407. PIPE_WAIT | PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 1, 5000, 6000,
  1408. NMPWAIT_USE_DEFAULT_WAIT, NULL);
  1409. ok(child_pipe != INVALID_HANDLE_VALUE, "CreateNamedPipeW failed: %u\n", GetLastError());
  1410. child_pipe_end = CreateFileW(L"\\\\.\\pipe\\pseudoconsoleserver", GENERIC_READ | GENERIC_WRITE, 0,
  1411. &sec_attr, OPEN_EXISTING, 0, NULL);
  1412. ok(child_pipe_end != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError());
  1413. read_mode = PIPE_READMODE_MESSAGE;
  1414. r = SetNamedPipeHandleState(child_pipe_end, &read_mode, NULL, NULL);
  1415. ok(r, "SetNamedPipeHandleState failed: %u\n", GetLastError());
  1416. hres = pCreatePseudoConsole(size, *console_pipe_end, *console_pipe_end, 0, &console);
  1417. ok(hres == S_OK, "CreatePseudoConsole failed: %08x\n", hres);
  1418. *child_process = run_child(console, child_pipe_end);
  1419. CloseHandle(child_pipe_end);
  1420. return console;
  1421. }
  1422. static void test_pseudoconsole(void)
  1423. {
  1424. HANDLE console_pipe_end, child_process;
  1425. BOOL broken_version;
  1426. HPCON console;
  1427. console = create_pseudo_console(&console_pipe_end, &child_process);
  1428. child_string_request(REQ_SET_TITLE, L"test title");
  1429. expect_output_sequence("\x1b[2J"); /* erase display */
  1430. skip_hide_cursor();
  1431. expect_output_sequence("\x1b[m"); /* default attributes */
  1432. expect_output_sequence("\x1b[H"); /* set cursor */
  1433. skip_sequence("\x1b[H"); /* some windows versions emit it twice */
  1434. expect_output_sequence("\x1b]0;test title"); /* set title */
  1435. broken_version = skip_byte(0); /* some win versions emit nullbyte */
  1436. expect_output_sequence("\x07");
  1437. skip_sequence("\x1b[?25h"); /* show cursor */
  1438. expect_empty_output();
  1439. if (!broken_version)
  1440. {
  1441. test_tty_output();
  1442. test_read_console();
  1443. test_tty_input();
  1444. }
  1445. else win_skip("Skipping tty output tests on broken Windows version\n");
  1446. CloseHandle(child_pipe);
  1447. wait_child_process(child_process);
  1448. CloseHandle(child_process);
  1449. /* native sometimes clears the screen here */
  1450. if (skip_sequence("\x1b[25l"))
  1451. {
  1452. unsigned int i;
  1453. skip_sequence("\x1b[H");
  1454. for (i = 0; i < 40; i++)
  1455. {
  1456. expect_output_sequence("\x1b[K");
  1457. if (i != 39) expect_output_sequence("\r\n");
  1458. }
  1459. skip_sequence("\x1b[H\x1b[?25h");
  1460. }
  1461. expect_empty_output();
  1462. pClosePseudoConsole(console);
  1463. CloseHandle(console_pipe_end);
  1464. CloseHandle(console_pipe);
  1465. }
  1466. START_TEST(tty)
  1467. {
  1468. HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll");
  1469. char **argv;
  1470. int argc;
  1471. argc = winetest_get_mainargs(&argv);
  1472. if (argc > 3)
  1473. {
  1474. HANDLE pipe;
  1475. DWORD mode;
  1476. sscanf(argv[3], "%p", &pipe);
  1477. /* if std output is console, silence debug output so it does not interfere with tests */
  1478. if (GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &mode))
  1479. winetest_debug = 0;
  1480. child_process(pipe);
  1481. return;
  1482. }
  1483. pCreatePseudoConsole = (void *)GetProcAddress(kernel32, "CreatePseudoConsole");
  1484. pClosePseudoConsole = (void *)GetProcAddress(kernel32, "ClosePseudoConsole");
  1485. if (!pCreatePseudoConsole)
  1486. {
  1487. win_skip("CreatePseudoConsole is not available\n");
  1488. return;
  1489. }
  1490. test_pseudoconsole();
  1491. }