crt.pp 23 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028
  1. {
  2. $Id$
  3. Borland Pascal 7 Compatible CRT Unit for win32
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. unit crt;
  11. {$mode objfpc}
  12. interface
  13. const
  14. { CRT modes }
  15. BW40 = 0; { 40x25 B/W on Color Adapter }
  16. CO40 = 1; { 40x25 Color on Color Adapter }
  17. BW80 = 2; { 80x25 B/W on Color Adapter }
  18. CO80 = 3; { 80x25 Color on Color Adapter }
  19. Mono = 7; { 80x25 on Monochrome Adapter }
  20. Font8x8 = 256; { Add-in for ROM font }
  21. { Mode constants for 3.0 compatibility }
  22. C40 = CO40;
  23. C80 = CO80;
  24. { Foreground and background color constants }
  25. Black = 0;
  26. Blue = 1;
  27. Green = 2;
  28. Cyan = 3;
  29. Red = 4;
  30. Magenta = 5;
  31. Brown = 6;
  32. LightGray = 7;
  33. { Foreground color constants }
  34. DarkGray = 8;
  35. LightBlue = 9;
  36. LightGreen = 10;
  37. LightCyan = 11;
  38. LightRed = 12;
  39. LightMagenta = 13;
  40. Yellow = 14;
  41. White = 15;
  42. { Add-in for blinking }
  43. Blink = 128;
  44. var
  45. { Interface variables }
  46. CheckBreak: Boolean; { Enable Ctrl-Break }
  47. CheckEOF: Boolean; { Enable Ctrl-Z }
  48. DirectVideo: Boolean; { Enable direct video addressing }
  49. CheckSnow: Boolean; { Enable snow filtering }
  50. LastMode: Word; { Current text mode }
  51. TextAttr: Byte; { Current text attribute }
  52. WindMin: Word; { Window upper left coordinates }
  53. WindMax: Word; { Window lower right coordinates }
  54. { Interface procedures }
  55. procedure AssignCrt(var F: Text);
  56. function KeyPressed: Boolean;
  57. function ReadKey: Char;
  58. procedure TextMode(Mode: Integer);
  59. procedure Window(X1,Y1,X2,Y2: Byte);
  60. procedure GotoXY(X,Y: Byte);
  61. function WhereX: Byte;
  62. function WhereY: Byte;
  63. procedure ClrScr;
  64. procedure ClrEol;
  65. procedure InsLine;
  66. procedure DelLine;
  67. procedure TextColor(Color: Byte);
  68. procedure TextBackground(Color: Byte);
  69. procedure LowVideo;
  70. procedure HighVideo;
  71. procedure NormVideo;
  72. procedure Delay(MS: Word);
  73. procedure Sound(Hz: Word);
  74. procedure NoSound;
  75. {Extra Functions}
  76. procedure cursoron;
  77. procedure cursoroff;
  78. procedure cursorbig;
  79. implementation
  80. uses
  81. dos,
  82. windows;
  83. var
  84. OutHandle : THandle;
  85. InputHandle : THandle;
  86. CursorSaveX : Longint;
  87. CursorSaveY : Longint;
  88. ScreenWidth : Longint;
  89. ScreenHeight : Longint;
  90. IsWindowsNT : Boolean;
  91. SaveCursorSize: Longint;
  92. {
  93. definition of textrec is in textrec.inc
  94. }
  95. {$i textrec.inc}
  96. {****************************************************************************
  97. Low level Routines
  98. ****************************************************************************}
  99. function GetPlatformID: Longint;
  100. var OsVersion: TOSVersionInfo;
  101. begin
  102. OsVersion.dwOsVersionInfoSize := SizeOf(OsVersion);
  103. GetVersionEx(OsVersion);
  104. Result := OsVersion.dwPlatformID;
  105. end; { func. GetPlatformID }
  106. procedure TurnMouseOff;
  107. var Mode: DWORD;
  108. begin
  109. if GetConsoleMode(InputHandle, @Mode) then { Turn the mouse-cursor off }
  110. begin
  111. Mode := Mode AND NOT enable_processed_input
  112. AND NOT enable_mouse_input;
  113. SetConsoleMode(InputHandle, Mode);
  114. end; { if }
  115. end; { proc. TurnMouseOff }
  116. function GetScreenHeight : longint;
  117. var ConsoleInfo: TConsoleScreenBufferinfo;
  118. res : longint;
  119. begin
  120. if not GetConsoleScreenBufferInfo(OutHandle, ConsoleInfo) then
  121. begin
  122. res:=GetLastError;
  123. Result:=25;
  124. {$ifdef SYSTEMDEBUG}
  125. Writeln(stderr,'GetScreenHeight failed GetLastError returns ',res);
  126. Halt(1);
  127. {$endif SYSTEMDEBUG}
  128. end
  129. else
  130. Result := ConsoleInfo.dwSize.Y;
  131. end; { func. GetScreenHeight }
  132. function GetScreenWidth : longint;
  133. var ConsoleInfo: TConsoleScreenBufferInfo;
  134. res : longint;
  135. begin
  136. if not GetConsoleScreenBufferInfo(OutHandle, ConsoleInfo)then
  137. begin
  138. res:=GetLastError;
  139. Result:=80;
  140. {$ifdef SYSTEMDEBUG}
  141. Writeln(stderr,'GetScreenWidth failed GetLastError returns ',res);
  142. Halt(1);
  143. {$endif SYSTEMDEBUG}
  144. end
  145. else
  146. Result := ConsoleInfo.dwSize.X;
  147. end; { func. GetScreenWidth }
  148. procedure SetScreenCursor(x,y : longint);
  149. var CurInfo: TCoord;
  150. begin
  151. FillChar(Curinfo, SizeOf(Curinfo), 0);
  152. CurInfo.X := X - 1;
  153. CurInfo.Y := Y - 1;
  154. SetConsoleCursorPosition(OutHandle, CurInfo);
  155. CursorSaveX := X - 1;
  156. CursorSaveY := Y - 1;
  157. end;
  158. procedure GetScreenCursor(var x,y : longint);
  159. begin
  160. X := CursorSaveX + 1;
  161. Y := CursorSaveY + 1;
  162. end;
  163. {****************************************************************************
  164. Helper Routines
  165. ****************************************************************************}
  166. Function WinMinX: Byte;
  167. {
  168. Current Minimum X coordinate
  169. }
  170. Begin
  171. WinMinX:=(WindMin and $ff)+1;
  172. End;
  173. Function WinMinY: Byte;
  174. {
  175. Current Minimum Y Coordinate
  176. }
  177. Begin
  178. WinMinY:=(WindMin shr 8)+1;
  179. End;
  180. Function WinMaxX: Byte;
  181. {
  182. Current Maximum X coordinate
  183. }
  184. Begin
  185. WinMaxX:=(WindMax and $ff)+1;
  186. End;
  187. Function WinMaxY: Byte;
  188. {
  189. Current Maximum Y coordinate;
  190. }
  191. Begin
  192. WinMaxY:=(WindMax shr 8) + 1;
  193. End;
  194. Function FullWin:boolean;
  195. {
  196. Full Screen 80x25? Window(1,1,80,25) is used, allows faster routines
  197. }
  198. begin
  199. FullWin:=(WinMinX=1) and (WinMinY=1) and
  200. (WinMaxX=ScreenWidth) and (WinMaxY=ScreenHeight);
  201. end;
  202. {****************************************************************************
  203. Public Crt Functions
  204. ****************************************************************************}
  205. procedure textmode(mode : integer);
  206. begin
  207. {!!! Not done yet !!! }
  208. end;
  209. Procedure TextColor(Color: Byte);
  210. {
  211. Switch foregroundcolor
  212. }
  213. Begin
  214. TextAttr:=(Color and $8f) or (TextAttr and $70);
  215. End;
  216. Procedure TextBackground(Color: Byte);
  217. {
  218. Switch backgroundcolor
  219. }
  220. Begin
  221. TextAttr:=((Color shl 4) and ($f0 and not Blink)) or (TextAttr and ($0f OR Blink) );
  222. End;
  223. Procedure HighVideo;
  224. {
  225. Set highlighted output.
  226. }
  227. Begin
  228. TextColor(TextAttr Or $08);
  229. End;
  230. Procedure LowVideo;
  231. {
  232. Set normal output
  233. }
  234. Begin
  235. TextColor(TextAttr And $77);
  236. End;
  237. Procedure NormVideo;
  238. {
  239. Set normal back and foregroundcolors.
  240. }
  241. Begin
  242. TextColor(7);
  243. TextBackGround(0);
  244. End;
  245. Procedure GotoXy(X: Byte; Y: Byte);
  246. {
  247. Go to coordinates X,Y in the current window.
  248. }
  249. Begin
  250. If (X>0) and (X<=WinMaxX- WinMinX+1) and
  251. (Y>0) and (Y<=WinMaxY-WinMinY+1) Then
  252. Begin
  253. Inc(X,WinMinX-1);
  254. Inc(Y,WinMinY-1);
  255. SetScreenCursor(x,y);
  256. End;
  257. End;
  258. Procedure Window(X1, Y1, X2, Y2: Byte);
  259. {
  260. Set screen window to the specified coordinates.
  261. }
  262. Begin
  263. if (X1>X2) or (X2>ScreenWidth) or
  264. (Y1>Y2) or (Y2>ScreenHeight) then
  265. exit;
  266. WindMin:=((Y1-1) Shl 8)+(X1-1);
  267. WindMax:=((Y2-1) Shl 8)+(X2-1);
  268. GoToXY(1,1);
  269. End;
  270. procedure ClrScr;
  271. var
  272. ClipRect: TSmallRect;
  273. SrcRect: TSmallRect;
  274. DestCoor: TCoord;
  275. CharInfo: TCharInfo;
  276. begin
  277. CharInfo.UnicodeChar := 32;
  278. CharInfo.Attributes := TextAttr;
  279. SrcRect.Left := WinMinX - 1;
  280. SrcRect.Top := WinMinY - 1;
  281. SrcRect.Right := WinMaxX - 1;
  282. SrcRect.Bottom := WinMaxY - 1;
  283. ClipRect := SrcRect;
  284. if IsWindowsNT then
  285. begin
  286. DestCoor.X := -WinMaxX;
  287. DestCoor.Y := -WinMaxY;
  288. ScrollConsoleScreenBuffer(OutHandle, SrcRect, ClipRect,
  289. DestCoor, CharInfo);
  290. end
  291. else begin { Win95 seems to have a bug in scrolling, unfortunately }
  292. { This routine 3 times copies the bottom 12 lines to the }
  293. { top part of the screen. This eventually will clear the }
  294. { screen. }
  295. DestCoor.X := WinMinX - 1;
  296. DestCoor.Y := WinMinY - (Succ((WinMaxY - WinMinY) div 2));
  297. {-------- Scroll 1st part }
  298. ScrollConsoleScreenBuffer(OutHandle, SrcRect, ClipRect,
  299. DestCoor, CharInfo);
  300. {-------- Scroll 2nd part }
  301. ScrollConsoleScreenBuffer(OutHandle, SrcRect, ClipRect,
  302. DestCoor, CharInfo);
  303. {-------- Scroll 3rd part (last line) }
  304. ScrollConsoleScreenBuffer(OutHandle, SrcRect, ClipRect,
  305. DestCoor, CharInfo);
  306. end; { if in Windows95 }
  307. GotoXY(1,1);
  308. end; { proc. ClrScr }
  309. procedure ClrEol;
  310. {
  311. Clear from current position to end of line.
  312. }
  313. var Temp: Dword;
  314. CharInfo: Char;
  315. Coord: TCoord;
  316. X,Y: Longint;
  317. begin
  318. GetScreenCursor(x,y);
  319. CharInfo := #32;
  320. Coord.X := X - 1;
  321. Coord.Y := Y - 1;
  322. FillConsoleOutputCharacter(OutHandle, CharInfo, WinMaxX - (X + 01), Coord, @Temp);
  323. end;
  324. Function WhereX: Byte;
  325. {
  326. Return current X-position of cursor.
  327. }
  328. var
  329. x,y : longint;
  330. Begin
  331. GetScreenCursor(x,y);
  332. WhereX:=x-WinMinX+1;
  333. End;
  334. Function WhereY: Byte;
  335. {
  336. Return current Y-position of cursor.
  337. }
  338. var
  339. x,y : longint;
  340. Begin
  341. GetScreenCursor(x,y);
  342. WhereY:=y-WinMinY+1;
  343. End;
  344. {*************************************************************************
  345. KeyBoard
  346. *************************************************************************}
  347. var
  348. ScanCode : char;
  349. SpecialKey : boolean;
  350. DoingNumChars: Boolean;
  351. DoingNumCode: Byte;
  352. Function RemapScanCode (ScanCode: byte; CtrlKeyState: byte; keycode:longint): byte;
  353. { Several remappings of scancodes are necessary to comply with what
  354. we get with MSDOS. Special Windows keys, as Alt-Tab, Ctrl-Esc etc.
  355. are excluded }
  356. var
  357. AltKey, CtrlKey, ShiftKey: boolean;
  358. const
  359. {
  360. Keypad key scancodes:
  361. Ctrl Norm
  362. $77 $47 - Home
  363. $8D $48 - Up arrow
  364. $84 $49 - PgUp
  365. $8E $4A - -
  366. $73 $4B - Left Arrow
  367. $8F $4C - 5
  368. $74 $4D - Right arrow
  369. $4E $4E - +
  370. $75 $4F - End
  371. $91 $50 - Down arrow
  372. $76 $51 - PgDn
  373. $92 $52 - Ins
  374. $93 $53 - Del
  375. }
  376. CtrlKeypadKeys: array[$47..$53] of byte =
  377. ($77, $8D, $84, $8E, $73, $8F, $74, $4E, $75, $91, $76, $92, $93);
  378. begin
  379. AltKey := ((CtrlKeyState AND
  380. (RIGHT_ALT_PRESSED OR LEFT_ALT_PRESSED)) > 0);
  381. CtrlKey := ((CtrlKeyState AND
  382. (RIGHT_CTRL_PRESSED OR LEFT_CTRL_PRESSED)) > 0);
  383. ShiftKey := ((CtrlKeyState AND SHIFT_PRESSED) > 0);
  384. if AltKey then begin
  385. Case KeyCode of
  386. VK_NUMPAD0 ..
  387. VK_NUMPAD9 : begin
  388. DoingNumChars := true;
  389. DoingNumCode := Byte((DoingNumCode * 10) + (KeyCode - VK_NUMPAD0));
  390. end;
  391. end; { case }
  392. case ScanCode of
  393. // Digits, -, =
  394. $02..$0D: inc(ScanCode, $76);
  395. // Function keys
  396. $3B..$44: inc(Scancode, $2D);
  397. $57..$58: inc(Scancode, $34);
  398. // Extended cursor block keys
  399. $47..$49, $4B, $4D, $4F..$53:
  400. inc(Scancode, $50);
  401. // Other keys
  402. $1C: Scancode := $A6; // Enter
  403. $35: Scancode := $A4; // / (keypad and normal!)
  404. end
  405. end
  406. else if CtrlKey then
  407. case Scancode of
  408. // Tab key
  409. $0F: Scancode := $94;
  410. // Function keys
  411. $3B..$44: inc(Scancode, $23);
  412. $57..$58: inc(Scancode, $32);
  413. // Keypad keys
  414. $35: Scancode := $95; // \
  415. $37: Scancode := $96; // *
  416. $47..$53: Scancode := CtrlKeypadKeys[Scancode];
  417. end
  418. else if ShiftKey then
  419. case Scancode of
  420. // Function keys
  421. $3B..$44: inc(Scancode, $19);
  422. $57..$58: inc(Scancode, $30);
  423. end
  424. else
  425. case Scancode of
  426. // Function keys
  427. $57..$58: inc(Scancode, $2E); // F11 and F12
  428. end;
  429. Result := ScanCode;
  430. end;
  431. function KeyPressed : boolean;
  432. var
  433. nevents, nread, i: longint;
  434. buf : TINPUTRECORD;
  435. AltKey: Boolean;
  436. begin
  437. KeyPressed := FALSE;
  438. if ScanCode <> #0 then
  439. KeyPressed := TRUE
  440. else
  441. begin
  442. nevents:=0;
  443. GetNumberOfConsoleInputEvents(TextRec(input).Handle,nevents);
  444. For i := 1 to nevents do
  445. begin
  446. ReadConsoleInputA(TextRec(input).Handle,buf,1,nread);
  447. if buf.EventType = KEY_EVENT then
  448. if buf.KeyEvent.bKeyDown then
  449. begin
  450. { Alt key is VK_MENU }
  451. { Capslock key is VK_CAPITAL }
  452. AltKey := ((Buf.KeyEvent.dwControlKeyState AND
  453. (RIGHT_ALT_PRESSED OR LEFT_ALT_PRESSED)) > 0);
  454. if (Buf.KeyEvent.wVirtualKeyCode in [VK_SHIFT, VK_MENU, VK_CONTROL,
  455. VK_CAPITAL, VK_NUMLOCK,
  456. VK_SCROLL]) then
  457. begin
  458. { Discard this key }
  459. end
  460. else begin
  461. KeyPressed := TRUE;
  462. if ord(buf.KeyEvent.AsciiChar) = 0 then
  463. begin
  464. SpecialKey := TRUE;
  465. ScanCode := Chr(RemapScanCode(Buf.KeyEvent.wVirtualScanCode, Buf.KeyEvent.dwControlKeyState,
  466. Buf.KeyEvent.wVirtualKeyCode));
  467. end
  468. else
  469. begin
  470. SpecialKey := FALSE;
  471. ScanCode := Chr(Ord(buf.KeyEvent.AsciiChar));
  472. end;
  473. if Buf.KeyEvent.wVirtualKeyCode in [VK_NUMPAD0..VK_NUMPAD9] then
  474. if AltKey then
  475. begin
  476. Keypressed := false;
  477. Specialkey := false;
  478. ScanCode := #0;
  479. end
  480. else BREAK;
  481. end;
  482. end { if }
  483. else if (Buf.KeyEvent.wVirtualKeyCode in [VK_MENU]) then
  484. if DoingNumChars then
  485. if DoingNumCode > 0 then
  486. begin
  487. ScanCode := Chr(DoingNumCode);
  488. Keypressed := true;
  489. DoingNumChars := false;
  490. DoingNumCode := 0;
  491. BREAK;
  492. end; { if }
  493. end;
  494. end;
  495. end;
  496. function ReadKey: char;
  497. begin
  498. repeat
  499. Sleep(1);
  500. until KeyPressed;
  501. if SpecialKey then begin
  502. ReadKey := #0;
  503. SpecialKey := FALSE;
  504. end
  505. else begin
  506. ReadKey := ScanCode;
  507. ScanCode := #0;
  508. end;
  509. end;
  510. {*************************************************************************
  511. Delay
  512. *************************************************************************}
  513. procedure Delay(MS: Word);
  514. begin
  515. Sleep(ms);
  516. end; { proc. Delay }
  517. procedure sound(hz : word);
  518. begin
  519. MessageBeep(0); { lame ;-) }
  520. end;
  521. procedure nosound;
  522. begin
  523. end;
  524. {****************************************************************************
  525. HighLevel Crt Functions
  526. ****************************************************************************}
  527. procedure removeline(y : longint);
  528. var
  529. ClipRect: TSmallRect;
  530. SrcRect: TSmallRect;
  531. DestCoor: TCoord;
  532. CharInfo: TCharInfo;
  533. begin
  534. CharInfo.UnicodeChar := 32;
  535. CharInfo.Attributes := TextAttr;
  536. Y := WinMinY + Y-1;
  537. SrcRect.Top := Y - 01;
  538. SrcRect.Left := WinMinX - 1;
  539. SrcRect.Right := WinMaxX - 1;
  540. SrcRect.Bottom := WinMaxY - 1;
  541. DestCoor.X := WinMinX - 1;
  542. DestCoor.Y := Y - 2;
  543. ClipRect := SrcRect;
  544. ScrollConsoleScreenBuffer(OutHandle, SrcRect, ClipRect, DestCoor, CharInfo);
  545. end; { proc. RemoveLine }
  546. procedure delline;
  547. begin
  548. removeline(wherey);
  549. end; { proc. DelLine }
  550. procedure insline;
  551. var
  552. ClipRect: TSmallRect;
  553. SrcRect: TSmallRect;
  554. DestCoor: TCoord;
  555. CharInfo: TCharInfo;
  556. X,Y: Longint;
  557. begin
  558. GetScreenCursor(X, Y);
  559. CharInfo.UnicodeChar := 32;
  560. CharInfo.Attributes := TextAttr;
  561. SrcRect.Top := Y - 1;
  562. SrcRect.Left := WinMinX - 1;
  563. SrcRect.Right := WinMaxX - 1;
  564. SrcRect.Bottom := WinMaxY - 1;
  565. DestCoor.X := WinMinX - 1;
  566. DestCoor.Y := Y;
  567. ClipRect := SrcRect;
  568. ScrollConsoleScreenBuffer(OutHandle, SrcRect, ClipRect, DestCoor, CharInfo);
  569. end; { proc. InsLine }
  570. {****************************************************************************
  571. Extra Crt Functions
  572. ****************************************************************************}
  573. procedure cursoron;
  574. var CursorInfo: TConsoleCursorInfo;
  575. begin
  576. GetConsoleCursorInfo(OutHandle, CursorInfo);
  577. CursorInfo.dwSize := SaveCursorSize;
  578. CursorInfo.bVisible := true;
  579. SetConsoleCursorInfo(OutHandle, CursorInfo);
  580. end;
  581. procedure cursoroff;
  582. var CursorInfo: TConsoleCursorInfo;
  583. begin
  584. GetConsoleCursorInfo(OutHandle, CursorInfo);
  585. CursorInfo.bVisible := false;
  586. SetConsoleCursorInfo(OutHandle, CursorInfo);
  587. end;
  588. procedure cursorbig;
  589. var CursorInfo: TConsoleCursorInfo;
  590. begin
  591. GetConsoleCursorInfo(OutHandle, CursorInfo);
  592. CursorInfo.dwSize := 100;
  593. CursorInfo.bVisible := true;
  594. SetConsoleCursorInfo(OutHandle, CursorInfo);
  595. end;
  596. {*****************************************************************************
  597. Read and Write routines
  598. *****************************************************************************}
  599. var
  600. CurrX, CurrY : longint;
  601. procedure WriteChar(c:char);
  602. var
  603. Cell : TCharInfo;
  604. BufSize : Coord; { Column-row size of source buffer }
  605. WritePos: TCoord; { Upper-left cell to write from }
  606. DestRect: TSmallRect;
  607. begin
  608. Case C of
  609. #10 : begin
  610. Inc(CurrY);
  611. end;
  612. #13 : begin
  613. CurrX := WinMinX;
  614. end; { if }
  615. #08 : begin
  616. if CurrX > WinMinX then Dec(CurrX);
  617. end; { ^H }
  618. #07 : begin
  619. // MessagBeep(0);
  620. end; { ^G }
  621. else begin
  622. BufSize.X := 01;
  623. BufSize.Y := 01;
  624. WritePos.X := 0;
  625. WritePos.Y := 0;
  626. Cell.UniCodeChar := Ord(c);
  627. Cell.Attributes := TextAttr;
  628. DestRect.Left := (CurrX - 01);
  629. DestRect.Top := (CurrY - 01);
  630. DestRect.Right := (CurrX - 01);
  631. DestRect.Bottom := (CurrY - 01);
  632. WriteConsoleOutput(OutHandle, Cell, BufSize, WritePos, @DestRect);
  633. Inc(CurrX);
  634. end; { else }
  635. end; { case }
  636. if CurrX > WinMaxX then
  637. begin
  638. CurrX := WinMinX;
  639. Inc(CurrY);
  640. end; { if }
  641. While CurrY > WinMaxY do
  642. begin
  643. RemoveLine(1);
  644. Dec(CurrY);
  645. end; { while }
  646. end;
  647. Function CrtWrite(var f : textrec):integer;
  648. var
  649. i : longint;
  650. begin
  651. GetScreenCursor(CurrX,CurrY);
  652. for i:=0 to f.bufpos-1 do
  653. WriteChar(f.buffer[i]);
  654. SetScreenCursor(CurrX,CurrY);
  655. f.bufpos:=0;
  656. CrtWrite:=0;
  657. end;
  658. Function CrtRead(Var F: TextRec): Integer;
  659. procedure BackSpace;
  660. begin
  661. if (f.bufpos>0) and (f.bufpos=f.bufend) then
  662. begin
  663. WriteChar(#8);
  664. WriteChar(' ');
  665. WriteChar(#8);
  666. dec(f.bufpos);
  667. dec(f.bufend);
  668. end;
  669. end;
  670. var
  671. ch : Char;
  672. Begin
  673. GetScreenCursor(CurrX,CurrY);
  674. f.bufpos:=0;
  675. f.bufend:=0;
  676. repeat
  677. if f.bufpos>f.bufend then
  678. f.bufend:=f.bufpos;
  679. SetScreenCursor(CurrX,CurrY);
  680. ch:=readkey;
  681. case ch of
  682. #0 : case readkey of
  683. #71 : while f.bufpos>0 do
  684. begin
  685. dec(f.bufpos);
  686. WriteChar(#8);
  687. end;
  688. #75 : if f.bufpos>0 then
  689. begin
  690. dec(f.bufpos);
  691. WriteChar(#8);
  692. end;
  693. #77 : if f.bufpos<f.bufend then
  694. begin
  695. WriteChar(f.bufptr^[f.bufpos]);
  696. inc(f.bufpos);
  697. end;
  698. #79 : while f.bufpos<f.bufend do
  699. begin
  700. WriteChar(f.bufptr^[f.bufpos]);
  701. inc(f.bufpos);
  702. end;
  703. end;
  704. ^S,
  705. #8 : BackSpace;
  706. ^Y,
  707. #27 : begin
  708. f.bufpos:=f.bufend;
  709. while f.bufend>0 do
  710. BackSpace;
  711. end;
  712. #13 : begin
  713. WriteChar(#13);
  714. WriteChar(#10);
  715. f.bufptr^[f.bufend]:=#13;
  716. f.bufptr^[f.bufend+1]:=#10;
  717. inc(f.bufend,2);
  718. break;
  719. end;
  720. #26 : if CheckEOF then
  721. begin
  722. f.bufptr^[f.bufend]:=#26;
  723. inc(f.bufend);
  724. break;
  725. end;
  726. else
  727. begin
  728. if f.bufpos<f.bufsize-2 then
  729. begin
  730. f.buffer[f.bufpos]:=ch;
  731. inc(f.bufpos);
  732. WriteChar(ch);
  733. end;
  734. end;
  735. end;
  736. until false;
  737. f.bufpos:=0;
  738. SetScreenCursor(CurrX,CurrY);
  739. CrtRead:=0;
  740. End;
  741. Function CrtReturn(Var F:TextRec):Integer;
  742. Begin
  743. CrtReturn:=0;
  744. end;
  745. Function CrtClose(Var F: TextRec): Integer;
  746. Begin
  747. F.Mode:=fmClosed;
  748. CrtClose:=0;
  749. End;
  750. Function CrtOpen(Var F: TextRec): Integer;
  751. Begin
  752. If F.Mode=fmOutput Then
  753. begin
  754. TextRec(F).InOutFunc:=@CrtWrite;
  755. TextRec(F).FlushFunc:=@CrtWrite;
  756. end
  757. Else
  758. begin
  759. F.Mode:=fmInput;
  760. TextRec(F).InOutFunc:=@CrtRead;
  761. TextRec(F).FlushFunc:=@CrtReturn;
  762. end;
  763. TextRec(F).CloseFunc:=@CrtClose;
  764. CrtOpen:=0;
  765. End;
  766. procedure AssignCrt(var F: Text);
  767. begin
  768. Assign(F,'');
  769. TextRec(F).OpenFunc:=@CrtOpen;
  770. end;
  771. const
  772. conout : pchar = 'CONOUT$';
  773. var
  774. CursorInfo : TConsoleCursorInfo;
  775. ConsoleInfo : TConsoleScreenBufferinfo;
  776. begin
  777. { Initialize the output handles }
  778. OutHandle := GetStdHandle(STD_OUTPUT_HANDLE);
  779. InputHandle := GetStdHandle(STD_INPUT_HANDLE);
  780. LastMode := 3;
  781. {--------------------- Get the cursor size and such -----------------------}
  782. FillChar(CursorInfo, SizeOf(CursorInfo), 00);
  783. GetConsoleCursorInfo(OutHandle, CursorInfo);
  784. SaveCursorSize := CursorInfo.dwSize;
  785. {------------------ Get the current cursor position and attr --------------}
  786. FillChar(ConsoleInfo, SizeOf(ConsoleInfo), 0);
  787. if not GetConsoleScreenBufferInfo(OutHandle, ConsoleInfo) then
  788. begin
  789. OutHandle:=CreateFile(ConOut, generic_read or generic_write,
  790. file_share_read or file_share_write,nil,
  791. open_existing,0,0);
  792. If (OutHandle=Invalid_handle_value) then
  793. begin
  794. Writeln(stderr,'No way to get the console handle');
  795. Halt(1);
  796. end;
  797. if not GetConsoleScreenBufferInfo(OutHandle, ConsoleInfo) then
  798. begin
  799. Writeln(stderr,'No way to get console screen buffer info');
  800. Halt(1);
  801. end;
  802. end;
  803. CursorSaveX := ConsoleInfo.dwCursorPosition.X;
  804. CursorSaveY := ConsoleInfo.dwCursorPosition.Y;
  805. TextAttr := ConsoleInfo.wAttributes;
  806. { Load startup values }
  807. ScreenWidth := GetScreenWidth;
  808. ScreenHeight := GetScreenHeight;
  809. IsWindowsNT := (GetPlatformID = VER_PLATFORM_WIN32_NT);
  810. TurnMouseOff;
  811. WindMax := (ScreenWidth - 1) OR ((ScreenHeight - 1) SHL 8);
  812. DoingNumChars := false;
  813. DoingNumCode := 0;
  814. { Redirect the standard output }
  815. AssignCrt(Output);
  816. Rewrite(Output);
  817. TextRec(Output).Handle:= OutHandle;
  818. AssignCrt(Input);
  819. Reset(Input);
  820. TextRec(Input).Handle:= InputHandle;
  821. end. { unit Crt }
  822. {
  823. $Log$
  824. Revision 1.15 2000-04-14 12:14:39 pierre
  825. * try to get it to work if output is redirected
  826. Revision 1.14 2000/02/26 14:57:17 florian
  827. * writing at coloumn <screenwidth> wasn't possible in some cases,
  828. fixed
  829. Revision 1.13 2000/02/09 16:59:34 peter
  830. * truncated log
  831. Revision 1.12 1999/10/22 14:36:20 peter
  832. * crtreturn also needs f:textrec as parameter
  833. Revision 1.11 1999/08/28 09:30:39 peter
  834. * fixes from Maarten Bekers
  835. Revision 1.10 1999/08/24 13:15:44 peter
  836. * Removeline fixed
  837. }