crt.pp 23 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022
  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. nevents:=0;
  442. GetNumberOfConsoleInputEvents(TextRec(input).Handle,nevents);
  443. while nevents>1 do
  444. begin
  445. ReadConsoleInputA(TextRec(input).Handle,buf,1,nread);
  446. if buf.EventType = KEY_EVENT then
  447. if buf.KeyEvent.bKeyDown then
  448. begin
  449. { Alt key is VK_MENU }
  450. { Capslock key is VK_CAPITAL }
  451. AltKey := ((Buf.KeyEvent.dwControlKeyState AND
  452. (RIGHT_ALT_PRESSED OR LEFT_ALT_PRESSED)) > 0);
  453. if not(Buf.KeyEvent.wVirtualKeyCode in [VK_SHIFT, VK_MENU, VK_CONTROL,
  454. VK_CAPITAL, VK_NUMLOCK,
  455. VK_SCROLL]) then
  456. begin
  457. keypressed:=true;
  458. if (ord(buf.KeyEvent.AsciiChar) = 0) or
  459. (buf.keyevent.dwControlKeyState=2) then
  460. begin
  461. SpecialKey := TRUE;
  462. ScanCode := Chr(RemapScanCode(Buf.KeyEvent.wVirtualScanCode, Buf.KeyEvent.dwControlKeyState,
  463. Buf.KeyEvent.wVirtualKeyCode));
  464. end
  465. else
  466. begin
  467. SpecialKey := FALSE;
  468. ScanCode := Chr(Ord(buf.KeyEvent.AsciiChar));
  469. end;
  470. if Buf.KeyEvent.wVirtualKeyCode in [VK_NUMPAD0..VK_NUMPAD9] then
  471. if AltKey then
  472. begin
  473. Keypressed := false;
  474. Specialkey := false;
  475. ScanCode := #0;
  476. end
  477. else break;
  478. end;
  479. end
  480. else if (Buf.KeyEvent.wVirtualKeyCode in [VK_MENU]) then
  481. if DoingNumChars then
  482. if DoingNumCode > 0 then
  483. begin
  484. ScanCode := Chr(DoingNumCode);
  485. Keypressed := true;
  486. DoingNumChars := false;
  487. DoingNumCode := 0;
  488. break
  489. end; { if }
  490. { if we got a key then we can exit }
  491. if keypressed then
  492. exit;
  493. GetNumberOfConsoleInputEvents(TextRec(input).Handle,nevents);
  494. end;
  495. end;
  496. end;
  497. function ReadKey: char;
  498. begin
  499. repeat
  500. Sleep(1);
  501. until KeyPressed;
  502. if SpecialKey then begin
  503. ReadKey := #0;
  504. SpecialKey := FALSE;
  505. end
  506. else begin
  507. ReadKey := ScanCode;
  508. ScanCode := #0;
  509. end;
  510. end;
  511. {*************************************************************************
  512. Delay
  513. *************************************************************************}
  514. procedure Delay(MS: Word);
  515. begin
  516. Sleep(ms);
  517. end; { proc. Delay }
  518. procedure sound(hz : word);
  519. begin
  520. MessageBeep(0); { lame ;-) }
  521. end;
  522. procedure nosound;
  523. begin
  524. end;
  525. {****************************************************************************
  526. HighLevel Crt Functions
  527. ****************************************************************************}
  528. procedure removeline(y : longint);
  529. var
  530. ClipRect: TSmallRect;
  531. SrcRect: TSmallRect;
  532. DestCoor: TCoord;
  533. CharInfo: TCharInfo;
  534. begin
  535. CharInfo.UnicodeChar := 32;
  536. CharInfo.Attributes := TextAttr;
  537. Y := WinMinY + Y-1;
  538. SrcRect.Top := Y - 01;
  539. SrcRect.Left := WinMinX - 1;
  540. SrcRect.Right := WinMaxX - 1;
  541. SrcRect.Bottom := WinMaxY - 1;
  542. DestCoor.X := WinMinX - 1;
  543. DestCoor.Y := Y - 2;
  544. ClipRect := SrcRect;
  545. ScrollConsoleScreenBuffer(OutHandle, SrcRect, ClipRect, DestCoor, CharInfo);
  546. end; { proc. RemoveLine }
  547. procedure delline;
  548. begin
  549. removeline(wherey);
  550. end; { proc. DelLine }
  551. procedure insline;
  552. var
  553. ClipRect: TSmallRect;
  554. SrcRect: TSmallRect;
  555. DestCoor: TCoord;
  556. CharInfo: TCharInfo;
  557. X,Y: Longint;
  558. begin
  559. GetScreenCursor(X, Y);
  560. CharInfo.UnicodeChar := 32;
  561. CharInfo.Attributes := TextAttr;
  562. SrcRect.Top := Y - 1;
  563. SrcRect.Left := WinMinX - 1;
  564. SrcRect.Right := WinMaxX - 1;
  565. SrcRect.Bottom := WinMaxY - 1;
  566. DestCoor.X := WinMinX - 1;
  567. DestCoor.Y := Y;
  568. ClipRect := SrcRect;
  569. ScrollConsoleScreenBuffer(OutHandle, SrcRect, ClipRect, DestCoor, CharInfo);
  570. end; { proc. InsLine }
  571. {****************************************************************************
  572. Extra Crt Functions
  573. ****************************************************************************}
  574. procedure cursoron;
  575. var CursorInfo: TConsoleCursorInfo;
  576. begin
  577. GetConsoleCursorInfo(OutHandle, CursorInfo);
  578. CursorInfo.dwSize := SaveCursorSize;
  579. CursorInfo.bVisible := true;
  580. SetConsoleCursorInfo(OutHandle, CursorInfo);
  581. end;
  582. procedure cursoroff;
  583. var CursorInfo: TConsoleCursorInfo;
  584. begin
  585. GetConsoleCursorInfo(OutHandle, CursorInfo);
  586. CursorInfo.bVisible := false;
  587. SetConsoleCursorInfo(OutHandle, CursorInfo);
  588. end;
  589. procedure cursorbig;
  590. var CursorInfo: TConsoleCursorInfo;
  591. begin
  592. GetConsoleCursorInfo(OutHandle, CursorInfo);
  593. CursorInfo.dwSize := 100;
  594. CursorInfo.bVisible := true;
  595. SetConsoleCursorInfo(OutHandle, CursorInfo);
  596. end;
  597. {*****************************************************************************
  598. Read and Write routines
  599. *****************************************************************************}
  600. var
  601. CurrX, CurrY : longint;
  602. procedure WriteChar(c:char);
  603. var
  604. Cell : TCharInfo;
  605. BufSize : Coord; { Column-row size of source buffer }
  606. WritePos: TCoord; { Upper-left cell to write from }
  607. DestRect: TSmallRect;
  608. begin
  609. Case C of
  610. #10 : begin
  611. Inc(CurrY);
  612. end;
  613. #13 : begin
  614. CurrX := WinMinX;
  615. end; { if }
  616. #08 : begin
  617. if CurrX > WinMinX then Dec(CurrX);
  618. end; { ^H }
  619. #07 : begin
  620. // MessagBeep(0);
  621. end; { ^G }
  622. else begin
  623. BufSize.X := 01;
  624. BufSize.Y := 01;
  625. WritePos.X := 0;
  626. WritePos.Y := 0;
  627. Cell.UniCodeChar := Ord(c);
  628. Cell.Attributes := TextAttr;
  629. DestRect.Left := (CurrX - 01);
  630. DestRect.Top := (CurrY - 01);
  631. DestRect.Right := (CurrX - 01);
  632. DestRect.Bottom := (CurrY - 01);
  633. WriteConsoleOutput(OutHandle, @Cell, BufSize, WritePos, DestRect);
  634. Inc(CurrX);
  635. end; { else }
  636. end; { case }
  637. if CurrX > WinMaxX then
  638. begin
  639. CurrX := WinMinX;
  640. Inc(CurrY);
  641. end; { if }
  642. While CurrY > WinMaxY do
  643. begin
  644. RemoveLine(1);
  645. Dec(CurrY);
  646. end; { while }
  647. end;
  648. Function CrtWrite(var f : textrec):integer;
  649. var
  650. i : longint;
  651. begin
  652. GetScreenCursor(CurrX,CurrY);
  653. for i:=0 to f.bufpos-1 do
  654. WriteChar(f.buffer[i]);
  655. SetScreenCursor(CurrX,CurrY);
  656. f.bufpos:=0;
  657. CrtWrite:=0;
  658. end;
  659. Function CrtRead(Var F: TextRec): Integer;
  660. procedure BackSpace;
  661. begin
  662. if (f.bufpos>0) and (f.bufpos=f.bufend) then
  663. begin
  664. WriteChar(#8);
  665. WriteChar(' ');
  666. WriteChar(#8);
  667. dec(f.bufpos);
  668. dec(f.bufend);
  669. end;
  670. end;
  671. var
  672. ch : Char;
  673. Begin
  674. GetScreenCursor(CurrX,CurrY);
  675. f.bufpos:=0;
  676. f.bufend:=0;
  677. repeat
  678. if f.bufpos>f.bufend then
  679. f.bufend:=f.bufpos;
  680. SetScreenCursor(CurrX,CurrY);
  681. ch:=readkey;
  682. case ch of
  683. #0 : case readkey of
  684. #71 : while f.bufpos>0 do
  685. begin
  686. dec(f.bufpos);
  687. WriteChar(#8);
  688. end;
  689. #75 : if f.bufpos>0 then
  690. begin
  691. dec(f.bufpos);
  692. WriteChar(#8);
  693. end;
  694. #77 : if f.bufpos<f.bufend then
  695. begin
  696. WriteChar(f.bufptr^[f.bufpos]);
  697. inc(f.bufpos);
  698. end;
  699. #79 : while f.bufpos<f.bufend do
  700. begin
  701. WriteChar(f.bufptr^[f.bufpos]);
  702. inc(f.bufpos);
  703. end;
  704. end;
  705. ^S,
  706. #8 : BackSpace;
  707. ^Y,
  708. #27 : begin
  709. f.bufpos:=f.bufend;
  710. while f.bufend>0 do
  711. BackSpace;
  712. end;
  713. #13 : begin
  714. WriteChar(#13);
  715. WriteChar(#10);
  716. f.bufptr^[f.bufend]:=#13;
  717. f.bufptr^[f.bufend+1]:=#10;
  718. inc(f.bufend,2);
  719. break;
  720. end;
  721. #26 : if CheckEOF then
  722. begin
  723. f.bufptr^[f.bufend]:=#26;
  724. inc(f.bufend);
  725. break;
  726. end;
  727. else
  728. begin
  729. if f.bufpos<f.bufsize-2 then
  730. begin
  731. f.buffer[f.bufpos]:=ch;
  732. inc(f.bufpos);
  733. WriteChar(ch);
  734. end;
  735. end;
  736. end;
  737. until false;
  738. f.bufpos:=0;
  739. SetScreenCursor(CurrX,CurrY);
  740. CrtRead:=0;
  741. End;
  742. Function CrtReturn(Var F:TextRec):Integer;
  743. Begin
  744. CrtReturn:=0;
  745. end;
  746. Function CrtClose(Var F: TextRec): Integer;
  747. Begin
  748. F.Mode:=fmClosed;
  749. CrtClose:=0;
  750. End;
  751. Function CrtOpen(Var F: TextRec): Integer;
  752. Begin
  753. If F.Mode=fmOutput Then
  754. begin
  755. TextRec(F).InOutFunc:=@CrtWrite;
  756. TextRec(F).FlushFunc:=@CrtWrite;
  757. end
  758. Else
  759. begin
  760. F.Mode:=fmInput;
  761. TextRec(F).InOutFunc:=@CrtRead;
  762. TextRec(F).FlushFunc:=@CrtReturn;
  763. end;
  764. TextRec(F).CloseFunc:=@CrtClose;
  765. CrtOpen:=0;
  766. End;
  767. procedure AssignCrt(var F: Text);
  768. begin
  769. Assign(F,'');
  770. TextRec(F).OpenFunc:=@CrtOpen;
  771. end;
  772. const
  773. conout : pchar = 'CONOUT$';
  774. var
  775. CursorInfo : TConsoleCursorInfo;
  776. ConsoleInfo : TConsoleScreenBufferinfo;
  777. begin
  778. { Initialize the output handles }
  779. OutHandle := GetStdHandle(STD_OUTPUT_HANDLE);
  780. InputHandle := GetStdHandle(STD_INPUT_HANDLE);
  781. LastMode := 3;
  782. {--------------------- Get the cursor size and such -----------------------}
  783. FillChar(CursorInfo, SizeOf(CursorInfo), 00);
  784. GetConsoleCursorInfo(OutHandle, CursorInfo);
  785. SaveCursorSize := CursorInfo.dwSize;
  786. {------------------ Get the current cursor position and attr --------------}
  787. FillChar(ConsoleInfo, SizeOf(ConsoleInfo), 0);
  788. if not GetConsoleScreenBufferInfo(OutHandle, ConsoleInfo) then
  789. begin
  790. OutHandle:=CreateFile(ConOut, generic_read or generic_write,
  791. file_share_read or file_share_write,nil,
  792. open_existing,0,0);
  793. If (OutHandle=Invalid_handle_value) then
  794. begin
  795. Writeln(stderr,'No way to get the console handle');
  796. Halt(1);
  797. end;
  798. if not GetConsoleScreenBufferInfo(OutHandle, ConsoleInfo) then
  799. begin
  800. Writeln(stderr,'No way to get console screen buffer info');
  801. Halt(1);
  802. end;
  803. end;
  804. CursorSaveX := ConsoleInfo.dwCursorPosition.X;
  805. CursorSaveY := ConsoleInfo.dwCursorPosition.Y;
  806. TextAttr := ConsoleInfo.wAttributes;
  807. { Load startup values }
  808. ScreenWidth := GetScreenWidth;
  809. ScreenHeight := GetScreenHeight;
  810. IsWindowsNT := (GetPlatformID = VER_PLATFORM_WIN32_NT);
  811. TurnMouseOff;
  812. WindMax := (ScreenWidth - 1) OR ((ScreenHeight - 1) SHL 8);
  813. DoingNumChars := false;
  814. DoingNumCode := 0;
  815. { Redirect the standard output }
  816. AssignCrt(Output);
  817. Rewrite(Output);
  818. TextRec(Output).Handle:= OutHandle;
  819. AssignCrt(Input);
  820. Reset(Input);
  821. TextRec(Input).Handle:= InputHandle;
  822. end. { unit Crt }
  823. {
  824. $Log$
  825. Revision 1.5 2000-12-15 13:16:30 jonas
  826. * fixed range check errors
  827. Revision 1.4 2000/12/09 13:27:41 florian
  828. * web bug 1228 fixed (keypressed ate too muck keys)
  829. Revision 1.3 2000/09/10 20:17:56 peter
  830. * fixed alt-<key>
  831. Revision 1.2 2000/07/13 11:33:56 michael
  832. + removed logs
  833. }