crt.pp 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by Michael Van Canneyt and Peter Vreman,
  4. members of the Free Pascal development team.
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit Crt;
  12. Interface
  13. {$i crth.inc}
  14. Const
  15. { Controlling consts }
  16. Flushing = false; {if true then don't buffer output}
  17. ConsoleMaxX = 1024;
  18. ConsoleMaxY = 1024;
  19. ScreenHeight : longint = 25;
  20. ScreenWidth : longint = 80;
  21. Type
  22. TCharAttr=packed record
  23. ch : char;
  24. attr : byte;
  25. end;
  26. TConsoleBuf=Array[0..ConsoleMaxX*ConsoleMaxY-1] of TCharAttr;
  27. PConsoleBuf=^TConsoleBuf;
  28. var
  29. ConsoleBuf : PConsoleBuf;
  30. Implementation
  31. uses BaseUnix ,unix, termio;
  32. {
  33. The definitions of TextRec and FileRec are in separate files.
  34. }
  35. {$i textrec.inc}
  36. Const
  37. OldTextAttr : byte = $07;
  38. Var
  39. CurrX,CurrY : Byte;
  40. OutputRedir, InputRedir : boolean; { is the output/input being redirected (not a TTY) }
  41. {$ifdef debugcrt}
  42. DebugFile : Text;
  43. {$endif}
  44. {*****************************************************************************
  45. Some Handy Functions Not in the System.PP
  46. *****************************************************************************}
  47. {$ifdef debugcrt}
  48. Procedure Debug(Msg : string);
  49. begin
  50. Writeln(DebugFile,Msg);
  51. end;
  52. {$endif}
  53. Function Str(l:longint):string;
  54. {
  55. Return a String of the longint
  56. }
  57. var
  58. hstr : string[32];
  59. begin
  60. System.Str(l,hstr);
  61. Str:=hstr;
  62. end;
  63. Function Max(l1,l2:longint):longint;
  64. {
  65. Return the maximum of l1 and l2
  66. }
  67. begin
  68. if l1>l2 then
  69. Max:=l1
  70. else
  71. Max:=l2;
  72. end;
  73. Function Min(l1,l2:longint):longint;
  74. {
  75. Return the minimum of l1 and l2
  76. }
  77. begin
  78. if l1<l2 then
  79. Min:=l1
  80. else
  81. Min:=l2;
  82. end;
  83. {*****************************************************************************
  84. Optimal AnsiString Conversion Routines
  85. *****************************************************************************}
  86. Function XY2Ansi(x,y,ox,oy:longint):String;
  87. {
  88. Returns a string with the escape sequences to go to X,Y on the screen
  89. }
  90. Begin
  91. if y=oy then
  92. begin
  93. if x=ox then
  94. begin
  95. // this workaround should improve behaviour on some terminals.
  96. // debian bug 216057 but I also observed this with video on FreeBSD
  97. if x=screenwidth then
  98. XY2Ansi:=#27'['+Str(y)+';'+Str(x)+'H'
  99. else
  100. // end workaround
  101. XY2Ansi:='';
  102. exit;
  103. end;
  104. {$ifdef Linux} // linux CRT shortcut
  105. if x=1 then
  106. begin
  107. XY2Ansi:=#13;
  108. exit;
  109. end;
  110. {$endif}
  111. if x>ox then
  112. begin
  113. XY2Ansi:=#27'['+Str(x-ox)+'C';
  114. exit;
  115. end
  116. else
  117. begin
  118. XY2Ansi:=#27'['+Str(ox-x)+'D';
  119. exit;
  120. end;
  121. end;
  122. if x=ox then
  123. begin
  124. if y>oy then
  125. begin
  126. XY2Ansi:=#27'['+Str(y-oy)+'B';
  127. exit;
  128. end
  129. else
  130. begin
  131. XY2Ansi:=#27'['+Str(oy-y)+'A';
  132. exit;
  133. end;
  134. end;
  135. {$ifdef Linux} // this shortcut isn't for everybody
  136. if (x=1) and (oy+1=y) then
  137. XY2Ansi:=#13#10
  138. else
  139. {$endif}
  140. XY2Ansi:=#27'['+Str(y)+';'+Str(x)+'H';
  141. End;
  142. const
  143. AnsiTbl : string[8]='04261537';
  144. Function Attr2Ansi(Attr,OAttr:longint):string;
  145. {
  146. Convert Attr to an Ansi String, the Optimal code is calculate
  147. with use of the old OAttr
  148. }
  149. var
  150. hstr : string[16];
  151. OFg,OBg,Fg,Bg : longint;
  152. procedure AddSep(ch:char);
  153. begin
  154. if length(hstr)>0 then
  155. hstr:=hstr+';';
  156. hstr:=hstr+ch;
  157. end;
  158. begin
  159. if Attr=OAttr then
  160. begin
  161. Attr2Ansi:='';
  162. exit;
  163. end;
  164. Hstr:='';
  165. Fg:=Attr and $f;
  166. Bg:=Attr shr 4;
  167. OFg:=OAttr and $f;
  168. OBg:=OAttr shr 4;
  169. if (OFg<>7) or (Fg=7) or ((OFg>7) and (Fg<8)) or ((OBg>7) and (Bg<8)) then
  170. begin
  171. hstr:='0';
  172. OFg:=7;
  173. OBg:=0;
  174. end;
  175. if (Fg>7) and (OFg<8) then
  176. begin
  177. AddSep('1');
  178. OFg:=OFg or 8;
  179. end;
  180. if (Bg and 8)<>(OBg and 8) then
  181. begin
  182. AddSep('5');
  183. OBg:=OBg or 8;
  184. end;
  185. if (Fg<>OFg) then
  186. begin
  187. AddSep('3');
  188. hstr:=hstr+AnsiTbl[(Fg and 7)+1];
  189. end;
  190. if (Bg<>OBg) then
  191. begin
  192. AddSep('4');
  193. hstr:=hstr+AnsiTbl[(Bg and 7)+1];
  194. end;
  195. if hstr='0' then
  196. hstr:='';
  197. Attr2Ansi:=#27'['+hstr+'m';
  198. end;
  199. Function Ansi2Attr(Const HStr:String;oattr:longint):longint;
  200. {
  201. Convert an Escape sequence to an attribute value, uses Oattr as the last
  202. color written
  203. }
  204. var
  205. i,j : longint;
  206. begin
  207. i:=2;
  208. if (Length(HStr)<3) or (Hstr[1]<>#27) or (Hstr[2]<>'[') then
  209. i:=255;
  210. while (i<length(Hstr)) do
  211. begin
  212. inc(i);
  213. case Hstr[i] of
  214. '0' : OAttr:=7;
  215. '1' : OAttr:=OAttr or $8;
  216. '5' : OAttr:=OAttr or $80;
  217. '3' : begin
  218. inc(i);
  219. j:=pos(Hstr[i],AnsiTbl);
  220. if j>0 then
  221. OAttr:=(OAttr and $f8) or (j-1);
  222. end;
  223. '4' : begin
  224. inc(i);
  225. j:=pos(Hstr[i],AnsiTbl);
  226. if j>0 then
  227. OAttr:=(OAttr and $8f) or ((j-1) shl 4);
  228. end;
  229. 'm' : i:=length(HStr);
  230. end;
  231. end;
  232. Ansi2Attr:=OAttr;
  233. end;
  234. {*****************************************************************************
  235. Buffered StdIn/StdOut IO
  236. *****************************************************************************}
  237. const
  238. ttyIn=0; {Handles for stdin/stdout}
  239. ttyOut=1;
  240. ttyFlush:boolean=true;
  241. {Buffered Input/Output}
  242. InSize=256;
  243. OutSize=1024;
  244. var
  245. InBuf : array[0..InSize-1] of char;
  246. InCnt,
  247. InHead,
  248. InTail : longint;
  249. OutBuf : array[0..OutSize-1] of char;
  250. OutCnt : longint;
  251. {Flush Output Buffer}
  252. procedure ttyFlushOutput;
  253. begin
  254. if OutCnt>0 then
  255. begin
  256. fpWrite(ttyOut,OutBuf,OutCnt);
  257. OutCnt:=0;
  258. end;
  259. end;
  260. Function ttySetFlush(b:boolean):boolean;
  261. begin
  262. ttySetFlush:=ttyFlush;
  263. ttyFlush:=b;
  264. if ttyFlush then
  265. ttyFlushOutput;
  266. end;
  267. {Send Char to Remote}
  268. Procedure ttySendChar(c:char);
  269. Begin
  270. if OutCnt<OutSize then
  271. begin
  272. OutBuf[OutCnt]:=c;
  273. inc(OutCnt);
  274. end;
  275. {Full ?}
  276. if (OutCnt>=OutSize) then
  277. ttyFlushOutput;
  278. End;
  279. {Send String to Remote}
  280. procedure ttySendStr(const hstr:string);
  281. var
  282. i : longint;
  283. begin
  284. for i:=1to length(hstr) do
  285. ttySendChar(hstr[i]);
  286. if ttyFlush then
  287. ttyFlushOutput;
  288. end;
  289. {Get Char from Remote}
  290. function ttyRecvChar:char;
  291. var
  292. Readed,i : longint;
  293. begin
  294. {Buffer Empty? Yes, Input from StdIn}
  295. if (InHead=InTail) then
  296. begin
  297. {Calc Amount of Chars to Read}
  298. i:=InSize-InHead;
  299. if InTail>InHead then
  300. i:=InTail-InHead;
  301. {Read}
  302. Readed:=fpread(TTYIn,InBuf[InHead],i);
  303. {Increase Counters}
  304. inc(InCnt,Readed);
  305. inc(InHead,Readed);
  306. {Wrap if End has Reached}
  307. if InHead>=InSize then
  308. InHead:=0;
  309. end;
  310. {Check Buffer}
  311. if (InCnt=0) then
  312. ttyRecvChar:=#0
  313. else
  314. begin
  315. ttyRecvChar:=InBuf[InTail];
  316. dec(InCnt);
  317. inc(InTail);
  318. if InTail>=InSize then
  319. InTail:=0;
  320. end;
  321. end;
  322. {*****************************************************************************
  323. Screen Routines not Window Depended
  324. *****************************************************************************}
  325. procedure ttyGotoXY(x,y:longint);
  326. {
  327. Goto XY on the Screen, if a value is 0 the goto the current
  328. postion of that value and always recalc the ansicode for it
  329. }
  330. begin
  331. if x=0 then
  332. begin
  333. x:=CurrX;
  334. CurrX:=$ff;
  335. end;
  336. if y=0 then
  337. begin
  338. y:=CurrY;
  339. CurrY:=$ff;
  340. end;
  341. if OutputRedir then
  342. begin
  343. if longint(y)-longint(CurrY)=1 then
  344. ttySendStr(#10);
  345. end
  346. else
  347. ttySendStr(XY2Ansi(x,y,CurrX,CurrY));
  348. CurrX:=x;
  349. CurrY:=y;
  350. end;
  351. procedure ttyColor(a:longint);
  352. {
  353. Set Attribute to A, only output if not the last attribute is set
  354. }
  355. begin
  356. if a<>OldTextAttr then
  357. begin
  358. if not OutputRedir then
  359. ttySendStr(Attr2Ansi(a,OldTextAttr));
  360. TextAttr:=a;
  361. OldTextAttr:=a;
  362. end;
  363. end;
  364. procedure ttyWrite(const s:string);
  365. {
  366. Write a string to the output, memory copy and Current X&Y are also updated
  367. }
  368. var
  369. idx,i : longint;
  370. begin
  371. ttySendStr(s);
  372. {Update MemCopy}
  373. idx:=(CurrY-1)*ScreenWidth-1;
  374. for i:=1 to length(s) do
  375. if s[i]=#8 then
  376. begin
  377. if CurrX>1 then
  378. dec(CurrX);
  379. end
  380. else
  381. begin
  382. ConsoleBuf^[idx+CurrX].ch:=s[i];
  383. ConsoleBuf^[idx+CurrX].attr:=TextAttr;
  384. inc(CurrX);
  385. If CurrX>ScreenWidth then
  386. CurrX:=$FF; // Mark as invalid.
  387. end;
  388. end;
  389. Function FullWin:boolean;
  390. {
  391. Full Screen 80x25? Window(1,1,80,25) is used, allows faster routines
  392. }
  393. begin
  394. FullWin:=(WindMinX=1) and (WindMinY=1) and
  395. (WindMaxX=ScreenWidth) and (WindMaxY=ScreenHeight);
  396. end;
  397. procedure LineWrite(const temp:String);
  398. {
  399. Write a Line to the screen, doesn't write on 80,25 under Dos
  400. the Current CurrX is set to WindMax. NO MEMORY UPDATE!
  401. }
  402. begin
  403. CurrX:=WindMaxX+1;
  404. ttySendStr(Temp);
  405. end;
  406. Procedure DoEmptyLine(y,xl,xh:Longint);
  407. {
  408. Write an empty line at row Y from column Xl to Xh. Memory is also updated.
  409. }
  410. Var
  411. len : Longint;
  412. blank_with_attribute : TCharAttr;
  413. Begin
  414. ttyGotoXY(xl,y);
  415. len:=xh-xl+1;
  416. LineWrite(Space(len));
  417. blank_with_attribute.ch:=' ';
  418. blank_with_attribute.attr:=TextAttr;
  419. FillWord(ConsoleBuf^[(y-1)*ScreenWidth+xl-1],len,word(blank_with_attribute));
  420. End;
  421. procedure DoScrollLine(y1,y2,xl,xh:longint);
  422. {
  423. Move Line y1 to y2, use only columns Xl-Xh, Memory is updated also
  424. }
  425. var
  426. Temp : string;
  427. idx,
  428. OldAttr,
  429. x,attr : longint;
  430. begin
  431. ttyGotoXY(xl,y2);
  432. { precalc ConsoleBuf[] y-offset }
  433. idx:=(y1-1)*ScreenWidth-1;
  434. { update screen }
  435. OldAttr:=$ff;
  436. Temp:='';
  437. For x:=xl To xh Do
  438. Begin
  439. attr:=ConsoleBuf^[idx+x].attr;
  440. if (attr<>OldAttr) and (not OutputRedir) then
  441. begin
  442. temp:=temp+Attr2Ansi(Attr,OldAttr);
  443. OldAttr:=Attr;
  444. end;
  445. Temp:=Temp+ConsoleBuf^[idx+x].ch;
  446. if (x=xh) or (length(Temp)>240) then
  447. begin
  448. LineWrite(Temp);
  449. Temp:='';
  450. end;
  451. End;
  452. {Update memory copy}
  453. Move(ConsoleBuf^[(y1-1)*ScreenWidth+xl-1],ConsoleBuf^[(y2-1)*ScreenWidth+xl-1],(xh-xl+1)*2);
  454. end;
  455. Procedure TextColor(Color: Byte);
  456. {
  457. Switch foregroundcolor
  458. }
  459. var AddBlink : byte;
  460. Begin
  461. If (Color>15) Then
  462. AddBlink:=Blink
  463. else
  464. AddBlink:=0;
  465. ttyColor((Color and $f) or (TextAttr and $70) or AddBlink);
  466. End;
  467. Procedure TextBackground(Color: Byte);
  468. {
  469. Switch backgroundcolor
  470. }
  471. Begin
  472. TextAttr:=((Color shl 4) and ($f0 and not Blink)) or (TextAttr and ($0f OR Blink));
  473. ttyColor(TextAttr);
  474. End;
  475. Procedure HighVideo;
  476. {
  477. Set highlighted output.
  478. }
  479. Begin
  480. TextColor(TextAttr Or $08);
  481. End;
  482. Procedure LowVideo;
  483. {
  484. Set normal output
  485. }
  486. Begin
  487. TextColor(TextAttr And $77);
  488. End;
  489. Procedure NormVideo;
  490. {
  491. Set normal back and foregroundcolors.
  492. }
  493. Begin
  494. TextColor(7);
  495. TextBackGround(0);
  496. End;
  497. Procedure GotoXy(X: tcrtcoord; Y: tcrtcoord);
  498. {
  499. Go to coordinates X,Y in the current window.
  500. }
  501. Begin
  502. If (X>0) and (X<=WindMaxX- WindMinX+1) and
  503. (Y>0) and (Y<=WindMaxY-WindMinY+1) Then
  504. Begin
  505. Inc(X,WindMinX-1);
  506. Inc(Y,WindMinY-1);
  507. ttyGotoXY(x,y);
  508. End;
  509. End;
  510. Procedure Window(X1, Y1, X2, Y2: Byte);
  511. {
  512. Set screen window to the specified coordinates.
  513. }
  514. Begin
  515. if (X1>X2) or (X2>ScreenWidth) or
  516. (Y1>Y2) or (Y2>ScreenHeight) then
  517. exit;
  518. WindMinX:=X1;
  519. WindMaxX:=X2;
  520. WindMinY:=Y1;
  521. WindMaxY:=Y2;
  522. WindMin:=((Y1-1) Shl 8)+(X1-1);
  523. WindMax:=((Y2-1) Shl 8)+(X2-1);
  524. GoToXY(1,1);
  525. End;
  526. Procedure ClrScr;
  527. {
  528. Clear the current window, and set the cursor on 1,1
  529. }
  530. Var
  531. CY,i : Longint;
  532. oldflush : boolean;
  533. blank_with_attribute : TCharAttr;
  534. Begin
  535. { See if color has changed }
  536. if OldTextAttr<>TextAttr then
  537. begin
  538. i:=TextAttr;
  539. TextAttr:=OldTextAttr;
  540. ttyColor(i);
  541. end;
  542. oldflush:=ttySetFlush(Flushing);
  543. if FullWin then
  544. begin
  545. if not OutputRedir then
  546. ttySendStr(#27'[H'#27'[2J');
  547. CurrX:=1;
  548. CurrY:=1;
  549. blank_with_attribute.ch := ' ';
  550. blank_with_attribute.attr := TextAttr;
  551. FillWord(ConsoleBuf^,ScreenWidth*ScreenHeight,word(blank_with_attribute));
  552. end
  553. else
  554. begin
  555. For Cy:=WindMinY To WindMaxY Do
  556. DoEmptyLine(Cy,WindMinX,WindMaxX);
  557. GoToXY(1,1);
  558. end;
  559. ttySetFlush(oldflush);
  560. End;
  561. Procedure ClrEol;
  562. {
  563. Clear from current position to end of line.
  564. }
  565. var
  566. len,i : longint;
  567. IsLastLine : boolean;
  568. Begin
  569. { See if color has changed }
  570. if OldTextAttr<>TextAttr then
  571. begin
  572. i:=TextAttr;
  573. TextAttr:=OldTextAttr;
  574. ttyColor(i);
  575. end;
  576. if FullWin or (WindMaxX = ScreenWidth) then
  577. begin
  578. if not OutputRedir then
  579. ttySendStr(#27'[K');
  580. end
  581. else
  582. begin
  583. { Tweak WindMaxx and WindMaxy so no scrolling happends }
  584. len:=WindMaxX-CurrX+1;
  585. IsLastLine:=false;
  586. if CurrY=WindMaxY then
  587. begin
  588. inc(WindMaxX,3);
  589. inc(WindMaxY,2);
  590. IsLastLine:=true;
  591. end;
  592. ttySendStr(Space(len));
  593. if IsLastLine then
  594. begin
  595. dec(WindMaxX,3);
  596. dec(WindMaxY,2);
  597. end;
  598. ttyGotoXY(0,0);
  599. end;
  600. End;
  601. Function WhereX: tcrtcoord;
  602. {
  603. Return current X-position of cursor.
  604. }
  605. Begin
  606. WhereX:=CurrX-WindMinX+1;
  607. End;
  608. Function WhereY: tcrtcoord;
  609. {
  610. Return current Y-position of cursor.
  611. }
  612. Begin
  613. WhereY:=CurrY-WindMinY+1;
  614. End;
  615. Procedure ScrollScrnRegionUp(xl,yl,xh,yh, count: longint);
  616. {
  617. Scroll the indicated region count lines up. The empty lines are filled
  618. with blanks in the current color. The screen position is restored
  619. afterwards.
  620. }
  621. Var
  622. y,oldx,oldy : byte;
  623. oldflush : boolean;
  624. Begin
  625. oldflush:=ttySetFlush(Flushing);
  626. oldx:=CurrX;
  627. oldy:=CurrY;
  628. {Scroll}
  629. For y:=yl to yh-count do
  630. DoScrollLine(y+count,y,xl,xh);
  631. {Restore TextAttr}
  632. ttySendStr(Attr2Ansi(TextAttr,$ff));
  633. {Fill the rest with empty lines}
  634. for y:=yh-count+1 to yh do
  635. DoEmptyLine(y,xl,xh);
  636. {Restore current position}
  637. ttyGotoXY(OldX,OldY);
  638. ttySetFlush(oldflush);
  639. End;
  640. Procedure ScrollScrnRegionDown(xl,yl,xh,yh, count: longint);
  641. {
  642. Scroll the indicated region count lines down. The empty lines are filled
  643. with blanks in the current color. The screen position is restored
  644. afterwards.
  645. }
  646. Var
  647. y,oldx,oldy : byte;
  648. oldflush : boolean;
  649. Begin
  650. oldflush:=ttySetFlush(Flushing);
  651. oldx:=CurrX;
  652. oldy:=CurrY;
  653. {Scroll}
  654. for y:=yh downto yl+count do
  655. DoScrollLine(y-count,y,xl,xh);
  656. {Restore TextAttr}
  657. ttySendStr(Attr2Ansi(TextAttr,$ff));
  658. {Fill the rest with empty lines}
  659. for y:=yl to yl+count-1 do
  660. DoEmptyLine(y,xl,xh);
  661. {Restore current position}
  662. ttyGotoXY(OldX,OldY);
  663. ttySetFlush(oldflush);
  664. End;
  665. {*************************************************************************
  666. KeyBoard
  667. *************************************************************************}
  668. Const
  669. KeyBufferSize = 20;
  670. var
  671. KeyBuffer : Array[0..KeyBufferSize-1] of Char;
  672. KeyPut,
  673. KeySend : longint;
  674. Procedure PushKey(Ch:char);
  675. Var
  676. Tmp : Longint;
  677. Begin
  678. Tmp:=KeyPut;
  679. Inc(KeyPut);
  680. If KeyPut>=KeyBufferSize Then
  681. KeyPut:=0;
  682. If KeyPut<>KeySend Then
  683. KeyBuffer[Tmp]:=Ch
  684. Else
  685. KeyPut:=Tmp;
  686. End;
  687. Function PopKey:char;
  688. Begin
  689. If KeyPut<>KeySend Then
  690. Begin
  691. PopKey:=KeyBuffer[KeySend];
  692. Inc(KeySend);
  693. If KeySend>=KeyBufferSize Then
  694. KeySend:=0;
  695. End
  696. Else
  697. PopKey:=#0;
  698. End;
  699. Procedure PushExt(b:byte);
  700. begin
  701. PushKey(#0);
  702. PushKey(chr(b));
  703. end;
  704. const
  705. AltKeyStr : string[38]='qwertyuiopasdfghjklzxcvbnm1234567890-=';
  706. AltCodeStr : string[38]=#016#017#018#019#020#021#022#023#024#025#030#031#032#033#034#035#036#037#038+
  707. #044#045#046#047#048#049#050#120#121#122#123#124#125#126#127#128#129#130#131;
  708. Function FAltKey(ch:char):byte;
  709. var
  710. Idx : longint;
  711. Begin
  712. Idx:=Pos(ch,AltKeyStr);
  713. if Idx>0 then
  714. FAltKey:=byte(AltCodeStr[Idx])
  715. else
  716. FAltKey:=0;
  717. End;
  718. { This one doesn't care about keypresses already processed by readkey }
  719. { and waiting in the KeyBuffer, only about waiting keypresses at the }
  720. { TTYLevel (including ones that are waiting in the TTYRecvChar buffer) }
  721. function sysKeyPressed: boolean;
  722. var
  723. fdsin : tfdSet;
  724. begin
  725. if (InCnt>0) then
  726. sysKeyPressed:=true
  727. else
  728. begin
  729. fpFD_ZERO(fdsin);
  730. fpFD_SET(TTYin,fdsin);
  731. sysKeypressed:=(fpSelect(TTYIn+1,@fdsin,nil,nil,0)>0);
  732. end;
  733. end;
  734. Function KeyPressed:Boolean;
  735. Begin
  736. Keypressed := (KeySend<>KeyPut) or sysKeyPressed;
  737. End;
  738. Function ReadKey:char;
  739. Var
  740. ch : char;
  741. OldState,
  742. State : longint;
  743. FDS : TFDSet;
  744. Begin
  745. {Check Buffer first}
  746. if KeySend<>KeyPut then
  747. begin
  748. ReadKey:=PopKey;
  749. exit;
  750. end;
  751. {Wait for Key}
  752. { Only if none are waiting! (JM) }
  753. if not sysKeyPressed then
  754. begin
  755. FpFD_ZERO (FDS);
  756. fpFD_SET (0,FDS);
  757. fpSelect (1,@FDS,nil,nil,nil);
  758. end;
  759. ch:=ttyRecvChar;
  760. {Esc Found ?}
  761. CASE ch OF
  762. #27: begin
  763. State:=1;
  764. Delay(10);
  765. { This has to be sysKeyPressed and not "keyPressed", since after }
  766. { one iteration keyPressed will always be true because of the }
  767. { pushKey commands (JM) }
  768. while (State<>0) and (sysKeyPressed) do
  769. begin
  770. ch:=ttyRecvChar;
  771. OldState:=State;
  772. State:=0;
  773. case OldState of
  774. 1 : begin {Esc}
  775. case ch of
  776. 'a'..'z',
  777. '0'..'9',
  778. '-','=' : PushExt(FAltKey(ch));
  779. #10 : PushKey(#10);
  780. '[' : State:=2;
  781. {$IFDEF Unix}
  782. 'O': State:=7;
  783. {$ENDIF}
  784. else
  785. begin
  786. PushKey(ch);
  787. PushKey(#27);
  788. end;
  789. end;
  790. end;
  791. 2 : begin {Esc[}
  792. case ch of
  793. '[' : State:=3;
  794. 'A' : PushExt(72);
  795. 'B' : PushExt(80);
  796. 'C' : PushExt(77);
  797. 'D' : PushExt(75);
  798. {$IFDEF FREEBSD}
  799. {'E' - Center key, not handled in DOS TP7}
  800. 'F' : PushExt(79); {End}
  801. 'G': PushExt(81); {PageDown}
  802. {$ELSE}
  803. 'G' : PushKey('5'); {Center key, Linux}
  804. {$ENDIF}
  805. 'H' : PushExt(71);
  806. {$IFDEF FREEBSD}
  807. 'I' : PushExt(73); {PageUp}
  808. {$ENDIF}
  809. 'K' : PushExt(79);
  810. {$IFDEF FREEBSD}
  811. 'L' : PushExt(82); {Insert - Deekoo}
  812. 'M' : PushExt(59); {F1-F10 - Deekoo}
  813. 'N' : PushExt(60); {F2}
  814. 'O' : PushExt(61); {F3}
  815. 'P' : PushExt(62); {F4}
  816. 'Q' : PushExt(63); {F5}
  817. 'R' : PushExt(64); {F6}
  818. 'S' : PushExt(65); {F7}
  819. 'T' : PushExt(66); {F8}
  820. 'U' : PushExt(67); {F9}
  821. 'V' : PushExt(68); {F10}
  822. {Not sure if TP/BP handles F11 and F12 like this normally;
  823. In pcemu, a TP7 executable handles 'em this way, though.}
  824. 'W' : PushExt(133); {F11}
  825. 'X' : PushExt(134); {F12}
  826. 'Y' : PushExt(84); {Shift-F1}
  827. 'Z' : PushExt(85); {Shift-F2}
  828. 'a' : PushExt(86); {Shift-F3}
  829. 'b' : PushExt(87); {Shift-F4}
  830. 'c' : PushExt(88); {Shift-F5}
  831. 'd' : PushExt(89); {Shift-F6}
  832. 'e' : PushExt(90); {Shift-F7}
  833. 'f' : PushExt(91); {Shift-F8}
  834. 'g' : PushExt(92); {Shift-F9}
  835. 'h' : PushExt(93); {Shift-F10}
  836. 'i' : PushExt(135); {Shift-F11}
  837. 'j' : PushExt(136); {Shift-F12}
  838. 'k' : PushExt(94); {Ctrl-F1}
  839. 'l' : PushExt(95);
  840. 'm' : PushExt(96);
  841. 'n' : PushExt(97);
  842. 'o' : PushExt(98);
  843. 'p' : PushExt(99);
  844. 'q' : PushExt(100);
  845. 'r' : PushExt(101);
  846. 's' : PushExt(102);
  847. 't' : PushExt(103); {Ctrl-F10}
  848. 'u' : PushExt(137); {Ctrl-F11}
  849. 'v' : PushExt(138); {Ctrl-F12}
  850. {$ENDIF}
  851. '1' : State:=4;
  852. '2' : State:=5;
  853. '3' : State:=6;
  854. '4' : PushExt(79);
  855. '5' : PushExt(73);
  856. '6' : PushExt(81);
  857. else
  858. begin
  859. PushKey(ch);
  860. PushKey('[');
  861. PushKey(#27);
  862. end;
  863. end;
  864. if ch in ['4'..'6'] then
  865. State:=255;
  866. end;
  867. 3 : begin {Esc[[}
  868. case ch of
  869. 'A' : PushExt(59);
  870. 'B' : PushExt(60);
  871. 'C' : PushExt(61);
  872. 'D' : PushExt(62);
  873. 'E' : PushExt(63);
  874. end;
  875. end;
  876. 4 : begin {Esc[1}
  877. case ch of
  878. '~' : PushExt(71);
  879. '5' : State := 8;
  880. '7' : PushExt(64);
  881. '8' : PushExt(65);
  882. '9' : PushExt(66);
  883. end;
  884. if not (Ch in ['~', '5']) then
  885. State:=255;
  886. end;
  887. 5 : begin {Esc[2}
  888. case ch of
  889. '~' : PushExt(82);
  890. '0' : pushExt(67);
  891. '1' : PushExt(68);
  892. '3' : PushExt(133); {F11}
  893. {Esc[23~ is also shift-F1,shift-F11}
  894. '4' : PushExt(134); {F12}
  895. {Esc[24~ is also shift-F2,shift-F12}
  896. '5' : PushExt(86); {Shift-F3}
  897. '6' : PushExt(87); {Shift-F4}
  898. '8' : PushExt(88); {Shift-F5}
  899. '9' : PushExt(89); {Shift-F6}
  900. end;
  901. if (Ch<>'~') then
  902. State:=255;
  903. end;
  904. 6 : begin {Esc[3}
  905. case ch of
  906. '~' : PushExt(83); {Del}
  907. '1' : PushExt(90); {Shift-F7}
  908. '2' : PushExt(91); {Shift-F8}
  909. '3' : PushExt(92); {Shift-F9}
  910. '4' : PushExt(93); {Shift-F10}
  911. end;
  912. if (Ch<>'~') then
  913. State:=255;
  914. end;
  915. {$ifdef Unix}
  916. 7 : begin {Esc[O}
  917. case ch of
  918. 'A' : PushExt(72);
  919. 'B' : PushExt(80);
  920. 'C' : PushExt(77);
  921. 'D' : PushExt(75);
  922. 'P' : PushExt(59);
  923. 'Q' : PushExt(60);
  924. 'R' : PushExt(61);
  925. 'S' : PushExt(62);
  926. end;
  927. end;
  928. {$endif}
  929. 8 : begin {Esc[15}
  930. case ch of
  931. '~' : PushExt(63);
  932. end;
  933. end;
  934. 255 : ;
  935. end;
  936. if State<>0 then
  937. Delay(10);
  938. end;
  939. if State=1 then
  940. PushKey(ch);
  941. end;
  942. #127: PushKey(#8);
  943. else PushKey(ch);
  944. End;
  945. ReadKey:=PopKey;
  946. End;
  947. Procedure Delay(MS: Word);
  948. {
  949. Wait for DTime milliseconds.
  950. }
  951. Begin
  952. fpSelect(0,nil,nil,nil,MS);
  953. End;
  954. {****************************************************************************
  955. Write(ln)/Read(ln) support
  956. ****************************************************************************}
  957. procedure DoLn;
  958. begin
  959. if CurrY=WindMaxY then
  960. begin
  961. if FullWin then
  962. begin
  963. ttySendStr(#10#13);
  964. CurrX:=WindMinX;
  965. CurrY:=WindMaxY;
  966. end
  967. else
  968. begin
  969. ScrollScrnRegionUp(WindMinX,WindMinY,WindMaxX,WindMaxY,1);
  970. ttyGotoXY(WindMinX,WindMaxY);
  971. end;
  972. end
  973. else
  974. ttyGotoXY(WindMinX,CurrY+1);
  975. end;
  976. var
  977. Lastansi : boolean;
  978. AnsiCode : string;
  979. Procedure DoWrite(const s:String);
  980. {
  981. Write string to screen, parse most common AnsiCodes
  982. }
  983. var
  984. found,
  985. OldFlush : boolean;
  986. x,y,
  987. i,j,
  988. SendBytes : longint;
  989. function AnsiPara(var hstr:string):byte;
  990. var
  991. k,j : longint;
  992. code : word;
  993. begin
  994. j:=pos(';',hstr);
  995. if j=0 then
  996. j:=length(hstr);
  997. val(copy(hstr,3,j-3),k,code);
  998. Delete(hstr,3,j-2);
  999. if k=0 then
  1000. k:=1;
  1001. AnsiPara:=k;
  1002. end;
  1003. procedure SendText;
  1004. var
  1005. LeftX : longint;
  1006. begin
  1007. while (SendBytes>0) do
  1008. begin
  1009. LeftX:=WindMaxX-CurrX+1;
  1010. if (SendBytes>=LeftX) then
  1011. begin
  1012. ttyWrite(Copy(s,i-SendBytes,LeftX));
  1013. dec(SendBytes,LeftX);
  1014. DoLn;
  1015. end
  1016. else
  1017. begin
  1018. ttyWrite(Copy(s,i-SendBytes,SendBytes));
  1019. SendBytes:=0;
  1020. end;
  1021. end;
  1022. end;
  1023. begin
  1024. oldflush:=ttySetFlush(Flushing);
  1025. { Support textattr:= changing }
  1026. if OldTextAttr<>TextAttr then
  1027. begin
  1028. i:=TextAttr;
  1029. TextAttr:=OldTextAttr;
  1030. ttyColor(i);
  1031. end;
  1032. { write the stuff }
  1033. SendBytes:=0;
  1034. i:=1;
  1035. while (i<=length(s)) do
  1036. begin
  1037. if (s[i]=#27) or (LastAnsi) then
  1038. begin
  1039. SendText;
  1040. LastAnsi:=false;
  1041. j:=i;
  1042. found:=false;
  1043. while (j<=length(s)) and (not found) do
  1044. begin
  1045. found:=not (s[j] in [#27,'[','0'..'9',';','?']);
  1046. inc(j);
  1047. end;
  1048. Ansicode:=AnsiCode+Copy(s,i,j-i);
  1049. if found then
  1050. begin
  1051. case AnsiCode[length(AnsiCode)] of
  1052. 'm' : ttyColor(Ansi2Attr(AnsiCode,TextAttr));
  1053. 'H' : begin {No other way :( Coz First Para=Y}
  1054. y:=AnsiPara(AnsiCode);
  1055. x:=AnsiPara(AnsiCode);
  1056. GotoXY(x,y);
  1057. end;
  1058. 'J' : if AnsiPara(AnsiCode)=2 then
  1059. ClrScr;
  1060. 'K' : ClrEol;
  1061. 'A' : GotoXY(CurrX,Max(CurrY-AnsiPara(AnsiCode),WindMinY));
  1062. 'B' : GotoXY(CurrX,Min(CurrY+AnsiPara(AnsiCode),WindMaxY));
  1063. 'C' : GotoXY(Min(CurrX+AnsiPara(AnsiCode),WindMaxX),CurrY);
  1064. 'D' : GotoXY(Max(CurrX-AnsiPara(AnsiCode),WindMinX),CurrY);
  1065. 'h' : ; {Stupid Thedraw [?7h Code}
  1066. else
  1067. found:=false;
  1068. end;
  1069. end
  1070. else
  1071. begin
  1072. LastAnsi:=true;
  1073. found:=true;
  1074. end;
  1075. {Clear AnsiCode?}
  1076. if not LastAnsi then
  1077. AnsiCode:='';
  1078. {Increase Idx or SendBytes}
  1079. if found then
  1080. i:=j-1
  1081. else
  1082. inc(SendBytes);
  1083. end
  1084. else
  1085. begin
  1086. LastAnsi:=false;
  1087. case s[i] of
  1088. #13 : begin {CR}
  1089. SendText;
  1090. ttyGotoXY(WindMinX,CurrY);
  1091. end;
  1092. #10 : begin {NL}
  1093. SendText;
  1094. DoLn;
  1095. end;
  1096. #9 : begin {Tab}
  1097. SendText;
  1098. ttyWrite(Space(9-((CurrX-1) and $08)));
  1099. end;
  1100. #8 : begin {BackSpace}
  1101. SendText;
  1102. ttyWrite(#8);
  1103. end;
  1104. else
  1105. inc(SendBytes);
  1106. end;
  1107. end;
  1108. inc(i);
  1109. end;
  1110. if SendBytes>0 then
  1111. SendText;
  1112. ttySetFlush(oldFLush);
  1113. end;
  1114. Function CrtWrite(Var F: TextRec): Integer;
  1115. {
  1116. Top level write function for CRT
  1117. }
  1118. Var
  1119. Temp : String;
  1120. idx,i : Longint;
  1121. oldflush : boolean;
  1122. Begin
  1123. oldflush:=ttySetFlush(Flushing);
  1124. idx:=0;
  1125. while (F.BufPos>0) do
  1126. begin
  1127. i:=F.BufPos;
  1128. if i>255 then
  1129. i:=255;
  1130. Move(F.BufPTR^[idx],Temp[1],i);
  1131. SetLength(Temp,i);
  1132. DoWrite(Temp);
  1133. dec(F.BufPos,i);
  1134. inc(idx,i);
  1135. end;
  1136. ttySetFlush(oldFLush);
  1137. CrtWrite:=0;
  1138. End;
  1139. Function CrtRead(Var F: TextRec): Integer;
  1140. {
  1141. Read from CRT associated file.
  1142. }
  1143. var
  1144. c : char;
  1145. i : longint;
  1146. Begin
  1147. if isATTY(F.Handle)=1 then
  1148. begin
  1149. F.BufPos := 0;
  1150. i := 0;
  1151. repeat
  1152. c := readkey;
  1153. case c of
  1154. { ignore special keys }
  1155. #0:
  1156. c:= readkey;
  1157. { Backspace }
  1158. #8:
  1159. if i > 0 then
  1160. begin
  1161. if not(OutputRedir or InputRedir) then
  1162. write(#8#32#8);
  1163. dec(i);
  1164. end;
  1165. { Unhandled extended key }
  1166. #27:;
  1167. { CR }
  1168. #13:
  1169. begin
  1170. F.BufPtr^[i] := #10;
  1171. if not(OutputRedir or InputRedir) then
  1172. write(#10);
  1173. inc(i);
  1174. end;
  1175. else
  1176. begin
  1177. if not(OutputRedir or InputRedir) then
  1178. write(c);
  1179. F.BufPtr^[i] := c;
  1180. inc(i);
  1181. end;
  1182. end;
  1183. until (c in [#10,#13]) or (i >= F.BufSize);
  1184. F.BufEnd := i;
  1185. CrtRead := 0;
  1186. exit;
  1187. end;
  1188. F.BufEnd:=fpRead(F.Handle, F.BufPtr^, F.BufSize);
  1189. { fix #13 only's -> #10 to overcome terminal setting }
  1190. for i:=1to F.BufEnd do
  1191. begin
  1192. if (F.BufPtr^[i-1]=#13) and (F.BufPtr^[i]<>#10) then
  1193. F.BufPtr^[i-1]:=#10;
  1194. end;
  1195. F.BufPos:=F.BufEnd;
  1196. if not(OutputRedir or InputRedir) then
  1197. CrtWrite(F)
  1198. else F.BufPos := 0;
  1199. CrtRead:=0;
  1200. End;
  1201. Function CrtReturn(Var F:TextRec):Integer;
  1202. Begin
  1203. CrtReturn:=0;
  1204. end;
  1205. Function CrtClose(Var F: TextRec): Integer;
  1206. {
  1207. Close CRT associated file.
  1208. }
  1209. Begin
  1210. F.Mode:=fmClosed;
  1211. CrtClose:=0;
  1212. End;
  1213. Function CrtOpen(Var F: TextRec): Integer;
  1214. {
  1215. Open CRT associated file.
  1216. }
  1217. Begin
  1218. If F.Mode=fmOutput Then
  1219. begin
  1220. TextRec(F).InOutFunc:=@CrtWrite;
  1221. TextRec(F).FlushFunc:=@CrtWrite;
  1222. end
  1223. Else
  1224. begin
  1225. F.Mode:=fmInput;
  1226. TextRec(F).InOutFunc:=@CrtRead;
  1227. TextRec(F).FlushFunc:=@CrtReturn;
  1228. end;
  1229. TextRec(F).CloseFunc:=@CrtClose;
  1230. CrtOpen:=0;
  1231. End;
  1232. procedure AssignCrt(var F: Text);
  1233. {
  1234. Assign a file to the console. All output on file goes to console instead.
  1235. }
  1236. begin
  1237. Assign(F,'');
  1238. TextRec(F).OpenFunc:=@CrtOpen;
  1239. end;
  1240. {******************************************************************************
  1241. High Level Functions
  1242. ******************************************************************************}
  1243. Procedure DelLine;
  1244. {
  1245. Delete current line. Scroll subsequent lines up
  1246. }
  1247. Begin
  1248. ScrollScrnRegionUp(WindMinX, CurrY, WindMaxX, WindMaxY, 1);
  1249. End;
  1250. Procedure InsLine;
  1251. {
  1252. Insert line at current cursor position. Scroll subsequent lines down.
  1253. }
  1254. Begin
  1255. ScrollScrnRegionDown(WindMinX, CurrY, WindMaxX, WindMaxY, 1);
  1256. End;
  1257. {$ifdef linux}
  1258. {$define havekiocsound}
  1259. const KIOCSOUND = $4B2F; // start sound generation (0 for off)
  1260. {$else}
  1261. {$ifdef FreeBSD}
  1262. const KIOCSOUND =$20004b3f;
  1263. {$define havekiocsound}
  1264. {$endif}
  1265. {$endif}
  1266. // ioctl might fail e.g. in putty. A redirect check is not enough,
  1267. // needs check for physical console too.
  1268. Procedure Sound(Hz: Word);
  1269. begin
  1270. {$ifdef havekiocsound}
  1271. if (not OutputRedir) and (hz>0) then
  1272. fpIoctl(TextRec(Output).Handle, KIOCSOUND, Pointer(1193180 div Hz));
  1273. {$endif}
  1274. end;
  1275. Procedure NoSound;
  1276. begin
  1277. {$ifdef havekiocsound}
  1278. if not OutputRedir then
  1279. fpIoctl(TextRec(Output).Handle, KIOCSOUND, nil);
  1280. {$endif}
  1281. end;
  1282. Procedure TextMode (Mode: word);
  1283. {
  1284. Only Clears Screen under linux}
  1285. begin
  1286. ClrScr;
  1287. end;
  1288. {******************************************************************************
  1289. Extra
  1290. ******************************************************************************}
  1291. procedure CursorBig;
  1292. begin
  1293. ttySendStr(#27'[?17;0;64c');
  1294. end;
  1295. procedure CursorOn;
  1296. begin
  1297. ttySendStr(#27'[?2c');
  1298. end;
  1299. procedure CursorOff;
  1300. begin
  1301. ttySendStr(#27'[?1c');
  1302. end;
  1303. {******************************************************************************
  1304. Initialization
  1305. ******************************************************************************}
  1306. var
  1307. OldIO : termio.TermIos;
  1308. inputRaw, outputRaw: boolean;
  1309. procedure saveRawSettings(const tio: termio.termios);
  1310. Begin
  1311. with tio do
  1312. begin
  1313. inputRaw :=
  1314. ((c_iflag and (IGNBRK or BRKINT or PARMRK or ISTRIP or
  1315. INLCR or IGNCR or ICRNL or IXON)) = 0) and
  1316. ((c_lflag and (ECHO or ECHONL or ICANON or ISIG or IEXTEN)) = 0);
  1317. outPutRaw :=
  1318. ((c_oflag and OPOST) = 0) and
  1319. ((c_cflag and (CSIZE or PARENB)) = 0) and
  1320. ((c_cflag and CS8) <> 0);
  1321. end;
  1322. end;
  1323. procedure restoreRawSettings(tio: termio.termios);
  1324. begin
  1325. with tio do
  1326. begin
  1327. if inputRaw then
  1328. begin
  1329. c_iflag := c_iflag and (not (IGNBRK or BRKINT or PARMRK or ISTRIP or
  1330. INLCR or IGNCR or ICRNL or IXON));
  1331. c_lflag := c_lflag and
  1332. (not (ECHO or ECHONL or ICANON or ISIG or IEXTEN));
  1333. end;
  1334. if outPutRaw then
  1335. begin
  1336. c_oflag := c_oflag and not(OPOST);
  1337. c_cflag := c_cflag and not(CSIZE or PARENB) or CS8;
  1338. end;
  1339. end;
  1340. end;
  1341. Procedure SetRawMode(b:boolean);
  1342. Var
  1343. Tio : Termios;
  1344. Begin
  1345. if b then
  1346. begin
  1347. TCGetAttr(1,Tio);
  1348. SaveRawSettings(Tio);
  1349. OldIO:=Tio;
  1350. CFMakeRaw(Tio);
  1351. end
  1352. else
  1353. begin
  1354. RestoreRawSettings(OldIO);
  1355. Tio:=OldIO;
  1356. end;
  1357. TCSetAttr(1,TCSANOW,Tio);
  1358. End;
  1359. procedure GetXY(var x,y:byte);
  1360. var
  1361. fds : tfdSet;
  1362. i,j,
  1363. readed : longint;
  1364. buf : array[0..255] of char;
  1365. s : string[16];
  1366. begin
  1367. x:=0;
  1368. y:=0;
  1369. s:=#27'[6n';
  1370. fpWrite(0,s[1],length(s));
  1371. fpFD_ZERO(fds);
  1372. fpFD_SET(1,fds);
  1373. readed:=0;
  1374. repeat
  1375. if (fpSelect(2,@fds,nil,nil,1000)>0) then
  1376. begin
  1377. readed:=readed+fpRead(1,buf[readed],sizeof(buf)-readed);
  1378. i:=0;
  1379. while (i+5<readed) and (buf[i]<>#27) and (buf[i+1]<>'[') do
  1380. inc(i);
  1381. if i+5<readed then
  1382. begin
  1383. s:=space(16);
  1384. move(buf[i+2],s[1],16);
  1385. j:=Pos('R',s);
  1386. if j>0 then
  1387. begin
  1388. i:=Pos(';',s);
  1389. Val(Copy(s,1,i-1),y);
  1390. Val(Copy(s,i+1,j-(i+1)),x);
  1391. break;
  1392. end;
  1393. end;
  1394. end
  1395. else
  1396. break;
  1397. until false;
  1398. end;
  1399. Procedure GetConsoleBuf;
  1400. var
  1401. WinInfo : TWinSize;
  1402. begin
  1403. if Assigned(ConsoleBuf) then
  1404. FreeMem(ConsoleBuf,ScreenHeight*ScreenWidth*2);
  1405. ScreenWidth:=0;
  1406. ScreenHeight:=0;
  1407. if (not OutputRedir) and (fpIOCtl(TextRec(Output).Handle,TIOCGWINSZ,@Wininfo)>=0) then
  1408. begin
  1409. ScreenWidth:=Wininfo.ws_col;
  1410. ScreenHeight:=Wininfo.ws_row;
  1411. end;
  1412. // Set some arbitrary defaults which make some sense...
  1413. If (ScreenWidth=0) then
  1414. ScreenWidth:=80;
  1415. If (ScreenHeight=0) then
  1416. ScreenHeight:=25;
  1417. GetMem(ConsoleBuf,ScreenHeight*ScreenWidth*2);
  1418. FillChar(ConsoleBuf^,ScreenHeight*ScreenWidth*2,0);
  1419. end;
  1420. Initialization
  1421. {$ifdef debugcrt}
  1422. Assign(DebugFile,'debug.txt');
  1423. ReWrite(DebugFile);
  1424. {$endif}
  1425. { Redirect the standard output }
  1426. assigncrt(Output);
  1427. Rewrite(Output);
  1428. TextRec(Output).Handle:=StdOutputHandle;
  1429. assigncrt(Input);
  1430. Reset(Input);
  1431. TextRec(Input).Handle:=StdInputHandle;
  1432. { Are we redirected to a file ? }
  1433. OutputRedir:= IsAtty(TextRec(Output).Handle)<>1;
  1434. { does the input come from another console or from a file? }
  1435. InputRedir :=
  1436. (IsAtty(TextRec(Input).Handle)<>1) or
  1437. (not OutputRedir and
  1438. (TTYName(TextRec(Input).Handle) <> TTYName(TextRec(Output).Handle)));
  1439. { Get Size of terminal and set WindMax to the window }
  1440. GetConsoleBuf;
  1441. WindMinX:=1;
  1442. WindMinY:=1;
  1443. WindMaxX:=ScreenWidth;
  1444. WindMaxY:=ScreenHeight;
  1445. WindMax:=((ScreenHeight-1) Shl 8)+(ScreenWidth-1);
  1446. {Get Current X&Y or Reset to Home}
  1447. if OutputRedir then
  1448. begin
  1449. CurrX:=1;
  1450. CurrY:=1;
  1451. end
  1452. else
  1453. begin
  1454. { Set default Terminal Settings }
  1455. SetRawMode(True);
  1456. { Get current X,Y if not set already }
  1457. GetXY(CurrX,CurrY);
  1458. if (CurrX=0) then
  1459. begin
  1460. CurrX:=1;
  1461. CurrY:=1;
  1462. ttySendStr(#27'[H');
  1463. end;
  1464. {Reset Attribute (TextAttr=7 at startup)}
  1465. ttySendStr(#27'[m');
  1466. end;
  1467. Finalization
  1468. {$ifdef debugcrt}
  1469. Close(DebugFile);
  1470. {$endif}
  1471. ttyFlushOutput;
  1472. if not OutputRedir then
  1473. SetRawMode(False);
  1474. { remove console buf }
  1475. if Assigned(ConsoleBuf) then
  1476. FreeMem(ConsoleBuf,ScreenHeight*ScreenWidth*2);
  1477. End.