crt.pp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by the Free Pascal development team.
  4. Borland Pascal 7 Compatible CRT Unit - win32 implentation
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit crt;
  12. interface
  13. {$i crth.inc}
  14. procedure Window32(X1,Y1,X2,Y2: DWord);
  15. procedure GotoXY32(X,Y: DWord);
  16. function WhereX32: DWord;
  17. function WhereY32: DWord;
  18. implementation
  19. uses
  20. windows;
  21. var
  22. SaveCursorSize: Longint;
  23. {
  24. definition of textrec is in textrec.inc
  25. }
  26. {$i textrec.inc}
  27. {****************************************************************************
  28. Low level Routines
  29. ****************************************************************************}
  30. procedure TurnMouseOff;
  31. var Mode: DWORD;
  32. begin
  33. if GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), @Mode) then begin { Turn the mouse-cursor off }
  34. Mode := Mode AND cardinal(NOT enable_processed_input)
  35. AND cardinal(NOT enable_mouse_input);
  36. SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), Mode);
  37. end; { if }
  38. end; { proc. TurnMouseOff }
  39. function GetScreenHeight : DWord;
  40. var
  41. ConsoleInfo: TConsoleScreenBufferinfo;
  42. begin
  43. if (not GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), ConsoleInfo)) then begin
  44. {$ifdef SYSTEMDEBUG}
  45. Writeln(stderr,'GetScreenHeight failed GetLastError returns ',GetLastError);
  46. Halt(1);
  47. {$endif SYSTEMDEBUG}
  48. // ts: this is really silly assumption; imho better: issue a halt
  49. GetScreenHeight:=25;
  50. end else
  51. GetScreenHeight := ConsoleInfo.dwSize.Y;
  52. end; { func. GetScreenHeight }
  53. function GetScreenWidth : DWord;
  54. var
  55. ConsoleInfo: TConsoleScreenBufferInfo;
  56. begin
  57. if (not GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), ConsoleInfo)) then begin
  58. {$ifdef SYSTEMDEBUG}
  59. Writeln(stderr,'GetScreenWidth failed GetLastError returns ',GetLastError);
  60. Halt(1);
  61. {$endif SYSTEMDEBUG}
  62. // ts: this is really silly assumption; imho better: issue a halt
  63. GetScreenWidth:=80;
  64. end else
  65. GetScreenWidth := ConsoleInfo.dwSize.X;
  66. end; { func. GetScreenWidth }
  67. procedure GetScreenCursor(var x : DWord; var y : DWord);
  68. var
  69. ConsoleInfo : TConsoleScreenBufferInfo;
  70. begin
  71. FillChar(ConsoleInfo, SizeOf(ConsoleInfo), 0);
  72. GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), ConsoleInfo);
  73. X := ConsoleInfo.dwCursorPosition.X + 1;
  74. Y := ConsoleInfo.dwCursorPosition.Y + 1;
  75. end;
  76. procedure SetScreenCursor(x,y : DWord);
  77. var
  78. CurInfo: TCoord;
  79. begin
  80. FillChar(Curinfo, SizeOf(Curinfo), 0);
  81. CurInfo.X := X - 1;
  82. CurInfo.Y := Y - 1;
  83. SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), CurInfo);
  84. end;
  85. {****************************************************************************
  86. Public Crt Functions
  87. ****************************************************************************}
  88. procedure TextMode (Mode: word);
  89. begin
  90. end;
  91. Procedure TextColor(Color: Byte);
  92. { Switch foregroundcolor }
  93. Begin
  94. TextAttr:=(Color and $8f) or (TextAttr and $70);
  95. End;
  96. Procedure TextBackground(Color: Byte);
  97. { Switch backgroundcolor }
  98. Begin
  99. TextAttr:=((Color shl 4) and ($f0 and not Blink)) or (TextAttr and ($0f OR Blink) );
  100. End;
  101. Procedure HighVideo;
  102. { Set highlighted output. }
  103. Begin
  104. TextColor(TextAttr Or $08);
  105. End;
  106. Procedure LowVideo;
  107. { Set normal output }
  108. Begin
  109. TextColor(TextAttr And $77);
  110. End;
  111. Procedure NormVideo;
  112. { Set normal back and foregroundcolors. }
  113. Begin
  114. TextColor(7);
  115. TextBackGround(0);
  116. End;
  117. Procedure GotoXY(X: tcrtcoord; Y: tcrtcoord);
  118. begin
  119. GotoXY32(X,Y);
  120. end;
  121. Procedure GotoXY32(X: DWord; Y: DWord);
  122. { Go to coordinates X,Y in the current window. }
  123. Begin
  124. If (X > 0) and (X <= (WindMaxX - WindMinX + 1)) and
  125. (Y > 0) and (Y <= (WindMaxY - WindMinY + 1)) Then Begin
  126. Inc(X, WindMinX - 1);
  127. Inc(Y, WindMinY - 1);
  128. SetScreenCursor(x,y);
  129. End;
  130. End;
  131. Procedure Window(X1, Y1, X2, Y2: Byte);
  132. begin
  133. Window32(X1,Y1,X2,Y2);
  134. end;
  135. Procedure Window32(X1, Y1, X2, Y2: DWord);
  136. {
  137. Set screen window to the specified coordinates.
  138. }
  139. Begin
  140. if (X1 > X2) or (X2 > GetScreenWidth) or
  141. (Y1 > Y2) or (Y2 > GetScreenHeight) then
  142. exit;
  143. WindMinY := Y1;
  144. WindMaxY := Y2;
  145. WindMinX := X1;
  146. WindMaxX := X2;
  147. WindMin:=((Y1-1) Shl 8)+(X1-1);
  148. WindMax:=((Y2-1) Shl 8)+(X2-1);
  149. GotoXY(1, 1);
  150. End;
  151. procedure ClrScr;
  152. var
  153. DestCoor: TCoord;
  154. numChars, x : DWord;
  155. begin
  156. DestCoor.X := WindMinX - 1;
  157. DestCoor.Y := WindMinY - 1;
  158. numChars := (WindMaxX - WindMinX + 1);
  159. repeat
  160. FillConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE), TextAttr,
  161. numChars, DestCoor, x);
  162. FillConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), #32,
  163. numChars, DestCoor, x);
  164. inc(DestCoor.Y);
  165. until DWord(DestCoor.Y)=WindMaxY;
  166. GotoXY(1, 1);
  167. end; { proc. ClrScr }
  168. procedure ClrEol;
  169. {
  170. Clear from current position to end of line.
  171. }
  172. var
  173. Temp: DWord;
  174. CharInfo: Char;
  175. Coord: TCoord;
  176. X,Y: DWord;
  177. begin
  178. GetScreenCursor(x, y);
  179. CharInfo := #32;
  180. Coord.X := X - 1;
  181. Coord.Y := Y - 1;
  182. FillConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), CharInfo, WindMaxX - X + 1,
  183. Coord, @Temp);
  184. FillConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE), TextAttr, WindMaxX - X + 1,
  185. Coord, @Temp);
  186. end;
  187. Function WhereX: tcrtcoord;
  188. begin
  189. WhereX:=WhereX32 mod 256;
  190. end;
  191. Function WhereX32: DWord;
  192. {
  193. Return current X-position of cursor.
  194. }
  195. var
  196. x,y : DWord;
  197. Begin
  198. GetScreenCursor(x, y);
  199. WhereX32:= x - WindMinX +1;
  200. End;
  201. Function WhereY: tcrtcoord;
  202. begin
  203. WhereY:=WhereY32 mod 256;
  204. end;
  205. Function WhereY32: DWord;
  206. {
  207. Return current Y-position of cursor.
  208. }
  209. var
  210. x, y : DWord;
  211. Begin
  212. GetScreenCursor(x, y);
  213. WhereY32:= y - WindMinY + 1;
  214. End;
  215. {*************************************************************************
  216. KeyBoard
  217. *************************************************************************}
  218. var
  219. ScanCode : char;
  220. SpecialKey : boolean;
  221. DoingNumChars: Boolean;
  222. DoingNumCode: Byte;
  223. Function RemapScanCode (ScanCode: byte; CtrlKeyState: byte; keycode:longint): byte;
  224. { Several remappings of scancodes are necessary to comply with what
  225. we get with MSDOS. Special Windows keys, as Alt-Tab, Ctrl-Esc etc.
  226. are excluded }
  227. var
  228. AltKey, CtrlKey, ShiftKey: boolean;
  229. const
  230. {
  231. Keypad key scancodes:
  232. Ctrl Norm
  233. $77 $47 - Home
  234. $8D $48 - Up arrow
  235. $84 $49 - PgUp
  236. $8E $4A - -
  237. $73 $4B - Left Arrow
  238. $8F $4C - 5
  239. $74 $4D - Right arrow
  240. $4E $4E - +
  241. $75 $4F - End
  242. $91 $50 - Down arrow
  243. $76 $51 - PgDn
  244. $92 $52 - Ins
  245. $93 $53 - Del
  246. }
  247. CtrlKeypadKeys: array[$47..$53] of byte =
  248. ($77, $8D, $84, $8E, $73, $8F, $74, $4E, $75, $91, $76, $92, $93);
  249. begin
  250. AltKey := ((CtrlKeyState AND
  251. (RIGHT_ALT_PRESSED OR LEFT_ALT_PRESSED)) > 0);
  252. CtrlKey := ((CtrlKeyState AND
  253. (RIGHT_CTRL_PRESSED OR LEFT_CTRL_PRESSED)) > 0);
  254. ShiftKey := ((CtrlKeyState AND SHIFT_PRESSED) > 0);
  255. if AltKey then
  256. begin
  257. case ScanCode of
  258. // Digits, -, =
  259. $02..$0D: inc(ScanCode, $76);
  260. // Function keys
  261. $3B..$44: inc(Scancode, $2D);
  262. $57..$58: inc(Scancode, $34);
  263. // Extended cursor block keys
  264. $47..$49, $4B, $4D, $4F..$53:
  265. inc(Scancode, $50);
  266. // Other keys
  267. $1C: Scancode := $A6; // Enter
  268. $35: Scancode := $A4; // / (keypad and normal!)
  269. end
  270. end
  271. else if CtrlKey then
  272. case Scancode of
  273. // Tab key
  274. $0F: Scancode := $94;
  275. // Function keys
  276. $3B..$44: inc(Scancode, $23);
  277. $57..$58: inc(Scancode, $32);
  278. // Keypad keys
  279. $35: Scancode := $95; // \
  280. $37: Scancode := $96; // *
  281. $47..$53: Scancode := CtrlKeypadKeys[Scancode];
  282. end
  283. else if ShiftKey then
  284. case Scancode of
  285. // Function keys
  286. $3B..$44: inc(Scancode, $19);
  287. $57..$58: inc(Scancode, $30);
  288. end
  289. else
  290. case Scancode of
  291. // Function keys
  292. $57..$58: inc(Scancode, $2E); // F11 and F12
  293. end;
  294. RemapScanCode := ScanCode;
  295. end;
  296. function KeyPressed : boolean;
  297. var
  298. nevents,nread : dword;
  299. buf : TINPUTRECORD;
  300. AltKey: Boolean;
  301. c : longint;
  302. begin
  303. KeyPressed := FALSE;
  304. if ScanCode <> #0 then
  305. KeyPressed := TRUE
  306. else
  307. begin
  308. GetNumberOfConsoleInputEvents(TextRec(input).Handle,nevents);
  309. while nevents>0 do
  310. begin
  311. ReadConsoleInputA(TextRec(input).Handle,buf,1,nread);
  312. if buf.EventType = KEY_EVENT then
  313. if buf.Event.KeyEvent.bKeyDown then
  314. begin
  315. { Alt key is VK_MENU }
  316. { Capslock key is VK_CAPITAL }
  317. AltKey := ((Buf.Event.KeyEvent.dwControlKeyState AND
  318. (RIGHT_ALT_PRESSED OR LEFT_ALT_PRESSED)) > 0);
  319. if not(Buf.Event.KeyEvent.wVirtualKeyCode in [VK_SHIFT, VK_MENU, VK_CONTROL,
  320. VK_CAPITAL, VK_NUMLOCK,
  321. VK_SCROLL]) then
  322. begin
  323. keypressed:=true;
  324. if (ord(buf.Event.KeyEvent.AsciiChar) = 0) or
  325. (buf.Event.KeyEvent.dwControlKeyState and (LEFT_ALT_PRESSED or ENHANCED_KEY) > 0) then
  326. begin
  327. SpecialKey := TRUE;
  328. ScanCode := Chr(RemapScanCode(Buf.Event.KeyEvent.wVirtualScanCode, Buf.Event.KeyEvent.dwControlKeyState,
  329. Buf.Event.KeyEvent.wVirtualKeyCode));
  330. end
  331. else
  332. begin
  333. { Map shift-tab }
  334. if (buf.Event.KeyEvent.AsciiChar=#9) and
  335. (buf.Event.KeyEvent.dwControlKeyState and SHIFT_PRESSED > 0) then
  336. begin
  337. SpecialKey := TRUE;
  338. ScanCode := #15;
  339. end
  340. else
  341. begin
  342. SpecialKey := FALSE;
  343. ScanCode := Chr(Ord(buf.Event.KeyEvent.AsciiChar));
  344. end;
  345. end;
  346. if AltKey then
  347. begin
  348. case Buf.Event.KeyEvent.wVirtualScanCode of
  349. 71 : c:=7;
  350. 72 : c:=8;
  351. 73 : c:=9;
  352. 75 : c:=4;
  353. 76 : c:=5;
  354. 77 : c:=6;
  355. 79 : c:=1;
  356. 80 : c:=2;
  357. 81 : c:=3;
  358. 82 : c:=0;
  359. else
  360. break;
  361. end;
  362. DoingNumChars := true;
  363. DoingNumCode := Byte((DoingNumCode * 10) + c);
  364. Keypressed := false;
  365. Specialkey := false;
  366. ScanCode := #0;
  367. end
  368. else
  369. break;
  370. end;
  371. end
  372. else
  373. begin
  374. if (Buf.Event.KeyEvent.wVirtualKeyCode in [VK_MENU]) then
  375. if DoingNumChars then
  376. if DoingNumCode > 0 then
  377. begin
  378. ScanCode := Chr(DoingNumCode);
  379. Keypressed := true;
  380. DoingNumChars := false;
  381. DoingNumCode := 0;
  382. break
  383. end; { if }
  384. end;
  385. { if we got a key then we can exit }
  386. if keypressed then
  387. exit;
  388. GetNumberOfConsoleInputEvents(TextRec(input).Handle,nevents);
  389. end;
  390. end;
  391. end;
  392. function ReadKey: char;
  393. begin
  394. while (not KeyPressed) do
  395. Sleep(1);
  396. if SpecialKey then begin
  397. ReadKey := #0;
  398. SpecialKey := FALSE;
  399. end else begin
  400. ReadKey := ScanCode;
  401. ScanCode := #0;
  402. end;
  403. end;
  404. {*************************************************************************
  405. Delay
  406. *************************************************************************}
  407. procedure Delay(MS: Word);
  408. begin
  409. Sleep(ms);
  410. end; { proc. Delay }
  411. procedure sound(hz : word);
  412. begin
  413. MessageBeep(0); { lame ;-) }
  414. end;
  415. procedure nosound;
  416. begin
  417. end;
  418. {****************************************************************************
  419. HighLevel Crt Functions
  420. ****************************************************************************}
  421. procedure removeline(y : DWord);
  422. var
  423. ClipRect: TSmallRect;
  424. SrcRect: TSmallRect;
  425. DestCoor: TCoord;
  426. CharInfo: TCharInfo;
  427. begin
  428. CharInfo.UnicodeChar := #32;
  429. CharInfo.Attributes := TextAttr;
  430. Y := (WindMinY - 1) + (Y - 1) + 1;
  431. SrcRect.Top := Y;
  432. SrcRect.Left := WindMinX - 1;
  433. SrcRect.Right := WindMaxX - 1;
  434. SrcRect.Bottom := WindMaxY - 1;
  435. DestCoor.X := WindMinX - 1;
  436. DestCoor.Y := Y - 1;
  437. ClipRect := SrcRect;
  438. cliprect.top := destcoor.y;
  439. ScrollConsoleScreenBuffer(GetStdHandle(STD_OUTPUT_HANDLE), SrcRect, ClipRect,
  440. DestCoor, CharInfo);
  441. end; { proc. RemoveLine }
  442. procedure delline;
  443. begin
  444. removeline(wherey);
  445. end; { proc. DelLine }
  446. procedure insline;
  447. var
  448. ClipRect: TSmallRect;
  449. SrcRect: TSmallRect;
  450. DestCoor: TCoord;
  451. CharInfo: TCharInfo;
  452. X,Y: DWord;
  453. begin
  454. GetScreenCursor(X, Y);
  455. CharInfo.UnicodeChar := #32;
  456. CharInfo.Attributes := TextAttr;
  457. SrcRect.Top := Y - 1;
  458. SrcRect.Left := WindMinX - 1;
  459. SrcRect.Right := WindMaxX - 1;
  460. SrcRect.Bottom := WindMaxY - 1 + 1;
  461. DestCoor.X := WindMinX - 1;
  462. DestCoor.Y := Y;
  463. ClipRect := SrcRect;
  464. ClipRect.Bottom := WindMaxY - 1;
  465. ScrollConsoleScreenBuffer(GetStdHandle(STD_OUTPUT_HANDLE), SrcRect, ClipRect,
  466. DestCoor, CharInfo);
  467. end; { proc. InsLine }
  468. {****************************************************************************
  469. Extra Crt Functions
  470. ****************************************************************************}
  471. procedure cursoron;
  472. var CursorInfo: TConsoleCursorInfo;
  473. begin
  474. GetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), CursorInfo);
  475. CursorInfo.dwSize := SaveCursorSize;
  476. CursorInfo.bVisible := true;
  477. SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), CursorInfo);
  478. end;
  479. procedure cursoroff;
  480. var CursorInfo: TConsoleCursorInfo;
  481. begin
  482. GetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), CursorInfo);
  483. CursorInfo.bVisible := false;
  484. SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), CursorInfo);
  485. end;
  486. procedure cursorbig;
  487. var CursorInfo: TConsoleCursorInfo;
  488. begin
  489. GetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), CursorInfo);
  490. CursorInfo.dwSize := 93;
  491. CursorInfo.bVisible := true;
  492. SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), CursorInfo);
  493. end;
  494. {*****************************************************************************
  495. Read and Write routines
  496. *****************************************************************************}
  497. var
  498. CurrX, CurrY : DWord;
  499. procedure WriteChar(c : char);
  500. var
  501. WritePos: Coord; { Upper-left cell to write from }
  502. numWritten : DWord;
  503. WinAttr : word;
  504. begin
  505. Case C of
  506. #10 : begin
  507. Inc(CurrY);
  508. end;
  509. #13 : begin
  510. CurrX := WindMinX;
  511. end; { if }
  512. #08 : begin
  513. if CurrX > WindMinX then Dec(CurrX);
  514. end; { ^H }
  515. #07 : begin
  516. //MessagBeep(0);
  517. end; { ^G }
  518. else begin
  519. WritePos.X := currX - 1;
  520. WritePos.Y := currY - 1;
  521. WriteConsoleOutputCharacter(GetStdhandle(STD_OUTPUT_HANDLE),
  522. @c, 1, writePos, numWritten);
  523. WinAttr:=TextAttr;
  524. WriteConsoleOutputAttribute(GetStdhandle(STD_OUTPUT_HANDLE),
  525. @WinAttr, 1, writePos, numWritten);
  526. Inc(CurrX);
  527. end; { else }
  528. end; { case }
  529. if CurrX > WindMaxX then begin
  530. CurrX := WindMinX;
  531. Inc(CurrY);
  532. end; { if }
  533. While CurrY > WindMaxY do begin
  534. RemoveLine(1);
  535. Dec(CurrY);
  536. end; { while }
  537. end;
  538. procedure WriteStr(const s: string);
  539. var
  540. WritePos: Coord; { Upper-left cell to write from }
  541. numWritten : DWord;
  542. WinAttr : word;
  543. i: integer;
  544. begin
  545. WritePos.X:=currX-2;
  546. WritePos.Y:=currY-1;
  547. WinAttr:=TextAttr;
  548. for i:=1 to Length(s) do
  549. begin
  550. Inc(WritePos.X);
  551. WriteConsoleOutputCharacter(GetStdhandle(STD_OUTPUT_HANDLE), @s[i], 1, writePos, numWritten);
  552. WriteConsoleOutputAttribute(GetStdhandle(STD_OUTPUT_HANDLE),@WinAttr, 1, writePos, numWritten);
  553. Inc(CurrX);
  554. if CurrX>WindMaxX then
  555. begin
  556. CurrX:=WindMinX;
  557. Inc(CurrY);
  558. While CurrY>WindMaxY do
  559. begin
  560. RemoveLine(1);
  561. Dec(CurrY);
  562. end;
  563. WritePos.X:=currX-2;
  564. WritePos.Y:=currY-1;
  565. end;
  566. end;
  567. end;
  568. Function CrtWrite(var f : textrec) : integer;
  569. var
  570. i : longint;
  571. s : string;
  572. OldConsoleOutputCP : Word;
  573. begin
  574. OldConsoleOutputCP:=GetConsoleOutputCP;
  575. SetConsoleOutputCP(GetACP);
  576. GetScreenCursor(CurrX, CurrY);
  577. s:='';
  578. for i:=0 to f.bufpos-1 do
  579. if f.buffer[i] in [#7,#8,#10,#13] then // special chars directly.
  580. begin
  581. if s<>'' then
  582. begin
  583. WriteStr(s);
  584. s:='';
  585. end;
  586. WriteChar(f.buffer[i]);
  587. end
  588. else
  589. s:=s+f.buffer[i];
  590. if s<>'' then
  591. WriteStr(s);
  592. SetScreenCursor(CurrX, CurrY);
  593. SetConsoleOutputCP(OldConsoleOutputCP);
  594. f.bufpos:=0;
  595. CrtWrite:=0;
  596. end;
  597. Function CrtRead(Var F: TextRec): Integer;
  598. procedure BackSpace;
  599. begin
  600. if (f.bufpos>0) and (f.bufpos=f.bufend) then begin
  601. WriteChar(#8);
  602. WriteChar(' ');
  603. WriteChar(#8);
  604. dec(f.bufpos);
  605. dec(f.bufend);
  606. end;
  607. end;
  608. var
  609. ch : Char;
  610. OldConsoleOutputCP : Word;
  611. Begin
  612. OldConsoleOutputCP:=GetConsoleOutputCP;
  613. SetConsoleOutputCP(GetACP);
  614. GetScreenCursor(CurrX,CurrY);
  615. f.bufpos:=0;
  616. f.bufend:=0;
  617. repeat
  618. if f.bufpos>f.bufend then
  619. f.bufend:=f.bufpos;
  620. SetScreenCursor(CurrX,CurrY);
  621. ch:=readkey;
  622. case ch of
  623. #0 : case readkey of
  624. #71 : while f.bufpos>0 do begin
  625. dec(f.bufpos);
  626. WriteChar(#8);
  627. end;
  628. #75 : if f.bufpos>0 then begin
  629. dec(f.bufpos);
  630. WriteChar(#8);
  631. end;
  632. #77 : if f.bufpos<f.bufend then begin
  633. WriteChar(f.bufptr^[f.bufpos]);
  634. inc(f.bufpos);
  635. end;
  636. #79 : while f.bufpos<f.bufend do begin
  637. WriteChar(f.bufptr^[f.bufpos]);
  638. inc(f.bufpos);
  639. end;
  640. #28: begin // numpad enter
  641. WriteChar(#13);
  642. WriteChar(#10);
  643. f.bufptr^[f.bufend]:=#13;
  644. f.bufptr^[f.bufend+1]:=#10;
  645. inc(f.bufend,2);
  646. break;
  647. end;
  648. #53: begin
  649. ch:='/';
  650. if f.bufpos<f.bufsize-2 then begin
  651. f.buffer[f.bufpos]:=ch;
  652. inc(f.bufpos);
  653. WriteChar(ch);
  654. end;
  655. end;
  656. end;
  657. ^S,
  658. #8 : BackSpace;
  659. ^Y,
  660. #27 : begin
  661. while f.bufpos<f.bufend do begin
  662. WriteChar(f.bufptr^[f.bufpos]);
  663. inc(f.bufpos);
  664. end;
  665. while f.bufend>0 do
  666. BackSpace;
  667. end;
  668. #13 : begin
  669. WriteChar(#13);
  670. WriteChar(#10);
  671. f.bufptr^[f.bufend]:=#13;
  672. f.bufptr^[f.bufend+1]:=#10;
  673. inc(f.bufend,2);
  674. break;
  675. end;
  676. #26 : if CheckEOF then begin
  677. f.bufptr^[f.bufend]:=#26;
  678. inc(f.bufend);
  679. break;
  680. end;
  681. else begin
  682. if f.bufpos<f.bufsize-2 then begin
  683. f.bufptr^[f.bufpos]:=ch;
  684. inc(f.bufpos);
  685. WriteChar(ch);
  686. end;
  687. end;
  688. end;
  689. until false;
  690. SetConsoleOutputCP(OldConsoleOutputCP);
  691. f.bufpos:=0;
  692. SetScreenCursor(CurrX, CurrY);
  693. CrtRead:=0;
  694. End;
  695. Function CrtReturn(Var F:TextRec):Integer;
  696. Begin
  697. CrtReturn:=0;
  698. end;
  699. Function CrtClose(Var F: TextRec): Integer;
  700. Begin
  701. F.Mode:=fmClosed;
  702. CrtClose:=0;
  703. End;
  704. Function CrtOpen(Var F: TextRec): Integer;
  705. Begin
  706. If F.Mode=fmOutput Then begin
  707. TextRec(F).InOutFunc:=@CrtWrite;
  708. TextRec(F).FlushFunc:=@CrtWrite;
  709. end Else begin
  710. F.Mode:=fmInput;
  711. TextRec(F).InOutFunc:=@CrtRead;
  712. TextRec(F).FlushFunc:=@CrtReturn;
  713. end;
  714. TextRec(F).CloseFunc:=@CrtClose;
  715. CrtOpen:=0;
  716. End;
  717. procedure AssignCrt(var F: Text);
  718. begin
  719. Assign(F,'');
  720. TextRec(F).OpenFunc:=@CrtOpen;
  721. end;
  722. var
  723. CursorInfo : TConsoleCursorInfo;
  724. ConsoleInfo : TConsoleScreenBufferinfo;
  725. // ts
  726. begin
  727. { Initialize the output handles }
  728. LastMode := 3;
  729. SetActiveWindow(0);
  730. {--------------------- Get the cursor size and such -----------------------}
  731. FillChar(CursorInfo, SizeOf(CursorInfo), 00);
  732. GetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), CursorInfo);
  733. SaveCursorSize := CursorInfo.dwSize;
  734. {------------------ Get the current cursor position and attr --------------}
  735. FillChar(ConsoleInfo, SizeOf(ConsoleInfo), 0);
  736. GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), ConsoleInfo);
  737. TextAttr := ConsoleInfo.wAttributes;
  738. { Not required, the dos crt does also not touch the mouse }
  739. {TurnMouseOff;}
  740. WindMinX := (ConsoleInfo.srWindow.Left) + 1;
  741. WindMinY := (ConsoleInfo.srWindow.Top) + 1;
  742. WindMaxX := (ConsoleInfo.srWindow.Right) + 1;
  743. WindMaxY := (ConsoleInfo.srWindow.Bottom) + 1;
  744. WindMax:=((WindMaxY-1) Shl 8)+(WindMaxX-1);
  745. DoingNumChars := false;
  746. DoingNumCode := 0;
  747. { Redirect the standard output }
  748. AssignCrt(Output);
  749. Rewrite(Output);
  750. TextRec(Output).Handle:= GetStdHandle(STD_OUTPUT_HANDLE);
  751. AssignCrt(Input);
  752. Reset(Input);
  753. TextRec(Input).Handle:= GetStdHandle(STD_INPUT_HANDLE);
  754. end. { unit Crt }