conhost.c 96 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826
  1. /*
  2. * Copyright 1998 Alexandre Julliard
  3. * Copyright 2001 Eric Pouech
  4. * Copyright 2012 Detlef Riekenberg
  5. * Copyright 2020 Jacek Caban
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this library; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  20. */
  21. #include <assert.h>
  22. #include <limits.h>
  23. #include "conhost.h"
  24. #include "wine/server.h"
  25. #include "wine/debug.h"
  26. WINE_DEFAULT_DEBUG_CHANNEL(console);
  27. static const char_info_t empty_char_info = { ' ', 0x0007 }; /* white on black space */
  28. static CRITICAL_SECTION console_section;
  29. static CRITICAL_SECTION_DEBUG critsect_debug =
  30. {
  31. 0, 0, &console_section,
  32. { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
  33. 0, 0, { (DWORD_PTR)(__FILE__ ": console_section") }
  34. };
  35. static CRITICAL_SECTION console_section = { &critsect_debug, -1, 0, 0, 0, 0 };
  36. static void *ioctl_buffer;
  37. static size_t ioctl_buffer_size;
  38. static void *alloc_ioctl_buffer( size_t size )
  39. {
  40. if (size > ioctl_buffer_size)
  41. {
  42. void *new_buffer;
  43. if (!(new_buffer = realloc( ioctl_buffer, size ))) return NULL;
  44. ioctl_buffer = new_buffer;
  45. ioctl_buffer_size = size;
  46. }
  47. return ioctl_buffer;
  48. }
  49. static int screen_buffer_compare_id( const void *key, const struct wine_rb_entry *entry )
  50. {
  51. struct screen_buffer *screen_buffer = WINE_RB_ENTRY_VALUE( entry, struct screen_buffer, entry );
  52. return PtrToLong(key) - screen_buffer->id;
  53. }
  54. static struct wine_rb_tree screen_buffer_map = { screen_buffer_compare_id };
  55. static void destroy_screen_buffer( struct screen_buffer *screen_buffer )
  56. {
  57. if (screen_buffer->console->active == screen_buffer)
  58. screen_buffer->console->active = NULL;
  59. wine_rb_remove( &screen_buffer_map, &screen_buffer->entry );
  60. free( screen_buffer->font.face_name );
  61. free( screen_buffer->data );
  62. free( screen_buffer );
  63. }
  64. static struct screen_buffer *create_screen_buffer( struct console *console, int id, int width, int height )
  65. {
  66. struct screen_buffer *screen_buffer;
  67. unsigned int i;
  68. if (!(screen_buffer = calloc( 1, sizeof(*screen_buffer) ))) return NULL;
  69. screen_buffer->console = console;
  70. screen_buffer->id = id;
  71. screen_buffer->mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
  72. screen_buffer->cursor_size = 25;
  73. screen_buffer->cursor_visible = 1;
  74. screen_buffer->width = width;
  75. screen_buffer->height = height;
  76. if (console->active)
  77. {
  78. screen_buffer->max_width = console->active->max_width;
  79. screen_buffer->max_height = console->active->max_height;
  80. screen_buffer->win.right = console->active->win.right - console->active->win.left;
  81. screen_buffer->win.bottom = console->active->win.bottom - console->active->win.top;
  82. screen_buffer->attr = console->active->attr;
  83. screen_buffer->popup_attr = console->active->attr;
  84. screen_buffer->font = console->active->font;
  85. if (screen_buffer->font.face_len)
  86. {
  87. screen_buffer->font.face_name = malloc( screen_buffer->font.face_len * sizeof(WCHAR) );
  88. if (!screen_buffer->font.face_name) return NULL;
  89. memcpy( screen_buffer->font.face_name, console->active->font.face_name,
  90. screen_buffer->font.face_len * sizeof(WCHAR) );
  91. }
  92. }
  93. else
  94. {
  95. screen_buffer->max_width = width;
  96. screen_buffer->max_height = height;
  97. screen_buffer->win.right = width - 1;
  98. screen_buffer->win.bottom = height - 1;
  99. screen_buffer->attr = FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_RED;
  100. screen_buffer->popup_attr = 0xf5;
  101. screen_buffer->font.weight = FW_NORMAL;
  102. screen_buffer->font.pitch_family = FIXED_PITCH | FF_DONTCARE;
  103. }
  104. if (wine_rb_put( &screen_buffer_map, LongToPtr(id), &screen_buffer->entry ))
  105. {
  106. free( screen_buffer );
  107. ERR( "id %x already exists\n", id );
  108. return NULL;
  109. }
  110. if (!(screen_buffer->data = malloc( screen_buffer->width * screen_buffer->height *
  111. sizeof(*screen_buffer->data) )))
  112. {
  113. destroy_screen_buffer( screen_buffer );
  114. return NULL;
  115. }
  116. /* clear the first row */
  117. for (i = 0; i < screen_buffer->width; i++) screen_buffer->data[i] = empty_char_info;
  118. /* and copy it to all other rows */
  119. for (i = 1; i < screen_buffer->height; i++)
  120. memcpy( &screen_buffer->data[i * screen_buffer->width], screen_buffer->data,
  121. screen_buffer->width * sizeof(char_info_t) );
  122. return screen_buffer;
  123. }
  124. static BOOL is_active( struct screen_buffer *screen_buffer )
  125. {
  126. return screen_buffer == screen_buffer->console->active;
  127. }
  128. static unsigned int get_tty_cp( struct console *console )
  129. {
  130. return console->is_unix ? CP_UNIXCP : CP_UTF8;
  131. }
  132. static void tty_flush( struct console *console )
  133. {
  134. if (!console->tty_output || !console->tty_buffer_count) return;
  135. TRACE("%s\n", debugstr_an(console->tty_buffer, console->tty_buffer_count));
  136. if (!WriteFile( console->tty_output, console->tty_buffer, console->tty_buffer_count,
  137. NULL, NULL ))
  138. WARN( "write failed: %u\n", GetLastError() );
  139. console->tty_buffer_count = 0;
  140. }
  141. static void tty_write( struct console *console, const char *buffer, size_t size )
  142. {
  143. if (!size || !console->tty_output) return;
  144. if (console->tty_buffer_count + size > sizeof(console->tty_buffer))
  145. tty_flush( console );
  146. if (console->tty_buffer_count + size <= sizeof(console->tty_buffer))
  147. {
  148. memcpy( console->tty_buffer + console->tty_buffer_count, buffer, size );
  149. console->tty_buffer_count += size;
  150. }
  151. else
  152. {
  153. assert( !console->tty_buffer_count );
  154. if (!WriteFile( console->tty_output, buffer, size, NULL, NULL ))
  155. WARN( "write failed: %u\n", GetLastError() );
  156. }
  157. }
  158. static void *tty_alloc_buffer( struct console *console, size_t size )
  159. {
  160. void *ret;
  161. if (console->tty_buffer_count + size > sizeof(console->tty_buffer)) return NULL;
  162. ret = console->tty_buffer + console->tty_buffer_count;
  163. console->tty_buffer_count += size;
  164. return ret;
  165. }
  166. static void hide_tty_cursor( struct console *console )
  167. {
  168. if (console->tty_cursor_visible)
  169. {
  170. tty_write( console, "\x1b[?25l", 6 );
  171. console->tty_cursor_visible = FALSE;
  172. }
  173. }
  174. static void set_tty_cursor( struct console *console, unsigned int x, unsigned int y )
  175. {
  176. char buf[64];
  177. if (console->tty_cursor_x == x && console->tty_cursor_y == y) return;
  178. if (!x && y == console->tty_cursor_y + 1) strcpy( buf, "\r\n" );
  179. else if (!x && y == console->tty_cursor_y) strcpy( buf, "\r" );
  180. else if (y == console->tty_cursor_y)
  181. {
  182. if (console->tty_cursor_x >= console->active->width)
  183. {
  184. if (console->is_unix)
  185. {
  186. /* Unix will usually have the cursor at width-1 in this case. instead of depending
  187. * on the exact behaviour, move the cursor to the first column and move forward
  188. * from there. */
  189. tty_write( console, "\r", 1 );
  190. console->tty_cursor_x = 0;
  191. }
  192. else if (console->active->mode & ENABLE_WRAP_AT_EOL_OUTPUT)
  193. {
  194. console->tty_cursor_x--;
  195. }
  196. if (console->tty_cursor_x == x) return;
  197. }
  198. if (x + 1 == console->tty_cursor_x) strcpy( buf, "\b" );
  199. else if (x > console->tty_cursor_x) sprintf( buf, "\x1b[%uC", x - console->tty_cursor_x );
  200. else sprintf( buf, "\x1b[%uD", console->tty_cursor_x - x );
  201. }
  202. else if (x || y)
  203. {
  204. hide_tty_cursor( console );
  205. sprintf( buf, "\x1b[%u;%uH", y + 1, x + 1);
  206. }
  207. else strcpy( buf, "\x1b[H" );
  208. console->tty_cursor_x = x;
  209. console->tty_cursor_y = y;
  210. tty_write( console, buf, strlen(buf) );
  211. }
  212. static void set_tty_cursor_relative( struct console *console, unsigned int x, unsigned int y )
  213. {
  214. if (y < console->tty_cursor_y)
  215. {
  216. char buf[64];
  217. sprintf( buf, "\x1b[%uA", console->tty_cursor_y - y );
  218. tty_write( console, buf, strlen(buf) );
  219. console->tty_cursor_y = y;
  220. }
  221. else
  222. {
  223. while (console->tty_cursor_y < y)
  224. {
  225. console->tty_cursor_x = 0;
  226. console->tty_cursor_y++;
  227. tty_write( console, "\r\n", 2 );
  228. }
  229. }
  230. set_tty_cursor( console, x, y );
  231. }
  232. static void set_tty_attr( struct console *console, unsigned int attr )
  233. {
  234. char buf[8];
  235. if ((attr & 0x0f) != (console->tty_attr & 0x0f))
  236. {
  237. if ((attr & 0x0f) != 7)
  238. {
  239. unsigned int n = 30;
  240. if (attr & FOREGROUND_BLUE) n += 4;
  241. if (attr & FOREGROUND_GREEN) n += 2;
  242. if (attr & FOREGROUND_RED) n += 1;
  243. if (attr & FOREGROUND_INTENSITY) n += 60;
  244. sprintf(buf, "\x1b[%um", n);
  245. tty_write( console, buf, strlen(buf) );
  246. }
  247. else tty_write( console, "\x1b[m", 3 );
  248. }
  249. if ((attr & 0xf0) != (console->tty_attr & 0xf0) && attr != 7)
  250. {
  251. unsigned int n = 40;
  252. if (attr & BACKGROUND_BLUE) n += 4;
  253. if (attr & BACKGROUND_GREEN) n += 2;
  254. if (attr & BACKGROUND_RED) n += 1;
  255. if (attr & BACKGROUND_INTENSITY) n += 60;
  256. sprintf(buf, "\x1b[%um", n);
  257. tty_write( console, buf, strlen(buf) );
  258. }
  259. console->tty_attr = attr;
  260. }
  261. static void tty_sync( struct console *console )
  262. {
  263. if (!console->tty_output) return;
  264. if (console->active->cursor_visible)
  265. {
  266. set_tty_cursor( console, get_bounded_cursor_x( console->active ), console->active->cursor_y );
  267. if (!console->tty_cursor_visible)
  268. {
  269. tty_write( console, "\x1b[?25h", 6 ); /* show cursor */
  270. console->tty_cursor_visible = TRUE;
  271. }
  272. }
  273. else if (console->tty_cursor_visible)
  274. hide_tty_cursor( console );
  275. tty_flush( console );
  276. }
  277. static void init_tty_output( struct console *console )
  278. {
  279. if (!console->is_unix)
  280. {
  281. /* initialize tty output, but don't flush */
  282. tty_write( console, "\x1b[2J", 4 ); /* clear screen */
  283. set_tty_attr( console, console->active->attr );
  284. tty_write( console, "\x1b[H", 3 ); /* move cursor to (0,0) */
  285. }
  286. else console->tty_attr = empty_char_info.attr;
  287. console->tty_cursor_visible = TRUE;
  288. }
  289. static void scroll_to_cursor( struct screen_buffer *screen_buffer )
  290. {
  291. unsigned int cursor_x = get_bounded_cursor_x( screen_buffer );
  292. int w = screen_buffer->win.right - screen_buffer->win.left + 1;
  293. int h = screen_buffer->win.bottom - screen_buffer->win.top + 1;
  294. if (cursor_x < screen_buffer->win.left)
  295. screen_buffer->win.left = min( cursor_x, screen_buffer->width - w );
  296. else if (cursor_x > screen_buffer->win.right)
  297. screen_buffer->win.left = max( cursor_x, w ) - w + 1;
  298. screen_buffer->win.right = screen_buffer->win.left + w - 1;
  299. if (screen_buffer->cursor_y < screen_buffer->win.top)
  300. screen_buffer->win.top = min( screen_buffer->cursor_y, screen_buffer->height - h );
  301. else if (screen_buffer->cursor_y > screen_buffer->win.bottom)
  302. screen_buffer->win.top = max( screen_buffer->cursor_y, h ) - h + 1;
  303. screen_buffer->win.bottom = screen_buffer->win.top + h - 1;
  304. }
  305. static void update_output( struct screen_buffer *screen_buffer, RECT *rect )
  306. {
  307. int x, y, size, trailing_spaces;
  308. char_info_t *ch;
  309. char buf[8];
  310. if (!is_active( screen_buffer ) || rect->top > rect->bottom || rect->right < rect->left)
  311. return;
  312. TRACE( "%s\n", wine_dbgstr_rect( rect ));
  313. if (screen_buffer->console->window)
  314. {
  315. update_window_region( screen_buffer->console, rect );
  316. return;
  317. }
  318. if (!screen_buffer->console->tty_output) return;
  319. hide_tty_cursor( screen_buffer->console );
  320. for (y = rect->top; y <= rect->bottom; y++)
  321. {
  322. for (trailing_spaces = 0; trailing_spaces < screen_buffer->width; trailing_spaces++)
  323. {
  324. ch = &screen_buffer->data[(y + 1) * screen_buffer->width - trailing_spaces - 1];
  325. if (ch->ch != ' ' || ch->attr != 7) break;
  326. }
  327. if (trailing_spaces < 4) trailing_spaces = 0;
  328. for (x = rect->left; x <= rect->right; x++)
  329. {
  330. ch = &screen_buffer->data[y * screen_buffer->width + x];
  331. set_tty_attr( screen_buffer->console, ch->attr );
  332. set_tty_cursor( screen_buffer->console, x, y );
  333. if (x + trailing_spaces >= screen_buffer->width)
  334. {
  335. tty_write( screen_buffer->console, "\x1b[K", 3 );
  336. break;
  337. }
  338. size = WideCharToMultiByte( get_tty_cp( screen_buffer->console ), 0,
  339. &ch->ch, 1, buf, sizeof(buf), NULL, NULL );
  340. tty_write( screen_buffer->console, buf, size );
  341. screen_buffer->console->tty_cursor_x++;
  342. }
  343. }
  344. empty_update_rect( screen_buffer, rect );
  345. }
  346. static void new_line( struct screen_buffer *screen_buffer, RECT *update_rect )
  347. {
  348. unsigned int i;
  349. assert( screen_buffer->cursor_y >= screen_buffer->height );
  350. screen_buffer->cursor_y = screen_buffer->height - 1;
  351. if (screen_buffer->console->tty_output)
  352. update_output( screen_buffer, update_rect );
  353. else
  354. SetRect( update_rect, 0, 0, screen_buffer->width - 1, screen_buffer->height - 1 );
  355. memmove( screen_buffer->data, screen_buffer->data + screen_buffer->width,
  356. screen_buffer->width * (screen_buffer->height - 1) * sizeof(*screen_buffer->data) );
  357. for (i = 0; i < screen_buffer->width; i++)
  358. screen_buffer->data[screen_buffer->width * (screen_buffer->height - 1) + i] = empty_char_info;
  359. if (is_active( screen_buffer ))
  360. {
  361. screen_buffer->console->tty_cursor_y--;
  362. if (screen_buffer->console->tty_cursor_y != screen_buffer->height - 2)
  363. set_tty_cursor( screen_buffer->console, 0, screen_buffer->height - 2 );
  364. set_tty_cursor( screen_buffer->console, 0, screen_buffer->height - 1 );
  365. }
  366. }
  367. static void write_char( struct screen_buffer *screen_buffer, WCHAR ch, RECT *update_rect, unsigned int *home_y )
  368. {
  369. if (screen_buffer->cursor_x == screen_buffer->width)
  370. {
  371. screen_buffer->cursor_x = 0;
  372. screen_buffer->cursor_y++;
  373. }
  374. if (screen_buffer->cursor_y == screen_buffer->height)
  375. {
  376. if (home_y)
  377. {
  378. if (!*home_y) return;
  379. (*home_y)--;
  380. }
  381. new_line( screen_buffer, update_rect );
  382. }
  383. screen_buffer->data[screen_buffer->cursor_y * screen_buffer->width + screen_buffer->cursor_x].ch = ch;
  384. screen_buffer->data[screen_buffer->cursor_y * screen_buffer->width + screen_buffer->cursor_x].attr = screen_buffer->attr;
  385. update_rect->left = min( update_rect->left, screen_buffer->cursor_x );
  386. update_rect->top = min( update_rect->top, screen_buffer->cursor_y );
  387. update_rect->right = max( update_rect->right, screen_buffer->cursor_x );
  388. update_rect->bottom = max( update_rect->bottom, screen_buffer->cursor_y );
  389. screen_buffer->cursor_x++;
  390. }
  391. static NTSTATUS read_complete( struct console *console, NTSTATUS status, const void *buf, size_t size, int signal )
  392. {
  393. SERVER_START_REQ( get_next_console_request )
  394. {
  395. req->handle = wine_server_obj_handle( console->server );
  396. req->signal = signal;
  397. req->read = 1;
  398. req->status = status;
  399. wine_server_add_data( req, buf, size );
  400. status = wine_server_call( req );
  401. }
  402. SERVER_END_REQ;
  403. if (status && (console->read_ioctl || status != STATUS_INVALID_HANDLE)) ERR( "failed: %#x\n", status );
  404. console->signaled = signal;
  405. console->read_ioctl = 0;
  406. console->pending_read = 0;
  407. return status;
  408. }
  409. static NTSTATUS read_console_input( struct console *console, size_t out_size )
  410. {
  411. size_t count = min( out_size / sizeof(INPUT_RECORD), console->record_count );
  412. TRACE("count %u\n", count);
  413. read_complete( console, STATUS_SUCCESS, console->records, count * sizeof(*console->records),
  414. console->record_count > count );
  415. if (count < console->record_count)
  416. memmove( console->records, console->records + count,
  417. (console->record_count - count) * sizeof(*console->records) );
  418. console->record_count -= count;
  419. return STATUS_SUCCESS;
  420. }
  421. static void read_from_buffer( struct console *console, size_t out_size )
  422. {
  423. size_t len, read_len = 0;
  424. char *buf = NULL;
  425. switch( console->read_ioctl )
  426. {
  427. case IOCTL_CONDRV_READ_CONSOLE:
  428. out_size = min( out_size, console->read_buffer_count * sizeof(WCHAR) );
  429. read_complete( console, STATUS_SUCCESS, console->read_buffer, out_size, console->record_count != 0 );
  430. read_len = out_size / sizeof(WCHAR);
  431. break;
  432. case IOCTL_CONDRV_READ_FILE:
  433. read_len = len = 0;
  434. while (read_len < console->read_buffer_count && len < out_size)
  435. {
  436. len += WideCharToMultiByte( console->input_cp, 0, console->read_buffer + read_len, 1, NULL, 0, NULL, NULL );
  437. read_len++;
  438. }
  439. if (len)
  440. {
  441. if (!(buf = malloc( len )))
  442. {
  443. read_complete( console, STATUS_NO_MEMORY, NULL, 0, console->record_count != 0 );
  444. return;
  445. }
  446. WideCharToMultiByte( console->input_cp, 0, console->read_buffer, read_len, buf, len, NULL, NULL );
  447. }
  448. len = min( out_size, len );
  449. read_complete( console, STATUS_SUCCESS, buf, len, console->record_count != 0 );
  450. free( buf );
  451. break;
  452. }
  453. if (read_len < console->read_buffer_count)
  454. {
  455. memmove( console->read_buffer, console->read_buffer + read_len,
  456. (console->read_buffer_count - read_len) * sizeof(WCHAR) );
  457. }
  458. if (!(console->read_buffer_count -= read_len))
  459. free( console->read_buffer );
  460. }
  461. static void append_input_history( struct console *console, const WCHAR *str, size_t len )
  462. {
  463. struct history_line *ptr;
  464. if (!console->history_size) return;
  465. /* don't duplicate entry */
  466. if (console->history_mode && console->history_index &&
  467. console->history[console->history_index - 1]->len == len &&
  468. !memcmp( console->history[console->history_index - 1]->text, str, len ))
  469. return;
  470. if (!(ptr = malloc( offsetof( struct history_line, text[len / sizeof(WCHAR)] )))) return;
  471. ptr->len = len;
  472. memcpy( ptr->text, str, len );
  473. if (console->history_index < console->history_size)
  474. {
  475. console->history[console->history_index++] = ptr;
  476. }
  477. else
  478. {
  479. free( console->history[0]) ;
  480. memmove( &console->history[0], &console->history[1],
  481. (console->history_size - 1) * sizeof(*console->history) );
  482. console->history[console->history_size - 1] = ptr;
  483. }
  484. }
  485. static void edit_line_update( struct console *console, unsigned int begin, unsigned int length )
  486. {
  487. struct edit_line *ctx = &console->edit_line;
  488. if (!length) return;
  489. ctx->update_begin = min( ctx->update_begin, begin );
  490. ctx->update_end = max( ctx->update_end, begin + length - 1 );
  491. }
  492. static BOOL edit_line_grow( struct console *console, size_t length )
  493. {
  494. struct edit_line *ctx = &console->edit_line;
  495. WCHAR *new_buf;
  496. size_t new_size;
  497. if (ctx->len + length < ctx->size) return TRUE;
  498. /* round up size to 32 byte-WCHAR boundary */
  499. new_size = (ctx->len + length + 32) & ~31;
  500. if (!(new_buf = realloc( ctx->buf, sizeof(WCHAR) * new_size )))
  501. {
  502. ctx->status = STATUS_NO_MEMORY;
  503. return FALSE;
  504. }
  505. ctx->buf = new_buf;
  506. ctx->size = new_size;
  507. return TRUE;
  508. }
  509. static void edit_line_delete( struct console *console, int begin, int end )
  510. {
  511. struct edit_line *ctx = &console->edit_line;
  512. unsigned int len = end - begin;
  513. edit_line_update( console, begin, ctx->len - begin );
  514. if (end < ctx->len)
  515. memmove( &ctx->buf[begin], &ctx->buf[end], (ctx->len - end) * sizeof(WCHAR));
  516. ctx->len -= len;
  517. edit_line_update( console, 0, ctx->len );
  518. ctx->buf[ctx->len] = 0;
  519. }
  520. static void edit_line_insert( struct console *console, const WCHAR *str, unsigned int len )
  521. {
  522. struct edit_line *ctx = &console->edit_line;
  523. unsigned int update_len;
  524. if (!len) return;
  525. if (ctx->insert_mode)
  526. {
  527. if (!edit_line_grow( console, len )) return;
  528. if (ctx->len > ctx->cursor)
  529. memmove( &ctx->buf[ctx->cursor + len], &ctx->buf[ctx->cursor],
  530. (ctx->len - ctx->cursor) * sizeof(WCHAR) );
  531. ctx->len += len;
  532. update_len = ctx->len - ctx->cursor;
  533. }
  534. else
  535. {
  536. if (ctx->cursor + len > ctx->len)
  537. {
  538. if (!edit_line_grow( console, (ctx->cursor + len) - ctx->len) )
  539. return;
  540. ctx->len = ctx->cursor + len;
  541. }
  542. update_len = len;
  543. }
  544. memcpy( &ctx->buf[ctx->cursor], str, len * sizeof(WCHAR) );
  545. ctx->buf[ctx->len] = 0;
  546. edit_line_update( console, ctx->cursor, update_len );
  547. ctx->cursor += len;
  548. }
  549. static void edit_line_save_yank( struct console *console, unsigned int begin, unsigned int end )
  550. {
  551. struct edit_line *ctx = &console->edit_line;
  552. unsigned int len = end - begin;
  553. if (len <= 0) return;
  554. free(ctx->yanked);
  555. ctx->yanked = malloc( (len + 1) * sizeof(WCHAR) );
  556. if (!ctx->yanked)
  557. {
  558. ctx->status = STATUS_NO_MEMORY;
  559. return;
  560. }
  561. memcpy( ctx->yanked, &ctx->buf[begin], len * sizeof(WCHAR) );
  562. ctx->yanked[len] = 0;
  563. }
  564. static int edit_line_left_word_transition( struct console *console, int offset )
  565. {
  566. offset--;
  567. while (offset >= 0 && !iswalnum( console->edit_line.buf[offset] )) offset--;
  568. while (offset >= 0 && iswalnum( console->edit_line.buf[offset] )) offset--;
  569. if (offset >= 0) offset++;
  570. return max( offset, 0 );
  571. }
  572. static int edit_line_right_word_transition( struct console *console, int offset )
  573. {
  574. offset++;
  575. while (offset <= console->edit_line.len && iswalnum( console->edit_line.buf[offset] ))
  576. offset++;
  577. while (offset <= console->edit_line.len && !iswalnum( console->edit_line.buf[offset] ))
  578. offset++;
  579. return min(offset, console->edit_line.len);
  580. }
  581. static WCHAR *edit_line_history( struct console *console, unsigned int index )
  582. {
  583. WCHAR *ptr = NULL;
  584. if (index < console->history_index)
  585. {
  586. if ((ptr = malloc( console->history[index]->len + sizeof(WCHAR) )))
  587. {
  588. memcpy( ptr, console->history[index]->text, console->history[index]->len );
  589. ptr[console->history[index]->len / sizeof(WCHAR)] = 0;
  590. }
  591. }
  592. else if(console->edit_line.current_history)
  593. {
  594. if ((ptr = malloc( (lstrlenW(console->edit_line.current_history) + 1) * sizeof(WCHAR) )))
  595. lstrcpyW( ptr, console->edit_line.current_history );
  596. }
  597. return ptr;
  598. }
  599. static void edit_line_move_to_history( struct console *console, int index )
  600. {
  601. struct edit_line *ctx = &console->edit_line;
  602. WCHAR *line = edit_line_history(console, index);
  603. size_t len = line ? lstrlenW(line) : 0;
  604. /* save current line edition for recall when needed */
  605. if (ctx->history_index == console->history_index)
  606. {
  607. free( ctx->current_history );
  608. ctx->current_history = malloc( (ctx->len + 1) * sizeof(WCHAR) );
  609. if (ctx->current_history)
  610. {
  611. memcpy( ctx->current_history, ctx->buf, (ctx->len + 1) * sizeof(WCHAR) );
  612. }
  613. else
  614. {
  615. ctx->status = STATUS_NO_MEMORY;
  616. return;
  617. }
  618. }
  619. /* need to clean also the screen if new string is shorter than old one */
  620. edit_line_delete(console, 0, ctx->len);
  621. ctx->cursor = 0;
  622. /* insert new string */
  623. if (edit_line_grow(console, len + 1))
  624. {
  625. edit_line_insert( console, line, len );
  626. ctx->history_index = index;
  627. }
  628. free(line);
  629. }
  630. static void edit_line_find_in_history( struct console *console )
  631. {
  632. struct edit_line *ctx = &console->edit_line;
  633. int start_pos = ctx->history_index;
  634. unsigned int len, oldoffset;
  635. WCHAR *line;
  636. if (!console->history_index) return;
  637. if (ctx->history_index && ctx->history_index == console->history_index)
  638. {
  639. start_pos--;
  640. ctx->history_index--;
  641. }
  642. do
  643. {
  644. line = edit_line_history(console, ctx->history_index);
  645. if (ctx->history_index) ctx->history_index--;
  646. else ctx->history_index = console->history_index - 1;
  647. len = lstrlenW(line) + 1;
  648. if (len >= ctx->cursor && !memcmp( ctx->buf, line, ctx->cursor * sizeof(WCHAR) ))
  649. {
  650. /* need to clean also the screen if new string is shorter than old one */
  651. edit_line_delete(console, 0, ctx->len);
  652. if (edit_line_grow(console, len))
  653. {
  654. oldoffset = ctx->cursor;
  655. ctx->cursor = 0;
  656. edit_line_insert( console, line, len - 1 );
  657. ctx->cursor = oldoffset;
  658. free(line);
  659. return;
  660. }
  661. }
  662. free(line);
  663. }
  664. while (ctx->history_index != start_pos);
  665. }
  666. static void edit_line_move_left( struct console *console )
  667. {
  668. if (console->edit_line.cursor > 0) console->edit_line.cursor--;
  669. }
  670. static void edit_line_move_right( struct console *console )
  671. {
  672. struct edit_line *ctx = &console->edit_line;
  673. if (ctx->cursor < ctx->len) ctx->cursor++;
  674. }
  675. static void edit_line_move_left_word( struct console *console )
  676. {
  677. console->edit_line.cursor = edit_line_left_word_transition( console, console->edit_line.cursor );
  678. }
  679. static void edit_line_move_right_word( struct console *console )
  680. {
  681. console->edit_line.cursor = edit_line_right_word_transition( console, console->edit_line.cursor );
  682. }
  683. static void edit_line_move_home( struct console *console )
  684. {
  685. console->edit_line.cursor = 0;
  686. }
  687. static void edit_line_move_end( struct console *console )
  688. {
  689. console->edit_line.cursor = console->edit_line.len;
  690. }
  691. static void edit_line_set_mark( struct console *console )
  692. {
  693. console->edit_line.mark = console->edit_line.cursor;
  694. }
  695. static void edit_line_exchange_mark( struct console *console )
  696. {
  697. struct edit_line *ctx = &console->edit_line;
  698. unsigned int cursor;
  699. if (ctx->mark > ctx->len) return;
  700. cursor = ctx->cursor;
  701. ctx->cursor = ctx->mark;
  702. ctx->mark = cursor;
  703. }
  704. static void edit_line_copy_marked_zone( struct console *console )
  705. {
  706. struct edit_line *ctx = &console->edit_line;
  707. unsigned int begin, end;
  708. if (ctx->mark > ctx->len || ctx->mark == ctx->cursor) return;
  709. if (ctx->mark > ctx->cursor)
  710. {
  711. begin = ctx->cursor;
  712. end = ctx->mark;
  713. }
  714. else
  715. {
  716. begin = ctx->mark;
  717. end = ctx->cursor;
  718. }
  719. edit_line_save_yank( console, begin, end );
  720. }
  721. static void edit_line_transpose_char( struct console *console )
  722. {
  723. struct edit_line *ctx = &console->edit_line;
  724. WCHAR c;
  725. if (!ctx->cursor || ctx->cursor == ctx->len) return;
  726. c = ctx->buf[ctx->cursor];
  727. ctx->buf[ctx->cursor] = ctx->buf[ctx->cursor - 1];
  728. ctx->buf[ctx->cursor - 1] = c;
  729. edit_line_update( console, ctx->cursor - 1, 2 );
  730. ctx->cursor++;
  731. }
  732. static void edit_line_transpose_words( struct console *console )
  733. {
  734. struct edit_line *ctx = &console->edit_line;
  735. unsigned int left_offset = edit_line_left_word_transition( console, ctx->cursor );
  736. unsigned int right_offset = edit_line_right_word_transition( console, ctx->cursor );
  737. if (left_offset < ctx->cursor && right_offset > ctx->cursor)
  738. {
  739. unsigned int len_r = right_offset - ctx->cursor;
  740. unsigned int len_l = ctx->cursor - left_offset;
  741. char *tmp = malloc( len_r * sizeof(WCHAR) );
  742. if (!tmp)
  743. {
  744. ctx->status = STATUS_NO_MEMORY;
  745. return;
  746. }
  747. memcpy( tmp, &ctx->buf[ctx->cursor], len_r * sizeof(WCHAR) );
  748. memmove( &ctx->buf[left_offset + len_r], &ctx->buf[left_offset],
  749. len_l * sizeof(WCHAR) );
  750. memcpy( &ctx->buf[left_offset], tmp, len_r * sizeof(WCHAR) );
  751. free(tmp);
  752. edit_line_update( console, left_offset, len_l + len_r );
  753. ctx->cursor = right_offset;
  754. }
  755. }
  756. static void edit_line_lower_case_word( struct console *console )
  757. {
  758. struct edit_line *ctx = &console->edit_line;
  759. unsigned int new_offset = edit_line_right_word_transition( console, ctx->cursor );
  760. if (new_offset != ctx->cursor)
  761. {
  762. CharLowerBuffW( ctx->buf + ctx->cursor, new_offset - ctx->cursor + 1 );
  763. edit_line_update( console, ctx->cursor, new_offset - ctx->cursor + 1 );
  764. ctx->cursor = new_offset;
  765. }
  766. }
  767. static void edit_line_upper_case_word( struct console *console )
  768. {
  769. struct edit_line *ctx = &console->edit_line;
  770. unsigned int new_offset = edit_line_right_word_transition( console, ctx->cursor );
  771. if (new_offset != ctx->cursor)
  772. {
  773. CharUpperBuffW( ctx->buf + ctx->cursor, new_offset - ctx->cursor + 1 );
  774. edit_line_update( console, ctx->cursor, new_offset - ctx->cursor + 1 );
  775. ctx->cursor = new_offset;
  776. }
  777. }
  778. static void edit_line_capitalize_word( struct console *console )
  779. {
  780. struct edit_line *ctx = &console->edit_line;
  781. unsigned int new_offset = edit_line_right_word_transition( console, ctx->cursor );
  782. if (new_offset != ctx->cursor)
  783. {
  784. CharUpperBuffW( ctx->buf + ctx->cursor, 1 );
  785. CharLowerBuffW( ctx->buf + ctx->cursor + 1, new_offset - ctx->cursor );
  786. edit_line_update( console, ctx->cursor, new_offset - ctx->cursor + 1 );
  787. ctx->cursor = new_offset;
  788. }
  789. }
  790. static void edit_line_yank( struct console *console )
  791. {
  792. struct edit_line *ctx = &console->edit_line;
  793. if (ctx->yanked) edit_line_insert( console, ctx->yanked, wcslen(ctx->yanked) );
  794. }
  795. static void edit_line_kill_suffix( struct console *console )
  796. {
  797. struct edit_line *ctx = &console->edit_line;
  798. edit_line_save_yank( console, ctx->cursor, ctx->len );
  799. edit_line_delete( console, ctx->cursor, ctx->len );
  800. }
  801. static void edit_line_kill_prefix( struct console *console )
  802. {
  803. struct edit_line *ctx = &console->edit_line;
  804. if (ctx->cursor)
  805. {
  806. edit_line_save_yank( console, 0, ctx->cursor );
  807. edit_line_delete( console, 0, ctx->cursor );
  808. ctx->cursor = 0;
  809. }
  810. }
  811. static void edit_line_kill_marked_zone( struct console *console )
  812. {
  813. struct edit_line *ctx = &console->edit_line;
  814. unsigned int begin, end;
  815. if (ctx->mark > ctx->len || ctx->mark == ctx->cursor)
  816. return;
  817. if (ctx->mark > ctx->cursor)
  818. {
  819. begin = ctx->cursor;
  820. end = ctx->mark;
  821. }
  822. else
  823. {
  824. begin = ctx->mark;
  825. end = ctx->cursor;
  826. }
  827. edit_line_save_yank( console, begin, end );
  828. edit_line_delete( console, begin, end );
  829. ctx->cursor = begin;
  830. }
  831. static void edit_line_delete_prev( struct console *console )
  832. {
  833. struct edit_line *ctx = &console->edit_line;
  834. if (ctx->cursor)
  835. {
  836. edit_line_delete( console, ctx->cursor - 1, ctx->cursor );
  837. ctx->cursor--;
  838. }
  839. }
  840. static void edit_line_delete_char( struct console *console )
  841. {
  842. struct edit_line *ctx = &console->edit_line;
  843. if (ctx->cursor < ctx->len)
  844. edit_line_delete( console, ctx->cursor, ctx->cursor + 1 );
  845. }
  846. static void edit_line_delete_left_word( struct console *console )
  847. {
  848. struct edit_line *ctx = &console->edit_line;
  849. unsigned int new_offset = edit_line_left_word_transition( console, ctx->cursor );
  850. if (new_offset != ctx->cursor)
  851. {
  852. edit_line_delete( console, new_offset, ctx->cursor );
  853. ctx->cursor = new_offset;
  854. }
  855. }
  856. static void edit_line_delete_right_word( struct console *console )
  857. {
  858. struct edit_line *ctx = &console->edit_line;
  859. unsigned int new_offset = edit_line_right_word_transition( console, ctx->cursor );
  860. if (new_offset != ctx->cursor)
  861. {
  862. edit_line_delete( console, ctx->cursor, new_offset );
  863. }
  864. }
  865. static void edit_line_move_to_prev_hist( struct console *console )
  866. {
  867. if (console->edit_line.history_index)
  868. edit_line_move_to_history( console, console->edit_line.history_index - 1 );
  869. }
  870. static void edit_line_move_to_next_hist( struct console *console )
  871. {
  872. if (console->edit_line.history_index < console->history_index)
  873. edit_line_move_to_history( console, console->edit_line.history_index + 1 );
  874. }
  875. static void edit_line_move_to_first_hist( struct console *console )
  876. {
  877. if (console->edit_line.history_index)
  878. edit_line_move_to_history( console, 0 );
  879. }
  880. static void edit_line_move_to_last_hist( struct console *console )
  881. {
  882. if (console->edit_line.history_index != console->history_index)
  883. edit_line_move_to_history( console, console->history_index );
  884. }
  885. static void edit_line_redraw( struct console *console )
  886. {
  887. if (console->mode & ENABLE_ECHO_INPUT)
  888. edit_line_update( console, 0, console->edit_line.len );
  889. }
  890. static void edit_line_toggle_insert( struct console *console )
  891. {
  892. struct edit_line *ctx = &console->edit_line;
  893. ctx->insert_key = !ctx->insert_key;
  894. console->active->cursor_size = ctx->insert_key ? 100 : 25;
  895. }
  896. static void edit_line_done( struct console *console )
  897. {
  898. console->edit_line.status = STATUS_SUCCESS;
  899. }
  900. struct edit_line_key_entry
  901. {
  902. WCHAR val; /* vk or unicode char */
  903. void (*func)( struct console *console );
  904. };
  905. struct edit_line_key_map
  906. {
  907. DWORD key_state; /* keyState (from INPUT_RECORD) to match */
  908. BOOL is_char; /* check vk or char */
  909. const struct edit_line_key_entry *entries;
  910. };
  911. #define CTRL(x) ((x) - '@')
  912. static const struct edit_line_key_entry std_key_map[] =
  913. {
  914. { VK_BACK, edit_line_delete_prev },
  915. { VK_RETURN, edit_line_done },
  916. { VK_DELETE, edit_line_delete_char },
  917. { 0 }
  918. };
  919. static const struct edit_line_key_entry emacs_key_map_ctrl[] =
  920. {
  921. { CTRL('@'), edit_line_set_mark },
  922. { CTRL('A'), edit_line_move_home },
  923. { CTRL('B'), edit_line_move_left },
  924. { CTRL('D'), edit_line_delete_char },
  925. { CTRL('E'), edit_line_move_end },
  926. { CTRL('F'), edit_line_move_right },
  927. { CTRL('H'), edit_line_delete_prev },
  928. { CTRL('J'), edit_line_done },
  929. { CTRL('K'), edit_line_kill_suffix },
  930. { CTRL('L'), edit_line_redraw },
  931. { CTRL('M'), edit_line_done },
  932. { CTRL('N'), edit_line_move_to_next_hist },
  933. { CTRL('P'), edit_line_move_to_prev_hist },
  934. { CTRL('T'), edit_line_transpose_char },
  935. { CTRL('W'), edit_line_kill_marked_zone },
  936. { CTRL('X'), edit_line_exchange_mark },
  937. { CTRL('Y'), edit_line_yank },
  938. { 0 }
  939. };
  940. static const struct edit_line_key_entry emacs_key_map_alt[] =
  941. {
  942. { 0x7f, edit_line_delete_left_word },
  943. { '<', edit_line_move_to_first_hist },
  944. { '>', edit_line_move_to_last_hist },
  945. { 'b', edit_line_move_left_word },
  946. { 'c', edit_line_capitalize_word },
  947. { 'd', edit_line_delete_right_word },
  948. { 'f', edit_line_move_right_word },
  949. { 'l', edit_line_lower_case_word },
  950. { 't', edit_line_transpose_words },
  951. { 'u', edit_line_upper_case_word },
  952. { 'w', edit_line_copy_marked_zone },
  953. { 0 }
  954. };
  955. static const struct edit_line_key_entry emacs_std_key_map[] =
  956. {
  957. { VK_PRIOR, edit_line_move_to_prev_hist },
  958. { VK_NEXT, edit_line_move_to_next_hist },
  959. { VK_END, edit_line_move_end },
  960. { VK_HOME, edit_line_move_home },
  961. { VK_RIGHT, edit_line_move_right },
  962. { VK_LEFT, edit_line_move_left },
  963. { VK_INSERT, edit_line_toggle_insert },
  964. { 0 }
  965. };
  966. static const struct edit_line_key_map emacs_key_map[] =
  967. {
  968. { 0, 0, std_key_map },
  969. { 0, 0, emacs_std_key_map },
  970. { RIGHT_ALT_PRESSED, 1, emacs_key_map_alt },
  971. { LEFT_ALT_PRESSED, 1, emacs_key_map_alt },
  972. { RIGHT_CTRL_PRESSED, 1, emacs_key_map_ctrl },
  973. { LEFT_CTRL_PRESSED, 1, emacs_key_map_ctrl },
  974. { 0 }
  975. };
  976. static const struct edit_line_key_entry win32_std_key_map[] =
  977. {
  978. { VK_LEFT, edit_line_move_left },
  979. { VK_RIGHT, edit_line_move_right },
  980. { VK_HOME, edit_line_move_home },
  981. { VK_END, edit_line_move_end },
  982. { VK_UP, edit_line_move_to_prev_hist },
  983. { VK_DOWN, edit_line_move_to_next_hist },
  984. { VK_INSERT, edit_line_toggle_insert },
  985. { VK_F8, edit_line_find_in_history },
  986. { 0 }
  987. };
  988. static const struct edit_line_key_entry win32_key_map_ctrl[] =
  989. {
  990. { VK_LEFT, edit_line_move_left_word },
  991. { VK_RIGHT, edit_line_move_right_word },
  992. { VK_END, edit_line_kill_suffix },
  993. { VK_HOME, edit_line_kill_prefix },
  994. { 'M', edit_line_done },
  995. { 0 }
  996. };
  997. static const struct edit_line_key_map win32_key_map[] =
  998. {
  999. { 0, 0, std_key_map },
  1000. { SHIFT_PRESSED, 0, std_key_map },
  1001. { 0, 0, win32_std_key_map },
  1002. { RIGHT_CTRL_PRESSED, 0, win32_key_map_ctrl },
  1003. { LEFT_CTRL_PRESSED, 0, win32_key_map_ctrl },
  1004. { 0 }
  1005. };
  1006. #undef CTRL
  1007. static unsigned int edit_line_string_width( const WCHAR *str, unsigned int len)
  1008. {
  1009. unsigned int i, offset = 0;
  1010. for (i = 0; i < len; i++) offset += str[i] < ' ' ? 2 : 1;
  1011. return offset;
  1012. }
  1013. static void update_read_output( struct console *console )
  1014. {
  1015. struct screen_buffer *screen_buffer = console->active;
  1016. struct edit_line *ctx = &console->edit_line;
  1017. int offset = 0, j, end_offset;
  1018. RECT update_rect;
  1019. empty_update_rect( screen_buffer, &update_rect );
  1020. if (ctx->update_end >= ctx->update_begin)
  1021. {
  1022. TRACE( "update %d-%d %s\n", ctx->update_begin, ctx->update_end,
  1023. debugstr_wn( ctx->buf + ctx->update_begin, ctx->update_end - ctx->update_begin + 1 ));
  1024. hide_tty_cursor( screen_buffer->console );
  1025. offset = edit_line_string_width( ctx->buf, ctx->update_begin );
  1026. screen_buffer->cursor_x = (ctx->home_x + offset) % screen_buffer->width;
  1027. screen_buffer->cursor_y = ctx->home_y + (ctx->home_x + offset) / screen_buffer->width;
  1028. for (j = ctx->update_begin; j <= ctx->update_end; j++)
  1029. {
  1030. if (screen_buffer->cursor_y >= screen_buffer->height && !ctx->home_y) break;
  1031. if (j >= ctx->len) break;
  1032. if (ctx->buf[j] < ' ')
  1033. {
  1034. write_char( screen_buffer, '^', &update_rect, &ctx->home_y );
  1035. write_char( screen_buffer, '@' + ctx->buf[j], &update_rect, &ctx->home_y );
  1036. offset += 2;
  1037. }
  1038. else
  1039. {
  1040. write_char( screen_buffer, ctx->buf[j], &update_rect, &ctx->home_y );
  1041. offset++;
  1042. }
  1043. }
  1044. end_offset = ctx->end_offset;
  1045. ctx->end_offset = offset;
  1046. if (j >= ctx->len)
  1047. {
  1048. /* clear trailing characters if buffer was shortened */
  1049. while (offset < end_offset && screen_buffer->cursor_y < screen_buffer->height)
  1050. {
  1051. write_char( screen_buffer, ' ', &update_rect, &ctx->home_y );
  1052. offset++;
  1053. }
  1054. }
  1055. }
  1056. if (!ctx->status)
  1057. {
  1058. offset = edit_line_string_width( ctx->buf, ctx->len );
  1059. screen_buffer->cursor_x = 0;
  1060. screen_buffer->cursor_y = ctx->home_y + (ctx->home_x + offset) / screen_buffer->width;
  1061. if (++screen_buffer->cursor_y >= screen_buffer->height)
  1062. new_line( screen_buffer, &update_rect );
  1063. }
  1064. else
  1065. {
  1066. offset = edit_line_string_width( ctx->buf, ctx->cursor );
  1067. screen_buffer->cursor_y = ctx->home_y + (ctx->home_x + offset) / screen_buffer->width;
  1068. if (screen_buffer->cursor_y < screen_buffer->height)
  1069. {
  1070. screen_buffer->cursor_x = (ctx->home_x + offset) % screen_buffer->width;
  1071. }
  1072. else
  1073. {
  1074. screen_buffer->cursor_x = screen_buffer->width - 1;
  1075. screen_buffer->cursor_y = screen_buffer->height - 1;
  1076. }
  1077. }
  1078. /* always try to use relative cursor positions in UNIX mode so that it works even if cursor
  1079. * position is out of sync */
  1080. if (update_rect.left <= update_rect.right && update_rect.top <= update_rect.bottom)
  1081. {
  1082. if (console->is_unix)
  1083. set_tty_cursor_relative( screen_buffer->console, update_rect.left, update_rect.top );
  1084. update_output( screen_buffer, &update_rect );
  1085. scroll_to_cursor( screen_buffer );
  1086. }
  1087. if (console->is_unix)
  1088. set_tty_cursor_relative( screen_buffer->console, screen_buffer->cursor_x, screen_buffer->cursor_y );
  1089. tty_sync( screen_buffer->console );
  1090. update_window_config( screen_buffer->console, TRUE );
  1091. }
  1092. static NTSTATUS process_console_input( struct console *console )
  1093. {
  1094. struct edit_line *ctx = &console->edit_line;
  1095. unsigned int i;
  1096. switch (console->read_ioctl)
  1097. {
  1098. case IOCTL_CONDRV_READ_INPUT:
  1099. if (console->record_count) read_console_input( console, console->pending_read );
  1100. return STATUS_SUCCESS;
  1101. case IOCTL_CONDRV_READ_CONSOLE:
  1102. case IOCTL_CONDRV_READ_FILE:
  1103. break;
  1104. default:
  1105. assert( !console->read_ioctl );
  1106. if (console->record_count && !console->signaled)
  1107. read_complete( console, STATUS_PENDING, NULL, 0, TRUE ); /* signal server */
  1108. return STATUS_SUCCESS;
  1109. }
  1110. ctx->update_begin = ctx->len + 1;
  1111. ctx->update_end = 0;
  1112. for (i = 0; i < console->record_count && ctx->status == STATUS_PENDING; i++)
  1113. {
  1114. void (*func)( struct console *console ) = NULL;
  1115. INPUT_RECORD ir = console->records[i];
  1116. if (ir.EventType != KEY_EVENT || !ir.Event.KeyEvent.bKeyDown) continue;
  1117. TRACE( "key code=%02x scan=%02x char=%02x state=%08x\n",
  1118. ir.Event.KeyEvent.wVirtualKeyCode, ir.Event.KeyEvent.wVirtualScanCode,
  1119. ir.Event.KeyEvent.uChar.UnicodeChar, ir.Event.KeyEvent.dwControlKeyState );
  1120. if (console->mode & ENABLE_LINE_INPUT)
  1121. {
  1122. const struct edit_line_key_entry *entry;
  1123. const struct edit_line_key_map *map;
  1124. unsigned int state;
  1125. /* mask out some bits which don't interest us */
  1126. state = ir.Event.KeyEvent.dwControlKeyState & ~(NUMLOCK_ON|SCROLLLOCK_ON|CAPSLOCK_ON|ENHANCED_KEY);
  1127. func = NULL;
  1128. for (map = console->edition_mode ? emacs_key_map : win32_key_map; map->entries != NULL; map++)
  1129. {
  1130. if (map->key_state != state)
  1131. continue;
  1132. if (map->is_char)
  1133. {
  1134. for (entry = &map->entries[0]; entry->func != 0; entry++)
  1135. if (entry->val == ir.Event.KeyEvent.uChar.UnicodeChar) break;
  1136. }
  1137. else
  1138. {
  1139. for (entry = &map->entries[0]; entry->func != 0; entry++)
  1140. if (entry->val == ir.Event.KeyEvent.wVirtualKeyCode) break;
  1141. }
  1142. if (entry->func)
  1143. {
  1144. func = entry->func;
  1145. break;
  1146. }
  1147. }
  1148. }
  1149. ctx->insert_mode = ((console->mode & (ENABLE_INSERT_MODE | ENABLE_EXTENDED_FLAGS)) ==
  1150. (ENABLE_INSERT_MODE | ENABLE_EXTENDED_FLAGS))
  1151. ^ ctx->insert_key;
  1152. if (func) func( console );
  1153. else if (ir.Event.KeyEvent.uChar.UnicodeChar)
  1154. edit_line_insert( console, &ir.Event.KeyEvent.uChar.UnicodeChar, 1 );
  1155. if (!(console->mode & ENABLE_LINE_INPUT) && ctx->status == STATUS_PENDING)
  1156. {
  1157. if (console->read_ioctl == IOCTL_CONDRV_READ_FILE)
  1158. {
  1159. if (WideCharToMultiByte(console->input_cp, 0, ctx->buf, ctx->len, NULL, 0, NULL, NULL)
  1160. >= console->pending_read)
  1161. ctx->status = STATUS_SUCCESS;
  1162. }
  1163. else if (ctx->len >= console->pending_read / sizeof(WCHAR))
  1164. ctx->status = STATUS_SUCCESS;
  1165. }
  1166. }
  1167. if (console->record_count > i) memmove( console->records, console->records + i,
  1168. (console->record_count - i) * sizeof(*console->records) );
  1169. console->record_count -= i;
  1170. if (ctx->status == STATUS_PENDING && !(console->mode & ENABLE_LINE_INPUT) && ctx->len)
  1171. ctx->status = STATUS_SUCCESS;
  1172. if (console->mode & ENABLE_ECHO_INPUT) update_read_output( console );
  1173. if (ctx->status == STATUS_PENDING) return STATUS_SUCCESS;
  1174. if (!ctx->status && (console->mode & ENABLE_LINE_INPUT))
  1175. {
  1176. if (ctx->len) append_input_history( console, ctx->buf, ctx->len * sizeof(WCHAR) );
  1177. if (edit_line_grow(console, 2))
  1178. {
  1179. ctx->buf[ctx->len++] = '\r';
  1180. ctx->buf[ctx->len++] = '\n';
  1181. ctx->buf[ctx->len] = 0;
  1182. TRACE( "return %s\n", debugstr_wn( ctx->buf, ctx->len ));
  1183. }
  1184. }
  1185. console->read_buffer = ctx->buf;
  1186. console->read_buffer_count = ctx->len;
  1187. console->read_buffer_size = ctx->size;
  1188. if (ctx->status) read_complete( console, ctx->status, NULL, 0, console->record_count );
  1189. else read_from_buffer( console, console->pending_read );
  1190. /* reset context */
  1191. free( ctx->yanked );
  1192. free( ctx->current_history );
  1193. memset( &console->edit_line, 0, sizeof(console->edit_line) );
  1194. return STATUS_SUCCESS;
  1195. }
  1196. static NTSTATUS read_console( struct console *console, unsigned int ioctl, size_t out_size )
  1197. {
  1198. TRACE("\n");
  1199. if (out_size > INT_MAX)
  1200. {
  1201. read_complete( console, STATUS_NO_MEMORY, NULL, 0, console->record_count );
  1202. return STATUS_NO_MEMORY;
  1203. }
  1204. console->read_ioctl = ioctl;
  1205. if (!out_size || console->read_buffer_count)
  1206. {
  1207. read_from_buffer( console, out_size );
  1208. return STATUS_SUCCESS;
  1209. }
  1210. console->edit_line.history_index = console->history_index;
  1211. console->edit_line.home_x = console->active->cursor_x;
  1212. console->edit_line.home_y = console->active->cursor_y;
  1213. console->edit_line.status = STATUS_PENDING;
  1214. if (edit_line_grow( console, 1 )) console->edit_line.buf[0] = 0;
  1215. console->pending_read = out_size;
  1216. return process_console_input( console );
  1217. }
  1218. /* add input events to a console input queue */
  1219. NTSTATUS write_console_input( struct console *console, const INPUT_RECORD *records,
  1220. unsigned int count, BOOL flush )
  1221. {
  1222. TRACE( "%u\n", count );
  1223. if (!count) return STATUS_SUCCESS;
  1224. if (console->record_count + count > console->record_size)
  1225. {
  1226. INPUT_RECORD *new_rec;
  1227. if (!(new_rec = realloc( console->records, (console->record_size * 2 + count) * sizeof(INPUT_RECORD) )))
  1228. return STATUS_NO_MEMORY;
  1229. console->records = new_rec;
  1230. console->record_size = console->record_size * 2 + count;
  1231. }
  1232. memcpy( console->records + console->record_count, records, count * sizeof(INPUT_RECORD) );
  1233. if (console->mode & ENABLE_PROCESSED_INPUT)
  1234. {
  1235. unsigned int i = 0;
  1236. while (i < count)
  1237. {
  1238. if (records[i].EventType == KEY_EVENT &&
  1239. records[i].Event.KeyEvent.uChar.UnicodeChar == 'C' - 64 &&
  1240. !(records[i].Event.KeyEvent.dwControlKeyState & ENHANCED_KEY))
  1241. {
  1242. if (i != count - 1)
  1243. memcpy( &console->records[console->record_count + i],
  1244. &console->records[console->record_count + i + 1],
  1245. (count - i - 1) * sizeof(INPUT_RECORD) );
  1246. count--;
  1247. if (records[i].Event.KeyEvent.bKeyDown)
  1248. {
  1249. struct condrv_ctrl_event ctrl_event;
  1250. IO_STATUS_BLOCK io;
  1251. ctrl_event.event = CTRL_C_EVENT;
  1252. ctrl_event.group_id = 0;
  1253. NtDeviceIoControlFile( console->server, NULL, NULL, NULL, &io, IOCTL_CONDRV_CTRL_EVENT,
  1254. &ctrl_event, sizeof(ctrl_event), NULL, 0 );
  1255. }
  1256. }
  1257. else i++;
  1258. }
  1259. }
  1260. console->record_count += count;
  1261. return flush ? process_console_input( console ) : STATUS_SUCCESS;
  1262. }
  1263. static void set_key_input_record( INPUT_RECORD *record, WCHAR ch, unsigned int vk, BOOL is_down, unsigned int ctrl_state )
  1264. {
  1265. record->EventType = KEY_EVENT;
  1266. record->Event.KeyEvent.bKeyDown = is_down;
  1267. record->Event.KeyEvent.wRepeatCount = 1;
  1268. record->Event.KeyEvent.uChar.UnicodeChar = ch;
  1269. record->Event.KeyEvent.wVirtualKeyCode = vk;
  1270. record->Event.KeyEvent.wVirtualScanCode = MapVirtualKeyW( vk, MAPVK_VK_TO_VSC );
  1271. record->Event.KeyEvent.dwControlKeyState = ctrl_state;
  1272. }
  1273. static NTSTATUS key_press( struct console *console, WCHAR ch, unsigned int vk, unsigned int ctrl_state )
  1274. {
  1275. INPUT_RECORD records[8];
  1276. unsigned int count = 0, ctrl = 0;
  1277. if (ctrl_state & SHIFT_PRESSED)
  1278. {
  1279. ctrl |= SHIFT_PRESSED;
  1280. set_key_input_record( &records[count++], 0, VK_SHIFT, TRUE, ctrl );
  1281. }
  1282. if (ctrl_state & LEFT_ALT_PRESSED)
  1283. {
  1284. ctrl |= LEFT_ALT_PRESSED;
  1285. set_key_input_record( &records[count++], 0, VK_MENU, TRUE, ctrl );
  1286. }
  1287. if (ctrl_state & LEFT_CTRL_PRESSED)
  1288. {
  1289. ctrl |= LEFT_CTRL_PRESSED;
  1290. set_key_input_record( &records[count++], 0, VK_CONTROL, TRUE, ctrl );
  1291. }
  1292. set_key_input_record( &records[count++], ch, vk, TRUE, ctrl );
  1293. set_key_input_record( &records[count++], ch, vk, FALSE, ctrl );
  1294. if (ctrl & LEFT_CTRL_PRESSED)
  1295. {
  1296. ctrl &= ~LEFT_CTRL_PRESSED;
  1297. set_key_input_record( &records[count++], 0, VK_CONTROL, FALSE, ctrl );
  1298. }
  1299. if (ctrl & LEFT_ALT_PRESSED)
  1300. {
  1301. ctrl &= ~LEFT_ALT_PRESSED;
  1302. set_key_input_record( &records[count++], 0, VK_MENU, FALSE, ctrl );
  1303. }
  1304. if (ctrl & SHIFT_PRESSED)
  1305. {
  1306. ctrl &= ~SHIFT_PRESSED;
  1307. set_key_input_record( &records[count++], 0, VK_SHIFT, FALSE, ctrl );
  1308. }
  1309. return write_console_input( console, records, count, FALSE );
  1310. }
  1311. static void char_key_press( struct console *console, WCHAR ch, unsigned int ctrl )
  1312. {
  1313. unsigned int vk = VkKeyScanW( ch );
  1314. if (vk == ~0) vk = 0;
  1315. if (vk & 0x0100) ctrl |= SHIFT_PRESSED;
  1316. if (vk & 0x0200) ctrl |= LEFT_CTRL_PRESSED;
  1317. if (vk & 0x0400) ctrl |= LEFT_ALT_PRESSED;
  1318. vk &= 0xff;
  1319. key_press( console, ch, vk, ctrl );
  1320. }
  1321. static unsigned int escape_char_to_vk( WCHAR ch )
  1322. {
  1323. switch (ch)
  1324. {
  1325. case 'A': return VK_UP;
  1326. case 'B': return VK_DOWN;
  1327. case 'C': return VK_RIGHT;
  1328. case 'D': return VK_LEFT;
  1329. case 'H': return VK_HOME;
  1330. case 'F': return VK_END;
  1331. case 'P': return VK_F1;
  1332. case 'Q': return VK_F2;
  1333. case 'R': return VK_F3;
  1334. case 'S': return VK_F4;
  1335. default: return 0;
  1336. }
  1337. }
  1338. static unsigned int escape_number_to_vk( unsigned int n )
  1339. {
  1340. switch(n)
  1341. {
  1342. case 2: return VK_INSERT;
  1343. case 3: return VK_DELETE;
  1344. case 5: return VK_PRIOR;
  1345. case 6: return VK_NEXT;
  1346. case 15: return VK_F5;
  1347. case 17: return VK_F6;
  1348. case 18: return VK_F7;
  1349. case 19: return VK_F8;
  1350. case 20: return VK_F9;
  1351. case 21: return VK_F10;
  1352. case 23: return VK_F11;
  1353. case 24: return VK_F12;
  1354. default: return 0;
  1355. }
  1356. }
  1357. static unsigned int convert_modifiers( unsigned int n )
  1358. {
  1359. unsigned int ctrl = 0;
  1360. if (!n || n > 16) return 0;
  1361. n--;
  1362. if (n & 1) ctrl |= SHIFT_PRESSED;
  1363. if (n & 2) ctrl |= LEFT_ALT_PRESSED;
  1364. if (n & 4) ctrl |= LEFT_CTRL_PRESSED;
  1365. return ctrl;
  1366. }
  1367. static unsigned int process_csi_sequence( struct console *console, const WCHAR *buf, size_t size )
  1368. {
  1369. unsigned int n, count = 0, params[8], params_cnt = 0, vk;
  1370. for (;;)
  1371. {
  1372. n = 0;
  1373. while (count < size && '0' <= buf[count] && buf[count] <= '9')
  1374. n = n * 10 + buf[count++] - '0';
  1375. if (params_cnt < ARRAY_SIZE(params)) params[params_cnt++] = n;
  1376. else FIXME( "too many params, skipping %u\n", n );
  1377. if (count == size) return 0;
  1378. if (buf[count] != ';') break;
  1379. if (++count == size) return 0;
  1380. }
  1381. if ((vk = escape_char_to_vk( buf[count] )))
  1382. {
  1383. key_press( console, 0, vk, params_cnt >= 2 ? convert_modifiers( params[1] ) : 0 );
  1384. return count + 1;
  1385. }
  1386. switch (buf[count])
  1387. {
  1388. case '~':
  1389. vk = escape_number_to_vk( params[0] );
  1390. key_press( console, 0, vk, params_cnt == 2 ? convert_modifiers( params[1] ) : 0 );
  1391. return count + 1;
  1392. default:
  1393. FIXME( "unhandled sequence %s\n", debugstr_wn( buf, size ));
  1394. return 0;
  1395. }
  1396. }
  1397. static unsigned int process_input_escape( struct console *console, const WCHAR *buf, size_t size )
  1398. {
  1399. unsigned int vk = 0, count = 0, nlen;
  1400. if (!size)
  1401. {
  1402. key_press( console, 0, VK_ESCAPE, 0 );
  1403. return 0;
  1404. }
  1405. switch(buf[0])
  1406. {
  1407. case '[':
  1408. if (++count == size) break;
  1409. if ((nlen = process_csi_sequence( console, buf + 1, size - 1 ))) return count + nlen;
  1410. break;
  1411. case 'O':
  1412. if (++count == size) break;
  1413. vk = escape_char_to_vk( buf[1] );
  1414. if (vk)
  1415. {
  1416. key_press( console, 0, vk, 0 );
  1417. return count + 1;
  1418. }
  1419. }
  1420. char_key_press( console, buf[0], LEFT_ALT_PRESSED );
  1421. return 1;
  1422. }
  1423. static DWORD WINAPI tty_input( void *param )
  1424. {
  1425. struct console *console = param;
  1426. IO_STATUS_BLOCK io;
  1427. HANDLE event;
  1428. char read_buf[4096];
  1429. WCHAR buf[4096];
  1430. DWORD count, i;
  1431. BOOL signaled;
  1432. NTSTATUS status;
  1433. if (console->is_unix)
  1434. {
  1435. unsigned int h = condrv_handle( console->tty_input );
  1436. status = NtDeviceIoControlFile( console->server, NULL, NULL, NULL, &io, IOCTL_CONDRV_SETUP_INPUT,
  1437. &h, sizeof(h), NULL, 0 );
  1438. if (status) ERR( "input setup failed: %#x\n", status );
  1439. }
  1440. event = CreateEventW( NULL, TRUE, FALSE, NULL );
  1441. for (;;)
  1442. {
  1443. status = NtReadFile( console->tty_input, event, NULL, NULL, &io, read_buf, sizeof(read_buf), NULL, NULL );
  1444. if (status == STATUS_PENDING)
  1445. {
  1446. if ((status = NtWaitForSingleObject( event, FALSE, NULL ))) break;
  1447. status = io.Status;
  1448. }
  1449. if (status) break;
  1450. EnterCriticalSection( &console_section );
  1451. signaled = console->record_count != 0;
  1452. /* FIXME: Handle partial char read */
  1453. count = MultiByteToWideChar( get_tty_cp( console ), 0, read_buf, io.Information, buf, ARRAY_SIZE(buf) );
  1454. TRACE( "%s\n", debugstr_wn(buf, count) );
  1455. for (i = 0; i < count; i++)
  1456. {
  1457. WCHAR ch = buf[i];
  1458. switch (ch)
  1459. {
  1460. case 3: /* end of text */
  1461. LeaveCriticalSection( &console_section );
  1462. goto done;
  1463. case '\n':
  1464. key_press( console, '\n', VK_RETURN, LEFT_CTRL_PRESSED );
  1465. break;
  1466. case '\b':
  1467. key_press( console, ch, 'H', LEFT_CTRL_PRESSED );
  1468. break;
  1469. case 0x1b:
  1470. i += process_input_escape( console, buf + i + 1, count - i - 1 );
  1471. break;
  1472. case 0x7f:
  1473. key_press( console, '\b', VK_BACK, 0 );
  1474. break;
  1475. default:
  1476. char_key_press( console, ch, 0 );
  1477. }
  1478. }
  1479. process_console_input( console );
  1480. if (!signaled && console->record_count)
  1481. {
  1482. assert( !console->read_ioctl );
  1483. read_complete( console, STATUS_SUCCESS, NULL, 0, TRUE ); /* signal console */
  1484. }
  1485. LeaveCriticalSection( &console_section );
  1486. }
  1487. TRACE( "NtReadFile failed: %#x\n", status );
  1488. done:
  1489. EnterCriticalSection( &console_section );
  1490. if (console->read_ioctl) read_complete( console, status, NULL, 0, FALSE );
  1491. if (console->is_unix)
  1492. {
  1493. unsigned int h = 0;
  1494. status = NtDeviceIoControlFile( console->server, NULL, NULL, NULL, &io, IOCTL_CONDRV_SETUP_INPUT,
  1495. &h, sizeof(h), NULL, 0 );
  1496. if (status) ERR( "input restore failed: %#x\n", status );
  1497. }
  1498. CloseHandle( console->input_thread );
  1499. console->input_thread = NULL;
  1500. LeaveCriticalSection( &console_section );
  1501. return 0;
  1502. }
  1503. static BOOL ensure_tty_input_thread( struct console *console )
  1504. {
  1505. if (!console->tty_input) return TRUE;
  1506. if (!console->input_thread)
  1507. console->input_thread = CreateThread( NULL, 0, tty_input, console, 0, NULL );
  1508. return console->input_thread != NULL;
  1509. }
  1510. static NTSTATUS screen_buffer_activate( struct screen_buffer *screen_buffer )
  1511. {
  1512. RECT update_rect;
  1513. TRACE( "%p\n", screen_buffer );
  1514. screen_buffer->console->active = screen_buffer;
  1515. SetRect( &update_rect, 0, 0, screen_buffer->width - 1, screen_buffer->height - 1 );
  1516. update_output( screen_buffer, &update_rect );
  1517. tty_sync( screen_buffer->console );
  1518. update_window_config( screen_buffer->console, FALSE );
  1519. return STATUS_SUCCESS;
  1520. }
  1521. static NTSTATUS get_output_info( struct screen_buffer *screen_buffer, size_t *out_size )
  1522. {
  1523. struct condrv_output_info *info;
  1524. *out_size = min( *out_size, sizeof(*info) + screen_buffer->font.face_len * sizeof(WCHAR) );
  1525. if (!(info = alloc_ioctl_buffer( *out_size ))) return STATUS_NO_MEMORY;
  1526. info->cursor_size = screen_buffer->cursor_size;
  1527. info->cursor_visible = screen_buffer->cursor_visible;
  1528. info->cursor_x = get_bounded_cursor_x( screen_buffer );
  1529. info->cursor_y = screen_buffer->cursor_y;
  1530. info->width = screen_buffer->width;
  1531. info->height = screen_buffer->height;
  1532. info->attr = screen_buffer->attr;
  1533. info->popup_attr = screen_buffer->popup_attr;
  1534. info->win_left = screen_buffer->win.left;
  1535. info->win_top = screen_buffer->win.top;
  1536. info->win_right = screen_buffer->win.right;
  1537. info->win_bottom = screen_buffer->win.bottom;
  1538. info->max_width = screen_buffer->max_width;
  1539. info->max_height = screen_buffer->max_height;
  1540. info->font_width = screen_buffer->font.width;
  1541. info->font_height = screen_buffer->font.height;
  1542. info->font_weight = screen_buffer->font.weight;
  1543. info->font_pitch_family = screen_buffer->font.pitch_family;
  1544. memcpy( info->color_map, screen_buffer->color_map, sizeof(info->color_map) );
  1545. if (*out_size > sizeof(*info)) memcpy( info + 1, screen_buffer->font.face_name, *out_size - sizeof(*info) );
  1546. TRACE( "%p cursor_size=%u cursor_visible=%x cursor=(%u,%u) width=%u height=%u win=%s attr=%x popup_attr=%x"
  1547. " font_width=%u font_height=%u %s\n", screen_buffer, info->cursor_size, info->cursor_visible,
  1548. info->cursor_x, info->cursor_y, info->width, info->height, wine_dbgstr_rect(&screen_buffer->win),
  1549. info->attr, info->popup_attr, info->font_width, info->font_height,
  1550. debugstr_wn( (const WCHAR *)(info + 1), (*out_size - sizeof(*info)) / sizeof(WCHAR) ) );
  1551. return STATUS_SUCCESS;
  1552. }
  1553. void notify_screen_buffer_size( struct screen_buffer *screen_buffer )
  1554. {
  1555. if (is_active( screen_buffer ) && screen_buffer->console->mode & ENABLE_WINDOW_INPUT)
  1556. {
  1557. INPUT_RECORD ir;
  1558. ir.EventType = WINDOW_BUFFER_SIZE_EVENT;
  1559. ir.Event.WindowBufferSizeEvent.dwSize.X = screen_buffer->width;
  1560. ir.Event.WindowBufferSizeEvent.dwSize.Y = screen_buffer->height;
  1561. write_console_input( screen_buffer->console, &ir, 1, TRUE );
  1562. }
  1563. }
  1564. NTSTATUS change_screen_buffer_size( struct screen_buffer *screen_buffer, int new_width, int new_height )
  1565. {
  1566. int i, old_width, old_height, copy_width, copy_height;
  1567. char_info_t *new_data;
  1568. if (!(new_data = malloc( new_width * new_height * sizeof(*new_data) ))) return STATUS_NO_MEMORY;
  1569. old_width = screen_buffer->width;
  1570. old_height = screen_buffer->height;
  1571. copy_width = min( old_width, new_width );
  1572. copy_height = min( old_height, new_height );
  1573. /* copy all the rows */
  1574. for (i = 0; i < copy_height; i++)
  1575. {
  1576. memcpy( &new_data[i * new_width], &screen_buffer->data[i * old_width],
  1577. copy_width * sizeof(char_info_t) );
  1578. }
  1579. /* clear the end of each row */
  1580. if (new_width > old_width)
  1581. {
  1582. /* fill first row */
  1583. for (i = old_width; i < new_width; i++) new_data[i] = empty_char_info;
  1584. /* and blast it to the other rows */
  1585. for (i = 1; i < copy_height; i++)
  1586. memcpy( &new_data[i * new_width + old_width], &new_data[old_width],
  1587. (new_width - old_width) * sizeof(char_info_t) );
  1588. }
  1589. /* clear remaining rows */
  1590. if (new_height > old_height)
  1591. {
  1592. /* fill first row */
  1593. for (i = 0; i < new_width; i++) new_data[old_height * new_width + i] = empty_char_info;
  1594. /* and blast it to the other rows */
  1595. for (i = old_height+1; i < new_height; i++)
  1596. memcpy( &new_data[i * new_width], &new_data[old_height * new_width],
  1597. new_width * sizeof(char_info_t) );
  1598. }
  1599. free( screen_buffer->data );
  1600. screen_buffer->data = new_data;
  1601. screen_buffer->width = new_width;
  1602. screen_buffer->height = new_height;
  1603. return STATUS_SUCCESS;
  1604. }
  1605. static NTSTATUS set_output_info( struct screen_buffer *screen_buffer,
  1606. const struct condrv_output_info_params *params )
  1607. {
  1608. const struct condrv_output_info *info = &params->info;
  1609. NTSTATUS status;
  1610. TRACE( "%p\n", screen_buffer );
  1611. if (params->mask & SET_CONSOLE_OUTPUT_INFO_CURSOR_GEOM)
  1612. {
  1613. if (info->cursor_size < 1 || info->cursor_size > 100) return STATUS_INVALID_PARAMETER;
  1614. screen_buffer->cursor_size = info->cursor_size;
  1615. screen_buffer->cursor_visible = !!info->cursor_visible;
  1616. }
  1617. if (params->mask & SET_CONSOLE_OUTPUT_INFO_CURSOR_POS)
  1618. {
  1619. if (info->cursor_x < 0 || info->cursor_x >= screen_buffer->width ||
  1620. info->cursor_y < 0 || info->cursor_y >= screen_buffer->height)
  1621. {
  1622. return STATUS_INVALID_PARAMETER;
  1623. }
  1624. if (screen_buffer->cursor_x != info->cursor_x || screen_buffer->cursor_y != info->cursor_y)
  1625. {
  1626. screen_buffer->cursor_x = info->cursor_x;
  1627. screen_buffer->cursor_y = info->cursor_y;
  1628. scroll_to_cursor( screen_buffer );
  1629. }
  1630. }
  1631. if (params->mask & SET_CONSOLE_OUTPUT_INFO_SIZE)
  1632. {
  1633. /* new screen-buffer cannot be smaller than actual window */
  1634. if (info->width < screen_buffer->win.right - screen_buffer->win.left + 1 ||
  1635. info->height < screen_buffer->win.bottom - screen_buffer->win.top + 1)
  1636. {
  1637. return STATUS_INVALID_PARAMETER;
  1638. }
  1639. /* FIXME: there are also some basic minimum and max size to deal with */
  1640. if ((status = change_screen_buffer_size( screen_buffer, info->width, info->height ))) return status;
  1641. /* scroll window to display sb */
  1642. if (screen_buffer->win.right >= info->width)
  1643. {
  1644. screen_buffer->win.right -= screen_buffer->win.left;
  1645. screen_buffer->win.left = 0;
  1646. }
  1647. if (screen_buffer->win.bottom >= info->height)
  1648. {
  1649. screen_buffer->win.bottom -= screen_buffer->win.top;
  1650. screen_buffer->win.top = 0;
  1651. }
  1652. if (screen_buffer->cursor_x >= info->width) screen_buffer->cursor_x = info->width - 1;
  1653. if (screen_buffer->cursor_y >= info->height) screen_buffer->cursor_y = info->height - 1;
  1654. notify_screen_buffer_size( screen_buffer );
  1655. }
  1656. if (params->mask & SET_CONSOLE_OUTPUT_INFO_ATTR)
  1657. {
  1658. screen_buffer->attr = info->attr;
  1659. }
  1660. if (params->mask & SET_CONSOLE_OUTPUT_INFO_POPUP_ATTR)
  1661. {
  1662. screen_buffer->popup_attr = info->popup_attr;
  1663. }
  1664. if (params->mask & SET_CONSOLE_OUTPUT_INFO_DISPLAY_WINDOW)
  1665. {
  1666. if (info->win_left < 0 || info->win_left > info->win_right ||
  1667. info->win_right >= screen_buffer->width ||
  1668. info->win_top < 0 || info->win_top > info->win_bottom ||
  1669. info->win_bottom >= screen_buffer->height)
  1670. {
  1671. return STATUS_INVALID_PARAMETER;
  1672. }
  1673. if (screen_buffer->win.left != info->win_left || screen_buffer->win.top != info->win_top ||
  1674. screen_buffer->win.right != info->win_right || screen_buffer->win.bottom != info->win_bottom)
  1675. {
  1676. screen_buffer->win.left = info->win_left;
  1677. screen_buffer->win.top = info->win_top;
  1678. screen_buffer->win.right = info->win_right;
  1679. screen_buffer->win.bottom = info->win_bottom;
  1680. }
  1681. }
  1682. if (params->mask & SET_CONSOLE_OUTPUT_INFO_MAX_SIZE)
  1683. {
  1684. screen_buffer->max_width = info->max_width;
  1685. screen_buffer->max_height = info->max_height;
  1686. }
  1687. if (is_active( screen_buffer ))
  1688. {
  1689. tty_sync( screen_buffer->console );
  1690. update_window_config( screen_buffer->console, FALSE );
  1691. }
  1692. return STATUS_SUCCESS;
  1693. }
  1694. static NTSTATUS write_console( struct screen_buffer *screen_buffer, const WCHAR *buffer, size_t len )
  1695. {
  1696. RECT update_rect;
  1697. size_t i, j;
  1698. TRACE( "%s\n", debugstr_wn(buffer, len) );
  1699. empty_update_rect( screen_buffer, &update_rect );
  1700. for (i = 0; i < len; i++)
  1701. {
  1702. if (screen_buffer->mode & ENABLE_PROCESSED_OUTPUT)
  1703. {
  1704. switch (buffer[i])
  1705. {
  1706. case '\b':
  1707. screen_buffer->cursor_x = get_bounded_cursor_x( screen_buffer );
  1708. if (screen_buffer->cursor_x) screen_buffer->cursor_x--;
  1709. continue;
  1710. case '\t':
  1711. j = min( screen_buffer->width - screen_buffer->cursor_x, 8 - (screen_buffer->cursor_x % 8) );
  1712. if (!j) j = 8;
  1713. while (j--) write_char( screen_buffer, ' ', &update_rect, NULL );
  1714. continue;
  1715. case '\n':
  1716. screen_buffer->cursor_x = 0;
  1717. if (++screen_buffer->cursor_y == screen_buffer->height)
  1718. new_line( screen_buffer, &update_rect );
  1719. else if (screen_buffer->mode & ENABLE_WRAP_AT_EOL_OUTPUT)
  1720. {
  1721. update_output( screen_buffer, &update_rect );
  1722. set_tty_cursor( screen_buffer->console, screen_buffer->cursor_x, screen_buffer->cursor_y );
  1723. }
  1724. continue;
  1725. case '\a':
  1726. FIXME( "beep\n" );
  1727. continue;
  1728. case '\r':
  1729. screen_buffer->cursor_x = 0;
  1730. continue;
  1731. }
  1732. }
  1733. if (screen_buffer->cursor_x == screen_buffer->width && !(screen_buffer->mode & ENABLE_WRAP_AT_EOL_OUTPUT))
  1734. screen_buffer->cursor_x = update_rect.left;
  1735. write_char( screen_buffer, buffer[i], &update_rect, NULL );
  1736. }
  1737. if (screen_buffer->cursor_x == screen_buffer->width)
  1738. {
  1739. if (screen_buffer->mode & ENABLE_WRAP_AT_EOL_OUTPUT)
  1740. {
  1741. if (!(screen_buffer->mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING))
  1742. {
  1743. screen_buffer->cursor_x = 0;
  1744. if (++screen_buffer->cursor_y == screen_buffer->height)
  1745. new_line( screen_buffer, &update_rect );
  1746. }
  1747. }
  1748. else screen_buffer->cursor_x = update_rect.left;
  1749. }
  1750. scroll_to_cursor( screen_buffer );
  1751. update_output( screen_buffer, &update_rect );
  1752. tty_sync( screen_buffer->console );
  1753. update_window_config( screen_buffer->console, TRUE );
  1754. return STATUS_SUCCESS;
  1755. }
  1756. static NTSTATUS write_output( struct screen_buffer *screen_buffer, const struct condrv_output_params *params,
  1757. size_t in_size, size_t *out_size )
  1758. {
  1759. unsigned int i, entry_size, entry_cnt, x, y;
  1760. char_info_t *dest;
  1761. char *src;
  1762. if (*out_size == sizeof(SMALL_RECT) && !params->width) return STATUS_INVALID_PARAMETER;
  1763. entry_size = params->mode == CHAR_INFO_MODE_TEXTATTR ? sizeof(char_info_t) : sizeof(WCHAR);
  1764. entry_cnt = (in_size - sizeof(*params)) / entry_size;
  1765. TRACE( "(%u,%u) cnt %u\n", params->x, params->y, entry_cnt );
  1766. if (params->x >= screen_buffer->width)
  1767. {
  1768. *out_size = 0;
  1769. return STATUS_SUCCESS;
  1770. }
  1771. for (i = 0, src = (char *)(params + 1); i < entry_cnt; i++, src += entry_size)
  1772. {
  1773. if (params->width)
  1774. {
  1775. x = params->x + i % params->width;
  1776. y = params->y + i / params->width;
  1777. if (x >= screen_buffer->width) continue;
  1778. }
  1779. else
  1780. {
  1781. x = (params->x + i) % screen_buffer->width;
  1782. y = params->y + (params->x + i) / screen_buffer->width;
  1783. }
  1784. if (y >= screen_buffer->height) break;
  1785. dest = &screen_buffer->data[y * screen_buffer->width + x];
  1786. switch(params->mode)
  1787. {
  1788. case CHAR_INFO_MODE_TEXT:
  1789. dest->ch = *(const WCHAR *)src;
  1790. break;
  1791. case CHAR_INFO_MODE_ATTR:
  1792. dest->attr = *(const unsigned short *)src;
  1793. break;
  1794. case CHAR_INFO_MODE_TEXTATTR:
  1795. *dest = *(const char_info_t *)src;
  1796. break;
  1797. default:
  1798. return STATUS_INVALID_PARAMETER;
  1799. }
  1800. }
  1801. if (i && is_active( screen_buffer ))
  1802. {
  1803. RECT update_rect;
  1804. update_rect.left = params->x;
  1805. update_rect.top = params->y;
  1806. if (params->width)
  1807. {
  1808. update_rect.bottom = min( params->y + entry_cnt / params->width, screen_buffer->height ) - 1;
  1809. update_rect.right = min( params->x + params->width, screen_buffer->width ) - 1;
  1810. }
  1811. else
  1812. {
  1813. update_rect.bottom = params->y + (params->x + i - 1) / screen_buffer->width;
  1814. if (update_rect.bottom != params->y)
  1815. {
  1816. update_rect.left = 0;
  1817. update_rect.right = screen_buffer->width - 1;
  1818. }
  1819. else
  1820. {
  1821. update_rect.right = params->x + i - 1;
  1822. }
  1823. }
  1824. update_output( screen_buffer, &update_rect );
  1825. tty_sync( screen_buffer->console );
  1826. }
  1827. if (*out_size == sizeof(SMALL_RECT))
  1828. {
  1829. SMALL_RECT *region;
  1830. unsigned int width = params->width;
  1831. x = params->x;
  1832. y = params->y;
  1833. if (!(region = alloc_ioctl_buffer( sizeof(*region )))) return STATUS_NO_MEMORY;
  1834. region->Left = x;
  1835. region->Top = y;
  1836. region->Right = min( x + width, screen_buffer->width ) - 1;
  1837. region->Bottom = min( y + entry_cnt / width, screen_buffer->height ) - 1;
  1838. }
  1839. else
  1840. {
  1841. DWORD *result;
  1842. if (!(result = alloc_ioctl_buffer( sizeof(*result )))) return STATUS_NO_MEMORY;
  1843. *result = i;
  1844. }
  1845. return STATUS_SUCCESS;
  1846. }
  1847. static NTSTATUS read_output( struct screen_buffer *screen_buffer, const struct condrv_output_params *params,
  1848. size_t *out_size )
  1849. {
  1850. enum char_info_mode mode;
  1851. unsigned int x, y, width;
  1852. unsigned int i, count;
  1853. x = params->x;
  1854. y = params->y;
  1855. mode = params->mode;
  1856. width = params->width;
  1857. TRACE( "(%u %u) mode %u width %u\n", x, y, mode, width );
  1858. switch(mode)
  1859. {
  1860. case CHAR_INFO_MODE_TEXT:
  1861. {
  1862. WCHAR *data;
  1863. char_info_t *src;
  1864. if (x >= screen_buffer->width || y >= screen_buffer->height)
  1865. {
  1866. *out_size = 0;
  1867. return STATUS_SUCCESS;
  1868. }
  1869. src = screen_buffer->data + y * screen_buffer->width + x;
  1870. count = min( screen_buffer->data + screen_buffer->height * screen_buffer->width - src,
  1871. *out_size / sizeof(*data) );
  1872. *out_size = count * sizeof(*data);
  1873. if (!(data = alloc_ioctl_buffer( *out_size ))) return STATUS_NO_MEMORY;
  1874. for (i = 0; i < count; i++) data[i] = src[i].ch;
  1875. }
  1876. break;
  1877. case CHAR_INFO_MODE_ATTR:
  1878. {
  1879. unsigned short *data;
  1880. char_info_t *src;
  1881. if (x >= screen_buffer->width || y >= screen_buffer->height)
  1882. {
  1883. *out_size = 0;
  1884. return STATUS_SUCCESS;
  1885. }
  1886. src = screen_buffer->data + y * screen_buffer->width + x;
  1887. count = min( screen_buffer->data + screen_buffer->height * screen_buffer->width - src,
  1888. *out_size / sizeof(*data) );
  1889. *out_size = count * sizeof(*data);
  1890. if (!(data = alloc_ioctl_buffer( *out_size ))) return STATUS_NO_MEMORY;
  1891. for (i = 0; i < count; i++) data[i] = src[i].attr;
  1892. }
  1893. break;
  1894. case CHAR_INFO_MODE_TEXTATTR:
  1895. {
  1896. SMALL_RECT *region;
  1897. char_info_t *data;
  1898. if (!width || *out_size < sizeof(*region) || x >= screen_buffer->width || y >= screen_buffer->height)
  1899. return STATUS_INVALID_PARAMETER;
  1900. count = min( (*out_size - sizeof(*region)) / (width * sizeof(*data)), screen_buffer->height - y );
  1901. width = min( width, screen_buffer->width - x );
  1902. *out_size = sizeof(*region) + width * count * sizeof(*data);
  1903. if (!(region = alloc_ioctl_buffer( *out_size ))) return STATUS_NO_MEMORY;
  1904. region->Left = x;
  1905. region->Top = y;
  1906. region->Right = x + width - 1;
  1907. region->Bottom = y + count - 1;
  1908. data = (char_info_t *)(region + 1);
  1909. for (i = 0; i < count; i++)
  1910. {
  1911. memcpy( &data[i * width], &screen_buffer->data[(y + i) * screen_buffer->width + x],
  1912. width * sizeof(*data) );
  1913. }
  1914. }
  1915. break;
  1916. default:
  1917. return STATUS_INVALID_PARAMETER;
  1918. }
  1919. return STATUS_SUCCESS;
  1920. }
  1921. static NTSTATUS fill_output( struct screen_buffer *screen_buffer, const struct condrv_fill_output_params *params )
  1922. {
  1923. char_info_t *end, *dest;
  1924. DWORD i, count, *result;
  1925. TRACE( "(%u %u) mode %u\n", params->x, params->y, params->mode );
  1926. if (params->y >= screen_buffer->height) return STATUS_SUCCESS;
  1927. dest = screen_buffer->data + min( params->y * screen_buffer->width + params->x,
  1928. screen_buffer->height * screen_buffer->width );
  1929. end = screen_buffer->data + screen_buffer->height * screen_buffer->width;
  1930. count = params->count;
  1931. if (count > end - dest) count = end - dest;
  1932. switch(params->mode)
  1933. {
  1934. case CHAR_INFO_MODE_TEXT:
  1935. for (i = 0; i < count; i++) dest[i].ch = params->ch;
  1936. break;
  1937. case CHAR_INFO_MODE_ATTR:
  1938. for (i = 0; i < count; i++) dest[i].attr = params->attr;
  1939. break;
  1940. case CHAR_INFO_MODE_TEXTATTR:
  1941. for (i = 0; i < count; i++)
  1942. {
  1943. dest[i].ch = params->ch;
  1944. dest[i].attr = params->attr;
  1945. }
  1946. break;
  1947. default:
  1948. return STATUS_INVALID_PARAMETER;
  1949. }
  1950. if (count && is_active(screen_buffer))
  1951. {
  1952. RECT update_rect;
  1953. SetRect( &update_rect,
  1954. params->x % screen_buffer->width,
  1955. params->y + params->x / screen_buffer->width,
  1956. (params->x + i - 1) % screen_buffer->width,
  1957. params->y + (params->x + i - 1) / screen_buffer->width );
  1958. update_output( screen_buffer, &update_rect );
  1959. tty_sync( screen_buffer->console );
  1960. }
  1961. if (!(result = alloc_ioctl_buffer( sizeof(*result) ))) return STATUS_NO_MEMORY;
  1962. *result = count;
  1963. return STATUS_SUCCESS;
  1964. }
  1965. static NTSTATUS scroll_output( struct screen_buffer *screen_buffer, const struct condrv_scroll_params *params )
  1966. {
  1967. int x, y, xsrc, ysrc, w, h;
  1968. char_info_t *psrc, *pdst;
  1969. SMALL_RECT src, dst;
  1970. RECT update_rect;
  1971. SMALL_RECT clip;
  1972. xsrc = params->scroll.Left;
  1973. ysrc = params->scroll.Top;
  1974. w = params->scroll.Right - params->scroll.Left + 1;
  1975. h = params->scroll.Bottom - params->scroll.Top + 1;
  1976. TRACE( "(%d %d) -> (%u %u) w %u h %u\n", xsrc, ysrc, params->origin.X, params->origin.Y, w, h );
  1977. clip.Left = max( params->clip.Left, 0 );
  1978. clip.Top = max( params->clip.Top, 0 );
  1979. clip.Right = min( params->clip.Right, screen_buffer->width - 1 );
  1980. clip.Bottom = min( params->clip.Bottom, screen_buffer->height - 1 );
  1981. if (clip.Left > clip.Right || clip.Top > clip.Bottom || params->scroll.Left < 0 || params->scroll.Top < 0 ||
  1982. params->scroll.Right >= screen_buffer->width || params->scroll.Bottom >= screen_buffer->height ||
  1983. params->scroll.Right < params->scroll.Left || params->scroll.Top > params->scroll.Bottom ||
  1984. params->origin.X < 0 || params->origin.X >= screen_buffer->width || params->origin.Y < 0 ||
  1985. params->origin.Y >= screen_buffer->height)
  1986. return STATUS_INVALID_PARAMETER;
  1987. src.Left = max( xsrc, clip.Left );
  1988. src.Top = max( ysrc, clip.Top );
  1989. src.Right = min( xsrc + w - 1, clip.Right );
  1990. src.Bottom = min( ysrc + h - 1, clip.Bottom );
  1991. dst.Left = params->origin.X;
  1992. dst.Top = params->origin.Y;
  1993. dst.Right = params->origin.X + w - 1;
  1994. dst.Bottom = params->origin.Y + h - 1;
  1995. if (dst.Left < clip.Left)
  1996. {
  1997. xsrc += clip.Left - dst.Left;
  1998. w -= clip.Left - dst.Left;
  1999. dst.Left = clip.Left;
  2000. }
  2001. if (dst.Top < clip.Top)
  2002. {
  2003. ysrc += clip.Top - dst.Top;
  2004. h -= clip.Top - dst.Top;
  2005. dst.Top = clip.Top;
  2006. }
  2007. if (dst.Right > clip.Right) w -= dst.Right - clip.Right;
  2008. if (dst.Bottom > clip.Bottom) h -= dst.Bottom - clip.Bottom;
  2009. if (w > 0 && h > 0)
  2010. {
  2011. if (ysrc < dst.Top)
  2012. {
  2013. psrc = &screen_buffer->data[(ysrc + h - 1) * screen_buffer->width + xsrc];
  2014. pdst = &screen_buffer->data[(dst.Top + h - 1) * screen_buffer->width + dst.Left];
  2015. for (y = h; y > 0; y--)
  2016. {
  2017. memcpy( pdst, psrc, w * sizeof(*pdst) );
  2018. pdst -= screen_buffer->width;
  2019. psrc -= screen_buffer->width;
  2020. }
  2021. }
  2022. else
  2023. {
  2024. psrc = &screen_buffer->data[ysrc * screen_buffer->width + xsrc];
  2025. pdst = &screen_buffer->data[dst.Top * screen_buffer->width + dst.Left];
  2026. for (y = 0; y < h; y++)
  2027. {
  2028. /* we use memmove here because when psrc and pdst are the same,
  2029. * copies are done on the same row, so the dst and src blocks
  2030. * can overlap */
  2031. memmove( pdst, psrc, w * sizeof(*pdst) );
  2032. pdst += screen_buffer->width;
  2033. psrc += screen_buffer->width;
  2034. }
  2035. }
  2036. }
  2037. for (y = src.Top; y <= src.Bottom; y++)
  2038. {
  2039. int left = src.Left;
  2040. int right = src.Right;
  2041. if (dst.Top <= y && y <= dst.Bottom)
  2042. {
  2043. if (dst.Left <= src.Left) left = max( left, dst.Right + 1 );
  2044. if (dst.Left >= src.Left) right = min( right, dst.Left - 1 );
  2045. }
  2046. for (x = left; x <= right; x++) screen_buffer->data[y * screen_buffer->width + x] = params->fill;
  2047. }
  2048. SetRect( &update_rect, min( src.Left, dst.Left ), min( src.Top, dst.Top ),
  2049. max( src.Right, dst.Right ), max( src.Bottom, dst.Bottom ));
  2050. update_output( screen_buffer, &update_rect );
  2051. tty_sync( screen_buffer->console );
  2052. return STATUS_SUCCESS;
  2053. }
  2054. static NTSTATUS set_console_title( struct console *console, const WCHAR *in_title, size_t size )
  2055. {
  2056. WCHAR *title = NULL;
  2057. TRACE( "%s\n", debugstr_wn(in_title, size / sizeof(WCHAR)) );
  2058. if (size)
  2059. {
  2060. if (!(title = malloc( size + sizeof(WCHAR) ))) return STATUS_NO_MEMORY;
  2061. memcpy( title, in_title, size );
  2062. title[size / sizeof(WCHAR)] = 0;
  2063. }
  2064. free( console->title );
  2065. console->title = title;
  2066. if (console->tty_output)
  2067. {
  2068. size_t len;
  2069. char *vt;
  2070. tty_write( console, "\x1b]0;", 4 );
  2071. len = WideCharToMultiByte( get_tty_cp( console ), 0, console->title, size / sizeof(WCHAR),
  2072. NULL, 0, NULL, NULL);
  2073. if ((vt = tty_alloc_buffer( console, len )))
  2074. WideCharToMultiByte( get_tty_cp( console ), 0, console->title, size / sizeof(WCHAR),
  2075. vt, len, NULL, NULL );
  2076. tty_write( console, "\x07", 1 );
  2077. tty_sync( console );
  2078. }
  2079. if (console->win)
  2080. SetWindowTextW( console->win, console->title );
  2081. return STATUS_SUCCESS;
  2082. }
  2083. static NTSTATUS screen_buffer_ioctl( struct screen_buffer *screen_buffer, unsigned int code,
  2084. const void *in_data, size_t in_size, size_t *out_size )
  2085. {
  2086. switch (code)
  2087. {
  2088. case IOCTL_CONDRV_CLOSE_OUTPUT:
  2089. if (in_size || *out_size) return STATUS_INVALID_PARAMETER;
  2090. destroy_screen_buffer( screen_buffer );
  2091. return STATUS_SUCCESS;
  2092. case IOCTL_CONDRV_ACTIVATE:
  2093. if (in_size || *out_size) return STATUS_INVALID_PARAMETER;
  2094. return screen_buffer_activate( screen_buffer );
  2095. case IOCTL_CONDRV_GET_MODE:
  2096. {
  2097. DWORD *mode;
  2098. TRACE( "returning mode %x\n", screen_buffer->mode );
  2099. if (in_size || *out_size != sizeof(*mode)) return STATUS_INVALID_PARAMETER;
  2100. if (!(mode = alloc_ioctl_buffer( *out_size ))) return STATUS_NO_MEMORY;
  2101. *mode = screen_buffer->mode;
  2102. return STATUS_SUCCESS;
  2103. }
  2104. case IOCTL_CONDRV_SET_MODE:
  2105. if (in_size != sizeof(unsigned int) || *out_size) return STATUS_INVALID_PARAMETER;
  2106. screen_buffer->mode = *(unsigned int *)in_data;
  2107. TRACE( "set %x mode\n", screen_buffer->mode );
  2108. return STATUS_SUCCESS;
  2109. case IOCTL_CONDRV_IS_UNIX:
  2110. return screen_buffer->console->is_unix ? STATUS_SUCCESS : STATUS_NOT_SUPPORTED;
  2111. case IOCTL_CONDRV_WRITE_CONSOLE:
  2112. if (in_size % sizeof(WCHAR) || *out_size) return STATUS_INVALID_PARAMETER;
  2113. return write_console( screen_buffer, in_data, in_size / sizeof(WCHAR) );
  2114. case IOCTL_CONDRV_WRITE_FILE:
  2115. {
  2116. unsigned int len;
  2117. WCHAR *buf;
  2118. NTSTATUS status;
  2119. len = MultiByteToWideChar( screen_buffer->console->output_cp, 0, in_data, in_size,
  2120. NULL, 0 );
  2121. if (!len) return STATUS_SUCCESS;
  2122. if (!(buf = malloc( len * sizeof(WCHAR) ))) return STATUS_NO_MEMORY;
  2123. MultiByteToWideChar( screen_buffer->console->output_cp, 0, in_data, in_size, buf, len );
  2124. status = write_console( screen_buffer, buf, len );
  2125. free( buf );
  2126. return status;
  2127. }
  2128. case IOCTL_CONDRV_WRITE_OUTPUT:
  2129. if ((*out_size != sizeof(DWORD) && *out_size != sizeof(SMALL_RECT)) ||
  2130. in_size < sizeof(struct condrv_output_params))
  2131. return STATUS_INVALID_PARAMETER;
  2132. return write_output( screen_buffer, in_data, in_size, out_size );
  2133. case IOCTL_CONDRV_READ_OUTPUT:
  2134. if (in_size != sizeof(struct condrv_output_params)) return STATUS_INVALID_PARAMETER;
  2135. return read_output( screen_buffer, in_data, out_size );
  2136. case IOCTL_CONDRV_GET_OUTPUT_INFO:
  2137. if (in_size || *out_size < sizeof(struct condrv_output_info)) return STATUS_INVALID_PARAMETER;
  2138. return get_output_info( screen_buffer, out_size );
  2139. case IOCTL_CONDRV_SET_OUTPUT_INFO:
  2140. if (in_size != sizeof(struct condrv_output_info_params) || *out_size) return STATUS_INVALID_PARAMETER;
  2141. return set_output_info( screen_buffer, in_data );
  2142. case IOCTL_CONDRV_FILL_OUTPUT:
  2143. if (in_size != sizeof(struct condrv_fill_output_params) || *out_size != sizeof(DWORD))
  2144. return STATUS_INVALID_PARAMETER;
  2145. return fill_output( screen_buffer, in_data );
  2146. case IOCTL_CONDRV_SCROLL:
  2147. if (in_size != sizeof(struct condrv_scroll_params) || *out_size)
  2148. return STATUS_INVALID_PARAMETER;
  2149. return scroll_output( screen_buffer, in_data );
  2150. default:
  2151. WARN( "invalid ioctl %x\n", code );
  2152. return STATUS_INVALID_HANDLE;
  2153. }
  2154. }
  2155. static NTSTATUS console_input_ioctl( struct console *console, unsigned int code, const void *in_data,
  2156. size_t in_size, size_t *out_size )
  2157. {
  2158. NTSTATUS status;
  2159. switch (code)
  2160. {
  2161. case IOCTL_CONDRV_GET_MODE:
  2162. {
  2163. DWORD *mode;
  2164. TRACE( "returning mode %x\n", console->mode );
  2165. if (in_size || *out_size != sizeof(*mode)) return STATUS_INVALID_PARAMETER;
  2166. if (!(mode = alloc_ioctl_buffer( *out_size ))) return STATUS_NO_MEMORY;
  2167. *mode = console->mode;
  2168. return STATUS_SUCCESS;
  2169. }
  2170. case IOCTL_CONDRV_SET_MODE:
  2171. if (in_size != sizeof(unsigned int) || *out_size) return STATUS_INVALID_PARAMETER;
  2172. console->mode = *(unsigned int *)in_data;
  2173. TRACE( "set %x mode\n", console->mode );
  2174. return STATUS_SUCCESS;
  2175. case IOCTL_CONDRV_IS_UNIX:
  2176. return console->is_unix ? STATUS_SUCCESS : STATUS_NOT_SUPPORTED;
  2177. case IOCTL_CONDRV_READ_CONSOLE:
  2178. if (in_size || *out_size % sizeof(WCHAR)) return STATUS_INVALID_PARAMETER;
  2179. ensure_tty_input_thread( console );
  2180. status = read_console( console, code, *out_size );
  2181. *out_size = 0;
  2182. return status;
  2183. case IOCTL_CONDRV_READ_FILE:
  2184. ensure_tty_input_thread( console );
  2185. status = read_console( console, code, *out_size );
  2186. *out_size = 0;
  2187. return status;
  2188. case IOCTL_CONDRV_READ_INPUT:
  2189. {
  2190. if (in_size) return STATUS_INVALID_PARAMETER;
  2191. ensure_tty_input_thread( console );
  2192. if (!console->record_count && *out_size)
  2193. {
  2194. TRACE( "pending read\n" );
  2195. console->read_ioctl = IOCTL_CONDRV_READ_INPUT;
  2196. console->pending_read = *out_size;
  2197. return STATUS_PENDING;
  2198. }
  2199. status = read_console_input( console, *out_size );
  2200. *out_size = 0;
  2201. return status;
  2202. }
  2203. case IOCTL_CONDRV_WRITE_INPUT:
  2204. if (in_size % sizeof(INPUT_RECORD) || *out_size) return STATUS_INVALID_PARAMETER;
  2205. return write_console_input( console, in_data, in_size / sizeof(INPUT_RECORD), TRUE );
  2206. case IOCTL_CONDRV_PEEK:
  2207. {
  2208. void *result;
  2209. TRACE( "peek\n" );
  2210. if (in_size) return STATUS_INVALID_PARAMETER;
  2211. ensure_tty_input_thread( console );
  2212. *out_size = min( *out_size, console->record_count * sizeof(INPUT_RECORD) );
  2213. if (!(result = alloc_ioctl_buffer( *out_size ))) return STATUS_NO_MEMORY;
  2214. if (*out_size) memcpy( result, console->records, *out_size );
  2215. return STATUS_SUCCESS;
  2216. }
  2217. case IOCTL_CONDRV_GET_INPUT_INFO:
  2218. {
  2219. struct condrv_input_info *info;
  2220. TRACE( "get info\n" );
  2221. if (in_size || *out_size != sizeof(*info)) return STATUS_INVALID_PARAMETER;
  2222. if (!(info = alloc_ioctl_buffer( sizeof(*info )))) return STATUS_NO_MEMORY;
  2223. info->input_cp = console->input_cp;
  2224. info->output_cp = console->output_cp;
  2225. info->input_count = console->record_count;
  2226. return STATUS_SUCCESS;
  2227. }
  2228. case IOCTL_CONDRV_GET_WINDOW:
  2229. {
  2230. condrv_handle_t *result;
  2231. TRACE( "get window\n" );
  2232. if (in_size || *out_size != sizeof(*result)) return STATUS_INVALID_PARAMETER;
  2233. if (!(result = alloc_ioctl_buffer( sizeof(*result )))) return STATUS_NO_MEMORY;
  2234. if (!console->win) init_message_window( console );
  2235. *result = condrv_handle( console->win );
  2236. return STATUS_SUCCESS;
  2237. }
  2238. case IOCTL_CONDRV_SET_INPUT_INFO:
  2239. {
  2240. const struct condrv_input_info_params *params = in_data;
  2241. TRACE( "set info\n" );
  2242. if (in_size != sizeof(*params) || *out_size) return STATUS_INVALID_PARAMETER;
  2243. if (params->mask & SET_CONSOLE_INPUT_INFO_INPUT_CODEPAGE)
  2244. {
  2245. if (!IsValidCodePage( params->info.input_cp )) return STATUS_INVALID_PARAMETER;
  2246. console->input_cp = params->info.input_cp;
  2247. }
  2248. if (params->mask & SET_CONSOLE_INPUT_INFO_OUTPUT_CODEPAGE)
  2249. {
  2250. if (!IsValidCodePage( params->info.output_cp )) return STATUS_INVALID_PARAMETER;
  2251. console->output_cp = params->info.output_cp;
  2252. }
  2253. return STATUS_SUCCESS;
  2254. }
  2255. case IOCTL_CONDRV_GET_TITLE:
  2256. {
  2257. WCHAR *result;
  2258. if (in_size) return STATUS_INVALID_PARAMETER;
  2259. TRACE( "returning title %s\n", debugstr_w(console->title) );
  2260. *out_size = min( *out_size, console->title ? wcslen( console->title ) * sizeof(WCHAR) : 0 );
  2261. if (!(result = alloc_ioctl_buffer( *out_size ))) return STATUS_NO_MEMORY;
  2262. if (*out_size) memcpy( result, console->title, *out_size );
  2263. return STATUS_SUCCESS;
  2264. }
  2265. case IOCTL_CONDRV_SET_TITLE:
  2266. if (in_size % sizeof(WCHAR) || *out_size) return STATUS_INVALID_PARAMETER;
  2267. return set_console_title( console, in_data, in_size );
  2268. case IOCTL_CONDRV_BEEP:
  2269. if (in_size || *out_size) return STATUS_INVALID_PARAMETER;
  2270. if (console->is_unix)
  2271. {
  2272. tty_write( console, "\a", 1 );
  2273. tty_sync( console );
  2274. }
  2275. return STATUS_SUCCESS;
  2276. case IOCTL_CONDRV_FLUSH:
  2277. if (in_size || *out_size) return STATUS_INVALID_PARAMETER;
  2278. TRACE( "flush\n" );
  2279. console->record_count = 0;
  2280. return STATUS_SUCCESS;
  2281. default:
  2282. WARN( "unsupported ioctl %x\n", code );
  2283. return STATUS_INVALID_HANDLE;
  2284. }
  2285. }
  2286. static NTSTATUS process_console_ioctls( struct console *console )
  2287. {
  2288. size_t out_size = 0, in_size;
  2289. unsigned int code;
  2290. int output;
  2291. NTSTATUS status = STATUS_SUCCESS;
  2292. for (;;)
  2293. {
  2294. if (status) out_size = 0;
  2295. console->signaled = console->record_count != 0;
  2296. SERVER_START_REQ( get_next_console_request )
  2297. {
  2298. req->handle = wine_server_obj_handle( console->server );
  2299. req->status = status;
  2300. req->signal = console->signaled;
  2301. wine_server_add_data( req, ioctl_buffer, out_size );
  2302. wine_server_set_reply( req, ioctl_buffer, ioctl_buffer_size );
  2303. status = wine_server_call( req );
  2304. code = reply->code;
  2305. output = reply->output;
  2306. out_size = reply->out_size;
  2307. in_size = wine_server_reply_size( reply );
  2308. }
  2309. SERVER_END_REQ;
  2310. if (status == STATUS_PENDING) return STATUS_SUCCESS;
  2311. if (status == STATUS_BUFFER_OVERFLOW)
  2312. {
  2313. if (!alloc_ioctl_buffer( out_size )) return STATUS_NO_MEMORY;
  2314. status = STATUS_SUCCESS;
  2315. continue;
  2316. }
  2317. if (status)
  2318. {
  2319. TRACE( "failed to get next request: %#x\n", status );
  2320. return status;
  2321. }
  2322. if (code == IOCTL_CONDRV_INIT_OUTPUT)
  2323. {
  2324. TRACE( "initializing output %x\n", output );
  2325. if (console->active)
  2326. create_screen_buffer( console, output, console->active->width, console->active->height );
  2327. else
  2328. create_screen_buffer( console, output, 80, 150 );
  2329. }
  2330. else if (!output)
  2331. {
  2332. status = console_input_ioctl( console, code, ioctl_buffer, in_size, &out_size );
  2333. }
  2334. else
  2335. {
  2336. struct wine_rb_entry *entry;
  2337. if (!(entry = wine_rb_get( &screen_buffer_map, LongToPtr(output) )))
  2338. {
  2339. ERR( "invalid screen buffer id %x\n", output );
  2340. status = STATUS_INVALID_HANDLE;
  2341. }
  2342. else
  2343. {
  2344. status = screen_buffer_ioctl( WINE_RB_ENTRY_VALUE( entry, struct screen_buffer, entry ), code,
  2345. ioctl_buffer, in_size, &out_size );
  2346. }
  2347. }
  2348. }
  2349. }
  2350. static int main_loop( struct console *console, HANDLE signal )
  2351. {
  2352. HANDLE signal_event = NULL;
  2353. HANDLE wait_handles[3];
  2354. unsigned int wait_cnt = 0;
  2355. unsigned short signal_id;
  2356. IO_STATUS_BLOCK signal_io;
  2357. NTSTATUS status;
  2358. DWORD res;
  2359. if (signal)
  2360. {
  2361. if (!(signal_event = CreateEventW( NULL, TRUE, FALSE, NULL ))) return 1;
  2362. status = NtReadFile( signal, signal_event, NULL, NULL, &signal_io, &signal_id,
  2363. sizeof(signal_id), NULL, NULL );
  2364. if (status && status != STATUS_PENDING) return 1;
  2365. }
  2366. if (!alloc_ioctl_buffer( 4096 )) return 1;
  2367. wait_handles[wait_cnt++] = console->server;
  2368. if (signal) wait_handles[wait_cnt++] = signal_event;
  2369. if (console->input_thread) wait_handles[wait_cnt++] = console->input_thread;
  2370. for (;;)
  2371. {
  2372. if (console->win)
  2373. res = MsgWaitForMultipleObjects( wait_cnt, wait_handles, FALSE, INFINITE, QS_ALLINPUT );
  2374. else
  2375. res = WaitForMultipleObjects( wait_cnt, wait_handles, FALSE, INFINITE );
  2376. if (res == WAIT_OBJECT_0 + wait_cnt)
  2377. {
  2378. MSG msg;
  2379. while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ))
  2380. {
  2381. if (msg.message == WM_QUIT) return 0;
  2382. DispatchMessageW(&msg);
  2383. }
  2384. continue;
  2385. }
  2386. switch (res)
  2387. {
  2388. case WAIT_OBJECT_0:
  2389. EnterCriticalSection( &console_section );
  2390. status = process_console_ioctls( console );
  2391. LeaveCriticalSection( &console_section );
  2392. if (status) return 0;
  2393. break;
  2394. case WAIT_OBJECT_0 + 1:
  2395. if (signal_io.Status || signal_io.Information != sizeof(signal_id))
  2396. {
  2397. TRACE( "signaled quit\n" );
  2398. return 0;
  2399. }
  2400. FIXME( "unimplemented signal %x\n", signal_id );
  2401. status = NtReadFile( signal, signal_event, NULL, NULL, &signal_io, &signal_id,
  2402. sizeof(signal_id), NULL, NULL );
  2403. if (status && status != STATUS_PENDING) return 1;
  2404. break;
  2405. default:
  2406. TRACE( "wait failed, quit\n");
  2407. return 0;
  2408. }
  2409. }
  2410. return 0;
  2411. }
  2412. int __cdecl wmain(int argc, WCHAR *argv[])
  2413. {
  2414. int headless = 0, i, width = 0, height = 0;
  2415. HANDLE signal = NULL;
  2416. WCHAR *end;
  2417. static struct console console;
  2418. for (i = 0; i < argc; i++) TRACE("%s ", wine_dbgstr_w(argv[i]));
  2419. TRACE("\n");
  2420. console.mode = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
  2421. ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT | ENABLE_INSERT_MODE |
  2422. ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS | ENABLE_AUTO_POSITION;
  2423. console.input_cp = console.output_cp = GetOEMCP();
  2424. console.history_size = 50;
  2425. if (!(console.history = calloc( console.history_size, sizeof(*console.history) ))) return 1;
  2426. for (i = 1; i < argc; i++)
  2427. {
  2428. if (!wcscmp( argv[i], L"--headless"))
  2429. {
  2430. headless = 1;
  2431. continue;
  2432. }
  2433. if (!wcscmp( argv[i], L"--unix"))
  2434. {
  2435. console.is_unix = 1;
  2436. headless = 1;
  2437. continue;
  2438. }
  2439. if (!wcscmp( argv[i], L"--width" ))
  2440. {
  2441. if (++i == argc) return 1;
  2442. width = wcstol( argv[i], &end, 0 );
  2443. if ((!width && !console.is_unix) || width > 0xffff || *end) return 1;
  2444. continue;
  2445. }
  2446. if (!wcscmp( argv[i], L"--height" ))
  2447. {
  2448. if (++i == argc) return 1;
  2449. height = wcstol( argv[i], &end, 0 );
  2450. if ((!height && !console.is_unix) || height > 0xffff || *end) return 1;
  2451. continue;
  2452. }
  2453. if (!wcscmp( argv[i], L"--signal" ))
  2454. {
  2455. if (++i == argc) return 1;
  2456. signal = ULongToHandle( wcstol( argv[i], &end, 0 ));
  2457. if (*end) return 1;
  2458. continue;
  2459. }
  2460. if (!wcscmp( argv[i], L"--server" ))
  2461. {
  2462. if (++i == argc) return 1;
  2463. console.server = ULongToHandle( wcstol( argv[i], &end, 0 ));
  2464. if (*end) return 1;
  2465. continue;
  2466. }
  2467. FIXME( "unknown option %s\n", debugstr_w(argv[i]) );
  2468. return 1;
  2469. }
  2470. if (!console.server)
  2471. {
  2472. ERR( "no server handle\n" );
  2473. return 1;
  2474. }
  2475. if (!width) width = 80;
  2476. if (!height) height = 150;
  2477. if (!(console.active = create_screen_buffer( &console, 1, width, height ))) return 1;
  2478. if (headless)
  2479. {
  2480. console.tty_input = GetStdHandle( STD_INPUT_HANDLE );
  2481. console.tty_output = GetStdHandle( STD_OUTPUT_HANDLE );
  2482. init_tty_output( &console );
  2483. if (!console.is_unix && !ensure_tty_input_thread( &console )) return 1;
  2484. }
  2485. else
  2486. {
  2487. STARTUPINFOW si;
  2488. if (!init_window( &console )) return 1;
  2489. GetStartupInfoW( &si );
  2490. set_console_title( &console, si.lpTitle, wcslen( si.lpTitle ) * sizeof(WCHAR) );
  2491. ShowWindow( console.win, (si.dwFlags & STARTF_USESHOWWINDOW) ? si.wShowWindow : SW_SHOW );
  2492. }
  2493. return main_loop( &console, signal );
  2494. }