crt.pp 29 KB

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