crt.pp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1993,97 by Michael Van Canneyt,
  5. member of the Free Pascal development team.
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit Crt;
  13. Interface
  14. Const
  15. { Controlling consts }
  16. Flushing=false; {if true then don't buffer output}
  17. ScreenWidth = 80;
  18. ScreenHeight = 25;
  19. { CRT modes }
  20. BW40 = 0; { 40x25 B/W on Color Adapter }
  21. CO40 = 1; { 40x25 Color on Color Adapter }
  22. BW80 = 2; { 80x25 B/W on Color Adapter }
  23. CO80 = 3; { 80x25 Color on Color Adapter }
  24. Mono = 7; { 80x25 on Monochrome Adapter }
  25. Font8x8 = 256; { Add-in for ROM font }
  26. { Mode constants for 3.0 compatibility }
  27. C40 = CO40;
  28. C80 = CO80;
  29. { Foreground and background color constants }
  30. Black = 0;
  31. Blue = 1;
  32. Green = 2;
  33. Cyan = 3;
  34. Red = 4;
  35. Magenta = 5;
  36. Brown = 6;
  37. LightGray = 7;
  38. { Foreground color constants }
  39. DarkGray = 8;
  40. LightBlue = 9;
  41. LightGreen = 10;
  42. LightCyan = 11;
  43. LightRed = 12;
  44. LightMagenta = 13;
  45. Yellow = 14;
  46. White = 15;
  47. { Add-in for blinking }
  48. Blink = 128;
  49. {Other Defaults}
  50. TextAttr : Byte = $07;
  51. LastMode : Word = 3;
  52. WindMin : Word = $0;
  53. WindMax : Word = $184f;
  54. var
  55. CheckBreak,
  56. CheckEOF,
  57. CheckSnow,
  58. DirectVideo: Boolean;
  59. Procedure AssignCrt(Var F: Text);
  60. Function KeyPressed: Boolean;
  61. Function ReadKey: Char;
  62. Procedure TextMode(Mode: Integer);
  63. Procedure Window(X1, Y1, X2, Y2: Byte);
  64. Procedure GoToXy(X: Byte; Y: Byte);
  65. Function WhereX: Byte;
  66. Function WhereY: Byte;
  67. Procedure ClrScr;
  68. Procedure ClrEol;
  69. Procedure InsLine;
  70. Procedure DelLine;
  71. Procedure TextColor(Color: Byte);
  72. Procedure TextBackground(Color: Byte);
  73. Procedure LowVideo;
  74. Procedure HighVideo;
  75. Procedure NormVideo;
  76. Procedure Delay(DTime: Word);
  77. Procedure Sound(Hz: Word);
  78. Procedure NoSound;
  79. Implementation
  80. uses Linux;
  81. {
  82. The definitions of TextRec and FileRec are in separate files.
  83. }
  84. {$i textrec.inc}
  85. {$i filerec.inc}
  86. Const
  87. OldTextAttr : byte = $07;
  88. Type
  89. TScreen=Array[1..ScreenHeight,1..ScreenWidth] of char;
  90. TScreenColors=Array[1..ScreenHeight,1..ScreenWidth] of byte;
  91. Var
  92. Scrn : TScreen;
  93. ScrnCol : TScreenColors;
  94. CurrX,CurrY : Byte;
  95. ExitSave : Pointer;
  96. Redir : boolean; { is the output being redirected (not a TTY) }
  97. {*****************************************************************************
  98. Some Handy Functions Not in the System.PP
  99. *****************************************************************************}
  100. Function Str(l:longint):string;
  101. {
  102. Return a String of the longint
  103. }
  104. var
  105. hstr : string[32];
  106. begin
  107. System.Str(l,hstr);
  108. Str:=hstr;
  109. end;
  110. Function Max(l1,l2:longint):longint;
  111. {
  112. Return the maximum of l1 and l2
  113. }
  114. begin
  115. if l1>l2 then
  116. Max:=l1
  117. else
  118. Max:=l2;
  119. end;
  120. Function Min(l1,l2:longint):longint;
  121. {
  122. Return the minimum of l1 and l2
  123. }
  124. begin
  125. if l1<l2 then
  126. Min:=l1
  127. else
  128. Min:=l2;
  129. end;
  130. {*****************************************************************************
  131. Optimal AnsiString Conversion Routines
  132. *****************************************************************************}
  133. Function XY2Ansi(x,y,ox,oy:byte):String;
  134. {
  135. Returns a string with the escape sequences to go to X,Y on the screen
  136. }
  137. Begin
  138. if y=oy then
  139. begin
  140. if x=ox then
  141. begin
  142. XY2Ansi:='';
  143. exit;
  144. end;
  145. if x=1 then
  146. begin
  147. XY2Ansi:=#13;
  148. exit;
  149. end;
  150. if x>ox then
  151. begin
  152. XY2Ansi:=#27'['+Str(x-ox)+'C';
  153. exit;
  154. end
  155. else
  156. begin
  157. XY2Ansi:=#27'['+Str(ox-x)+'D';
  158. exit;
  159. end;
  160. end;
  161. if x=ox then
  162. begin
  163. if y>oy then
  164. begin
  165. XY2Ansi:=#27'['+Str(y-oy)+'B';
  166. exit;
  167. end
  168. else
  169. begin
  170. XY2Ansi:=#27'['+Str(oy-y)+'A';
  171. exit;
  172. end;
  173. end;
  174. if (x=1) and (oy+1=y) then
  175. XY2Ansi:=#13#10
  176. else
  177. XY2Ansi:=#27'['+Str(y)+';'+Str(x)+'H';
  178. End;
  179. const
  180. AnsiTbl : string[8]='04261537';
  181. Function Attr2Ansi(Attr,OAttr:byte):string;
  182. {
  183. Convert Attr to an Ansi String, the Optimal code is calculate
  184. with use of the old OAttr
  185. }
  186. var
  187. hstr : string[16];
  188. OFg,OBg,Fg,Bg : byte;
  189. procedure AddSep(ch:char);
  190. begin
  191. if length(hstr)>0 then
  192. hstr:=hstr+';';
  193. hstr:=hstr+ch;
  194. end;
  195. begin
  196. if Attr=OAttr then
  197. begin
  198. Attr2Ansi:='';
  199. exit;
  200. end;
  201. Hstr:='';
  202. Fg:=Attr and $f;
  203. Bg:=Attr shr 4;
  204. OFg:=Attr and $f;
  205. OBg:=Attr shr 4;
  206. if (OFg<>7) or (Fg=7) or ((OFg>7) and (Fg<8)) or ((OBg>7) and (Bg<8)) then
  207. begin
  208. hstr:='0';
  209. OFg:=7;
  210. OBg:=0;
  211. end;
  212. if (Fg>7) and (OFg<8) then
  213. begin
  214. AddSep('1');
  215. OFg:=OFg or 8;
  216. end;
  217. if (Bg and 8)<>(OBg and 8) then
  218. begin
  219. AddSep('5');
  220. OBg:=OBg or 8;
  221. end;
  222. if (Fg<>OFg) then
  223. begin
  224. AddSep('3');
  225. hstr:=hstr+AnsiTbl[(Fg and 7)+1];
  226. end;
  227. if (Bg<>OBg) then
  228. begin
  229. AddSep('4');
  230. hstr:=hstr+AnsiTbl[(Bg and 7)+1];
  231. end;
  232. if hstr='0' then
  233. hstr:='';
  234. Attr2Ansi:=#27'['+hstr+'m';
  235. end;
  236. Function Ansi2Attr(Const HStr:String;oattr:byte):byte;
  237. {
  238. Convert an Escape sequence to an attribute value, uses Oattr as the last
  239. color written
  240. }
  241. var
  242. i,j : byte;
  243. begin
  244. i:=2;
  245. if (Length(HStr)<3) or (Hstr[1]<>#27) or (Hstr[2]<>'[') then
  246. i:=255;
  247. while (i<length(Hstr)) do
  248. begin
  249. inc(i);
  250. case Hstr[i] of
  251. '0' : OAttr:=7;
  252. '1' : OAttr:=OAttr or $8;
  253. '5' : OAttr:=OAttr or $80;
  254. '3' : begin
  255. inc(i);
  256. j:=pos(Hstr[i],AnsiTbl);
  257. if j>0 then
  258. OAttr:=(OAttr and $f8) or (j-1);
  259. end;
  260. '4' : begin
  261. inc(i);
  262. j:=pos(Hstr[i],AnsiTbl);
  263. if j>0 then
  264. OAttr:=(OAttr and $8f) or ((j-1) shl 4);
  265. end;
  266. 'm' : i:=length(HStr);
  267. end;
  268. end;
  269. Ansi2Attr:=OAttr;
  270. end;
  271. {*****************************************************************************
  272. Buffered StdIn/StdOut IO
  273. *****************************************************************************}
  274. const
  275. ttyIn=0; {Handles for stdin/stdout}
  276. ttyOut=1;
  277. ttyFlush:boolean=true;
  278. {Buffered Input/Output}
  279. InSize=256;
  280. OutSize=1024;
  281. var
  282. InBuf : array[0..InSize-1] of char;
  283. InCnt,
  284. InHead,
  285. InTail : longint;
  286. OutBuf : array[0..OutSize-1] of char;
  287. OutCnt : longint;
  288. {Flush Output Buffer}
  289. procedure ttyFlushOutput;
  290. begin
  291. if OutCnt>0 then
  292. begin
  293. fdWrite(ttyOut,OutBuf,OutCnt);
  294. OutCnt:=0;
  295. end;
  296. end;
  297. Function ttySetFlush(b:boolean):boolean;
  298. begin
  299. ttySetFlush:=ttyFlush;
  300. ttyFlush:=b;
  301. if ttyFlush then
  302. ttyFlushOutput;
  303. end;
  304. {Send Char to Remote}
  305. Procedure ttySendChar(c:char);
  306. Begin
  307. if OutCnt<OutSize then
  308. begin
  309. OutBuf[OutCnt]:=c;
  310. inc(OutCnt);
  311. end;
  312. {Full ?}
  313. if (OutCnt>=OutSize) then
  314. ttyFlushOutput;
  315. End;
  316. {Send String to Remote}
  317. procedure ttySendStr(const hstr:string);
  318. var
  319. i : word;
  320. begin
  321. for i:=1to length(hstr) do
  322. ttySendChar(hstr[i]);
  323. if ttyFlush then
  324. ttyFlushOutput;
  325. end;
  326. {Get Char from Remote}
  327. function ttyRecvChar:char;
  328. var
  329. Readed,i : word;
  330. begin
  331. {Buffer Empty? Yes, Input from StdIn}
  332. if (InHead=InTail) then
  333. begin
  334. {Calc Amount of Chars to Read}
  335. i:=InSize-InHead;
  336. if InTail>InHead then
  337. i:=InTail-InHead;
  338. {Read}
  339. Readed:=fdRead(TTYIn,InBuf[InHead],i);
  340. {Increase Counters}
  341. inc(InCnt,Readed);
  342. inc(InHead,Readed);
  343. {Wrap if End has Reached}
  344. if InHead>=InSize then
  345. InHead:=0;
  346. end;
  347. {Check Buffer}
  348. if (InCnt=0) then
  349. ttyRecvChar:=#0
  350. else
  351. begin
  352. ttyRecvChar:=InBuf[InTail];
  353. dec(InCnt);
  354. inc(InTail);
  355. if InTail>=InSize then
  356. InTail:=0;
  357. end;
  358. end;
  359. {*****************************************************************************
  360. Screen Routines not Window Depended
  361. *****************************************************************************}
  362. procedure ttyGotoXY(x,y:byte);
  363. {
  364. Goto XY on the Screen, if a value is 0 the goto the current
  365. postion of that value and always recalc the ansicode for it
  366. }
  367. begin
  368. if x=0 then
  369. begin
  370. x:=CurrX;
  371. CurrX:=$ff;
  372. end;
  373. if y=0 then
  374. begin
  375. y:=CurrY;
  376. CurrY:=$ff;
  377. end;
  378. if Redir then
  379. begin
  380. if longint(y)-longint(CurrY)=1 then
  381. ttySendStr(#10);
  382. end
  383. else
  384. ttySendStr(XY2Ansi(x,y,CurrX,CurrY));
  385. CurrX:=x;
  386. CurrY:=y;
  387. end;
  388. procedure ttyColor(a:byte);
  389. {
  390. Set Attribute to A, only output if not the last attribute is set
  391. }
  392. begin
  393. if a<>TextAttr then
  394. begin
  395. if not Redir then
  396. ttySendStr(Attr2Ansi(a,TextAttr));
  397. TextAttr:=a;
  398. OldTextAttr:=a;
  399. end;
  400. end;
  401. procedure ttyWrite(const s:string);
  402. {
  403. Write a string to the output, memory copy and Current X&Y are also updated
  404. }
  405. var
  406. i : word;
  407. begin
  408. ttySendStr(s);
  409. {Update MemCopy}
  410. for i:=1to length(s) do
  411. begin
  412. Scrn[CurrY,CurrX]:=s[i];
  413. ScrnCol[CurrY,CurrX]:=TextAttr;
  414. inc(CurrX);
  415. if CurrX>ScreenWidth then
  416. CurrX:=ScreenWidth;
  417. end;
  418. end;
  419. Function WinMinX: Byte;
  420. {
  421. Current Minimum X coordinate
  422. }
  423. Begin
  424. WinMinX:=(WindMin and $ff)+1;
  425. End;
  426. Function WinMinY: Byte;
  427. {
  428. Current Minimum Y Coordinate
  429. }
  430. Begin
  431. WinMinY:=(WindMin shr 8)+1;
  432. End;
  433. Function WinMaxX: Byte;
  434. {
  435. Current Maximum X coordinate
  436. }
  437. Begin
  438. WinMaxX:=(WindMax and $ff)+1;
  439. End;
  440. Function WinMaxY: Byte;
  441. {
  442. Current Maximum Y coordinate;
  443. }
  444. Begin
  445. WinMaxY:=(WindMax shr 8) + 1;
  446. End;
  447. Function FullWin:boolean;
  448. {
  449. Full Screen 80x25? Window(1,1,80,25) is used, allows faster routines
  450. }
  451. begin
  452. FullWin:=(WindMax-WindMin=$184f);
  453. end;
  454. procedure LineWrite(temp:String);
  455. {
  456. Write a Line to the screen, doesn't write on 80,25 under Dos
  457. the Current CurrX is set to WinMax. NO MEMORY UPDATE!
  458. }
  459. begin
  460. CurrX:=WinMaxX+1;
  461. if (CurrX>=ScreenWidth) then
  462. CurrX:=WinMaxX;
  463. ttySendStr(Temp);
  464. end;
  465. procedure DoEmptyLine(y,xl,xh:byte);
  466. {
  467. Write an Empty line at Row Y from Col Xl to XH, Memory is also updated
  468. }
  469. begin
  470. ttyGotoXY(xl,y);
  471. LineWrite(Space(xh-xl+1));
  472. FillChar(Scrn[y],ScreenWidth,' ');
  473. FillChar(ScrnCol[y],ScreenWidth,TextAttr);
  474. end;
  475. procedure DoScrollLine(y1,y2,xl,xh:byte);
  476. {
  477. Move Line y1 to y2, use only columns Xl-Xh, Memory is updated also
  478. }
  479. var
  480. Temp : string;
  481. OldAttr,
  482. x,attr : byte;
  483. begin
  484. ttyGotoXY(xl,y2);
  485. OldAttr:=$ff;
  486. Temp:='';
  487. For x:=xl To xh Do
  488. Begin
  489. attr:=ScrnCol[y1,x];
  490. if attr<>OldAttr then
  491. begin
  492. temp:=temp+Attr2Ansi(Attr,OldAttr);
  493. OldAttr:=Attr;
  494. end;
  495. Temp:=Temp+Scrn[y1,x];
  496. if (x=xh) or (length(Temp)>240) then
  497. begin
  498. LineWrite(Temp);
  499. Temp:='';
  500. end;
  501. End;
  502. {Update memory copy}
  503. Move(Scrn[y1,1],Scrn[y2,1],ScreenWidth);
  504. Move(ScrnCol[y1,1],ScrnCol[y2,1],ScreenWidth);
  505. end;
  506. Procedure TextColor(Color: Byte);
  507. {
  508. Switch foregroundcolor
  509. }
  510. Begin
  511. ttyColor((Color and $8f) or (TextAttr and $70));
  512. End;
  513. Procedure TextBackground(Color: Byte);
  514. {
  515. Switch backgroundcolor
  516. }
  517. Begin
  518. ttyColor((Color shl 4) or (TextAttr and $0f));
  519. End;
  520. Procedure HighVideo;
  521. {
  522. Set highlighted output.
  523. }
  524. Begin
  525. TextColor(TextAttr Or $08);
  526. End;
  527. Procedure LowVideo;
  528. {
  529. Set normal output
  530. }
  531. Begin
  532. TextColor(TextAttr And $77);
  533. End;
  534. Procedure NormVideo;
  535. {
  536. Set normal back and foregroundcolors.
  537. }
  538. Begin
  539. TextColor(7);
  540. TextBackGround(0);
  541. End;
  542. Procedure GotoXy(X: Byte; Y: Byte);
  543. {
  544. Go to coordinates X,Y in the current window.
  545. }
  546. Begin
  547. If (X>0) and (X<=WinMaxX- WinMinX+1) and
  548. (Y>0) and (Y<=WinMaxY-WinMinY+1) Then
  549. Begin
  550. Inc(X,WinMinX-1);
  551. Inc(Y,WinMinY-1);
  552. ttyGotoXY(x,y);
  553. End;
  554. End;
  555. Procedure Window(X1, Y1, X2, Y2: Byte);
  556. {
  557. Set screen window to the specified coordinates.
  558. }
  559. Begin
  560. if (X1>X2) or (X2>ScreenWidth) or
  561. (Y1>Y2) or (Y2>ScreenHeight) then
  562. exit;
  563. WindMin:=((Y1-1) Shl 8)+(X1-1);
  564. WindMax:=((Y2-1) Shl 8)+(X2-1);
  565. GoToXY(1,1);
  566. End;
  567. Procedure ClrScr;
  568. {
  569. Clear the current window, and set the cursor on x1,y1
  570. }
  571. Var
  572. CY : Integer;
  573. oldflush : boolean;
  574. I : Integer;
  575. Begin
  576. { See if color has changed }
  577. if OldTextAttr<>TextAttr then
  578. begin
  579. i:=TextAttr;
  580. TextAttr:=OldTextAttr;
  581. ttyColor(i);
  582. end;
  583. oldflush:=ttySetFlush(Flushing);
  584. if FullWin then
  585. begin
  586. if not Redir then
  587. ttySendStr(#27'[H'#27'[2J');
  588. CurrX:=1;
  589. CurrY:=1;
  590. FillChar(Scrn,sizeof(Scrn),' ');
  591. FillChar(ScrnCol,sizeof(ScrnCol),TextAttr);
  592. end
  593. else
  594. begin
  595. For Cy:=WinMinY To WinMaxY Do
  596. DoEmptyLine(Cy,WinMinX,WinMaxX);
  597. GoToXY(1,1);
  598. end;
  599. ttySetFlush(oldflush);
  600. End;
  601. Procedure ClrEol;
  602. {
  603. Clear from current position to end of line.
  604. }
  605. Var I : integer;
  606. Begin
  607. { See if color has changed }
  608. if OldTextAttr<>TextAttr then
  609. begin
  610. i:=TextAttr;
  611. TextAttr:=OldTextAttr;
  612. ttyColor(i);
  613. end;
  614. if FullWin then
  615. begin
  616. if not Redir then
  617. ttySendStr(#27'[K');
  618. end
  619. else
  620. begin
  621. ttySendStr(Space(WinMaxX-CurrX));
  622. ttyGotoXY(0,CurrY);
  623. end;
  624. End;
  625. Function WhereX: Byte;
  626. {
  627. Return current X-position of cursor.
  628. }
  629. Begin
  630. WhereX:=CurrX-WinMinX+1;
  631. End;
  632. Function WhereY: Byte;
  633. {
  634. Return current Y-position of cursor.
  635. }
  636. Begin
  637. WhereY:=CurrY-WinMinY+1;
  638. End;
  639. Procedure ScrollScrnRegionUp(xl,yl,xh,yh, count: Byte);
  640. {
  641. Scroll the indicated region count lines up. The empty lines are filled
  642. with blanks in the current color. The screen position is restored
  643. afterwards.
  644. }
  645. Var
  646. y,oldx,oldy : byte;
  647. oldflush : boolean;
  648. Begin
  649. oldflush:=ttySetFlush(Flushing);
  650. oldx:=CurrX;
  651. oldy:=CurrY;
  652. {Scroll}
  653. For y:=yl to yh-count do
  654. DoScrollLine(y+count,y,xl,xh);
  655. {Restore TextAttr}
  656. ttySendStr(Attr2Ansi(TextAttr,$ff));
  657. {Fill the rest with empty lines}
  658. for y:=yh-count+1 to yh do
  659. DoEmptyLine(y,xl,xh);
  660. {Restore current position}
  661. ttyGotoXY(OldX,OldY);
  662. ttySetFlush(oldflush);
  663. End;
  664. Procedure ScrollScrnRegionDown(xl,yl,xh,yh, count: Byte);
  665. {
  666. Scroll the indicated region count lines down. The empty lines are filled
  667. with blanks in the current color. The screen position is restored
  668. afterwards.
  669. }
  670. Var
  671. y,oldx,oldy : byte;
  672. oldflush : boolean;
  673. Begin
  674. oldflush:=ttySetFlush(Flushing);
  675. oldx:=CurrX;
  676. oldy:=CurrY;
  677. {Scroll}
  678. for y:=yh downto yl+count do
  679. DoScrollLine(y-count,y,xl,xh);
  680. {Restore TextAttr}
  681. ttySendStr(Attr2Ansi(TextAttr,$ff));
  682. {Fill the rest with empty lines}
  683. for y:=yl to yl+count-1 do
  684. DoEmptyLine(y,xl,xh);
  685. {Restore current position}
  686. ttyGotoXY(OldX,OldY);
  687. ttySetFlush(oldflush);
  688. End;
  689. Procedure ScrollWindow(xl,yl,xh,yh : Byte; count: LongInt);
  690. {
  691. Scroll the indicated region up or down, depending on the sign
  692. of count.
  693. }
  694. begin
  695. If ((xl>xh) or (xh>ScreenWidth)) or
  696. ((yl>yh) or (yl>ScreenHeight)) or
  697. (abs(Count)>yh-yl+1) then
  698. exit;
  699. If count<0 then
  700. ScrollScrnRegionDown (xl,yl,xh,yh,abs(count))
  701. else
  702. ScrollScrnRegionUp (xl,yl,xh,yh,count);
  703. end;
  704. {*************************************************************************
  705. KeyBoard
  706. *************************************************************************}
  707. Const
  708. KeyBufferSize = 20;
  709. var
  710. KeyBuffer : Array[0..KeyBufferSize-1] of Char;
  711. KeyPut,
  712. KeySend : Byte;
  713. Procedure PushKey(Ch:char);
  714. Var
  715. Tmp : Word;
  716. Begin
  717. Tmp:=KeyPut;
  718. Inc(KeyPut);
  719. If KeyPut>=KeyBufferSize Then
  720. KeyPut:=0;
  721. If KeyPut<>KeySend Then
  722. KeyBuffer[Tmp]:=Ch
  723. Else
  724. KeyPut:=Tmp;
  725. End;
  726. Function PopKey:char;
  727. Begin
  728. If KeyPut<>KeySend Then
  729. Begin
  730. PopKey:=KeyBuffer[KeySend];
  731. Inc(KeySend);
  732. If KeySend>=KeyBufferSize Then
  733. KeySend:=0;
  734. End
  735. Else
  736. PopKey:=#0;
  737. End;
  738. Procedure PushExt(b:byte);
  739. begin
  740. PushKey(#0);
  741. PushKey(chr(b));
  742. end;
  743. const
  744. AltKeyStr : string[38]='qwertyuiopasdfghjklzxcvbnm1234567890-=';
  745. AltCodeStr : string[38]=#016#017#018#019#020#021#022#023#024#025#030#031#032#033#034#035#036#037#038+
  746. #044#045#046#047#048#049#050#120#121#122#123#124#125#126#127#128#129#130#131;
  747. Function FAltKey(ch:char):byte;
  748. var
  749. Idx : byte;
  750. Begin
  751. Idx:=Pos(ch,AltKeyStr);
  752. if Idx>0 then
  753. FAltKey:=byte(AltCodeStr[Idx])
  754. else
  755. FAltKey:=0;
  756. End;
  757. Function KeyPressed:Boolean;
  758. var
  759. fdsin : fdSet;
  760. Begin
  761. if (KeySend<>KeyPut) or (InCnt>0) then
  762. KeyPressed:=true
  763. else
  764. begin
  765. FD_Zero(fdsin);
  766. fd_Set(TTYin,fdsin);
  767. Keypressed:=(Select(TTYIn+1,@fdsin,nil,nil,0)>0);
  768. end;
  769. End;
  770. Function ReadKey:char;
  771. Var
  772. ch : char;
  773. OldState,
  774. State : Word;
  775. Begin
  776. {Check Buffer first}
  777. if KeySend<>KeyPut then
  778. begin
  779. ReadKey:=PopKey;
  780. exit;
  781. end;
  782. {Wait for Key}
  783. repeat
  784. until keypressed;
  785. ch:=ttyRecvChar;
  786. {Esc Found ?}
  787. If (ch=#27) then
  788. begin
  789. State:=1;
  790. Delay(10);
  791. while (State<>0) and (KeyPressed) do
  792. begin
  793. ch:=ttyRecvChar;
  794. OldState:=State;
  795. State:=0;
  796. case OldState of
  797. 1 : begin {Esc}
  798. case ch of
  799. 'a'..'z',
  800. '0'..'9',
  801. '-','=' : PushExt(FAltKey(ch));
  802. #10 : PushKey(#10);
  803. '[' : State:=2;
  804. else
  805. begin
  806. PushKey(ch);
  807. PushKey(#27);
  808. end;
  809. end;
  810. end;
  811. 2 : begin {Esc[}
  812. case ch of
  813. '[' : State:=3;
  814. 'A' : PushExt(72);
  815. 'B' : PushExt(80);
  816. 'C' : PushExt(77);
  817. 'D' : PushExt(75);
  818. 'G' : PushKey('5');
  819. 'H' : PushExt(71);
  820. 'K' : PushExt(79);
  821. '1' : State:=4;
  822. '2' : State:=5;
  823. '3' : PushExt(83);
  824. '4' : PushExt(79);
  825. '5' : PushExt(73);
  826. '6' : PushExt(81);
  827. else
  828. begin
  829. PushKey(ch);
  830. PushKey('[');
  831. PushKey(#27);
  832. end;
  833. end;
  834. if ch in ['3'..'6'] then
  835. State:=255;
  836. end;
  837. 3 : begin {Esc[[}
  838. case ch of
  839. 'A' : PushExt(59);
  840. 'B' : PushExt(60);
  841. 'C' : PushExt(61);
  842. 'D' : PushExt(62);
  843. 'E' : PushExt(63);
  844. end;
  845. end;
  846. 4 : begin
  847. case ch of
  848. '~' : PushExt(71);
  849. '7' : PushExt(64);
  850. '8' : PushExt(65);
  851. '9' : PushExt(66);
  852. end;
  853. if (Ch<>'~') then
  854. State:=255;
  855. end;
  856. 5 : begin
  857. case ch of
  858. '~' : PushExt(82);
  859. '0' : pushExt(67);
  860. '1' : PushExt(68);
  861. '3' : PushExt(133);
  862. '4' : PushExt(134);
  863. end;
  864. if (Ch<>'~') then
  865. State:=255;
  866. end;
  867. 255 : ;
  868. end;
  869. if State<>0 then
  870. Delay(10);
  871. end;
  872. if State=1 then
  873. PushKey(ch);
  874. end
  875. else
  876. Begin
  877. case ch of
  878. #127 : PushExt(83);
  879. else
  880. PushKey(ch);
  881. end;
  882. End;
  883. ReadKey:=PopKey;
  884. End;
  885. Procedure Delay(DTime: Word);
  886. {
  887. Wait for DTime milliseconds.
  888. }
  889. Begin
  890. Select(0,nil,nil,nil,DTime);
  891. End;
  892. {****************************************************************************
  893. HighLevel Crt Functions
  894. ****************************************************************************}
  895. procedure DoLn;
  896. begin
  897. if CurrY=WinMaxY then
  898. begin
  899. if FullWin then
  900. begin
  901. ttySendStr(#10#13);
  902. CurrX:=WinMinX;
  903. CurrY:=WinMaxY;
  904. end
  905. else
  906. begin
  907. ScrollScrnRegionUp(WinMinX,WinMinY,WinMaxX,WinMaxY,1);
  908. ttyGotoXY(WinMinX,WinMaxY);
  909. end;
  910. end
  911. else
  912. ttyGotoXY(WinMinX,CurrY+1);
  913. end;
  914. var
  915. Lastansi : boolean;
  916. AnsiCode : string[32];
  917. Procedure DoWrite(const s:String);
  918. {
  919. Write string to screen, parse most common AnsiCodes
  920. }
  921. var
  922. found,
  923. OldFlush : boolean;
  924. x,y : byte;
  925. i,j,
  926. SendBytes : word;
  927. function AnsiPara(var hstr:string):byte;
  928. var
  929. k,j : byte;
  930. code : word;
  931. begin
  932. j:=pos(';',hstr);
  933. if j=0 then
  934. j:=length(hstr);
  935. val(copy(hstr,3,j-3),k,code);
  936. Delete(hstr,3,j-2);
  937. if k=0 then
  938. k:=1;
  939. AnsiPara:=k;
  940. end;
  941. procedure SendText;
  942. var
  943. LeftX : word;
  944. begin
  945. while (SendBytes>0) do
  946. begin
  947. LeftX:=WinMaxX-CurrX+1;
  948. if (SendBytes>LeftX) or (CurrX+SendBytes=81) then
  949. begin
  950. ttyWrite(Copy(s,i-SendBytes,LeftX));
  951. dec(SendBytes,LeftX);
  952. DoLn;
  953. end
  954. else
  955. begin
  956. ttyWrite(Copy(s,i-SendBytes,SendBytes));
  957. SendBytes:=0;
  958. end;
  959. end;
  960. end;
  961. begin
  962. oldflush:=ttySetFlush(Flushing);
  963. { Support textattr:= changing }
  964. if OldTextAttr<>TextAttr then
  965. begin
  966. i:=TextAttr;
  967. TextAttr:=OldTextAttr;
  968. ttyColor(i);
  969. end;
  970. { write the stuff }
  971. SendBytes:=0;
  972. i:=1;
  973. while (i<=length(s)) do
  974. begin
  975. if (s[i]=#27) or (LastAnsi) then
  976. begin
  977. SendText;
  978. LastAnsi:=false;
  979. j:=i;
  980. found:=false;
  981. while (j<=length(s)) and (not found) do
  982. begin
  983. found:=not (s[j] in [#27,'[','0'..'9',';','?']);
  984. inc(j);
  985. end;
  986. Ansicode:=AnsiCode+Copy(s,i,j-i);
  987. if found then
  988. begin
  989. case AnsiCode[length(AnsiCode)] of
  990. 'm' : ttyColor(Ansi2Attr(AnsiCode,TextAttr));
  991. 'H' : begin {No other way :( Coz First Para=Y}
  992. y:=AnsiPara(AnsiCode);
  993. x:=AnsiPara(AnsiCode);
  994. GotoXY(y,x);
  995. end;
  996. 'J' : if AnsiPara(AnsiCode)=2 then
  997. ClrScr;
  998. 'K' : ClrEol;
  999. 'A' : GotoXY(CurrX,Max(CurrY-AnsiPara(AnsiCode),WinMinY));
  1000. 'B' : GotoXY(CurrX,Min(CurrY+AnsiPara(AnsiCode),WinMaxY));
  1001. 'C' : GotoXY(Min(CurrX+AnsiPara(AnsiCode),WinMaxX),CurrY);
  1002. 'D' : GotoXY(Max(CurrX-AnsiPara(AnsiCode),WinMinX),CurrY);
  1003. 'h' : ; {Stupid Thedraw [?7h Code}
  1004. else
  1005. found:=false;
  1006. end;
  1007. end
  1008. else
  1009. begin
  1010. LastAnsi:=true;
  1011. found:=true;
  1012. end;
  1013. {Clear AnsiCode?}
  1014. if not LastAnsi then
  1015. AnsiCode:='';
  1016. {Increase Idx or SendBytes}
  1017. if found then
  1018. i:=j-1
  1019. else
  1020. inc(SendBytes);
  1021. end
  1022. else
  1023. begin
  1024. LastAnsi:=false;
  1025. case s[i] of
  1026. #13 : begin {CR}
  1027. SendText;
  1028. ttyGotoXY(WinMinX,CurrY);
  1029. end;
  1030. #10 : begin {NL}
  1031. SendText;
  1032. DoLn;
  1033. end;
  1034. #9 : begin {Tab}
  1035. SendText;
  1036. ttyWrite(Space(9-((CurrX-1) and $08)));
  1037. end;
  1038. else
  1039. inc(SendBytes);
  1040. end;
  1041. end;
  1042. inc(i);
  1043. end;
  1044. if SendBytes>0 then
  1045. SendText;
  1046. ttySetFlush(oldFLush);
  1047. end;
  1048. Function CrtWrite(Var F: TextRec): Integer;
  1049. {
  1050. Top level write function for CRT
  1051. }
  1052. Var
  1053. Temp : String;
  1054. Begin
  1055. Move(F.BufPTR^[0],Temp[1],F.BufPos);
  1056. temp[0]:=chr(F.BufPos);
  1057. DoWrite(Temp);
  1058. F.BufPos:=0;
  1059. CrtWrite:=0;
  1060. End;
  1061. Function CrtClose(Var F: TextRec): Integer;
  1062. {
  1063. Close CRT associated file.
  1064. }
  1065. Begin
  1066. F.Mode:=fmClosed;
  1067. CrtClose:=0;
  1068. End;
  1069. Function CrtOpen(Var F: TextRec): Integer;
  1070. {
  1071. Open CRT associated file.
  1072. }
  1073. Begin
  1074. If F.Mode = fmOutput Then
  1075. CrtOpen:=0
  1076. Else
  1077. CrtOpen:=5;
  1078. End;
  1079. Function CrtRead(Var F: TextRec): Integer;
  1080. {
  1081. Read from CRT associated file.
  1082. }
  1083. Begin
  1084. F.BufEnd:=fdRead(F.Handle, F.BufPtr^, F.BufSize);
  1085. F.BufPos:=F.BufEnd;
  1086. CrtWrite(F);
  1087. CrtRead:=0;
  1088. End;
  1089. Function CrtInOut(Var F: TextRec): Integer;
  1090. {
  1091. InOut function for CRT associated file.
  1092. }
  1093. Begin
  1094. Case F.Mode of
  1095. fmInput: CrtInOut:=CrtRead(F);
  1096. fmOutput: CrtInOut:=CrtWrite(F);
  1097. End;
  1098. End;
  1099. Procedure AssignCrt(Var F: Text);
  1100. {
  1101. Assign a file to the console. All output on file goes to console instead.
  1102. }
  1103. Begin
  1104. TextRec(F).Mode:=fmClosed;
  1105. TextRec(F).BufSize:=SizeOf(TextBuf);
  1106. TextRec(F).BufPtr:=@TextRec(F).Buffer;
  1107. TextRec(F).BufPos:=0;
  1108. TextRec(F).OpenFunc:=@CrtOpen;
  1109. TextRec(F).InOutFunc:=@CrtInOut;
  1110. TextRec(F).FlushFunc:=@CrtWrite;
  1111. TextRec(F).CloseFunc:=@CrtClose;
  1112. TextRec(F).Name[0]:='.';
  1113. TextRec(F).Name[1]:=#0;
  1114. End;
  1115. Procedure DelLine;
  1116. {
  1117. Delete current line. Scroll subsequent lines up
  1118. }
  1119. Begin
  1120. ScrollScrnRegionUp(WinMinX, CurrY, WinMaxX, WinMaxY, 1);
  1121. End;
  1122. Procedure InsLine;
  1123. {
  1124. Insert line at current cursor position. Scroll subsequent lines down.
  1125. }
  1126. Begin
  1127. ScrollScrnRegionDown(WinMinX, CurrY, WinMaxX, WinMaxY, 1);
  1128. End;
  1129. Procedure Sound(Hz: Word);
  1130. {
  1131. Does nothing under linux
  1132. }
  1133. begin
  1134. end;
  1135. Procedure NoSound;
  1136. {
  1137. Does nothing under linux
  1138. }
  1139. begin
  1140. end;
  1141. Procedure TextMode(Mode: Integer);
  1142. {
  1143. Only Clears Screen under linux
  1144. }
  1145. begin
  1146. ClrScr;
  1147. end;
  1148. {******************************************************************************
  1149. Initialization
  1150. ******************************************************************************}
  1151. var
  1152. OldIO : TermIos;
  1153. Procedure SetRawMode(b:boolean);
  1154. Var
  1155. Tio : Termios;
  1156. Begin
  1157. if b then
  1158. begin
  1159. TCGetAttr(1,Tio);
  1160. OldIO:=Tio;
  1161. CFMakeRaw(Tio);
  1162. Tio.C_IFlag:=Tio.C_IFlag or ICRNL;
  1163. end
  1164. else
  1165. Tio:=OldIO;
  1166. TCSetAttr(1,TCSANOW,Tio);
  1167. End;
  1168. procedure GetXY(var x,y:byte);
  1169. var
  1170. fds : fdSet;
  1171. i,j,
  1172. readed : longint;
  1173. buf : array[0..255] of char;
  1174. s : string[16];
  1175. begin
  1176. x:=0;
  1177. y:=0;
  1178. s:=#27'[6n';
  1179. fdWrite(0,s[1],length(s));
  1180. FD_Zero(fds);
  1181. FD_Set(1,fds);
  1182. if (Select(2,@fds,nil,nil,1000)>0) then
  1183. begin
  1184. readed:=fdRead(1,buf,sizeof(buf));
  1185. i:=0;
  1186. while (i+4<readed) and (buf[i]<>#27) and (buf[i+1]<>'[') do
  1187. inc(i);
  1188. if i+4<readed then
  1189. begin
  1190. s[1]:=#16;
  1191. move(buf[i+2],s[1],16);
  1192. i:=Pos(';',s);
  1193. if i>0 then
  1194. begin
  1195. Val(Copy(s,1,i-1),y);
  1196. j:=Pos('R',s);
  1197. if j=0 then
  1198. j:=length(s)+1;
  1199. Val(Copy(s,i+1,j-i),x);
  1200. end;
  1201. end;
  1202. end;
  1203. end;
  1204. Procedure CrtExit;
  1205. {
  1206. We need to restore normal keyboard mode upon exit !!
  1207. }
  1208. Begin
  1209. ttyFlushOutput;
  1210. SetRawMode(False);
  1211. ExitProc:=ExitSave;
  1212. End;
  1213. Begin
  1214. {Hook Exit}
  1215. ExitSave:=ExitProc;
  1216. ExitProc:=@CrtExit;
  1217. {Assign Input and Output to Crt}
  1218. AssignCrt(Output);
  1219. AssignCrt(Input);
  1220. TextRec(Output).Mode:=fmOutput;
  1221. TextRec(Input).Mode:=fmInput;
  1222. Redir:=not IsAtty(TextRec(Output).Handle);
  1223. {Set default Terminal Settings}
  1224. SetRawMode(True);
  1225. {Get Current X&Y or Reset to Home}
  1226. if Redir then
  1227. begin
  1228. CurrX:=1;
  1229. CurrY:=1;
  1230. end
  1231. else
  1232. begin
  1233. GetXY(CurrX,CurrY);
  1234. if (CurrX=0) then
  1235. begin
  1236. CurrX:=1;
  1237. CurrY:=1;
  1238. ttySendStr(#27'[H');
  1239. end;
  1240. {Reset Attribute (TextAttr=7 at startup)}
  1241. ttySendStr(#27'[m');
  1242. end;
  1243. End.
  1244. {
  1245. $Log$
  1246. Revision 1.4 1998-05-06 12:35:26 michael
  1247. + Removed log from before restored version.
  1248. Revision 1.3 1998/04/16 07:49:11 michael
  1249. * fixed bug. Clrscr and Clreol didn't take change in textattr in account.
  1250. Revision 1.2 1998/04/05 13:56:54 peter
  1251. - fixed mouse to compile with $i386_att
  1252. + linux crt supports redirecting (not Esc-codes anymore)
  1253. Revision 1.1.1.1 1998/03/25 11:18:43 root
  1254. * Restored version
  1255. }