crt.pp 23 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024
  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 cardinal(NOT enable_processed_input)
  112. AND cardinal(NOT enable_mouse_input);
  113. SetConsoleMode(InputHandle, Mode);
  114. end; { if }
  115. end; { proc. TurnMouseOff }
  116. function GetScreenHeight : longint;
  117. var
  118. ConsoleInfo: TConsoleScreenBufferinfo;
  119. begin
  120. if not GetConsoleScreenBufferInfo(OutHandle, ConsoleInfo) then
  121. begin
  122. {$ifdef SYSTEMDEBUG}
  123. Writeln(stderr,'GetScreenHeight failed GetLastError returns ',GetLastError);
  124. Halt(1);
  125. {$endif SYSTEMDEBUG}
  126. Result:=25;
  127. end
  128. else
  129. Result := ConsoleInfo.dwSize.Y;
  130. end; { func. GetScreenHeight }
  131. function GetScreenWidth : longint;
  132. var
  133. ConsoleInfo: TConsoleScreenBufferInfo;
  134. begin
  135. if not GetConsoleScreenBufferInfo(OutHandle, ConsoleInfo) then
  136. begin
  137. {$ifdef SYSTEMDEBUG}
  138. Writeln(stderr,'GetScreenWidth failed GetLastError returns ',GetLastError);
  139. Halt(1);
  140. {$endif SYSTEMDEBUG}
  141. Result:=80;
  142. end
  143. else
  144. Result := ConsoleInfo.dwSize.X;
  145. end; { func. GetScreenWidth }
  146. procedure SetScreenCursor(x,y : longint);
  147. var
  148. CurInfo: TCoord;
  149. begin
  150. FillChar(Curinfo, SizeOf(Curinfo), 0);
  151. CurInfo.X := X - 1;
  152. CurInfo.Y := Y - 1;
  153. SetConsoleCursorPosition(OutHandle, CurInfo);
  154. CursorSaveX := X - 1;
  155. CursorSaveY := Y - 1;
  156. end;
  157. procedure GetScreenCursor(var x,y : longint);
  158. begin
  159. X := CursorSaveX + 1;
  160. Y := CursorSaveY + 1;
  161. end;
  162. {****************************************************************************
  163. Helper Routines
  164. ****************************************************************************}
  165. Function WinMinX: Byte;
  166. {
  167. Current Minimum X coordinate
  168. }
  169. Begin
  170. WinMinX:=(WindMin and $ff)+1;
  171. End;
  172. Function WinMinY: Byte;
  173. {
  174. Current Minimum Y Coordinate
  175. }
  176. Begin
  177. WinMinY:=(WindMin shr 8)+1;
  178. End;
  179. Function WinMaxX: Byte;
  180. {
  181. Current Maximum X coordinate
  182. }
  183. Begin
  184. WinMaxX:=(WindMax and $ff)+1;
  185. End;
  186. Function WinMaxY: Byte;
  187. {
  188. Current Maximum Y coordinate;
  189. }
  190. Begin
  191. WinMaxY:=(WindMax shr 8) + 1;
  192. End;
  193. Function FullWin:boolean;
  194. {
  195. Full Screen 80x25? Window(1,1,80,25) is used, allows faster routines
  196. }
  197. begin
  198. FullWin:=(WinMinX=1) and (WinMinY=1) and
  199. (WinMaxX=ScreenWidth) and (WinMaxY=ScreenHeight);
  200. end;
  201. {****************************************************************************
  202. Public Crt Functions
  203. ****************************************************************************}
  204. procedure textmode(mode : integer);
  205. begin
  206. {!!! Not done yet !!! }
  207. end;
  208. Procedure TextColor(Color: Byte);
  209. {
  210. Switch foregroundcolor
  211. }
  212. Begin
  213. TextAttr:=(Color and $8f) or (TextAttr and $70);
  214. End;
  215. Procedure TextBackground(Color: Byte);
  216. {
  217. Switch backgroundcolor
  218. }
  219. Begin
  220. TextAttr:=((Color shl 4) and ($f0 and not Blink)) or (TextAttr and ($0f OR Blink) );
  221. End;
  222. Procedure HighVideo;
  223. {
  224. Set highlighted output.
  225. }
  226. Begin
  227. TextColor(TextAttr Or $08);
  228. End;
  229. Procedure LowVideo;
  230. {
  231. Set normal output
  232. }
  233. Begin
  234. TextColor(TextAttr And $77);
  235. End;
  236. Procedure NormVideo;
  237. {
  238. Set normal back and foregroundcolors.
  239. }
  240. Begin
  241. TextColor(7);
  242. TextBackGround(0);
  243. End;
  244. Procedure GotoXy(X: Byte; Y: Byte);
  245. {
  246. Go to coordinates X,Y in the current window.
  247. }
  248. Begin
  249. If (X>0) and (X<=WinMaxX- WinMinX+1) and
  250. (Y>0) and (Y<=WinMaxY-WinMinY+1) Then
  251. Begin
  252. Inc(X,WinMinX-1);
  253. Inc(Y,WinMinY-1);
  254. SetScreenCursor(x,y);
  255. End;
  256. End;
  257. Procedure Window(X1, Y1, X2, Y2: Byte);
  258. {
  259. Set screen window to the specified coordinates.
  260. }
  261. Begin
  262. if (X1>X2) or (X2>ScreenWidth) or
  263. (Y1>Y2) or (Y2>ScreenHeight) then
  264. exit;
  265. WindMin:=((Y1-1) Shl 8)+(X1-1);
  266. WindMax:=((Y2-1) Shl 8)+(X2-1);
  267. GoToXY(1,1);
  268. End;
  269. procedure ClrScr;
  270. var
  271. ClipRect: TSmallRect;
  272. SrcRect: TSmallRect;
  273. DestCoor: TCoord;
  274. CharInfo: TCharInfo;
  275. begin
  276. CharInfo.UnicodeChar := 32;
  277. CharInfo.Attributes := TextAttr;
  278. SrcRect.Left := WinMinX - 1;
  279. SrcRect.Top := WinMinY - 1;
  280. SrcRect.Right := WinMaxX - 1;
  281. SrcRect.Bottom := WinMaxY - 1;
  282. ClipRect := SrcRect;
  283. if IsWindowsNT then
  284. begin
  285. DestCoor.X := -WinMaxX;
  286. DestCoor.Y := -WinMaxY;
  287. ScrollConsoleScreenBuffer(OutHandle, SrcRect, ClipRect,
  288. DestCoor, CharInfo);
  289. end
  290. else begin { Win95 seems to have a bug in scrolling, unfortunately }
  291. { This routine 3 times copies the bottom 12 lines to the }
  292. { top part of the screen. This eventually will clear the }
  293. { screen. }
  294. DestCoor.X := WinMinX - 1;
  295. DestCoor.Y := WinMinY - (Succ((WinMaxY - WinMinY) div 2));
  296. {-------- Scroll 1st part }
  297. ScrollConsoleScreenBuffer(OutHandle, SrcRect, ClipRect,
  298. DestCoor, CharInfo);
  299. {-------- Scroll 2nd part }
  300. ScrollConsoleScreenBuffer(OutHandle, SrcRect, ClipRect,
  301. DestCoor, CharInfo);
  302. {-------- Scroll 3rd part (last line) }
  303. ScrollConsoleScreenBuffer(OutHandle, SrcRect, ClipRect,
  304. DestCoor, CharInfo);
  305. end; { if in Windows95 }
  306. GotoXY(1,1);
  307. end; { proc. ClrScr }
  308. procedure ClrEol;
  309. {
  310. Clear from current position to end of line.
  311. }
  312. var Temp: Dword;
  313. CharInfo: Char;
  314. Coord: TCoord;
  315. X,Y: Longint;
  316. begin
  317. GetScreenCursor(x,y);
  318. CharInfo := #32;
  319. Coord.X := X - 1;
  320. Coord.Y := Y - 1;
  321. FillConsoleOutputCharacter(OutHandle, CharInfo, WinMaxX - (X + 01), Coord, @Temp);
  322. end;
  323. Function WhereX: Byte;
  324. {
  325. Return current X-position of cursor.
  326. }
  327. var
  328. x,y : longint;
  329. Begin
  330. GetScreenCursor(x,y);
  331. WhereX:=x-WinMinX+1;
  332. End;
  333. Function WhereY: Byte;
  334. {
  335. Return current Y-position of cursor.
  336. }
  337. var
  338. x,y : longint;
  339. Begin
  340. GetScreenCursor(x,y);
  341. WhereY:=y-WinMinY+1;
  342. End;
  343. {*************************************************************************
  344. KeyBoard
  345. *************************************************************************}
  346. var
  347. ScanCode : char;
  348. SpecialKey : boolean;
  349. DoingNumChars: Boolean;
  350. DoingNumCode: Byte;
  351. Function RemapScanCode (ScanCode: byte; CtrlKeyState: byte; keycode:longint): byte;
  352. { Several remappings of scancodes are necessary to comply with what
  353. we get with MSDOS. Special Windows keys, as Alt-Tab, Ctrl-Esc etc.
  354. are excluded }
  355. var
  356. AltKey, CtrlKey, ShiftKey: boolean;
  357. const
  358. {
  359. Keypad key scancodes:
  360. Ctrl Norm
  361. $77 $47 - Home
  362. $8D $48 - Up arrow
  363. $84 $49 - PgUp
  364. $8E $4A - -
  365. $73 $4B - Left Arrow
  366. $8F $4C - 5
  367. $74 $4D - Right arrow
  368. $4E $4E - +
  369. $75 $4F - End
  370. $91 $50 - Down arrow
  371. $76 $51 - PgDn
  372. $92 $52 - Ins
  373. $93 $53 - Del
  374. }
  375. CtrlKeypadKeys: array[$47..$53] of byte =
  376. ($77, $8D, $84, $8E, $73, $8F, $74, $4E, $75, $91, $76, $92, $93);
  377. begin
  378. AltKey := ((CtrlKeyState AND
  379. (RIGHT_ALT_PRESSED OR LEFT_ALT_PRESSED)) > 0);
  380. CtrlKey := ((CtrlKeyState AND
  381. (RIGHT_CTRL_PRESSED OR LEFT_CTRL_PRESSED)) > 0);
  382. ShiftKey := ((CtrlKeyState AND SHIFT_PRESSED) > 0);
  383. if AltKey then begin
  384. Case KeyCode of
  385. VK_NUMPAD0 ..
  386. VK_NUMPAD9 : begin
  387. DoingNumChars := true;
  388. DoingNumCode := Byte((DoingNumCode * 10) + (KeyCode - VK_NUMPAD0));
  389. end;
  390. end; { case }
  391. case ScanCode of
  392. // Digits, -, =
  393. $02..$0D: inc(ScanCode, $76);
  394. // Function keys
  395. $3B..$44: inc(Scancode, $2D);
  396. $57..$58: inc(Scancode, $34);
  397. // Extended cursor block keys
  398. $47..$49, $4B, $4D, $4F..$53:
  399. inc(Scancode, $50);
  400. // Other keys
  401. $1C: Scancode := $A6; // Enter
  402. $35: Scancode := $A4; // / (keypad and normal!)
  403. end
  404. end
  405. else if CtrlKey then
  406. case Scancode of
  407. // Tab key
  408. $0F: Scancode := $94;
  409. // Function keys
  410. $3B..$44: inc(Scancode, $23);
  411. $57..$58: inc(Scancode, $32);
  412. // Keypad keys
  413. $35: Scancode := $95; // \
  414. $37: Scancode := $96; // *
  415. $47..$53: Scancode := CtrlKeypadKeys[Scancode];
  416. end
  417. else if ShiftKey then
  418. case Scancode of
  419. // Function keys
  420. $3B..$44: inc(Scancode, $19);
  421. $57..$58: inc(Scancode, $30);
  422. end
  423. else
  424. case Scancode of
  425. // Function keys
  426. $57..$58: inc(Scancode, $2E); // F11 and F12
  427. end;
  428. Result := ScanCode;
  429. end;
  430. function KeyPressed : boolean;
  431. var
  432. nevents, nread, i: longint;
  433. buf : TINPUTRECORD;
  434. AltKey: Boolean;
  435. begin
  436. KeyPressed := FALSE;
  437. if ScanCode <> #0 then
  438. KeyPressed := TRUE
  439. else
  440. begin
  441. GetNumberOfConsoleInputEvents(TextRec(input).Handle,nevents);
  442. while nevents>0 do
  443. begin
  444. ReadConsoleInputA(TextRec(input).Handle,buf,1,nread);
  445. if buf.EventType = KEY_EVENT then
  446. if buf.KeyEvent.bKeyDown then
  447. begin
  448. { Alt key is VK_MENU }
  449. { Capslock key is VK_CAPITAL }
  450. AltKey := ((Buf.KeyEvent.dwControlKeyState AND
  451. (RIGHT_ALT_PRESSED OR LEFT_ALT_PRESSED)) > 0);
  452. if not(Buf.KeyEvent.wVirtualKeyCode in [VK_SHIFT, VK_MENU, VK_CONTROL,
  453. VK_CAPITAL, VK_NUMLOCK,
  454. VK_SCROLL]) then
  455. begin
  456. keypressed:=true;
  457. if (ord(buf.KeyEvent.AsciiChar) = 0) or
  458. (buf.keyevent.dwControlKeyState=2) then
  459. begin
  460. SpecialKey := TRUE;
  461. ScanCode := Chr(RemapScanCode(Buf.KeyEvent.wVirtualScanCode, Buf.KeyEvent.dwControlKeyState,
  462. Buf.KeyEvent.wVirtualKeyCode));
  463. end
  464. else
  465. begin
  466. SpecialKey := FALSE;
  467. ScanCode := Chr(Ord(buf.KeyEvent.AsciiChar));
  468. end;
  469. if Buf.KeyEvent.wVirtualKeyCode in [VK_NUMPAD0..VK_NUMPAD9] then
  470. if AltKey then
  471. begin
  472. Keypressed := false;
  473. Specialkey := false;
  474. ScanCode := #0;
  475. end
  476. else break;
  477. end;
  478. end
  479. else if (Buf.KeyEvent.wVirtualKeyCode in [VK_MENU]) then
  480. if DoingNumChars then
  481. if DoingNumCode > 0 then
  482. begin
  483. ScanCode := Chr(DoingNumCode);
  484. Keypressed := true;
  485. DoingNumChars := false;
  486. DoingNumCode := 0;
  487. break
  488. end; { if }
  489. { if we got a key then we can exit }
  490. if keypressed then
  491. exit;
  492. GetNumberOfConsoleInputEvents(TextRec(input).Handle,nevents);
  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.6 2001-01-03 21:01:50 florian
  825. * fixed the repeat key bug introduced by my last patch
  826. Revision 1.5 2000/12/15 13:16:30 jonas
  827. * fixed range check errors
  828. Revision 1.4 2000/12/09 13:27:41 florian
  829. * web bug 1228 fixed (keypressed ate too muck keys)
  830. Revision 1.3 2000/09/10 20:17:56 peter
  831. * fixed alt-<key>
  832. Revision 1.2 2000/07/13 11:33:56 michael
  833. + removed logs
  834. }