video.pp 37 KB

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