crt.pp 36 KB

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