video.pp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185
  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. {$I-}
  14. {$GOTO on}
  15. {*****************************************************************************}
  16. interface
  17. {*****************************************************************************}
  18. {$i videoh.inc}
  19. type Tencoding=(cp437, {Codepage 437}
  20. cp850, {Codepage 850}
  21. cp852, {Codepage 852}
  22. cp866, {Codepage 866}
  23. koi8r, {KOI8-R codepage}
  24. iso01, {ISO 8859-1}
  25. iso02, {ISO 8859-2}
  26. iso03, {ISO 8859-3}
  27. iso04, {ISO 8859-4}
  28. iso05, {ISO 8859-5}
  29. iso06, {ISO 8859-6}
  30. iso07, {ISO 8859-7}
  31. iso08, {ISO 8859-8}
  32. iso09, {ISO 8859-9}
  33. iso10, {ISO 8859-10}
  34. iso13, {ISO 8859-13}
  35. iso14, {ISO 8859-14}
  36. iso15); {ISO 8859-15}
  37. const {Contains all code pages that can be considered a normal vga font.
  38. Note: KOI8-R has line drawing characters in wrong place. Support
  39. can perhaps be added, for now we'll let it rest.}
  40. vga_codepages=[cp437,cp850,cp852,cp866];
  41. iso_codepages=[iso01,iso02,iso03,iso04,iso05,iso06,iso07,iso08,
  42. iso09,iso10,iso13,iso14,iso15];
  43. var internal_codepage,external_codepage:Tencoding;
  44. {*****************************************************************************}
  45. implementation
  46. {*****************************************************************************}
  47. uses baseunix,termio,strings
  48. {$ifdef linux},linuxvcs{$endif};
  49. {$i video.inc}
  50. {$i convert.inc}
  51. type Tconsole_type=(ttyNetwork
  52. {$ifdef linux},ttyLinux{$endif}
  53. ,ttyFreeBSD
  54. ,ttyNetBSD);
  55. Tconversion=(cv_none,
  56. cv_cp437_to_iso01,
  57. cv_cp850_to_iso01,
  58. cv_linuxlowascii_to_vga);
  59. Ttermcode=(
  60. enter_alt_charset_mode,
  61. exit_alt_charset_mode,
  62. clear_screen,
  63. cursor_home,
  64. cursor_normal,
  65. cursor_visible_underline,
  66. cursor_visible_block,
  67. cursor_invisible,
  68. enter_ca_mode,
  69. exit_ca_mode,
  70. exit_am_mode,
  71. ena_acs
  72. );
  73. Ttermcodes=array[Ttermcode] of Pchar;
  74. Ptermcodes=^Ttermcodes;
  75. const term_codes_ansi:Ttermcodes=
  76. (#$1B#$5B#$31#$31#$6D, {enter_alt_charset_mode}
  77. #$1B#$5B#$31#$30#$6D, {exit_alt_charset_mode}
  78. #$1B#$5B#$48#$1B#$5B#$4A, {clear_screen}
  79. #$1B#$5B#$48, {cursor_home}
  80. nil, {cursor_normal}
  81. nil, {cursor visible, underline}
  82. nil, {cursor visible, block}
  83. nil, {cursor_invisible}
  84. nil, {enter_ca_mode}
  85. nil, {exit_ca_mode}
  86. nil, {exit_am_mode}
  87. nil); {ena_acs}
  88. term_codes_freebsd:Ttermcodes=
  89. (nil, {enter_alt_charset_mode}
  90. nil, {exit_alt_charset_mode}
  91. #$1B#$5B#$48#$1B#$5B#$4A, {clear_screen}
  92. #$1B#$5B#$48, {cursor_home}
  93. #$1B#$5B#$3D#$30#$43, {cursor_normal}
  94. #$1B#$5B#$3D#$31#$43, {cursor visible, underline}
  95. #$1B#$5B#$3D#$31#$43, {cursor visible, block}
  96. nil, {cursor_invisible}
  97. nil, {enter_ca_mode}
  98. nil, {exit_ca_mode}
  99. nil, {exit_am_mode}
  100. nil); {ena_acs}
  101. term_codes_linux:Ttermcodes=
  102. (#$1B#$5B#$31#$31#$6D, {enter_alt_charset_mode}
  103. #$1B#$5B#$31#$30#$6D, {exit_alt_charset_mode}
  104. #$1B#$5B#$48#$1B#$5B#$4A, {clear_screen}
  105. #$1B#$5B#$48, {cursor_home}
  106. #$1B'[?25h'#$1B'[?0c', {cursor_normal}
  107. #$1B'[?0c', {cursor visible, underline}
  108. #$1B'[?17;0;127c', {cursor visible, block}
  109. #$1B'[?1c', {cursor_invisible}
  110. nil, {enter_ca_mode}
  111. nil, {exit_ca_mode}
  112. nil, {exit_am_mode}
  113. nil); {ena_acs}
  114. term_codes_vt100:Ttermcodes=
  115. (#$0E, {enter_alt_charset_mode}
  116. #$0F, {exit_alt_charset_mode}
  117. #$1B#$5B#$48#$1B#$5B#$4A{#$24#$3C#$35#$30#$3E}, {clear_screen}
  118. #$1B#$5B#$48, {cursor_home}
  119. nil, {cursor_normal}
  120. nil, {cursor visible, underline}
  121. nil, {cursor visible, block}
  122. nil, {cursor_invisible}
  123. nil, {enter_ca_mode}
  124. nil, {exit_ca_mode}
  125. #$1B#$5B#$3F#$37#$6C, {exit_am_mode}
  126. #$1B#$28#$42#$1B#$29#$30); {ena_acs}
  127. term_codes_vt220:Ttermcodes=
  128. (#$1B#$28#$30{#$24#$3C#$32#$3E}, {enter_alt_charset_mode}
  129. #$1B#$28#$42{#$24#$3C#$34#$3E}, {exit_alt_charset_mode}
  130. #$1B#$5B#$48#$1B#$5B#$4A, {clear_screen}
  131. #$1B#$5B#$48, {cursor_home}
  132. nil, {cursor_normal}
  133. nil, {cursor visible, underline}
  134. nil, {cursor visible, block}
  135. nil, {cursor_invisible}
  136. nil, {enter_ca_mode}
  137. nil, {exit_ca_mode}
  138. #$1B#$5B#$3F#$37#$6C, {exit_am_mode}
  139. #$1B#$29#$30); {ena_acs}
  140. term_codes_xterm:Ttermcodes=
  141. (#$0E, {enter_alt_charset_mode}
  142. #$0F, {exit_alt_charset_mode}
  143. #$1B#$5B#$48#$1B#$5B#$32#$4A, {clear_screen}
  144. #$1B#$5B#$48, {cursor_home}
  145. #$1B#$5B#$3F#$31#$32#$6C#$1B#$5B#$3F#$32#$35#$68, {cursor_normal}
  146. #$1B#$5B#$3F#$31#$32#$3B#$32#$35#$68, {cursor visible, underline}
  147. #$1B#$5B#$3F#$31#$32#$3B#$32#$35#$68, {cursor visible, block}
  148. #$1B#$5B#$3F#$32#$35#$6C, {cursor_invisible}
  149. #$1B#$5B#$3F#$31#$30#$34#$39#$68, {enter_ca_mode}
  150. #$1B#$5B#$3F#$31#$30#$34#$39#$6C, {exit_ca_mode}
  151. #$1B#$5B#$3F#$37#$6C, {exit_am_mode}
  152. #$1B#$28#$42#$1B#$29#$30); {ena_acs}
  153. const terminal_names:array[0..8] of string[7]=(
  154. 'ansi',
  155. 'cons',
  156. 'eterm',
  157. 'gnome',
  158. 'konsole',
  159. 'linux',
  160. 'vt100',
  161. 'vt220',
  162. 'xterm');
  163. terminal_data:array[0..8] of Ptermcodes=(
  164. @term_codes_ansi,
  165. @term_codes_freebsd,
  166. @term_codes_xterm,
  167. @term_codes_xterm,
  168. @term_codes_xterm,
  169. @term_codes_linux,
  170. @term_codes_vt100,
  171. @term_codes_vt220,
  172. @term_codes_xterm);
  173. const convert:Tconversion=cv_none;
  174. var
  175. LastCursorType : byte;
  176. TtyFd: Longint;
  177. Console: Tconsole_type;
  178. cur_term_strings:Ptermcodes;
  179. {$ifdef logging}
  180. f: file;
  181. const
  182. logstart: string = '';
  183. nl: char = #10;
  184. logend: string = #10#10;
  185. {$endif logging}
  186. {$ifdef cpui386}
  187. {$ASMMODE ATT}
  188. {$endif cpui386}
  189. const
  190. { can_delete_term : boolean = false;}
  191. ACSIn : string = '';
  192. ACSOut : string = '';
  193. in_ACS : boolean =false;
  194. function convert_vga_to_acs(ch:char):word;
  195. {Ch contains a character in the VGA character set (i.e. codepage 437).
  196. This routine tries to convert some VGA symbols as well as possible to the
  197. xterm alternate character set.
  198. Return type is word to allow expanding to UCS-2 characters in the
  199. future.}
  200. begin
  201. case ch of
  202. #18:
  203. convert_vga_to_acs:=word('|');
  204. #24, #30: {}
  205. convert_vga_to_acs:=word('^');
  206. #25, #31: {}
  207. convert_vga_to_acs:=word('v');
  208. #26, #16: {Never introduce a ctrl-Z ... }
  209. convert_vga_to_acs:=word('>');
  210. {#27,} #17: {}
  211. convert_vga_to_acs:=word('<');
  212. #176, #177, #178: {°±²}
  213. convert_vga_to_acs:=$f800+word('a');
  214. #180, #181, #182, #185: {´µ¶¹}
  215. convert_vga_to_acs:=$f800+word('u');
  216. #183, #184, #187, #191: {·¸»¿}
  217. convert_vga_to_acs:=$f800+word('k');
  218. #188, #189, #190, #217: {¼½¾Ù}
  219. convert_vga_to_acs:=$f800+word('j');
  220. #192, #200, #211, #212: {ÀÈÓÔ}
  221. convert_vga_to_acs:=$f800+word('m');
  222. #193, #202, #207, #208: {ÁÊÏÐ}
  223. convert_vga_to_acs:=$f800+word('v');
  224. #194, #203, #209, #210: {ÂËÑÒ}
  225. convert_vga_to_acs:=$f800+word('w');
  226. #195, #198, #199, #204: {ÃÆÇÌ}
  227. convert_vga_to_acs:=$f800+word('t');
  228. #196, #205: {ÄÍ}
  229. convert_vga_to_acs:=$f800+word('q');
  230. #179, #186: {³º}
  231. convert_vga_to_acs:=$f800+word('x');
  232. #197, #206, #215, #216: {ÅÎר}
  233. convert_vga_to_acs:=$f800+word('n');
  234. #201, #213, #214, #218: {ÉÕÖÚ}
  235. convert_vga_to_acs:=$f800+word('l');
  236. #254: { þ }
  237. convert_vga_to_acs:=word('*');
  238. { Shadows for Buttons }
  239. #220 { Ü },
  240. #223: { ß }
  241. convert_vga_to_acs:=$f800+word('a');
  242. else
  243. convert_vga_to_acs:=word(ch);
  244. end;
  245. end;
  246. procedure SendEscapeSeqNdx(ndx:Ttermcode);
  247. var p:PChar;
  248. begin
  249. { Always true because of vt100 default.
  250. if not assigned(cur_term_Strings) then
  251. exit}{RunError(219)};
  252. p:=cur_term_strings^[ndx];
  253. if p<>nil then
  254. fpwrite(stdoutputhandle,p^,strlen(p));
  255. end;
  256. procedure SendEscapeSeq(const S: String);
  257. begin
  258. fpWrite(stdoutputhandle, S[1], Length(S));
  259. end;
  260. function IntStr(l:longint):string;
  261. begin
  262. Str(l,intstr);
  263. end;
  264. Function XY2Ansi(x,y,ox,oy:longint):String;
  265. {
  266. Returns a string with the escape sequences to go to X,Y on the screen.
  267. Note that x, y, ox, oy are 1-based (i.e. top-left corner of the screen
  268. is (1, 1)), while SetCursorPos parameters and CursorX and CursorY
  269. are 0-based (top-left corner of the screen is (0, 0)).
  270. }
  271. var delta:longint;
  272. direction:char;
  273. movement:string[32];
  274. begin
  275. if ((x=1) and (oy+1=y)) and (console<>ttyfreebsd) then
  276. begin
  277. XY2Ansi:=#13#10;
  278. exit;
  279. end;
  280. direction:='H';
  281. if y=oy then
  282. begin
  283. if x=ox then
  284. begin
  285. XY2Ansi:='';
  286. exit;
  287. end;
  288. if x=1 then
  289. begin
  290. XY2Ansi:=#13;
  291. exit;
  292. end;
  293. delta:=ox-x;
  294. direction:=char(byte('C')+byte(x<=ox));
  295. end;
  296. if x=ox then
  297. begin
  298. delta:=oy-y;
  299. direction:=char(byte('A')+byte(y>oy));
  300. end;
  301. if direction='H' then
  302. movement:=intstr(y)+';'+intstr(x)
  303. else
  304. movement:=intstr(abs(delta));
  305. xy2ansi:=#27'['+movement+direction;
  306. end;
  307. const ansitbl:array[0..7] of char='04261537';
  308. Function Attr2Ansi(Attr,OAttr:longint):string;
  309. {
  310. Convert Attr to an Ansi String, the Optimal code is calculate
  311. with use of the old OAttr
  312. }
  313. var
  314. hstr : string[16];
  315. OFg,OBg,Fg,Bg : longint;
  316. procedure AddSep(ch:char);
  317. begin
  318. if length(hstr)>0 then
  319. hstr:=hstr+';';
  320. hstr:=hstr+ch;
  321. end;
  322. begin
  323. if Attr=OAttr then
  324. begin
  325. Attr2Ansi:='';
  326. exit;
  327. end;
  328. Hstr:='';
  329. Fg:=Attr and $f;
  330. Bg:=Attr shr 4;
  331. OFg:=OAttr and $f;
  332. OBg:=OAttr shr 4;
  333. if (OFg<>7) or (Fg=7) or ((OFg>7) and (Fg<8)) or ((OBg>7) and (Bg<8)) then
  334. begin
  335. hstr:='0';
  336. OFg:=7;
  337. OBg:=0;
  338. end;
  339. if (Fg>7) and (OFg<8) then
  340. begin
  341. AddSep('1');
  342. OFg:=OFg or 8;
  343. end;
  344. if (Bg and 8)<>(OBg and 8) then
  345. begin
  346. AddSep('5');
  347. OBg:=OBg or 8;
  348. end;
  349. if (Fg<>OFg) then
  350. begin
  351. AddSep('3');
  352. hstr:=hstr+AnsiTbl[fg and 7];
  353. end;
  354. if (Bg<>OBg) then
  355. begin
  356. AddSep('4');
  357. hstr:=hstr+AnsiTbl[bg and 7];
  358. end;
  359. if hstr='0' then
  360. hstr:='';
  361. Attr2Ansi:=#27'['+hstr+'m';
  362. end;
  363. procedure UpdateTTY(Force:boolean);
  364. type
  365. tchattr=packed record
  366. {$ifdef ENDIAN_LITTLE}
  367. ch : char;
  368. attr : byte;
  369. {$else}
  370. attr : byte;
  371. ch : char;
  372. {$endif}
  373. end;
  374. var
  375. outbuf : array[0..1023+255] of char;
  376. chattr : tchattr;
  377. skipped : boolean;
  378. outptr,
  379. spaces,
  380. eol,
  381. x,y,
  382. LastX,LastY,
  383. SpaceAttr,
  384. LastAttr : longint;
  385. p,pold : pvideocell;
  386. LastLineWidth : Longint;
  387. function transform_cp437_to_iso01(const st:string):string;
  388. var i:byte;
  389. c:char;
  390. converted:word;
  391. begin
  392. transform_cp437_to_iso01:='';
  393. for i:=1 to length(st) do
  394. begin
  395. c:=st[i];
  396. case c of
  397. #0..#31:
  398. converted:=convert_lowascii_to_iso01[c];
  399. #128..#255:
  400. converted:=convert_cp437_to_iso01[c];
  401. else
  402. converted:=byte(c);
  403. end;
  404. if converted and $ff00=$f800 then
  405. begin
  406. if not in_ACS then
  407. begin
  408. transform_cp437_to_iso01:=transform_cp437_to_iso01+ACSIn;
  409. in_ACS:=true;
  410. end;
  411. c:=char(converted and $ff);
  412. end
  413. else
  414. if in_ACS then
  415. begin
  416. transform_cp437_to_iso01:=transform_cp437_to_iso01+ACSOut+
  417. Attr2Ansi(LastAttr,0);
  418. in_ACS:=false;
  419. end;
  420. transform_cp437_to_iso01:=transform_cp437_to_iso01+c;
  421. end;
  422. end;
  423. function transform_cp850_to_iso01(const st:string):string;
  424. var i:byte;
  425. c:char;
  426. converted:word;
  427. begin
  428. transform_cp850_to_iso01:='';
  429. for i:=1 to length(st) do
  430. begin
  431. c:=st[i];
  432. case c of
  433. #0..#31:
  434. converted:=convert_lowascii_to_iso01[c];
  435. #128..#255:
  436. converted:=convert_cp850_to_iso01[c];
  437. else
  438. converted:=byte(c);
  439. end;
  440. if converted and $ff00=$f800 then
  441. begin
  442. if not in_ACS then
  443. begin
  444. transform_cp850_to_iso01:=transform_cp850_to_iso01+ACSIn;
  445. in_ACS:=true;
  446. end;
  447. end
  448. else
  449. if in_ACS then
  450. begin
  451. transform_cp850_to_iso01:=transform_cp850_to_iso01+ACSOut+
  452. Attr2Ansi(LastAttr,0);
  453. in_ACS:=false;
  454. end;
  455. c:=char(converted and $ff);
  456. transform_cp850_to_iso01:=transform_cp850_to_iso01+c;
  457. end;
  458. end;
  459. function transform_linuxlowascii_to_vga(const st:string):string;
  460. var i:byte;
  461. c:char;
  462. converted:word;
  463. begin
  464. transform_linuxlowascii_to_vga:='';
  465. for i:=1 to length(st) do
  466. begin
  467. c:=st[i];
  468. case c of
  469. #0..#31:
  470. converted:=convert_linuxlowascii_to_vga[c];
  471. else
  472. converted:=byte(c);
  473. end;
  474. c:=char(converted and $ff);
  475. transform_linuxlowascii_to_vga:=transform_linuxlowascii_to_vga+c;
  476. end;
  477. end;
  478. function transform(const hstr:string):string;
  479. begin
  480. case convert of
  481. cv_linuxlowascii_to_vga:
  482. transform:=transform_linuxlowascii_to_vga(hstr);
  483. cv_cp437_to_iso01:
  484. transform:=transform_cp437_to_iso01(hstr);
  485. cv_cp850_to_iso01:
  486. transform:=transform_cp850_to_iso01(hstr);
  487. else
  488. transform:=hstr;
  489. end;
  490. end;
  491. procedure outdata(hstr:string);
  492. begin
  493. If Length(HStr)>0 Then
  494. Begin
  495. while (eol>0) do
  496. begin
  497. hstr:=#13#10+hstr;
  498. dec(eol);
  499. end;
  500. { if (convert=cv_vga_to_acs) and (ACSIn<>'') and (ACSOut<>'') then
  501. transform_using_acs(Hstr);}
  502. move(hstr[1],outbuf[outptr],length(hstr));
  503. inc(outptr,length(hstr));
  504. if outptr>=1024 then
  505. begin
  506. {$ifdef logging}
  507. blockwrite(f,logstart[1],length(logstart));
  508. blockwrite(f,nl,1);
  509. blockwrite(f,outptr,sizeof(outptr));
  510. blockwrite(f,nl,1);
  511. blockwrite(f,outbuf,outptr);
  512. blockwrite(f,nl,1);
  513. {$endif logging}
  514. fpWrite(stdoutputhandle,outbuf,outptr);
  515. outptr:=0;
  516. end;
  517. end;
  518. end;
  519. procedure OutClr(c:byte);
  520. begin
  521. if c=LastAttr then
  522. exit;
  523. OutData(Attr2Ansi(c,LastAttr));
  524. LastAttr:=c;
  525. end;
  526. procedure OutSpaces;
  527. begin
  528. if (Spaces=0) then
  529. exit;
  530. OutClr(SpaceAttr);
  531. OutData(Space(Spaces));
  532. LastX:=x;
  533. LastY:=y;
  534. Spaces:=0;
  535. end;
  536. (*
  537. function GetTermString(ndx:Ttermcode):String;
  538. var
  539. P{,pdelay}: PChar;
  540. begin
  541. GetTermString:='';
  542. if not assigned(cur_term_Strings) then
  543. exit{RunError(219)};
  544. P:=cur_term_Strings^[Ndx];
  545. if assigned(p) then
  546. begin { Do not transmit the delays }
  547. { pdelay:=strpos(p,'$<');
  548. if assigned(pdelay) then
  549. pdelay^:=#0;}
  550. GetTermString:=StrPas(p);
  551. { if assigned(pdelay) then
  552. pdelay^:='$';}
  553. end;
  554. end;
  555. *)
  556. begin
  557. OutPtr:=0;
  558. Eol:=0;
  559. skipped:=true;
  560. p:=PVideoCell(VideoBuf);
  561. pold:=PVideoCell(OldVideoBuf);
  562. { init Attr, X,Y and set autowrap off }
  563. SendEscapeSeq(#27'[m'#27'[?7l'{#27'[H'} );
  564. // 1.0.x: SendEscapeSeq(#27'[m'{#27'[H'});
  565. LastAttr:=7;
  566. LastX:=-1;
  567. LastY:=-1;
  568. for y:=1 to ScreenHeight do
  569. begin
  570. SpaceAttr:=0;
  571. Spaces:=0;
  572. LastLineWidth:=ScreenWidth;
  573. If (y=ScreenHeight) And (Console=ttyFreeBSD) {And :am: is on} Then
  574. LastLineWidth:=ScreenWidth-2;
  575. for x:=1 to LastLineWidth do
  576. begin
  577. if (not force) and (p^=pold^) then
  578. begin
  579. if (Spaces>0) then
  580. OutSpaces;
  581. skipped:=true;
  582. end
  583. else
  584. begin
  585. if skipped then
  586. begin
  587. OutData(XY2Ansi(x,y,LastX,LastY));
  588. LastX:=x;
  589. LastY:=y;
  590. skipped:=false;
  591. end;
  592. chattr:=tchattr(p^);
  593. { if chattr.ch in [#0,#255] then
  594. chattr.ch:=' ';}
  595. if chattr.ch=' ' then
  596. begin
  597. if Spaces=0 then
  598. SpaceAttr:=chattr.Attr;
  599. if (chattr.attr and $f0)=(spaceattr and $f0) then
  600. chattr.Attr:=SpaceAttr
  601. else
  602. begin
  603. OutSpaces;
  604. SpaceAttr:=chattr.Attr;
  605. end;
  606. inc(Spaces);
  607. end
  608. else
  609. begin
  610. if (Spaces>0) then
  611. OutSpaces;
  612. { if ord(chattr.ch)<32 then
  613. begin
  614. Chattr.Attr:= $ff xor Chattr.Attr;
  615. ChAttr.ch:=chr(ord(chattr.ch)+ord('A')-1);
  616. end;}
  617. if LastAttr<>chattr.Attr then
  618. OutClr(chattr.Attr);
  619. OutData(transform(chattr.ch));
  620. LastX:=x+1;
  621. LastY:=y;
  622. end;
  623. p^:=tvideocell(chattr);
  624. end;
  625. inc(p);
  626. inc(pold);
  627. end;
  628. if (Spaces>0) then
  629. OutSpaces;
  630. if force then
  631. inc(eol)
  632. else
  633. skipped:=true;
  634. end;
  635. eol:=0;
  636. {if am in capabilities? Then}
  637. if (Console=ttyFreeBSD) and (Plongint(p)^<>plongint(pold)^) Then
  638. begin
  639. OutData(XY2Ansi(ScreenWidth,ScreenHeight,LastX,LastY));
  640. OutData(#8);
  641. {Output last char}
  642. chattr:=tchattr(p[1]);
  643. if LastAttr<>chattr.Attr then
  644. OutClr(chattr.Attr);
  645. OutData(transform(chattr.ch));
  646. inc(LastX);
  647. // OutData(XY2Ansi(ScreenWidth-1,ScreenHeight,LastX,LastY));
  648. // OutData(GetTermString(Insert_character));
  649. OutData(#8+#27+'[1@');
  650. chattr:=tchattr(p^);
  651. if LastAttr<>chattr.Attr then
  652. OutClr(chattr.Attr);
  653. OutData(transform(chattr.ch));
  654. inc(LastX);
  655. end;
  656. OutData(XY2Ansi(CursorX+1,CursorY+1,LastX,LastY));
  657. {$ifdef logging}
  658. blockwrite(f,logstart[1],length(logstart));
  659. blockwrite(f,nl,1);
  660. blockwrite(f,outptr,sizeof(outptr));
  661. blockwrite(f,nl,1);
  662. blockwrite(f,outbuf,outptr);
  663. blockwrite(f,nl,1);
  664. {$endif logging}
  665. fpWrite(stdoutputhandle,outbuf,outptr);
  666. if in_ACS then
  667. SendEscapeSeqNdx(exit_alt_charset_mode);
  668. {turn autowrap on}
  669. // SendEscapeSeq(#27'[?7h');
  670. end;
  671. {$ifdef linux}
  672. procedure update_vcsa(force:boolean);
  673. const max_updates=64;
  674. label update,update_all,equal_loop,unequal_loop;
  675. var position,update_count,i:word;
  676. update_positions:array[0..max_updates-1] of word;
  677. update_lengths:array[0..max_updates-1] of word;
  678. begin
  679. if force then
  680. goto update_all;
  681. update_count:=0;
  682. i:=0;
  683. equal_loop:
  684. repeat
  685. if videobuf^[i]<>oldvideobuf^[i] then
  686. goto unequal_loop;
  687. inc(i);
  688. until i>videobufsize div 2;
  689. goto update;
  690. unequal_loop:
  691. if update_count>=max_updates then
  692. goto update_all;
  693. update_positions[update_count]:=i;
  694. update_lengths[update_count]:=0;
  695. inc(update_count);
  696. repeat
  697. if videobuf^[i]=oldvideobuf^[i] then
  698. goto equal_loop;
  699. inc(i);
  700. inc(update_lengths[update_count-1]);
  701. until i>videobufsize div 2;
  702. update:
  703. for i:=1 to update_count do
  704. begin
  705. position:=update_positions[i-1];
  706. fppwrite(ttyfd,videobuf^[position],update_lengths[i-1]*2,4+position*2);
  707. end;
  708. exit;
  709. update_all:
  710. fppwrite(ttyfd,videobuf^,videobufsize,4);
  711. end;
  712. {$endif}
  713. var
  714. preInitVideoTio, postInitVideoTio: termio.termios;
  715. inputRaw, outputRaw: boolean;
  716. procedure saveRawSettings(const tio: termio.termios);
  717. begin
  718. with tio do
  719. begin
  720. inputRaw :=
  721. ((c_iflag and (IGNBRK or BRKINT or PARMRK or ISTRIP or
  722. INLCR or IGNCR or ICRNL or IXON)) = 0) and
  723. ((c_lflag and (ECHO or ECHONL or ICANON or ISIG or IEXTEN)) = 0);
  724. outPutRaw :=
  725. ((c_oflag and OPOST) = 0) and
  726. ((c_cflag and (CSIZE or PARENB)) = 0) and
  727. ((c_cflag and CS8) <> 0);
  728. end;
  729. end;
  730. procedure restoreRawSettings(tio: termio.termios);
  731. begin
  732. with tio do
  733. begin
  734. if inputRaw then
  735. begin
  736. c_iflag := c_iflag and (not (IGNBRK or BRKINT or PARMRK or ISTRIP or
  737. INLCR or IGNCR or ICRNL or IXON));
  738. c_lflag := c_lflag and
  739. (not (ECHO or ECHONL or ICANON or ISIG or IEXTEN));
  740. c_cc[VMIN]:=1;
  741. c_cc[VTIME]:=0;
  742. end;
  743. if outPutRaw then
  744. begin
  745. c_oflag := c_oflag and not(OPOST);
  746. c_cflag := c_cflag and not(CSIZE or PARENB) or CS8;
  747. end;
  748. end;
  749. TCSetAttr(1,TCSANOW,tio);
  750. end;
  751. procedure decide_codepages;
  752. var s:string;
  753. begin
  754. {$ifdef linux}
  755. if console=ttyLinux then
  756. begin
  757. s:=upcase(fpgetenv('CONSOLEFONT_CP'));
  758. if s='CP437' then
  759. external_codepage:=cp437
  760. else if s='CP850' then
  761. external_codepage:=cp850;
  762. end;
  763. {$endif}
  764. {A non-vcsa Linux console can display most control characters, but not all.}
  765. if {$ifdef linux}(console<>ttyLinux) and{$endif}
  766. (cur_term_strings=@term_codes_linux) then
  767. convert:=cv_linuxlowascii_to_vga;
  768. case external_codepage of
  769. iso01: {West Europe}
  770. begin
  771. internal_codepage:=cp850;
  772. convert:=cv_cp850_to_iso01;
  773. end;
  774. iso02: {East Europe}
  775. internal_codepage:=cp852;
  776. iso05: {Cyrillic}
  777. internal_codepage:=cp866;
  778. else
  779. if internal_codepage in vga_codepages then
  780. internal_codepage:=external_codepage
  781. else
  782. {We don't know how to convert to the external codepage. Use codepage
  783. 437 in the hope that the actual font has similarity to codepage 437.}
  784. internal_codepage:=cp437;
  785. end;
  786. end;
  787. procedure prepareInitVideo;
  788. begin
  789. TCGetAttr(1,preInitVideoTio);
  790. saveRawSettings(preInitVideoTio);
  791. end;
  792. procedure videoInitDone;
  793. begin
  794. TCGetAttr(1,postInitVideoTio);
  795. restoreRawSettings(postInitVideoTio);
  796. end;
  797. procedure prepareDoneVideo;
  798. var
  799. tio: termio.termios;
  800. begin
  801. TCGetAttr(1,tio);
  802. saveRawSettings(tio);
  803. TCSetAttr(1,TCSANOW,postInitVideoTio);
  804. end;
  805. procedure doneVideoDone;
  806. begin
  807. restoreRawSettings(preInitVideoTio);
  808. end;
  809. procedure SysInitVideo;
  810. var
  811. FName: String;
  812. WS: packed record
  813. ws_row, ws_col, ws_xpixel, ws_ypixel: Word;
  814. end;
  815. { Err: Longint;}
  816. { prev_term : TerminalCommon_ptr1;}
  817. term:string;
  818. i:word;
  819. {$ifdef Linux}
  820. s:string[15];
  821. {$endif}
  822. {$ifdef freebsd}
  823. ThisTTY: String[30];
  824. {$endif}
  825. const font_vga:array[0..11] of char=#15#27'%@'#27'(U'#27'[3h';
  826. font_custom:array[0..2] of char=#27'(K';
  827. begin
  828. { check for tty }
  829. if (IsATTY(stdinputhandle)=1) then
  830. begin
  831. { save current terminal characteristics and remove rawness }
  832. prepareInitVideo;
  833. { running on a tty, find out whether locally or remotely }
  834. TTyfd:=-1;
  835. Console:=TTyNetwork; {Default: Network or other vtxxx tty}
  836. cur_term_strings:=@term_codes_vt100; {Default: vt100}
  837. external_codepage:=iso01; {Default: ISO-8859-1}
  838. {$ifdef linux}
  839. if vcs_device>=0 then
  840. begin
  841. str(vcs_device,s);
  842. fname:='/dev/vcsa'+s;
  843. { open console, $1b6=rw-rw-rw- }
  844. ttyfd:=fpopen(fname,$1b6,O_RDWR);
  845. if ttyfd<>-1 then
  846. console:=ttylinux
  847. else
  848. if try_grab_vcsa then
  849. begin
  850. ttyfd:=fpopen(fname,$1b6,O_RDWR);
  851. if ttyfd<>-1 then
  852. begin
  853. console:=ttylinux;
  854. external_codepage:=cp437; {VCSA defaults to codepage 437.}
  855. end;
  856. end;
  857. end;
  858. {$endif}
  859. {$ifdef freebsd}
  860. ThisTTY:=TTYName(stdinputhandle);
  861. if copy(ThisTTY, 1, 9) = '/dev/ttyv' then {FreeBSD has these}
  862. begin
  863. { check for (Free?)BSD native}
  864. if (ThisTTY[10]>='0') and (ThisTTY[10]<='9') Then
  865. Console:=ttyFreeBSD; {TTYFd ?}
  866. end;
  867. {$endif}
  868. term:=fpgetenv('TERM');
  869. for i:=low(terminal_names) to high(terminal_names) do
  870. if copy(term,1,length(terminal_names[i]))=terminal_names[i] then
  871. cur_term_strings:=terminal_data[i];
  872. if cur_term_strings=@term_codes_freebsd then
  873. console:=ttyFreeBSD;
  874. {$ifdef linux}
  875. if (console<>ttylinux) then
  876. begin
  877. {$endif}
  878. if cur_term_strings=@term_codes_linux then
  879. begin
  880. {Executed in case ttylinux is false (i.e. no vcsa), but
  881. TERM=linux.}
  882. {Enable the VGA character set (codepage 437,850,....)}
  883. fpwrite(stdoutputhandle,font_vga,sizeof(font_vga));
  884. external_codepage:=cp437; {Now default to codepage 437.}
  885. end
  886. else
  887. {No VGA font :( }
  888. fpwrite(stdoutputhandle,font_custom,sizeof(font_vga));
  889. { running on a remote terminal, no error with /dev/vcsa }
  890. {$ifdef linux}
  891. end;
  892. {$endif}
  893. fpioctl(stdinputhandle, TIOCGWINSZ, @WS);
  894. if WS.ws_Col=0 then
  895. WS.ws_Col:=80;
  896. if WS.ws_Row=0 then
  897. WS.ws_Row:=25;
  898. ScreenWidth:=WS.ws_Col;
  899. { TDrawBuffer only has FVMaxWidth elements
  900. larger values lead to crashes }
  901. if ScreenWidth> FVMaxWidth then
  902. ScreenWidth:=FVMaxWidth;
  903. ScreenHeight:=WS.ws_Row;
  904. CursorX:=0;
  905. CursorY:=0;
  906. LastCursorType:=$ff;
  907. ScreenColor:=True;
  908. { Start with a clear screen }
  909. {$ifdef linux}
  910. if Console<>ttylinux then
  911. begin
  912. {$endif}
  913. SendEscapeSeqNdx(cursor_home);
  914. SendEscapeSeqNdx(cursor_normal);
  915. SendEscapeSeqNdx(cursor_visible_underline);
  916. SendEscapeSeqNdx(enter_ca_mode);
  917. SetCursorType(crUnderLine);
  918. If Console=ttyFreeBSD Then
  919. SendEscapeSeqNdx(exit_am_mode);
  920. {$ifdef linux}
  921. end;
  922. {$endif}
  923. { Always true because of vt100 default...
  924. if assigned(cur_term_Strings) then
  925. begin}
  926. ACSIn:=StrPas(cur_term_strings^[enter_alt_charset_mode]);
  927. ACSOut:=StrPas(cur_term_strings^[exit_alt_charset_mode]);
  928. if (ACSIn<>'') and (ACSOut<>'') then
  929. SendEscapeSeqNdx(ena_acs);
  930. (* If fpGetEnv('TERM')='xterm' then
  931. convert:=cv_vga_to_acs; {use of acs for xterm is ok}*)
  932. { end
  933. else
  934. begin
  935. ACSIn:='';
  936. ACSOut:='';
  937. end;}
  938. {$ifdef logging}
  939. assign(f,'video.log');
  940. rewrite(f,1);
  941. {$endif logging}
  942. { save new terminal characteristics and possible restore rawness }
  943. videoInitDone;
  944. end
  945. else
  946. ErrorCode:=errVioInit; { not a TTY }
  947. decide_codepages;
  948. end;
  949. procedure SysDoneVideo;
  950. var font_custom:array[0..2] of char=#27'(K';
  951. begin
  952. prepareDoneVideo;
  953. SetCursorType(crUnderLine);
  954. {$ifdef linux}
  955. if Console=ttylinux then
  956. SetCursorPos(0,0)
  957. else
  958. begin
  959. {$endif}
  960. SendEscapeSeqNdx(exit_ca_mode);
  961. SendEscapeSeqNdx(cursor_home);
  962. SendEscapeSeqNdx(cursor_normal);
  963. SendEscapeSeqNdx(cursor_visible_underline);
  964. SendEscapeSeq(#27'[H');
  965. if cur_term_strings=@term_codes_linux then
  966. begin
  967. {Executed in case ttylinux is false (i.e. no vcsa), but
  968. TERM=linux.}
  969. {Enable the character set set through setfont}
  970. fpwrite(stdoutputhandle,font_custom,3);
  971. end;
  972. {$ifdef linux}
  973. end;
  974. {$endif}
  975. ACSIn:='';
  976. ACSOut:='';
  977. doneVideoDone;
  978. {$ifdef logging}
  979. close(f);
  980. {$endif logging}
  981. end;
  982. procedure SysClearScreen;
  983. begin
  984. {$ifdef linux}
  985. if Console=ttylinux then
  986. UpdateScreen(true)
  987. else
  988. begin
  989. {$endif}
  990. SendEscapeSeq(#27'[0m');
  991. SendEscapeSeqNdx(clear_screen);
  992. {$ifdef linux}
  993. end;
  994. {$endif}
  995. end;
  996. procedure SysUpdateScreen(Force: Boolean);
  997. var
  998. DoUpdate : boolean;
  999. i : longint;
  1000. p1,p2 : plongint;
  1001. begin
  1002. {$ifdef linux}
  1003. if console=ttylinux then
  1004. update_vcsa(force)
  1005. else
  1006. {$endif}
  1007. updateTTY(force);
  1008. move(VideoBuf^,OldVideoBuf^,VideoBufSize);
  1009. end;
  1010. function SysGetCapabilities: Word;
  1011. begin
  1012. { about cpColor... we should check the terminfo database... }
  1013. SysGetCapabilities:=cpUnderLine + cpBlink + cpColor;
  1014. end;
  1015. procedure SysSetCursorPos(NewCursorX, NewCursorY: Word);
  1016. var
  1017. Pos : array [1..2] of Byte;
  1018. begin
  1019. if (CursorX=NewCursorX) and (CursorY=NewCursorY) then
  1020. exit;
  1021. {$ifdef linux}
  1022. if Console=ttylinux then
  1023. begin
  1024. Pos[1]:=NewCursorX;
  1025. Pos[2]:=NewCursorY;
  1026. fppwrite(ttyfd,pos,2,2);
  1027. end
  1028. else
  1029. {$endif}
  1030. { newcursorx,y and CursorX,Y are 0 based ! }
  1031. SendEscapeSeq(XY2Ansi(NewCursorX+1,NewCursorY+1,CursorX+1,CursorY+1));
  1032. CursorX:=NewCursorX;
  1033. CursorY:=NewCursorY;
  1034. end;
  1035. function SysGetCursorType: Word;
  1036. begin
  1037. SysGetCursorType:=LastCursorType;
  1038. end;
  1039. procedure SysSetCursorType(NewType: Word);
  1040. begin
  1041. If LastCursorType=NewType then
  1042. exit;
  1043. LastCursorType:=NewType;
  1044. case NewType of
  1045. crBlock:
  1046. SendEscapeSeqNdx(cursor_visible_block);
  1047. crHidden:
  1048. SendEscapeSeqNdx(cursor_invisible);
  1049. else
  1050. SendEscapeSeqNdx(cursor_normal);
  1051. end;
  1052. end;
  1053. Const
  1054. SysVideoDriver : TVideoDriver = (
  1055. InitDriver : @SysInitVideo;
  1056. DoneDriver : @SysDoneVideo;
  1057. UpdateScreen : @SysUpdateScreen;
  1058. ClearScreen : @SysClearScreen;
  1059. SetVideoMode : Nil;
  1060. GetVideoModeCount : Nil;
  1061. GetVideoModeData : Nil;
  1062. SetCursorPos : @SysSetCursorPos;
  1063. GetCursorType : @SysGetCursorType;
  1064. SetCursorType : @SysSetCursorType;
  1065. GetCapabilities : @SysGetCapabilities;
  1066. );
  1067. initialization
  1068. SetVideoDriver(SysVideoDriver);
  1069. end.