crt.pp 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483
  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:longint):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:longint):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 : longint;
  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:longint):longint;
  237. {
  238. Convert an Escape sequence to an attribute value, uses Oattr as the last
  239. color written
  240. }
  241. var
  242. i,j : longint;
  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 : longint;
  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 : longint;
  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:longint);
  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:longint);
  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 : longint;
  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(const 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:longint);
  466. {
  467. Write an Empty line at Row Y from Col Xl to XH, Memory is also updated
  468. }
  469. var
  470. len : longint;
  471. begin
  472. ttyGotoXY(xl,y);
  473. len:=xh-xl+1;
  474. LineWrite(Space(len));
  475. FillChar(Scrn[y,xl],len,' ');
  476. FillChar(ScrnCol[y,xl],len,TextAttr);
  477. end;
  478. procedure DoScrollLine(y1,y2,xl,xh:longint);
  479. {
  480. Move Line y1 to y2, use only columns Xl-Xh, Memory is updated also
  481. }
  482. var
  483. Temp : string;
  484. len,
  485. OldAttr,
  486. x,attr : longint;
  487. begin
  488. ttyGotoXY(xl,y2);
  489. OldAttr:=$ff;
  490. Temp:='';
  491. For x:=xl To xh Do
  492. Begin
  493. attr:=ScrnCol[y1,x];
  494. if attr<>OldAttr then
  495. begin
  496. temp:=temp+Attr2Ansi(Attr,OldAttr);
  497. OldAttr:=Attr;
  498. end;
  499. Temp:=Temp+Scrn[y1,x];
  500. if (x=xh) or (length(Temp)>240) then
  501. begin
  502. LineWrite(Temp);
  503. Temp:='';
  504. end;
  505. End;
  506. {Update memory copy}
  507. len:=xh-xl+1;
  508. Move(Scrn[y1,xl],Scrn[y2,xl],len);
  509. Move(ScrnCol[y1,xl],ScrnCol[y2,xl],len);
  510. end;
  511. Procedure TextColor(Color: Byte);
  512. {
  513. Switch foregroundcolor
  514. }
  515. Begin
  516. ttyColor((Color and $8f) or (TextAttr and $70));
  517. End;
  518. Procedure TextBackground(Color: Byte);
  519. {
  520. Switch backgroundcolor
  521. }
  522. Begin
  523. ttyColor((Color shl 4) or (TextAttr and $0f));
  524. End;
  525. Procedure HighVideo;
  526. {
  527. Set highlighted output.
  528. }
  529. Begin
  530. TextColor(TextAttr Or $08);
  531. End;
  532. Procedure LowVideo;
  533. {
  534. Set normal output
  535. }
  536. Begin
  537. TextColor(TextAttr And $77);
  538. End;
  539. Procedure NormVideo;
  540. {
  541. Set normal back and foregroundcolors.
  542. }
  543. Begin
  544. TextColor(7);
  545. TextBackGround(0);
  546. End;
  547. Procedure GotoXy(X: Byte; Y: Byte);
  548. {
  549. Go to coordinates X,Y in the current window.
  550. }
  551. Begin
  552. If (X>0) and (X<=WinMaxX- WinMinX+1) and
  553. (Y>0) and (Y<=WinMaxY-WinMinY+1) Then
  554. Begin
  555. Inc(X,WinMinX-1);
  556. Inc(Y,WinMinY-1);
  557. ttyGotoXY(x,y);
  558. End;
  559. End;
  560. Procedure Window(X1, Y1, X2, Y2: Byte);
  561. {
  562. Set screen window to the specified coordinates.
  563. }
  564. Begin
  565. if (X1>X2) or (X2>ScreenWidth) or
  566. (Y1>Y2) or (Y2>ScreenHeight) then
  567. exit;
  568. WindMin:=((Y1-1) Shl 8)+(X1-1);
  569. WindMax:=((Y2-1) Shl 8)+(X2-1);
  570. GoToXY(1,1);
  571. End;
  572. Procedure ClrScr;
  573. {
  574. Clear the current window, and set the cursor on x1,y1
  575. }
  576. Var
  577. CY : Integer;
  578. oldflush : boolean;
  579. I : Integer;
  580. Begin
  581. { See if color has changed }
  582. if OldTextAttr<>TextAttr then
  583. begin
  584. i:=TextAttr;
  585. TextAttr:=OldTextAttr;
  586. ttyColor(i);
  587. end;
  588. oldflush:=ttySetFlush(Flushing);
  589. if FullWin then
  590. begin
  591. if not Redir then
  592. ttySendStr(#27'[H'#27'[2J');
  593. CurrX:=1;
  594. CurrY:=1;
  595. FillChar(Scrn,sizeof(Scrn),' ');
  596. FillChar(ScrnCol,sizeof(ScrnCol),TextAttr);
  597. end
  598. else
  599. begin
  600. For Cy:=WinMinY To WinMaxY Do
  601. DoEmptyLine(Cy,WinMinX,WinMaxX);
  602. GoToXY(1,1);
  603. end;
  604. ttySetFlush(oldflush);
  605. End;
  606. Procedure ClrEol;
  607. {
  608. Clear from current position to end of line.
  609. }
  610. var
  611. len,i : longint;
  612. IsLastLine : boolean;
  613. Begin
  614. { See if color has changed }
  615. if OldTextAttr<>TextAttr then
  616. begin
  617. i:=TextAttr;
  618. TextAttr:=OldTextAttr;
  619. ttyColor(i);
  620. end;
  621. if FullWin or (WinMaxX = ScreenWidth) then
  622. begin
  623. if not Redir then
  624. ttySendStr(#27'[K');
  625. end
  626. else
  627. begin
  628. { Tweak windmax so no scrolling happends }
  629. len:=WinMaxX-CurrX+1;
  630. IsLastLine:=false;
  631. if CurrY=WinMaxY then
  632. begin
  633. inc(WindMax,$0203);
  634. IsLastLine:=true;
  635. end;
  636. ttySendStr(Space(len));
  637. if IsLastLine then
  638. dec(WindMax,$0203);
  639. ttyGotoXY(0,0);
  640. end;
  641. End;
  642. Function WhereX: Byte;
  643. {
  644. Return current X-position of cursor.
  645. }
  646. Begin
  647. WhereX:=CurrX-WinMinX+1;
  648. End;
  649. Function WhereY: Byte;
  650. {
  651. Return current Y-position of cursor.
  652. }
  653. Begin
  654. WhereY:=CurrY-WinMinY+1;
  655. End;
  656. Procedure ScrollScrnRegionUp(xl,yl,xh,yh, count: longint);
  657. {
  658. Scroll the indicated region count lines up. The empty lines are filled
  659. with blanks in the current color. The screen position is restored
  660. afterwards.
  661. }
  662. Var
  663. y,oldx,oldy : byte;
  664. oldflush : boolean;
  665. Begin
  666. oldflush:=ttySetFlush(Flushing);
  667. oldx:=CurrX;
  668. oldy:=CurrY;
  669. {Scroll}
  670. For y:=yl to yh-count do
  671. DoScrollLine(y+count,y,xl,xh);
  672. {Restore TextAttr}
  673. ttySendStr(Attr2Ansi(TextAttr,$ff));
  674. {Fill the rest with empty lines}
  675. for y:=yh-count+1 to yh do
  676. DoEmptyLine(y,xl,xh);
  677. {Restore current position}
  678. ttyGotoXY(OldX,OldY);
  679. ttySetFlush(oldflush);
  680. End;
  681. Procedure ScrollScrnRegionDown(xl,yl,xh,yh, count: longint);
  682. {
  683. Scroll the indicated region count lines down. The empty lines are filled
  684. with blanks in the current color. The screen position is restored
  685. afterwards.
  686. }
  687. Var
  688. y,oldx,oldy : byte;
  689. oldflush : boolean;
  690. Begin
  691. oldflush:=ttySetFlush(Flushing);
  692. oldx:=CurrX;
  693. oldy:=CurrY;
  694. {Scroll}
  695. for y:=yh downto yl+count do
  696. DoScrollLine(y-count,y,xl,xh);
  697. {Restore TextAttr}
  698. ttySendStr(Attr2Ansi(TextAttr,$ff));
  699. {Fill the rest with empty lines}
  700. for y:=yl to yl+count-1 do
  701. DoEmptyLine(y,xl,xh);
  702. {Restore current position}
  703. ttyGotoXY(OldX,OldY);
  704. ttySetFlush(oldflush);
  705. End;
  706. {*************************************************************************
  707. KeyBoard
  708. *************************************************************************}
  709. Const
  710. KeyBufferSize = 20;
  711. var
  712. KeyBuffer : Array[0..KeyBufferSize-1] of Char;
  713. KeyPut,
  714. KeySend : longint;
  715. Procedure PushKey(Ch:char);
  716. Var
  717. Tmp : Word;
  718. Begin
  719. Tmp:=KeyPut;
  720. Inc(KeyPut);
  721. If KeyPut>=KeyBufferSize Then
  722. KeyPut:=0;
  723. If KeyPut<>KeySend Then
  724. KeyBuffer[Tmp]:=Ch
  725. Else
  726. KeyPut:=Tmp;
  727. End;
  728. Function PopKey:char;
  729. Begin
  730. If KeyPut<>KeySend Then
  731. Begin
  732. PopKey:=KeyBuffer[KeySend];
  733. Inc(KeySend);
  734. If KeySend>=KeyBufferSize Then
  735. KeySend:=0;
  736. End
  737. Else
  738. PopKey:=#0;
  739. End;
  740. Procedure PushExt(b:byte);
  741. begin
  742. PushKey(#0);
  743. PushKey(chr(b));
  744. end;
  745. const
  746. AltKeyStr : string[38]='qwertyuiopasdfghjklzxcvbnm1234567890-=';
  747. AltCodeStr : string[38]=#016#017#018#019#020#021#022#023#024#025#030#031#032#033#034#035#036#037#038+
  748. #044#045#046#047#048#049#050#120#121#122#123#124#125#126#127#128#129#130#131;
  749. Function FAltKey(ch:char):byte;
  750. var
  751. Idx : longint;
  752. Begin
  753. Idx:=Pos(ch,AltKeyStr);
  754. if Idx>0 then
  755. FAltKey:=byte(AltCodeStr[Idx])
  756. else
  757. FAltKey:=0;
  758. End;
  759. Function KeyPressed:Boolean;
  760. var
  761. fdsin : fdSet;
  762. Begin
  763. if (KeySend<>KeyPut) or (InCnt>0) then
  764. KeyPressed:=true
  765. else
  766. begin
  767. FD_Zero(fdsin);
  768. fd_Set(TTYin,fdsin);
  769. Keypressed:=(Select(TTYIn+1,@fdsin,nil,nil,0)>0);
  770. end;
  771. End;
  772. Function ReadKey:char;
  773. Var
  774. ch : char;
  775. OldState,
  776. State : longint;
  777. Begin
  778. {Check Buffer first}
  779. if KeySend<>KeyPut then
  780. begin
  781. ReadKey:=PopKey;
  782. exit;
  783. end;
  784. {Wait for Key}
  785. repeat
  786. until keypressed;
  787. ch:=ttyRecvChar;
  788. {Esc Found ?}
  789. If (ch=#27) then
  790. begin
  791. State:=1;
  792. Delay(10);
  793. while (State<>0) and (KeyPressed) do
  794. begin
  795. ch:=ttyRecvChar;
  796. OldState:=State;
  797. State:=0;
  798. case OldState of
  799. 1 : begin {Esc}
  800. case ch of
  801. 'a'..'z',
  802. '0'..'9',
  803. '-','=' : PushExt(FAltKey(ch));
  804. #10 : PushKey(#10);
  805. '[' : State:=2;
  806. else
  807. begin
  808. PushKey(ch);
  809. PushKey(#27);
  810. end;
  811. end;
  812. end;
  813. 2 : begin {Esc[}
  814. case ch of
  815. '[' : State:=3;
  816. 'A' : PushExt(72);
  817. 'B' : PushExt(80);
  818. 'C' : PushExt(77);
  819. 'D' : PushExt(75);
  820. 'G' : PushKey('5');
  821. 'H' : PushExt(71);
  822. 'K' : PushExt(79);
  823. '1' : State:=4;
  824. '2' : State:=5;
  825. '3' : PushExt(83);
  826. '4' : PushExt(79);
  827. '5' : PushExt(73);
  828. '6' : PushExt(81);
  829. else
  830. begin
  831. PushKey(ch);
  832. PushKey('[');
  833. PushKey(#27);
  834. end;
  835. end;
  836. if ch in ['3'..'6'] then
  837. State:=255;
  838. end;
  839. 3 : begin {Esc[[}
  840. case ch of
  841. 'A' : PushExt(59);
  842. 'B' : PushExt(60);
  843. 'C' : PushExt(61);
  844. 'D' : PushExt(62);
  845. 'E' : PushExt(63);
  846. end;
  847. end;
  848. 4 : begin
  849. case ch of
  850. '~' : PushExt(71);
  851. '7' : PushExt(64);
  852. '8' : PushExt(65);
  853. '9' : PushExt(66);
  854. end;
  855. if (Ch<>'~') then
  856. State:=255;
  857. end;
  858. 5 : begin
  859. case ch of
  860. '~' : PushExt(82);
  861. '0' : pushExt(67);
  862. '1' : PushExt(68);
  863. '3' : PushExt(133);
  864. '4' : PushExt(134);
  865. end;
  866. if (Ch<>'~') then
  867. State:=255;
  868. end;
  869. 255 : ;
  870. end;
  871. if State<>0 then
  872. Delay(10);
  873. end;
  874. if State=1 then
  875. PushKey(ch);
  876. end
  877. else
  878. Begin
  879. case ch of
  880. #127 : PushExt(83);
  881. else
  882. PushKey(ch);
  883. end;
  884. End;
  885. ReadKey:=PopKey;
  886. End;
  887. Procedure Delay(DTime: Word);
  888. {
  889. Wait for DTime milliseconds.
  890. }
  891. Begin
  892. Select(0,nil,nil,nil,DTime);
  893. End;
  894. {****************************************************************************
  895. HighLevel Crt Functions
  896. ****************************************************************************}
  897. procedure DoLn;
  898. begin
  899. if CurrY=WinMaxY then
  900. begin
  901. if FullWin then
  902. begin
  903. ttySendStr(#10#13);
  904. CurrX:=WinMinX;
  905. CurrY:=WinMaxY;
  906. end
  907. else
  908. begin
  909. ScrollScrnRegionUp(WinMinX,WinMinY,WinMaxX,WinMaxY,1);
  910. ttyGotoXY(WinMinX,WinMaxY);
  911. end;
  912. end
  913. else
  914. ttyGotoXY(WinMinX,CurrY+1);
  915. end;
  916. var
  917. Lastansi : boolean;
  918. AnsiCode : string[32];
  919. Procedure DoWrite(const s:String);
  920. {
  921. Write string to screen, parse most common AnsiCodes
  922. }
  923. var
  924. found,
  925. OldFlush : boolean;
  926. x,y,
  927. i,j,
  928. SendBytes : longint;
  929. function AnsiPara(var hstr:string):byte;
  930. var
  931. k,j : longint;
  932. code : word;
  933. begin
  934. j:=pos(';',hstr);
  935. if j=0 then
  936. j:=length(hstr);
  937. val(copy(hstr,3,j-3),k,code);
  938. Delete(hstr,3,j-2);
  939. if k=0 then
  940. k:=1;
  941. AnsiPara:=k;
  942. end;
  943. procedure SendText;
  944. var
  945. LeftX : longint;
  946. begin
  947. while (SendBytes>0) do
  948. begin
  949. LeftX:=WinMaxX-CurrX+1;
  950. if (SendBytes>LeftX) or (CurrX+SendBytes=81) then
  951. begin
  952. ttyWrite(Copy(s,i-SendBytes,LeftX));
  953. dec(SendBytes,LeftX);
  954. DoLn;
  955. end
  956. else
  957. begin
  958. ttyWrite(Copy(s,i-SendBytes,SendBytes));
  959. SendBytes:=0;
  960. end;
  961. end;
  962. end;
  963. begin
  964. oldflush:=ttySetFlush(Flushing);
  965. { Support textattr:= changing }
  966. if OldTextAttr<>TextAttr then
  967. begin
  968. i:=TextAttr;
  969. TextAttr:=OldTextAttr;
  970. ttyColor(i);
  971. end;
  972. { write the stuff }
  973. SendBytes:=0;
  974. i:=1;
  975. while (i<=length(s)) do
  976. begin
  977. if (s[i]=#27) or (LastAnsi) then
  978. begin
  979. SendText;
  980. LastAnsi:=false;
  981. j:=i;
  982. found:=false;
  983. while (j<=length(s)) and (not found) do
  984. begin
  985. found:=not (s[j] in [#27,'[','0'..'9',';','?']);
  986. inc(j);
  987. end;
  988. Ansicode:=AnsiCode+Copy(s,i,j-i);
  989. if found then
  990. begin
  991. case AnsiCode[length(AnsiCode)] of
  992. 'm' : ttyColor(Ansi2Attr(AnsiCode,TextAttr));
  993. 'H' : begin {No other way :( Coz First Para=Y}
  994. y:=AnsiPara(AnsiCode);
  995. x:=AnsiPara(AnsiCode);
  996. GotoXY(y,x);
  997. end;
  998. 'J' : if AnsiPara(AnsiCode)=2 then
  999. ClrScr;
  1000. 'K' : ClrEol;
  1001. 'A' : GotoXY(CurrX,Max(CurrY-AnsiPara(AnsiCode),WinMinY));
  1002. 'B' : GotoXY(CurrX,Min(CurrY+AnsiPara(AnsiCode),WinMaxY));
  1003. 'C' : GotoXY(Min(CurrX+AnsiPara(AnsiCode),WinMaxX),CurrY);
  1004. 'D' : GotoXY(Max(CurrX-AnsiPara(AnsiCode),WinMinX),CurrY);
  1005. 'h' : ; {Stupid Thedraw [?7h Code}
  1006. else
  1007. found:=false;
  1008. end;
  1009. end
  1010. else
  1011. begin
  1012. LastAnsi:=true;
  1013. found:=true;
  1014. end;
  1015. {Clear AnsiCode?}
  1016. if not LastAnsi then
  1017. AnsiCode:='';
  1018. {Increase Idx or SendBytes}
  1019. if found then
  1020. i:=j-1
  1021. else
  1022. inc(SendBytes);
  1023. end
  1024. else
  1025. begin
  1026. LastAnsi:=false;
  1027. case s[i] of
  1028. #13 : begin {CR}
  1029. SendText;
  1030. ttyGotoXY(WinMinX,CurrY);
  1031. end;
  1032. #10 : begin {NL}
  1033. SendText;
  1034. DoLn;
  1035. end;
  1036. #9 : begin {Tab}
  1037. SendText;
  1038. ttyWrite(Space(9-((CurrX-1) and $08)));
  1039. end;
  1040. else
  1041. inc(SendBytes);
  1042. end;
  1043. end;
  1044. inc(i);
  1045. end;
  1046. if SendBytes>0 then
  1047. SendText;
  1048. ttySetFlush(oldFLush);
  1049. end;
  1050. Function CrtWrite(Var F: TextRec): Integer;
  1051. {
  1052. Top level write function for CRT
  1053. }
  1054. Var
  1055. Temp : String;
  1056. Begin
  1057. Move(F.BufPTR^[0],Temp[1],F.BufPos);
  1058. temp[0]:=chr(F.BufPos);
  1059. DoWrite(Temp);
  1060. F.BufPos:=0;
  1061. CrtWrite:=0;
  1062. End;
  1063. Function CrtClose(Var F: TextRec): Integer;
  1064. {
  1065. Close CRT associated file.
  1066. }
  1067. Begin
  1068. F.Mode:=fmClosed;
  1069. CrtClose:=0;
  1070. End;
  1071. Function CrtOpen(Var F: TextRec): Integer;
  1072. {
  1073. Open CRT associated file.
  1074. }
  1075. Begin
  1076. If F.Mode = fmOutput Then
  1077. CrtOpen:=0
  1078. Else
  1079. CrtOpen:=5;
  1080. End;
  1081. Function CrtRead(Var F: TextRec): Integer;
  1082. {
  1083. Read from CRT associated file.
  1084. }
  1085. var
  1086. i : longint;
  1087. Begin
  1088. F.BufEnd:=fdRead(F.Handle, F.BufPtr^, F.BufSize);
  1089. { fix #13 only's -> #10 to overcome terminal setting }
  1090. for i:=1to F.BufEnd do
  1091. begin
  1092. if (F.BufPtr^[i-1]=#13) and (F.BufPtr^[i]<>#10) then
  1093. F.BufPtr^[i-1]:=#10;
  1094. end;
  1095. F.BufPos:=F.BufEnd;
  1096. CrtWrite(F);
  1097. CrtRead:=0;
  1098. End;
  1099. Function CrtInOut(Var F: TextRec): Integer;
  1100. {
  1101. InOut function for CRT associated file.
  1102. }
  1103. Begin
  1104. Case F.Mode of
  1105. fmInput: CrtInOut:=CrtRead(F);
  1106. fmOutput: CrtInOut:=CrtWrite(F);
  1107. End;
  1108. End;
  1109. Procedure AssignCrt(Var F: Text);
  1110. {
  1111. Assign a file to the console. All output on file goes to console instead.
  1112. }
  1113. Begin
  1114. TextRec(F).Mode:=fmClosed;
  1115. TextRec(F).BufSize:=SizeOf(TextBuf);
  1116. TextRec(F).BufPtr:=@TextRec(F).Buffer;
  1117. TextRec(F).BufPos:=0;
  1118. TextRec(F).OpenFunc:=@CrtOpen;
  1119. TextRec(F).InOutFunc:=@CrtInOut;
  1120. TextRec(F).FlushFunc:=@CrtWrite;
  1121. TextRec(F).CloseFunc:=@CrtClose;
  1122. TextRec(F).Name[0]:='.';
  1123. TextRec(F).Name[1]:=#0;
  1124. End;
  1125. Procedure DelLine;
  1126. {
  1127. Delete current line. Scroll subsequent lines up
  1128. }
  1129. Begin
  1130. ScrollScrnRegionUp(WinMinX, CurrY, WinMaxX, WinMaxY, 1);
  1131. End;
  1132. Procedure InsLine;
  1133. {
  1134. Insert line at current cursor position. Scroll subsequent lines down.
  1135. }
  1136. Begin
  1137. ScrollScrnRegionDown(WinMinX, CurrY, WinMaxX, WinMaxY, 1);
  1138. End;
  1139. Procedure Sound(Hz: Word);
  1140. {
  1141. Does nothing under linux
  1142. }
  1143. begin
  1144. end;
  1145. Procedure NoSound;
  1146. {
  1147. Does nothing under linux
  1148. }
  1149. begin
  1150. end;
  1151. Procedure TextMode(Mode: Integer);
  1152. {
  1153. Only Clears Screen under linux
  1154. }
  1155. begin
  1156. ClrScr;
  1157. end;
  1158. {******************************************************************************
  1159. Initialization
  1160. ******************************************************************************}
  1161. var
  1162. OldIO : TermIos;
  1163. Procedure SetRawMode(b:boolean);
  1164. Var
  1165. Tio : Termios;
  1166. Begin
  1167. if b then
  1168. begin
  1169. TCGetAttr(1,Tio);
  1170. OldIO:=Tio;
  1171. CFMakeRaw(Tio);
  1172. end
  1173. else
  1174. Tio:=OldIO;
  1175. TCSetAttr(1,TCSANOW,Tio);
  1176. End;
  1177. procedure GetXY(var x,y:byte);
  1178. var
  1179. fds : fdSet;
  1180. i,j,
  1181. readed : longint;
  1182. buf : array[0..255] of char;
  1183. s : string[16];
  1184. begin
  1185. x:=0;
  1186. y:=0;
  1187. s:=#27'[6n';
  1188. fdWrite(0,s[1],length(s));
  1189. FD_Zero(fds);
  1190. FD_Set(1,fds);
  1191. if (Select(2,@fds,nil,nil,1000)>0) then
  1192. begin
  1193. readed:=fdRead(1,buf,sizeof(buf));
  1194. i:=0;
  1195. while (i+4<readed) and (buf[i]<>#27) and (buf[i+1]<>'[') do
  1196. inc(i);
  1197. if i+4<readed then
  1198. begin
  1199. s[1]:=#16;
  1200. move(buf[i+2],s[1],16);
  1201. i:=Pos(';',s);
  1202. if i>0 then
  1203. begin
  1204. Val(Copy(s,1,i-1),y);
  1205. j:=Pos('R',s);
  1206. if j=0 then
  1207. j:=length(s)+1;
  1208. Val(Copy(s,i+1,j-i),x);
  1209. end;
  1210. end;
  1211. end;
  1212. end;
  1213. Procedure CrtExit;
  1214. {
  1215. We need to restore normal keyboard mode upon exit !!
  1216. }
  1217. Begin
  1218. ttyFlushOutput;
  1219. SetRawMode(False);
  1220. ExitProc:=ExitSave;
  1221. End;
  1222. Begin
  1223. {Hook Exit}
  1224. ExitSave:=ExitProc;
  1225. ExitProc:=@CrtExit;
  1226. {Assign Input and Output to Crt}
  1227. AssignCrt(Output);
  1228. AssignCrt(Input);
  1229. TextRec(Output).Mode:=fmOutput;
  1230. TextRec(Input).Mode:=fmInput;
  1231. Redir:=not IsAtty(TextRec(Output).Handle);
  1232. {Set default Terminal Settings}
  1233. SetRawMode(True);
  1234. {Get Current X&Y or Reset to Home}
  1235. if Redir then
  1236. begin
  1237. CurrX:=1;
  1238. CurrY:=1;
  1239. end
  1240. else
  1241. begin
  1242. GetXY(CurrX,CurrY);
  1243. if (CurrX=0) then
  1244. begin
  1245. CurrX:=1;
  1246. CurrY:=1;
  1247. ttySendStr(#27'[H');
  1248. end;
  1249. {Reset Attribute (TextAttr=7 at startup)}
  1250. ttySendStr(#27'[m');
  1251. end;
  1252. End.
  1253. {
  1254. $Log$
  1255. Revision 1.7 1998-07-04 11:17:18 peter
  1256. * fixes for window (from "Heinz Ziegenhorn" <[email protected]>)
  1257. Revision 1.6 1998/06/19 16:51:50 peter
  1258. * added #13 -> #10 translation for CrtRead to overcome readln probs
  1259. Revision 1.5 1998/06/19 14:47:52 michael
  1260. + Enter key maps again to #13
  1261. Revision 1.4 1998/05/06 12:35:26 michael
  1262. + Removed log from before restored version.
  1263. Revision 1.3 1998/04/16 07:49:11 michael
  1264. * fixed bug. Clrscr and Clreol didn't take change in textattr in account.
  1265. Revision 1.2 1998/04/05 13:56:54 peter
  1266. - fixed mouse to compile with $i386_att
  1267. + linux crt supports redirecting (not Esc-codes anymore)
  1268. Revision 1.1.1.1 1998/03/25 11:18:43 root
  1269. * Restored version
  1270. }