conhost.c 101 KB

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