video.pp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by Florian Klaempfl
  4. member of the Free Pascal development team
  5. Video unit for linux
  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 Video;
  13. interface
  14. {$i videoh.inc}
  15. implementation
  16. uses
  17. BaseUnix, Strings, TermInfo, termio;
  18. {$i video.inc}
  19. Type TConsoleType = (ttyNetwork,ttyLinux,ttyFreeBSD,ttyNetBSD);
  20. var
  21. LastCursorType : byte;
  22. TtyFd: Longint;
  23. Console: TConsoleType;
  24. {$ifdef logging}
  25. f: file;
  26. const
  27. logstart: string = '';
  28. nl: char = #10;
  29. logend: string = #10#10;
  30. {$endif logging}
  31. {$ifdef cpui386}
  32. {$ASMMODE ATT}
  33. {$endif cpui386}
  34. const
  35. can_delete_term : boolean = false;
  36. ACSIn : string = '';
  37. ACSOut : string = '';
  38. InACS : boolean =false;
  39. function IsACS(var ch,ACSchar : char): boolean;
  40. begin
  41. IsACS:=false;
  42. case ch of
  43. #24, #30: {}
  44. ch:='^';
  45. #25, #31: {}
  46. ch:='v';
  47. #26, #16: {Never introduce a ctrl-Z ... }
  48. ch:='>';
  49. {#27,needed in Escape sequences} #17: {}
  50. ch:='<';
  51. #176, #177, #178: {°±²}
  52. begin
  53. IsACS:=true;
  54. ACSChar:='a';
  55. end;
  56. #180, #181, #182, #185: {´µ¶¹}
  57. begin
  58. IsACS:=true;
  59. ACSChar:='u';
  60. end;
  61. #183, #184, #187, #191: {·¸»¿}
  62. begin
  63. IsACS:=true;
  64. ACSChar:='k';
  65. end;
  66. #188, #189, #190, #217: {¼½¾Ù}
  67. begin
  68. IsACS:=true;
  69. ACSChar:='j';
  70. end;
  71. #192, #200, #211, #212: {ÀÈÓÔ}
  72. begin
  73. IsACS:=true;
  74. ACSChar:='m';
  75. end;
  76. #193, #202, #207, #208: {ÁÊÏÐ}
  77. begin
  78. IsACS:=true;
  79. ACSChar:='v';
  80. end;
  81. #194, #203, #209, #210: {ÂËÑÒ}
  82. begin
  83. IsACS:=true;
  84. ACSChar:='w';
  85. end;
  86. #195, #198, #199, #204: {ÃÆÇÌ}
  87. begin
  88. IsACS:=true;
  89. ACSChar:='t';
  90. end;
  91. #196, #205: {ÄÍ}
  92. begin
  93. IsACS:=true;
  94. ACSChar:='q';
  95. end;
  96. #179, #186: {³º}
  97. begin
  98. IsACS:=true;
  99. ACSChar:='x';
  100. end;
  101. #197, #206, #215, #216: {ÅÎר}
  102. begin
  103. IsACS:=true;
  104. ACSChar:='n';
  105. end;
  106. #201, #213, #214, #218: {ÉÕÖÚ}
  107. begin
  108. IsACS:=true;
  109. ACSChar:='l';
  110. end;
  111. #254: { þ }
  112. begin
  113. ch:='*';
  114. end;
  115. { Shadows for Buttons }
  116. #220: { Ü }
  117. begin
  118. IsACS:=true;
  119. ACSChar:='a';
  120. end;
  121. #223: { ß }
  122. begin
  123. IsACS:=true;
  124. ACSChar:='a';
  125. end;
  126. end;
  127. end;
  128. function SendEscapeSeqNdx(Ndx: Word) : boolean;
  129. var
  130. P,pdelay: PChar;
  131. begin
  132. SendEscapeSeqNdx:=false;
  133. if not assigned(cur_term_Strings) then
  134. exit{RunError(219)};
  135. P:=cur_term_Strings^[Ndx];
  136. if assigned(p) then
  137. begin { Do not transmit the delays }
  138. pdelay:=strpos(p,'$<');
  139. if assigned(pdelay) then
  140. pdelay^:=#0;
  141. fpWrite(stdoutputhandle, P^, StrLen(P));
  142. SendEscapeSeqNdx:=true;
  143. if assigned(pdelay) then
  144. pdelay^:='$';
  145. end;
  146. end;
  147. procedure SendEscapeSeq(const S: String);
  148. begin
  149. fpWrite(stdoutputhandle, S[1], Length(S));
  150. end;
  151. Function IntStr(l:longint):string;
  152. var
  153. s : string;
  154. begin
  155. Str(l,s);
  156. IntStr:=s;
  157. end;
  158. Function XY2Ansi(x,y,ox,oy:longint):String;
  159. {
  160. Returns a string with the escape sequences to go to X,Y on the screen.
  161. Note that x, y, ox, oy are 1-based (i.e. top-left corner of the screen
  162. is (1, 1)), while SetCursorPos parameters and CursorX and CursorY
  163. are 0-based (top-left corner of the screen is (0, 0)).
  164. }
  165. Begin
  166. if y=oy then
  167. begin
  168. if x=ox then
  169. begin
  170. XY2Ansi:='';
  171. exit;
  172. end;
  173. if x=1 then
  174. begin
  175. XY2Ansi:=#13;
  176. exit;
  177. end;
  178. if x>ox then
  179. begin
  180. XY2Ansi:=#27'['+IntStr(x-ox)+'C';
  181. exit;
  182. end
  183. else
  184. begin
  185. XY2Ansi:=#27'['+IntStr(ox-x)+'D';
  186. exit;
  187. end;
  188. end;
  189. if x=ox then
  190. begin
  191. if y>oy then
  192. begin
  193. XY2Ansi:=#27'['+IntStr(y-oy)+'B';
  194. exit;
  195. end
  196. else
  197. begin
  198. XY2Ansi:=#27'['+IntStr(oy-y)+'A';
  199. exit;
  200. end;
  201. end;
  202. if ((x=1) and (oy+1=y)) and (console<>ttyfreebsd) then
  203. XY2Ansi:=#13#10
  204. else
  205. XY2Ansi:=#27'['+IntStr(y)+';'+IntStr(x)+'H';
  206. End;
  207. const
  208. AnsiTbl : string[8]='04261537';
  209. Function Attr2Ansi(Attr,OAttr:longint):string;
  210. {
  211. Convert Attr to an Ansi String, the Optimal code is calculate
  212. with use of the old OAttr
  213. }
  214. var
  215. hstr : string[16];
  216. OFg,OBg,Fg,Bg : longint;
  217. procedure AddSep(ch:char);
  218. begin
  219. if length(hstr)>0 then
  220. hstr:=hstr+';';
  221. hstr:=hstr+ch;
  222. end;
  223. begin
  224. if Attr=OAttr then
  225. begin
  226. Attr2Ansi:='';
  227. exit;
  228. end;
  229. Hstr:='';
  230. Fg:=Attr and $f;
  231. Bg:=Attr shr 4;
  232. OFg:=OAttr and $f;
  233. OBg:=OAttr shr 4;
  234. if (OFg<>7) or (Fg=7) or ((OFg>7) and (Fg<8)) or ((OBg>7) and (Bg<8)) then
  235. begin
  236. hstr:='0';
  237. OFg:=7;
  238. OBg:=0;
  239. end;
  240. if (Fg>7) and (OFg<8) then
  241. begin
  242. AddSep('1');
  243. OFg:=OFg or 8;
  244. end;
  245. if (Bg and 8)<>(OBg and 8) then
  246. begin
  247. AddSep('5');
  248. OBg:=OBg or 8;
  249. end;
  250. if (Fg<>OFg) then
  251. begin
  252. AddSep('3');
  253. hstr:=hstr+AnsiTbl[(Fg and 7)+1];
  254. end;
  255. if (Bg<>OBg) then
  256. begin
  257. AddSep('4');
  258. hstr:=hstr+AnsiTbl[(Bg and 7)+1];
  259. end;
  260. if hstr='0' then
  261. hstr:='';
  262. Attr2Ansi:=#27'['+hstr+'m';
  263. end;
  264. procedure UpdateTTY(Force:boolean);
  265. type
  266. tchattr=packed record
  267. {$ifdef ENDIAN_LITTLE}
  268. ch : char;
  269. attr : byte;
  270. {$else}
  271. attr : byte;
  272. ch : char;
  273. {$endif}
  274. end;
  275. var
  276. outbuf : array[0..1023+255] of char;
  277. chattr : tchattr;
  278. skipped : boolean;
  279. outptr,
  280. spaces,
  281. eol,
  282. x,y,
  283. LastX,LastY,
  284. SpaceAttr,
  285. LastAttr : longint;
  286. p,pold : pvideocell;
  287. LastLineWidth : Longint;
  288. procedure TransformUsingACS(var st : string);
  289. var
  290. res : string;
  291. i : longint;
  292. ch,ACSch : char;
  293. begin
  294. res:='';
  295. for i:=1 to length(st) do
  296. begin
  297. ch:=st[i];
  298. if IsACS(ch,ACSch) then
  299. begin
  300. if not InACS then
  301. begin
  302. res:=res+ACSIn;
  303. InACS:=true;
  304. end;
  305. res:=res+ACSch;
  306. end
  307. else
  308. begin
  309. if InACS then
  310. begin
  311. res:=res+ACSOut+Attr2Ansi(LastAttr,0);
  312. InACS:=false;
  313. end;
  314. res:=res+ch;
  315. end;
  316. end;
  317. st:=res;
  318. end;
  319. procedure outdata(hstr:string);
  320. begin
  321. If Length(HStr)>0 Then
  322. Begin
  323. while (eol>0) do
  324. begin
  325. hstr:=#13#10+hstr;
  326. dec(eol);
  327. end;
  328. if NoExtendedFrame and (ACSIn<>'') and (ACSOut<>'') then
  329. TransformUsingACS(Hstr);
  330. move(hstr[1],outbuf[outptr],length(hstr));
  331. inc(outptr,length(hstr));
  332. if outptr>=1024 then
  333. begin
  334. {$ifdef logging}
  335. blockwrite(f,logstart[1],length(logstart));
  336. blockwrite(f,nl,1);
  337. blockwrite(f,outptr,sizeof(outptr));
  338. blockwrite(f,nl,1);
  339. blockwrite(f,outbuf,outptr);
  340. blockwrite(f,nl,1);
  341. {$endif logging}
  342. fpWrite(stdoutputhandle,outbuf,outptr);
  343. outptr:=0;
  344. end;
  345. end;
  346. end;
  347. procedure OutClr(c:byte);
  348. begin
  349. if c=LastAttr then
  350. exit;
  351. OutData(Attr2Ansi(c,LastAttr));
  352. LastAttr:=c;
  353. end;
  354. procedure OutSpaces;
  355. begin
  356. if (Spaces=0) then
  357. exit;
  358. OutClr(SpaceAttr);
  359. OutData(Space(Spaces));
  360. LastX:=x;
  361. LastY:=y;
  362. Spaces:=0;
  363. end;
  364. function GetTermString(ndx:word):String;
  365. var
  366. P,pdelay: PChar;
  367. begin
  368. GetTermString:='';
  369. if not assigned(cur_term_Strings) then
  370. exit{RunError(219)};
  371. P:=cur_term_Strings^[Ndx];
  372. if assigned(p) then
  373. begin { Do not transmit the delays }
  374. pdelay:=strpos(p,'$<');
  375. if assigned(pdelay) then
  376. pdelay^:=#0;
  377. GetTermString:=StrPas(p);
  378. if assigned(pdelay) then
  379. pdelay^:='$';
  380. end;
  381. end;
  382. begin
  383. OutPtr:=0;
  384. Eol:=0;
  385. skipped:=true;
  386. p:=PVideoCell(VideoBuf);
  387. pold:=PVideoCell(OldVideoBuf);
  388. { init Attr, X,Y and set autowrap off }
  389. SendEscapeSeq(#27'[m'#27'[?7l'{#27'[H'} );
  390. // 1.0.x: SendEscapeSeq(#27'[m'{#27'[H'});
  391. LastAttr:=7;
  392. LastX:=-1;
  393. LastY:=-1;
  394. for y:=1 to ScreenHeight do
  395. begin
  396. SpaceAttr:=0;
  397. Spaces:=0;
  398. LastLineWidth:=ScreenWidth;
  399. If (y=ScreenHeight) And (Console=ttyFreeBSD) {And :am: is on} Then
  400. LastLineWidth:=ScreenWidth-2;
  401. for x:=1 to LastLineWidth do
  402. begin
  403. if (not force) and (p^=pold^) then
  404. begin
  405. if (Spaces>0) then
  406. OutSpaces;
  407. skipped:=true;
  408. end
  409. else
  410. begin
  411. if skipped then
  412. begin
  413. OutData(XY2Ansi(x,y,LastX,LastY));
  414. LastX:=x;
  415. LastY:=y;
  416. skipped:=false;
  417. end;
  418. chattr:=tchattr(p^);
  419. if chattr.ch in [#0,#255] then
  420. chattr.ch:=' ';
  421. if chattr.ch=' ' then
  422. begin
  423. if Spaces=0 then
  424. SpaceAttr:=chattr.Attr;
  425. if (chattr.attr and $f0)=(spaceattr and $f0) then
  426. chattr.Attr:=SpaceAttr
  427. else
  428. begin
  429. OutSpaces;
  430. SpaceAttr:=chattr.Attr;
  431. end;
  432. inc(Spaces);
  433. end
  434. else
  435. begin
  436. if (Spaces>0) then
  437. OutSpaces;
  438. if ord(chattr.ch)<32 then
  439. begin
  440. Chattr.Attr:= $ff xor Chattr.Attr;
  441. ChAttr.ch:= chr(ord(chattr.ch)+ord('A')-1);
  442. end;
  443. if LastAttr<>chattr.Attr then
  444. OutClr(chattr.Attr);
  445. OutData(chattr.ch);
  446. LastX:=x+1;
  447. LastY:=y;
  448. end;
  449. p^:=tvideocell(chattr);
  450. end;
  451. inc(p);
  452. inc(pold);
  453. end;
  454. if (Spaces>0) then
  455. OutSpaces;
  456. if force then
  457. inc(eol)
  458. else
  459. skipped:=true;
  460. end;
  461. eol:=0;
  462. {if am in capabilities? Then}
  463. If (Console=ttyFreeBSD) and (Plongint(p)^<>plongint(pold)^) Then
  464. Begin
  465. OutData(XY2Ansi(ScreenWidth,ScreenHeight,LastX,LastY));
  466. OutData(#8);
  467. {Output last char}
  468. chattr:=tchattr(p[1]);
  469. if LastAttr<>chattr.Attr then
  470. OutClr(chattr.Attr);
  471. OutData(chattr.ch);
  472. inc(LastX);
  473. // OutData(XY2Ansi(ScreenWidth-1,ScreenHeight,LastX,LastY));
  474. // OutData(GetTermString(Insert_character));
  475. OutData(#8+#27+'[1@');
  476. chattr:=tchattr(p^);
  477. if LastAttr<>chattr.Attr then
  478. OutClr(chattr.Attr);
  479. OutData(chattr.ch);
  480. inc(LastX);
  481. end;
  482. OutData(XY2Ansi(CursorX+1,CursorY+1,LastX,LastY));
  483. {$ifdef logging}
  484. blockwrite(f,logstart[1],length(logstart));
  485. blockwrite(f,nl,1);
  486. blockwrite(f,outptr,sizeof(outptr));
  487. blockwrite(f,nl,1);
  488. blockwrite(f,outbuf,outptr);
  489. blockwrite(f,nl,1);
  490. {$endif logging}
  491. fpWrite(stdoutputhandle,outbuf,outptr);
  492. if InACS then
  493. SendEscapeSeqNdx(exit_alt_charset_mode);
  494. {turn autowrap on}
  495. // SendEscapeSeq(#27'[?7h');
  496. end;
  497. var
  498. preInitVideoTio, postInitVideoTio: termio.termios;
  499. inputRaw, outputRaw: boolean;
  500. procedure saveRawSettings(const tio: termio.termios);
  501. Begin
  502. with tio do
  503. begin
  504. inputRaw :=
  505. ((c_iflag and (IGNBRK or BRKINT or PARMRK or ISTRIP or
  506. INLCR or IGNCR or ICRNL or IXON)) = 0) and
  507. ((c_lflag and (ECHO or ECHONL or ICANON or ISIG or IEXTEN)) = 0);
  508. outPutRaw :=
  509. ((c_oflag and OPOST) = 0) and
  510. ((c_cflag and (CSIZE or PARENB)) = 0) and
  511. ((c_cflag and CS8) <> 0);
  512. end;
  513. end;
  514. procedure restoreRawSettings(tio: termio.termios);
  515. begin
  516. with tio do
  517. begin
  518. if inputRaw then
  519. begin
  520. c_iflag := c_iflag and (not (IGNBRK or BRKINT or PARMRK or ISTRIP or
  521. INLCR or IGNCR or ICRNL or IXON));
  522. c_lflag := c_lflag and
  523. (not (ECHO or ECHONL or ICANON or ISIG or IEXTEN));
  524. c_cc[VMIN]:=1;
  525. c_cc[VTIME]:=0;
  526. end;
  527. if outPutRaw then
  528. begin
  529. c_oflag := c_oflag and not(OPOST);
  530. c_cflag := c_cflag and not(CSIZE or PARENB) or CS8;
  531. end;
  532. end;
  533. TCSetAttr(1,TCSANOW,tio);
  534. end;
  535. procedure prepareInitVideo;
  536. begin
  537. TCGetAttr(1,preInitVideoTio);
  538. saveRawSettings(preInitVideoTio);
  539. end;
  540. procedure videoInitDone;
  541. begin
  542. TCGetAttr(1,postInitVideoTio);
  543. restoreRawSettings(postInitVideoTio);
  544. end;
  545. procedure prepareDoneVideo;
  546. var
  547. tio: termio.termios;
  548. begin
  549. TCGetAttr(1,tio);
  550. saveRawSettings(tio);
  551. TCSetAttr(1,TCSANOW,postInitVideoTio);
  552. end;
  553. procedure doneVideoDone;
  554. begin
  555. restoreRawSettings(preInitVideoTio);
  556. end;
  557. procedure SysInitVideo;
  558. const
  559. fontstr : string[3]=#27'(K';
  560. var
  561. ThisTTY: String[30];
  562. FName: String;
  563. WS: packed record
  564. ws_row, ws_col, ws_xpixel, ws_ypixel: Word;
  565. end;
  566. Err: Longint;
  567. prev_term : TerminalCommon_ptr1;
  568. begin
  569. {$ifndef CPUI386}
  570. LowAscii:=false;
  571. {$endif CPUI386}
  572. { check for tty }
  573. ThisTTY:=TTYName(stdinputhandle);
  574. if (IsATTY(stdinputhandle)=1) then
  575. begin
  576. { save current terminal characteristics and remove rawness }
  577. prepareInitVideo;
  578. { write code to set a correct font }
  579. fpWrite(stdoutputhandle,fontstr[1],length(fontstr));
  580. { running on a tty, find out whether locally or remotely }
  581. TTyfd:=-1;
  582. Console:=TTyNetwork; {Default: Network or other vtxxx tty}
  583. if (Copy(ThisTTY, 1, 8) = '/dev/tty') and
  584. not (ThisTTY[9] IN ['p'..'u','P']) then // FreeBSD has these
  585. begin
  586. { running on the console }
  587. Case ThisTTY[9] of
  588. '0'..'9' : begin { running Linux on native console or native-emulation }
  589. FName:='/dev/vcsa' + ThisTTY[9];
  590. { open console, $1b6=rw-rw-rw- }
  591. TTYFd:=fpOpen(FName, $1b6, O_RdWr);
  592. IF TTYFd <>-1 Then
  593. Console:=ttyLinux;
  594. end;
  595. 'v' : { check for (Free?)BSD native}
  596. If (ThisTTY[10]>='0') and (ThisTTY[10]<='9') Then
  597. Console:=ttyFreeBSD; {TTYFd ?}
  598. end;
  599. end;
  600. If (Copy(fpGetEnv('TERM'),1,4)='cons') Then // cons<lines>
  601. Console:=ttyFreeBSD;
  602. If Console<>ttylinux Then
  603. begin
  604. { running on a remote terminal, no error with /dev/vcsa }
  605. LowAscii:=false;
  606. //TTYFd:=stdoutputhandle;
  607. end;
  608. fpioctl(stdinputhandle, TIOCGWINSZ, @WS);
  609. if WS.ws_Col=0 then
  610. WS.ws_Col:=80;
  611. if WS.ws_Row=0 then
  612. WS.ws_Row:=25;
  613. ScreenWidth:=WS.ws_Col;
  614. { TDrawBuffer only has FVMaxWidth elements
  615. larger values lead to crashes }
  616. if ScreenWidth> FVMaxWidth then
  617. ScreenWidth:=FVMaxWidth;
  618. ScreenHeight:=WS.ws_Row;
  619. CursorX:=0;
  620. CursorY:=0;
  621. LastCursorType:=$ff;
  622. ScreenColor:=True;
  623. { Start with a clear screen }
  624. if Console<>ttylinux then
  625. begin
  626. prev_term:=cur_term;
  627. setupterm(nil, stdoutputhandle, err);
  628. can_delete_term:=assigned(prev_term) and (prev_term<>cur_term);
  629. SendEscapeSeqNdx(cursor_home);
  630. SendEscapeSeqNdx(cursor_normal);
  631. SendEscapeSeqNdx(cursor_visible);
  632. SendEscapeSeqNdx(enter_ca_mode);
  633. SetCursorType(crUnderLine);
  634. If Console=ttyFreeBSD Then
  635. SendEscapeSeqNdx(exit_am_mode);
  636. end
  637. else if not assigned(cur_term) then
  638. begin
  639. setupterm(nil, stdoutputhandle, err);
  640. can_delete_term:=false;
  641. end;
  642. if assigned(cur_term_Strings) then
  643. begin
  644. ACSIn:=StrPas(cur_term_Strings^[enter_alt_charset_mode]);
  645. ACSOut:=StrPas(cur_term_Strings^[exit_alt_charset_mode]);
  646. if (ACSIn<>'') and (ACSOut<>'') then
  647. SendEscapeSeqNdx(ena_acs);
  648. if pos('$<',ACSIn)>0 then
  649. ACSIn:=Copy(ACSIn,1,Pos('$<',ACSIn)-1);
  650. if pos('$<',ACSOut)>0 then
  651. ACSOut:=Copy(ACSOut,1,Pos('$<',ACSOut)-1);
  652. If fpGetEnv('TERM')='xterm' then
  653. NoExtendedFrame := true; {use of acs for xterm is ok}
  654. end
  655. else
  656. begin
  657. ACSIn:='';
  658. ACSOut:='';
  659. end;
  660. {$ifdef logging}
  661. assign(f,'video.log');
  662. rewrite(f,1);
  663. {$endif logging}
  664. { save new terminal characteristics and possible restore rawness }
  665. videoInitDone;
  666. end
  667. else
  668. ErrorCode:=errVioInit; { not a TTY }
  669. end;
  670. procedure SysDoneVideo;
  671. begin
  672. prepareDoneVideo;
  673. if Console=ttylinux then
  674. SetCursorPos(0,0)
  675. else
  676. begin
  677. SendEscapeSeqNdx(exit_ca_mode);
  678. SendEscapeSeqNdx(cursor_home);
  679. SendEscapeSeqNdx(cursor_normal);
  680. SendEscapeSeqNdx(cursor_visible);
  681. SetCursorType(crUnderLine);
  682. SendEscapeSeq(#27'[H');
  683. end;
  684. ACSIn:='';
  685. ACSOut:='';
  686. doneVideoDone;
  687. { FreeBSD gives an error here.
  688. According to Pierre this could be more a NCurses version thing that
  689. a FreeBSD one. FreeBSD 4.4 has ncurses 5.
  690. MvdV102003: Since I ran 1.1 with newer FreeBSD without problem, I let it be for now}
  691. if can_delete_term then
  692. begin
  693. del_curterm(cur_term);
  694. can_delete_term:=false;
  695. end;
  696. {$ifdef logging}
  697. close(f);
  698. {$endif logging}
  699. end;
  700. procedure SysClearScreen;
  701. begin
  702. if Console=ttylinux then
  703. UpdateScreen(true)
  704. else
  705. begin
  706. SendEscapeSeq(#27'[0m');
  707. SendEscapeSeqNdx(clear_screen);
  708. end;
  709. end;
  710. procedure SysUpdateScreen(Force: Boolean);
  711. var
  712. DoUpdate : boolean;
  713. i : longint;
  714. p1,p2 : plongint;
  715. begin
  716. if not force then
  717. begin
  718. {$ifdef cpui386}
  719. asm
  720. pushl %esi
  721. pushl %edi
  722. movl VideoBuf,%esi
  723. movl OldVideoBuf,%edi
  724. movl VideoBufSize,%ecx
  725. shrl $2,%ecx
  726. repe
  727. cmpsl
  728. setne DoUpdate
  729. popl %edi
  730. popl %esi
  731. end;
  732. {$else not cpui386}
  733. p1:=plongint(VideoBuf);
  734. p2:=plongint(OldVideoBuf);
  735. for i:=0 to VideoBufSize div 2 do
  736. if (p1^<>p2^) then
  737. begin
  738. DoUpdate:=true;
  739. break;
  740. end
  741. else
  742. begin
  743. { Inc does add sizeof(longint) to both pointer values }
  744. inc(p1);
  745. inc(p2);
  746. end;
  747. {$endif not cpui386}
  748. end
  749. else
  750. DoUpdate:=true;
  751. if not DoUpdate then
  752. exit;
  753. if Console=ttylinux then
  754. begin
  755. fplSeek(TTYFd, 4, Seek_Set);
  756. fpWrite(TTYFd, VideoBuf^,VideoBufSize);
  757. end
  758. else
  759. begin
  760. UpdateTTY(force);
  761. end;
  762. Move(VideoBuf^, OldVideoBuf^, VideoBufSize);
  763. end;
  764. function SysGetCapabilities: Word;
  765. begin
  766. { about cpColor... we should check the terminfo database... }
  767. SysGetCapabilities:=cpUnderLine + cpBlink + cpColor;
  768. end;
  769. procedure SysSetCursorPos(NewCursorX, NewCursorY: Word);
  770. var
  771. Pos : array [1..2] of Byte;
  772. begin
  773. if (CursorX=NewCursorX) and (CursorY=NewCursorY) then
  774. exit;
  775. if Console=ttylinux then
  776. begin
  777. fplSeek(TTYFd, 2, Seek_Set);
  778. Pos[1]:=NewCursorX;
  779. Pos[2]:=NewCursorY;
  780. fpWrite(TTYFd, Pos, 2);
  781. end
  782. else
  783. begin
  784. { newcursorx,y and CursorX,Y are 0 based ! }
  785. SendEscapeSeq(XY2Ansi(NewCursorX+1,NewCursorY+1,CursorX+1,CursorY+1));
  786. end;
  787. CursorX:=NewCursorX;
  788. CursorY:=NewCursorY;
  789. end;
  790. function SysGetCursorType: Word;
  791. begin
  792. SysGetCursorType:=LastCursorType;
  793. end;
  794. procedure SysSetCursorType(NewType: Word);
  795. begin
  796. If LastCursorType=NewType then
  797. exit;
  798. LastCursorType:=NewType;
  799. case NewType of
  800. crBlock :
  801. Begin
  802. If not SendEscapeSeqNdx(cursor_visible) then
  803. If Console<>ttyFreeBSD Then // should be done only for linux?
  804. SendEscapeSeq(#27'[?17;0;64c');
  805. End;
  806. crHidden :
  807. Begin
  808. If not SendEscapeSeqNdx(cursor_invisible) then
  809. If Console<>ttyFreeBSD Then
  810. SendEscapeSeq(#27'[?1c');
  811. End;
  812. else
  813. begin
  814. If not SendEscapeSeqNdx(cursor_normal) then
  815. If Console<>ttyFreeBSD Then
  816. SendEscapeSeq(#27'[?2c');
  817. end;
  818. end;
  819. end;
  820. Const
  821. SysVideoDriver : TVideoDriver = (
  822. InitDriver : @SysInitVideo;
  823. DoneDriver : @SysDoneVideo;
  824. UpdateScreen : @SysUpdateScreen;
  825. ClearScreen : @SysClearScreen;
  826. SetVideoMode : Nil;
  827. GetVideoModeCount : Nil;
  828. GetVideoModeData : Nil;
  829. SetCursorPos : @SysSetCursorPos;
  830. GetCursorType : @SysGetCursorType;
  831. SetCursorType : @SysSetCursorType;
  832. GetCapabilities : @SysGetCapabilities;
  833. );
  834. initialization
  835. SetVideoDriver(SysVideoDriver);
  836. end.