crt.pp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by the Free Pascal development team.
  4. Borland Pascal 7 Compatible CRT Unit - Go32V2 implementation
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit crt;
  12. {$GOTO on}
  13. interface
  14. {$i crth.inc}
  15. Var
  16. ScreenWidth,
  17. ScreenHeight : word;
  18. implementation
  19. uses
  20. dos;
  21. {$ASMMODE INTEL}
  22. var
  23. DelayCnt : Longint;
  24. VidSeg : Word;
  25. {
  26. definition of textrec is in textrec.inc
  27. }
  28. {$i textrec.inc}
  29. {****************************************************************************
  30. Low level Routines
  31. ****************************************************************************}
  32. procedure dosmemfillword(segm, ofs: Word; count: Word; w: Word); assembler;
  33. asm
  34. mov ax, segm
  35. mov es, ax
  36. mov di, ofs
  37. mov ax, w
  38. mov cx, count
  39. rep stosw
  40. end;
  41. procedure dosmemmove(sseg, sofs, dseg, dofs: Word; count: Word); assembler;
  42. asm
  43. mov ax, dseg
  44. mov es, ax
  45. mov di, dofs
  46. mov si, sofs
  47. mov dx, count
  48. mov cx, dx
  49. mov ax, sseg
  50. push ds
  51. mov ds, ax
  52. shr cx, 1
  53. jz @@1
  54. rep movsw
  55. @@1:
  56. and dl, 1
  57. jz @@2
  58. rep movsb
  59. @@2:
  60. pop ds
  61. end;
  62. procedure setscreenmode(mode : byte);
  63. var
  64. regs : registers;
  65. begin
  66. regs.ax:=mode;
  67. intr($10,regs);
  68. end;
  69. function GetScreenHeight : word;
  70. begin
  71. getscreenheight:=mem[$40:$84]+1;
  72. If mem[$40:$84]=0 then
  73. getscreenheight := 25;
  74. end;
  75. function GetScreenWidth : word;
  76. begin
  77. getscreenwidth:=memw[$40:$4a];
  78. end;
  79. procedure SetScreenCursor(x,y : smallint);
  80. var
  81. regs : registers;
  82. begin
  83. regs.ax:=$0200;
  84. regs.bx:=0;
  85. regs.dx:=(y-1) shl 8+(x-1);
  86. intr($10,regs);
  87. end;
  88. procedure GetScreenCursor(var x,y : smallint);
  89. begin
  90. x:=mem[$40:$50]+1;
  91. y:=mem[$40:$51]+1;
  92. end;
  93. procedure DetectSnow;
  94. var
  95. regs: Registers;
  96. ega_switches: Byte;
  97. begin
  98. { the CGA snow bug exists only in 80x25 text modes. The 40x25 text modes and
  99. the graphics modes have no snow even on a true CGA. The monochrome 80x25
  100. text mode (lastmode=7) is not supported by CGA and is not snowy on every
  101. video card that support it (MDA, Hercules, EGA, VGA+) }
  102. if (lastmode<>2) and (lastmode<>3) then
  103. begin
  104. CheckSnow:=false;
  105. exit;
  106. end;
  107. { MCGA/VGA+ test }
  108. regs.ax:=$1A00;
  109. intr($10,regs);
  110. { function supported? }
  111. if regs.al=$1A then
  112. begin
  113. { at this point we have established that an MCGA or VGA+ card is present
  114. in the system. However there could still be two video cards present
  115. (i.e. an oldschool dual monitor configuration), and one of them could be
  116. a CGA, so check BL (=active display code) as well. }
  117. CheckSnow:=regs.bl=2;
  118. exit;
  119. end;
  120. { EGA test }
  121. regs.ah:=$12;
  122. regs.bx:=$FF10;
  123. intr($10,regs);
  124. { function supported? }
  125. if regs.bh<>$FF then
  126. begin
  127. ega_switches:=regs.cl and $0f;
  128. { in all the following cases a CGA card is also present and the EGA only
  129. works in monochrome mode, but we've already checked that we're not in a
  130. monochrome text mode (because lastmode<>7), so it must be the CGA
  131. currently active }
  132. CheckSnow:=(ega_switches=4) { primary CGA 40x25, secondary EGA+ 80x25 mono }
  133. or (ega_switches=5) { primary CGA 80x25, secondary EGA+ 80x25 mono }
  134. or (ega_switches=10) { primary EGA+ 80x25 mono, secondary CGA 40x25 (optional) }
  135. or (ega_switches=11); { primary EGA+ 80x25 mono, secondary CGA 80x25 (optional) }
  136. exit;
  137. end;
  138. CheckSnow:=true;
  139. end;
  140. {****************************************************************************
  141. Helper Routines
  142. ****************************************************************************}
  143. var
  144. WinMin: packed record
  145. X, Y: Byte;
  146. end absolute WindMin;
  147. WinMax: packed record
  148. X, Y: Byte;
  149. end absolute WindMax;
  150. Function FullWin:boolean;
  151. {
  152. Full Screen 80x25? Window(1,1,80,25) is used, allows faster routines
  153. }
  154. begin
  155. FullWin:=(WinMin.X=0) and (WinMin.Y=0) and
  156. (word(WinMax.X+1)=ScreenWidth) and (word(WinMax.Y+1)=ScreenHeight);
  157. end;
  158. {****************************************************************************
  159. Public Crt Functions
  160. ****************************************************************************}
  161. procedure textmode (Mode: word);
  162. var
  163. regs : registers;
  164. begin
  165. lastmode:=mode;
  166. mode:=mode and $ff;
  167. setscreenmode(mode);
  168. { set 8x8 font }
  169. if (lastmode and $100)<>0 then
  170. begin
  171. regs.ax:=$1112;
  172. regs.bx:=$0;
  173. intr($10,regs);
  174. end;
  175. screenwidth:=getscreenwidth;
  176. screenheight:=getscreenheight;
  177. windmin:=0;
  178. windmax:=(screenwidth-1) or ((screenheight-1) shl 8);
  179. DetectSnow;
  180. end;
  181. Procedure TextColor(Color: Byte);
  182. {
  183. Switch foregroundcolor
  184. }
  185. Begin
  186. TextAttr:=(Color and $f) or (TextAttr and $70);
  187. If (Color>15) Then TextAttr:=TextAttr Or Blink;
  188. End;
  189. Procedure TextBackground(Color: Byte);
  190. {
  191. Switch backgroundcolor
  192. }
  193. Begin
  194. TextAttr:=((Color shl 4) and ($f0 and not Blink)) or (TextAttr and ($0f OR Blink) );
  195. End;
  196. Procedure HighVideo;
  197. {
  198. Set highlighted output.
  199. }
  200. Begin
  201. TextColor(TextAttr Or $08);
  202. End;
  203. Procedure LowVideo;
  204. {
  205. Set normal output
  206. }
  207. Begin
  208. TextColor(TextAttr And $77);
  209. End;
  210. Procedure NormVideo;
  211. {
  212. Set normal back and foregroundcolors.
  213. }
  214. Begin
  215. TextColor(7);
  216. TextBackGround(0);
  217. End;
  218. Procedure GotoXy(X: tcrtcoord; Y: tcrtcoord);
  219. {
  220. Go to coordinates X,Y in the current window.
  221. }
  222. Begin
  223. If (X>0) and (X<=WinMax.X- WinMin.X+1) and
  224. (Y>0) and (Y<=WinMax.Y-WinMin.Y+1) Then
  225. Begin
  226. Inc(X,WinMin.X);
  227. Inc(Y,WinMin.Y);
  228. SetScreenCursor(x,y);
  229. End;
  230. End;
  231. Procedure Window(X1, Y1, X2, Y2: Byte);
  232. {
  233. Set screen window to the specified coordinates.
  234. }
  235. Begin
  236. if (X1>X2) or (word(X2)>ScreenWidth) or
  237. (Y1>Y2) or (word(Y2)>ScreenHeight) then
  238. exit;
  239. WindMin:=((Y1-1) Shl 8)+(X1-1);
  240. WindMax:=((Y2-1) Shl 8)+(X2-1);
  241. GoToXY(1,1);
  242. End;
  243. Procedure ClrScr;
  244. {
  245. Clear the current window, and set the cursor on 1,1
  246. }
  247. var
  248. fil : word;
  249. y : word;
  250. begin
  251. fil:=32 or (textattr shl 8);
  252. if FullWin then
  253. DosmemFillWord(VidSeg,0,ScreenHeight*ScreenWidth,fil)
  254. else
  255. begin
  256. for y:=WinMin.Y to WinMax.Y do
  257. DosmemFillWord(VidSeg,(y*ScreenWidth+word(WinMin.X))*2,WinMax.X-WinMin.X+1,fil);
  258. end;
  259. Gotoxy(1,1);
  260. end;
  261. Procedure ClrEol;
  262. {
  263. Clear from current position to end of line.
  264. }
  265. var
  266. x,y : smallint;
  267. fil : word;
  268. Begin
  269. GetScreenCursor(x,y);
  270. fil:=32 or (textattr shl 8);
  271. if x<=(WinMax.X+1) then
  272. DosmemFillword(VidSeg,(word(y-1)*ScreenWidth+word(x-1))*2,WinMax.X-x+2,fil);
  273. End;
  274. Function WhereX: tcrtcoord;
  275. {
  276. Return current X-position of cursor.
  277. }
  278. var
  279. x,y : smallint;
  280. Begin
  281. GetScreenCursor(x,y);
  282. WhereX:=x-WinMin.X;
  283. End;
  284. Function WhereY: tcrtcoord;
  285. {
  286. Return current Y-position of cursor.
  287. }
  288. var
  289. x,y : smallint;
  290. Begin
  291. GetScreenCursor(x,y);
  292. WhereY:=y-WinMin.Y;
  293. End;
  294. {*************************************************************************
  295. KeyBoard
  296. *************************************************************************}
  297. var
  298. keyboard_type: byte; { 0=83/84-key keyboard, $10=101/102+ keyboard }
  299. is_last : boolean;
  300. last : char;
  301. procedure DetectKeyboard;
  302. var
  303. regs: registers;
  304. begin
  305. keyboard_type:=0;
  306. if (Mem[$40:$96] and $10)<>0 then
  307. begin
  308. regs.ax:=$1200;
  309. intr($16,regs);
  310. if regs.ax<>$1200 then
  311. keyboard_type:=$10;
  312. end;
  313. end;
  314. function readkey : char;
  315. var
  316. char2 : char;
  317. char1 : char;
  318. regs : registers;
  319. begin
  320. if is_last then
  321. begin
  322. is_last:=false;
  323. readkey:=last;
  324. end
  325. else
  326. begin
  327. regs.ah:=keyboard_type;
  328. intr($16,regs);
  329. if (regs.al=$e0) and (regs.ah<>0) then
  330. regs.al:=0;
  331. char1:=chr(regs.al);
  332. char2:=chr(regs.ah);
  333. if char1=#0 then
  334. begin
  335. is_last:=true;
  336. last:=char2;
  337. end;
  338. readkey:=char1;
  339. end;
  340. end;
  341. function keypressed : boolean;
  342. var
  343. regs : registers;
  344. begin
  345. if is_last then
  346. begin
  347. keypressed:=true;
  348. exit;
  349. end
  350. else
  351. begin
  352. regs.ah:=keyboard_type+1;
  353. intr($16,regs);
  354. keypressed:=((regs.flags and fZero) = 0);
  355. end;
  356. end;
  357. {*************************************************************************
  358. Delay
  359. *************************************************************************}
  360. procedure Delayloop;assembler;nostackframe;
  361. label
  362. LDelayLoop1, LDelayLoop2;
  363. asm
  364. { input:
  365. es:di = $40:$6c
  366. bx = value of [es:dx] before the call
  367. dx:ax = counter }
  368. LDelayLoop1:
  369. sub ax, 1
  370. sbb dx, 0
  371. jc .LDelayLoop2
  372. cmp bx, word es:[di]
  373. je .LDelayLoop1
  374. LDelayLoop2:
  375. end;
  376. procedure initdelay;
  377. label
  378. LInitDel1;
  379. begin
  380. asm
  381. { for some reason, using int $31/ax=$901 doesn't work here }
  382. { and interrupts are always disabled at this point when }
  383. { running a program inside gdb(pas). Web bug 1345 (JM) }
  384. sti
  385. mov ax, $40
  386. mov es, ax
  387. mov di, $6c
  388. mov bx, es:[di]
  389. LInitDel1:
  390. cmp bx, es:[di]
  391. je LInitDel1
  392. mov bx, es:[di]
  393. mov ax, $FFFF
  394. mov dx, $FFFF
  395. call DelayLoop
  396. mov [DelayCnt], ax
  397. mov [DelayCnt + 2], dx
  398. end ['AX','BX','DX', 'DI'];
  399. DelayCnt := -DelayCnt div $55;
  400. end;
  401. procedure Delay(MS: Word);assembler;
  402. label
  403. LDelay1, LDelay2;
  404. asm
  405. mov ax, $40
  406. mov es, ax
  407. xor di, di
  408. mov cx, MS
  409. test cx, cx
  410. jz LDelay2
  411. mov si, [DelayCnt + 2]
  412. mov bx, es:[di]
  413. LDelay1:
  414. mov ax, [DelayCnt]
  415. mov dx, si
  416. call DelayLoop
  417. loop LDelay1
  418. LDelay2:
  419. end;
  420. procedure sound(hz : word);
  421. label
  422. Lsound_next;
  423. begin
  424. if hz=0 then
  425. begin
  426. nosound;
  427. exit;
  428. end;
  429. asm
  430. mov cx, hz
  431. { dx:ax = 1193046 }
  432. mov ax, $3456
  433. mov dx, $12
  434. div cx
  435. mov cx, ax
  436. in al, $61
  437. test al, 3
  438. jnz Lsound_next
  439. or al, 3
  440. out $61, al
  441. mov al, $b6
  442. out $43, al
  443. Lsound_next:
  444. mov al, cl
  445. out $42, al
  446. mov al, ch
  447. out $42, al
  448. end ['AX','CX','DX'];
  449. end;
  450. procedure nosound; assembler; nostackframe;
  451. asm
  452. in al, $61
  453. and al, $fc
  454. out $61, al
  455. end;
  456. {****************************************************************************
  457. HighLevel Crt Functions
  458. ****************************************************************************}
  459. procedure removeline(y : word);
  460. var
  461. fil : word;
  462. begin
  463. fil:=32 or (textattr shl 8);
  464. y:=WinMin.Y+y;
  465. While (y<=WinMax.Y) do
  466. begin
  467. dosmemmove(VidSeg,(y*ScreenWidth+word(WinMin.X))*2,
  468. VidSeg,((y-1)*ScreenWidth+word(WinMin.X))*2,(WinMax.X-WinMin.X+1)*2);
  469. inc(y);
  470. end;
  471. dosmemfillword(VidSeg,(word(WinMax.Y)*ScreenWidth+word(WinMin.X))*2,(WinMax.X-WinMin.X+1),fil);
  472. end;
  473. procedure delline;
  474. begin
  475. removeline(wherey);
  476. end;
  477. procedure insline;
  478. var
  479. my,y : smallint;
  480. fil : word;
  481. begin
  482. fil:=32 or (textattr shl 8);
  483. y:=WhereY;
  484. my:=WinMax.Y-WinMin.Y;
  485. while (my>=y) do
  486. begin
  487. dosmemmove(VidSeg,(word(WinMin.Y+my-1)*ScreenWidth+word(WinMin.X))*2,
  488. VidSeg,(word(WinMin.Y+my)*ScreenWidth+word(WinMin.X))*2,(WinMax.X-WinMin.X+1)*2);
  489. dec(my);
  490. end;
  491. dosmemfillword(VidSeg,(word(WinMin.Y+y-1)*ScreenWidth+word(WinMin.X))*2,(WinMax.X-WinMin.X+1),fil);
  492. end;
  493. {****************************************************************************
  494. Extra Crt Functions
  495. ****************************************************************************}
  496. procedure cursoron;
  497. var
  498. regs : registers;
  499. begin
  500. regs.ax:=$0100;
  501. If VidSeg=$b800 then
  502. regs.cx:=$0607
  503. else
  504. regs.cx:=$b0d;
  505. intr($10,regs);
  506. end;
  507. procedure cursoroff;
  508. var
  509. regs : registers;
  510. begin
  511. regs.ax:=$0100;
  512. regs.cx:=$2000;
  513. intr($10,regs);
  514. end;
  515. procedure cursorbig;
  516. var
  517. regs : registers;
  518. begin
  519. regs.ax:=$0100;
  520. regs.cx:=$0007;
  521. intr($10,regs);
  522. end;
  523. {*****************************************************************************
  524. Read and Write routines
  525. *****************************************************************************}
  526. var
  527. CurrX,CurrY : smallint;
  528. Procedure VidMemWriteWord(vidmem_offset,w: word);assembler;
  529. label
  530. in_retrace, no_retrace, no_snow, done;
  531. asm
  532. mov di, vidmem_offset
  533. xor ax, ax
  534. mov es, ax
  535. mov dx, es:[$463]
  536. add dx, 6 { DX = CRT Status Register }
  537. mov ax, VidSeg
  538. mov es, ax
  539. test CheckSnow, 1
  540. jz no_snow
  541. mov bx, w
  542. { time critical code follows }
  543. { if you ever need to change this code, make sure you test it on a real }
  544. { 4.77 MHz 8088 with an original IBM CGA card and make sure it doesn't }
  545. { produce snow }
  546. cli
  547. in_retrace:
  548. in al, dx
  549. shr al, 1
  550. jc in_retrace
  551. no_retrace:
  552. in al, dx
  553. shr al, 1
  554. jnc no_retrace
  555. xchg ax, bx
  556. stosw
  557. sti
  558. { time critical code ends here }
  559. jmp done
  560. { separate code path to avoid the unnecessary sti }
  561. no_snow:
  562. mov ax, w
  563. stosw
  564. done:
  565. end;
  566. Procedure WriteChar(c:char);
  567. var
  568. regs : registers;
  569. begin
  570. case c of
  571. #10 : inc(CurrY);
  572. #13 : CurrX:=WinMin.X+1;
  573. #8 : begin
  574. if CurrX>(WinMin.X+1) then
  575. dec(CurrX);
  576. end;
  577. #7 : begin { beep }
  578. regs.dl:=7;
  579. regs.ah:=2;
  580. intr($21,regs);
  581. end;
  582. else
  583. begin
  584. VidMemWriteWord((word(CurrY-1)*ScreenWidth+word(CurrX-1))*2,(textattr shl 8) or byte(c));
  585. inc(CurrX);
  586. end;
  587. end;
  588. if CurrX>(WinMax.X+1) then
  589. begin
  590. CurrX:=(WinMin.X+1);
  591. inc(CurrY);
  592. end;
  593. while CurrY>(WinMax.Y+1) do
  594. begin
  595. removeline(1);
  596. dec(CurrY);
  597. end;
  598. end;
  599. Procedure CrtWrite(var f : textrec);
  600. var
  601. i : smallint;
  602. begin
  603. GetScreenCursor(CurrX,CurrY);
  604. for i:=0 to f.bufpos-1 do
  605. WriteChar(f.buffer[i]);
  606. SetScreenCursor(CurrX,CurrY);
  607. f.bufpos:=0;
  608. end;
  609. Procedure CrtRead(Var F: TextRec);
  610. procedure BackSpace;
  611. begin
  612. if (f.bufpos>0) and (f.bufpos=f.bufend) then
  613. begin
  614. WriteChar(#8);
  615. WriteChar(' ');
  616. WriteChar(#8);
  617. dec(f.bufpos);
  618. dec(f.bufend);
  619. end;
  620. end;
  621. var
  622. ch : Char;
  623. Begin
  624. GetScreenCursor(CurrX,CurrY);
  625. f.bufpos:=0;
  626. f.bufend:=0;
  627. repeat
  628. if f.bufpos>f.bufend then
  629. f.bufend:=f.bufpos;
  630. SetScreenCursor(CurrX,CurrY);
  631. ch:=readkey;
  632. case ch of
  633. #0 : case readkey of
  634. #71 : while f.bufpos>0 do
  635. begin
  636. dec(f.bufpos);
  637. WriteChar(#8);
  638. end;
  639. #75 : if f.bufpos>0 then
  640. begin
  641. dec(f.bufpos);
  642. WriteChar(#8);
  643. end;
  644. #77 : if f.bufpos<f.bufend then
  645. begin
  646. WriteChar(f.bufptr^[f.bufpos]);
  647. inc(f.bufpos);
  648. end;
  649. #79 : while f.bufpos<f.bufend do
  650. begin
  651. WriteChar(f.bufptr^[f.bufpos]);
  652. inc(f.bufpos);
  653. end;
  654. end;
  655. ^S,
  656. #8 : BackSpace;
  657. ^Y,
  658. #27 : begin
  659. while f.bufpos<f.bufend do begin
  660. WriteChar(f.bufptr^[f.bufpos]);
  661. inc(f.bufpos);
  662. end;
  663. while f.bufend>0 do
  664. BackSpace;
  665. end;
  666. #13 : begin
  667. WriteChar(#13);
  668. WriteChar(#10);
  669. f.bufptr^[f.bufend]:=#13;
  670. f.bufptr^[f.bufend+1]:=#10;
  671. inc(f.bufend,2);
  672. break;
  673. end;
  674. #26 : if CheckEOF then
  675. begin
  676. f.bufptr^[f.bufend]:=#26;
  677. inc(f.bufend);
  678. break;
  679. end;
  680. else
  681. begin
  682. if f.bufpos<f.bufsize-2 then
  683. begin
  684. f.buffer[f.bufpos]:=ch;
  685. inc(f.bufpos);
  686. WriteChar(ch);
  687. end;
  688. end;
  689. end;
  690. until false;
  691. f.bufpos:=0;
  692. SetScreenCursor(CurrX,CurrY);
  693. End;
  694. Procedure CrtReturn(Var F: TextRec);
  695. Begin
  696. end;
  697. Procedure CrtClose(Var F: TextRec);
  698. Begin
  699. F.Mode:=fmClosed;
  700. End;
  701. Procedure CrtOpen(Var F: TextRec);
  702. Begin
  703. If F.Mode=fmOutput Then
  704. begin
  705. TextRec(F).InOutFunc:=@CrtWrite;
  706. TextRec(F).FlushFunc:=@CrtWrite;
  707. end
  708. Else
  709. begin
  710. F.Mode:=fmInput;
  711. TextRec(F).InOutFunc:=@CrtRead;
  712. TextRec(F).FlushFunc:=@CrtReturn;
  713. end;
  714. TextRec(F).CloseFunc:=@CrtClose;
  715. End;
  716. procedure AssignCrt(var F: Text);
  717. begin
  718. Assign(F,'');
  719. TextRec(F).OpenFunc:=@CrtOpen;
  720. end;
  721. { use the C version to avoid using dpmiexcp unit
  722. which makes sysutils and exceptions working incorrectly PM }
  723. //function __djgpp_set_ctrl_c(enable : longint) : boolean;cdecl;external;
  724. var
  725. x,y : smallint;
  726. begin
  727. { Detect keyboard type }
  728. DetectKeyboard;
  729. { Load startup values }
  730. ScreenWidth:=GetScreenWidth;
  731. ScreenHeight:=GetScreenHeight;
  732. WindMax:=(ScreenWidth-1) or ((ScreenHeight-1) shl 8);
  733. { Load TextAttr }
  734. GetScreenCursor(x,y);
  735. lastmode := mem[$40:$49];
  736. if screenheight>25 then
  737. lastmode:=lastmode or $100;
  738. DetectSnow;
  739. If not(lastmode=Mono) then
  740. VidSeg := $b800
  741. else
  742. VidSeg := $b000;
  743. TextAttr:=mem[VidSeg:(word(y-1)*ScreenWidth+word(x-1))*2+1];
  744. { Redirect the standard output }
  745. assigncrt(Output);
  746. Rewrite(Output);
  747. TextRec(Output).Handle:=StdOutputHandle;
  748. assigncrt(Input);
  749. Reset(Input);
  750. TextRec(Input).Handle:=StdInputHandle;
  751. { Calculates delay calibration }
  752. initdelay;
  753. { Enable ctrl-c input (JM) }
  754. // __djgpp_set_ctrl_c(0);
  755. end.