home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / tpw / doc / wincrt.pas < prev    next >
Pascal/Delphi Source File  |  1991-05-20  |  19KB  |  773 lines

  1.  
  2. {*******************************************************}
  3. {                                                       }
  4. {       Turbo Pascal Runtime Library                    }
  5. {       Windows CRT Interface Unit                      }
  6. {                                                       }
  7. {       Copyright (c) 1991 Borland International        }
  8. {                                                       }
  9. {*******************************************************}
  10.  
  11. unit WinCrt;
  12.  
  13. {$S-}
  14.  
  15. interface
  16.  
  17. uses WinTypes, WinProcs, WinDos;
  18.  
  19. const
  20.   WindowOrg: TPoint =                       { CRT window origin }
  21.     (X: cw_UseDefault; Y: cw_UseDefault);
  22.   WindowSize: TPoint =                      { CRT window size }
  23.     (X: cw_UseDefault; Y: cw_UseDefault);
  24.   ScreenSize: TPoint = (X: 80; Y: 25);      { Screen buffer dimensions }
  25.   Cursor: TPoint = (X: 0; Y: 0);            { Cursor location }
  26.   Origin: TPoint = (X: 0; Y: 0);            { Client area origin }
  27.   InactiveTitle: PChar = '(Inactive %s)';   { Inactive window title }
  28.   AutoTracking: Boolean = True;             { Track cursor on Write? }
  29.   CheckEOF: Boolean = False;                { Allow Ctrl-Z for EOF? }
  30.   CheckBreak: Boolean = True;               { Allow Ctrl-C for break? }
  31.  
  32. var
  33.   WindowTitle: array[0..79] of Char;        { CRT window title }
  34.  
  35. procedure InitWinCrt;
  36. procedure DoneWinCrt;
  37.  
  38. procedure WriteBuf(Buffer: PChar; Count: Word);
  39. procedure WriteChar(Ch: Char);
  40.  
  41. function KeyPressed: Boolean;
  42. function ReadKey: Char;
  43. function ReadBuf(Buffer: PChar; Count: Word): Word;
  44.  
  45. procedure GotoXY(X, Y: Integer);
  46. function WhereX: Integer;
  47. function WhereY: Integer;
  48. procedure ClrScr;
  49. procedure ClrEol;
  50.  
  51. procedure CursorTo(X, Y: Integer);
  52. procedure ScrollTo(X, Y: Integer);
  53. procedure TrackCursor;
  54.  
  55. procedure AssignCrt(var F: Text);
  56.  
  57. implementation
  58.  
  59. { Double word record }
  60.  
  61. type
  62.   LongRec = record
  63.     Lo, Hi: Integer;
  64.   end;
  65.  
  66. { MinMaxInfo array }
  67.  
  68. type
  69.   PMinMaxInfo = ^TMinMaxInfo;
  70.   TMinMaxInfo = array[0..4] of TPoint;
  71.  
  72. { Scroll key definition record }
  73.  
  74. type
  75.   TScrollKey = record
  76.     Key: Byte;
  77.     Ctrl: Boolean;
  78.     SBar: Byte;
  79.     Action: Byte;
  80.   end;
  81.  
  82. { CRT window procedure }
  83.  
  84. function CrtWinProc(Window: HWnd; Message, WParam: Word;
  85.   LParam: Longint): Longint; export; forward;
  86.  
  87. { CRT window class }
  88.  
  89. const
  90.   CrtClass: TWndClass = (
  91.     style: cs_HRedraw + cs_VRedraw;
  92.     lpfnWndProc: @CrtWinProc;
  93.     cbClsExtra: 0;
  94.     cbWndExtra: 0;
  95.     hInstance: 0;
  96.     hIcon: 0;
  97.     hCursor: 0;
  98.     hbrBackground: 0;
  99.     lpszMenuName: nil;
  100.     lpszClassName: 'TPWinCrt');
  101.  
  102. const
  103.   CrtWindow: HWnd = 0;                  { CRT window handle }
  104.   FirstLine: Integer = 0;               { First line in circular buffer }
  105.   KeyCount: Integer = 0;                { Count of keys in KeyBuffer }
  106.   Created: Boolean = False;           { CRT window created? }
  107.   Focused: Boolean = False;             { CRT window focused? }
  108.   Reading: Boolean = False;             { Reading from CRT window? }
  109.   Painting: Boolean = False;            { Handling wm_Paint? }
  110.  
  111. var
  112.   SaveExit: Pointer;                    { Saved exit procedure pointer }
  113.   ScreenBuffer: PChar;                  { Screen buffer pointer }
  114.   ClientSize: TPoint;                   { Client area dimensions }
  115.   Range: TPoint;                        { Scroll bar ranges }
  116.   CharSize: TPoint;                     { Character cell size }
  117.   CharAscent: Integer;                  { Character ascent }
  118.   DC: HDC;                              { Global device context }
  119.   PS: TPaintStruct;                     { Global paint structure }
  120.   SaveFont: HFont;                      { Saved device context font }
  121.   KeyBuffer: array[0..63] of Char;      { Keyboard type-ahead buffer }
  122.  
  123. { Scroll keys table }
  124.  
  125. const
  126.   ScrollKeyCount = 12;
  127.   ScrollKeys: array[1..ScrollKeyCount] of TScrollKey = (
  128.     (Key: vk_Left;  Ctrl: False; SBar: sb_Horz; Action: sb_LineUp),
  129.     (Key: vk_Right; Ctrl: False; SBar: sb_Horz; Action: sb_LineDown),
  130.     (Key: vk_Left;  Ctrl: True;  SBar: sb_Horz; Action: sb_PageUp),
  131.     (Key: vk_Right; Ctrl: True;  SBar: sb_Horz; Action: sb_PageDown),
  132.     (Key: vk_Home;  Ctrl: False; SBar: sb_Horz; Action: sb_Top),
  133.     (Key: vk_End;   Ctrl: False; SBar: sb_Horz; Action: sb_Bottom),
  134.     (Key: vk_Up;    Ctrl: False; SBar: sb_Vert; Action: sb_LineUp),
  135.     (Key: vk_Down;  Ctrl: False; SBar: sb_Vert; Action: sb_LineDown),
  136.     (Key: vk_Prior; Ctrl: False; SBar: sb_Vert; Action: sb_PageUp),
  137.     (Key: vk_Next;  Ctrl: False; SBar: sb_Vert; Action: sb_PageDown),
  138.     (Key: vk_Home;  Ctrl: True;  SBar: sb_Vert; Action: sb_Top),
  139.     (Key: vk_End;   Ctrl: True;  SBar: sb_Vert; Action: sb_Bottom));
  140.  
  141. { Return the smaller of two integer values }
  142.  
  143. function Min(X, Y: Integer): Integer;
  144. begin
  145.   if X < Y then Min := X else Min := Y;
  146. end;
  147.  
  148. { Return the larger of two integer values }
  149.  
  150. function Max(X, Y: Integer): Integer;
  151. begin
  152.   if X > Y then Max := X else Max := Y;
  153. end;
  154.  
  155. { Allocate device context }
  156.  
  157. procedure InitDeviceContext;
  158. begin
  159.   if Painting then
  160.     DC := BeginPaint(CrtWindow, PS) else
  161.     DC := GetDC(CrtWindow);
  162.   SaveFont := SelectObject(DC, GetStockObject(System_Fixed_Font));
  163. end;
  164.  
  165. { Release device context }
  166.  
  167. procedure DoneDeviceContext;
  168. begin
  169.   SelectObject(DC, SaveFont);
  170.   if Painting then
  171.     EndPaint(CrtWindow, PS) else
  172.     ReleaseDC(CrtWindow, DC);
  173. end;
  174.  
  175. { Show caret }
  176.  
  177. procedure ShowCursor;
  178. begin
  179.   CreateCaret(CrtWindow, 0, CharSize.X, 2);
  180.   SetCaretPos((Cursor.X - Origin.X) * CharSize.X,
  181.     (Cursor.Y - Origin.Y) * CharSize.Y + CharAscent);
  182.   ShowCaret(CrtWindow);
  183. end;
  184.  
  185. { Hide caret }
  186.  
  187. procedure HideCursor;
  188. begin
  189.   DestroyCaret;
  190. end;
  191.  
  192. { Update scroll bars }
  193.  
  194. procedure SetScrollBars;
  195. begin
  196.   SetScrollRange(CrtWindow, sb_Horz, 0, Max(1, Range.X), False);
  197.   SetScrollPos(CrtWindow, sb_Horz, Origin.X, True);
  198.   SetScrollRange(CrtWindow, sb_Vert, 0, Max(1, Range.Y), False);
  199.   SetScrollPos(CrtWindow, sb_Vert, Origin.Y, True);
  200. end;
  201.  
  202. { Terminate CRT window }
  203.  
  204. procedure Terminate;
  205. begin
  206.   if Focused and Reading then HideCursor;
  207.   Halt(255);
  208. end;
  209.  
  210. { Set cursor position }
  211.  
  212. procedure CursorTo(X, Y: Integer);
  213. begin
  214.   Cursor.X := Max(0, Min(X, ScreenSize.X - 1));
  215.   Cursor.Y := Max(0, Min(Y, ScreenSize.Y - 1));
  216. end;
  217.  
  218. { Scroll window to given origin }
  219.  
  220. procedure ScrollTo(X, Y: Integer);
  221. begin
  222.   if Created then
  223.   begin
  224.     X := Max(0, Min(X, Range.X));
  225.     Y := Max(0, Min(Y, Range.Y));
  226.     if (X <> Origin.X) or (Y <> Origin.Y) then
  227.     begin
  228.       if X <> Origin.X then SetScrollPos(CrtWindow, sb_Horz, X, True);
  229.       if Y <> Origin.Y then SetScrollPos(CrtWindow, sb_Vert, Y, True);
  230.       ScrollWindow(CrtWindow,
  231.     (Origin.X - X) * CharSize.X,
  232.     (Origin.Y - Y) * CharSize.Y, nil, nil);
  233.       Origin.X := X;
  234.       Origin.Y := Y;
  235.       UpdateWindow(CrtWindow);
  236.     end;
  237.   end;
  238. end;
  239.  
  240. { Scroll to make cursor visible }
  241.  
  242. procedure TrackCursor;
  243. begin
  244.   ScrollTo(Max(Cursor.X - ClientSize.X + 1, Min(Origin.X, Cursor.X)),
  245.     Max(Cursor.Y - ClientSize.Y + 1, Min(Origin.Y, Cursor.Y)));
  246. end;
  247.  
  248. { Return pointer to location in screen buffer }
  249.  
  250. function ScreenPtr(X, Y: Integer): PChar;
  251. begin
  252.   Inc(Y, FirstLine);
  253.   if Y >= ScreenSize.Y then Dec(Y, ScreenSize.Y);
  254.   ScreenPtr := @ScreenBuffer[Y * ScreenSize.X + X];
  255. end;
  256.  
  257. { Update text on cursor line }
  258.  
  259. procedure ShowText(L, R: Integer);
  260. begin
  261.   if L < R then
  262.   begin
  263.     InitDeviceContext;
  264.     TextOut(DC, (L - Origin.X) * CharSize.X,
  265.       (Cursor.Y - Origin.Y) * CharSize.Y,
  266.       ScreenPtr(L, Cursor.Y), R - L);
  267.     DoneDeviceContext;
  268.   end;
  269. end;
  270.  
  271. { Write text buffer to CRT window }
  272.  
  273. procedure WriteBuf(Buffer: PChar; Count: Word);
  274. var
  275.   L, R: Integer;
  276.  
  277. procedure NewLine;
  278. begin
  279.   ShowText(L, R);
  280.   L := 0;
  281.   R := 0;
  282.   Cursor.X := 0;
  283.   Inc(Cursor.Y);
  284.   if Cursor.Y = ScreenSize.Y then
  285.   begin
  286.     Dec(Cursor.Y);
  287.     Inc(FirstLine);
  288.     if FirstLine = ScreenSize.Y then FirstLine := 0;
  289.     FillChar(ScreenPtr(0, Cursor.Y)^, ScreenSize.X, ' ');
  290.     ScrollWindow(CrtWindow, 0, -CharSize.Y, nil, nil);
  291.     UpdateWindow(CrtWindow);
  292.   end;
  293. end;
  294.  
  295. begin
  296.   InitWinCrt;
  297.   L := Cursor.X;
  298.   R := Cursor.X;
  299.   while Count > 0 do
  300.   begin
  301.     case Buffer^ of
  302.       #32..#255:
  303.     begin
  304.       ScreenPtr(Cursor.X, Cursor.Y)^ := Buffer^;
  305.       Inc(Cursor.X);
  306.       if Cursor.X > R then R := Cursor.X;
  307.       if Cursor.X = ScreenSize.X then NewLine;
  308.     end;
  309.       #13:
  310.     NewLine;
  311.       #8:
  312.     if Cursor.X > 0 then
  313.     begin
  314.       Dec(Cursor.X);
  315.       ScreenPtr(Cursor.X, Cursor.Y)^ := ' ';
  316.       if Cursor.X < L then L := Cursor.X;
  317.     end;
  318.       #7:
  319.         MessageBeep(0);
  320.     end;
  321.     Inc(Buffer);
  322.     Dec(Count);
  323.   end;
  324.   ShowText(L, R);
  325.   if AutoTracking then TrackCursor;
  326. end;
  327.  
  328. { Write character to CRT window }
  329.  
  330. procedure WriteChar(Ch: Char);
  331. begin
  332.   WriteBuf(@Ch, 1);
  333. end;
  334.  
  335. { Return keyboard status }
  336.  
  337. function KeyPressed: Boolean;
  338. var
  339.   M: TMsg;
  340. begin
  341.   InitWinCrt;
  342.   while PeekMessage(M, 0, 0, 0, pm_Remove) do
  343.   begin
  344.     if M.Message = wm_Quit then Terminate;
  345.     TranslateMessage(M);
  346.     DispatchMessage(M);
  347.   end;
  348.   KeyPressed := KeyCount > 0;
  349. end;
  350.  
  351. { Read key from CRT window }
  352.  
  353. function ReadKey: Char;
  354. begin
  355.   TrackCursor;
  356.   if not KeyPressed then
  357.   begin
  358.     Reading := True;
  359.     if Focused then ShowCursor;
  360.     repeat until KeyPressed;
  361.     if Focused then HideCursor;
  362.     Reading := False;
  363.   end;
  364.   ReadKey := KeyBuffer[0];
  365.   Dec(KeyCount);
  366.   Move(KeyBuffer[1], KeyBuffer[0], KeyCount);
  367. end;
  368.  
  369. { Read text buffer from CRT window }
  370.  
  371. function ReadBuf(Buffer: PChar; Count: Word): Word;
  372. var
  373.   Ch: Char;
  374.   I: Word;
  375. begin
  376.   I := 0;
  377.   repeat
  378.     Ch := ReadKey;
  379.     case Ch of
  380.       #8:
  381.     if I > 0 then
  382.     begin
  383.       Dec(I);
  384.       WriteChar(#8);
  385.     end;
  386.       #32..#255:
  387.     if I < Count - 2 then
  388.     begin
  389.       Buffer[I] := Ch;
  390.       Inc(I);
  391.       WriteChar(Ch);
  392.     end;
  393.     end;
  394.   until (Ch = #13) or (CheckEOF and (Ch = #26));
  395.   Buffer[I] := Ch;
  396.   Inc(I);
  397.   if Ch = #13 then
  398.   begin
  399.     Buffer[I] := #10;
  400.     Inc(I);
  401.     WriteChar(#13);
  402.   end;
  403.   TrackCursor;
  404.   ReadBuf := I;
  405. end;
  406.  
  407. { Set cursor position }
  408.  
  409. procedure GotoXY(X, Y: Integer);
  410. begin
  411.   CursorTo(X - 1, Y - 1);
  412. end;
  413.  
  414. { Return cursor X position }
  415.  
  416. function WhereX: Integer;
  417. begin
  418.   WhereX := Cursor.X + 1;
  419. end;
  420.  
  421. { Return cursor Y position }
  422.  
  423. function WhereY: Integer;
  424. begin
  425.   WhereY := Cursor.Y + 1;
  426. end;
  427.  
  428. { Clear screen }
  429.  
  430. procedure ClrScr;
  431. begin
  432.   InitWinCrt;
  433.   FillChar(ScreenBuffer^, ScreenSize.X * ScreenSize.Y, ' ');
  434.   Longint(Cursor) := 0;
  435.   Longint(Origin) := 0;
  436.   SetScrollBars;
  437.   InvalidateRect(CrtWindow, nil, True);
  438.   UpdateWindow(CrtWindow);
  439. end;
  440.  
  441. { Clear to end of line }
  442.  
  443. procedure ClrEol;
  444. begin
  445.   InitWinCrt;
  446.   FillChar(ScreenPtr(Cursor.X, Cursor.Y)^, ScreenSize.X - Cursor.X, ' ');
  447.   ShowText(Cursor.X, ScreenSize.X);
  448. end;
  449.  
  450. { wm_Create message handler }
  451.  
  452. procedure WindowCreate;
  453. begin
  454.   Created := True;
  455.   GetMem(ScreenBuffer, ScreenSize.X * ScreenSize.Y);
  456.   FillChar(ScreenBuffer^, ScreenSize.X * ScreenSize.Y, ' ');
  457.   if not CheckBreak then
  458.     EnableMenuItem(GetSystemMenu(CrtWindow, False), sc_Close,
  459.       mf_Disabled + mf_Grayed);
  460. end;
  461.  
  462. { wm_Paint message handler }
  463.  
  464. procedure WindowPaint;
  465. var
  466.   X1, X2, Y1, Y2: Integer;
  467. begin
  468.   Painting := True;
  469.   InitDeviceContext;
  470.   X1 := Max(0, PS.rcPaint.left div CharSize.X + Origin.X);
  471.   X2 := Min(ScreenSize.X,
  472.     (PS.rcPaint.right + CharSize.X - 1) div CharSize.X + Origin.X);
  473.   Y1 := Max(0, PS.rcPaint.top div CharSize.Y + Origin.Y);
  474.   Y2 := Min(ScreenSize.Y,
  475.     (PS.rcPaint.bottom + CharSize.Y - 1) div CharSize.Y + Origin.Y);
  476.   while Y1 < Y2 do
  477.   begin
  478.     TextOut(DC, (X1 - Origin.X) * CharSize.X, (Y1 - Origin.Y) * CharSize.Y,
  479.       ScreenPtr(X1, Y1), X2 - X1);
  480.     Inc(Y1);
  481.   end;
  482.   DoneDeviceContext;
  483.   Painting := False;
  484. end;
  485.  
  486. { wm_VScroll and wm_HScroll message handler }
  487.  
  488. procedure WindowScroll(Which, Action, Thumb: Integer);
  489. var
  490.   X, Y: Integer;
  491.  
  492. function GetNewPos(Pos, Page, Range: Integer): Integer;
  493. begin
  494.   case Action of
  495.     sb_LineUp: GetNewPos := Pos - 1;
  496.     sb_LineDown: GetNewPos := Pos + 1;
  497.     sb_PageUp: GetNewPos := Pos - Page;
  498.     sb_PageDown: GetNewPos := Pos + Page;
  499.     sb_Top: GetNewPos := 0;
  500.     sb_Bottom: GetNewPos := Range;
  501.     sb_ThumbPosition: GetNewPos := Thumb;
  502.   else
  503.     GetNewPos := Pos;
  504.   end;
  505. end;
  506.  
  507. begin
  508.   X := Origin.X;
  509.   Y := Origin.Y;
  510.   case Which of
  511.     sb_Horz: X := GetNewPos(X, ClientSize.X div 2, Range.X);
  512.     sb_Vert: Y := GetNewPos(Y, ClientSize.Y, Range.Y);
  513.   end;
  514.   ScrollTo(X, Y);
  515. end;
  516.  
  517. { wm_Size message handler }
  518.  
  519. procedure WindowResize(X, Y: Integer);
  520. begin
  521.   if Focused and Reading then HideCursor;
  522.   ClientSize.X := X div CharSize.X;
  523.   ClientSize.Y := Y div CharSize.Y;
  524.   Range.X := Max(0, ScreenSize.X - ClientSize.X);
  525.   Range.Y := Max(0, ScreenSize.Y - ClientSize.Y);
  526.   Origin.X := Min(Origin.X, Range.X);
  527.   Origin.Y := Min(Origin.Y, Range.Y);
  528.   SetScrollBars;
  529.   if Focused and Reading then ShowCursor;
  530. end;
  531.  
  532. { wm_GetMinMaxInfo message handler }
  533.  
  534. procedure WindowMinMaxInfo(MinMaxInfo: PMinMaxInfo);
  535. var
  536.   X, Y: Integer;
  537.   Metrics: TTextMetric;
  538. begin
  539.   InitDeviceContext;
  540.   GetTextMetrics(DC, Metrics);
  541.   CharSize.X := Metrics.tmMaxCharWidth;
  542.   CharSize.Y := Metrics.tmHeight + Metrics.tmExternalLeading;
  543.   CharAscent := Metrics.tmAscent;
  544.   X := Min(ScreenSize.X * CharSize.X + GetSystemMetrics(sm_CXVScroll),
  545.     GetSystemMetrics(sm_CXScreen)) + GetSystemMetrics(sm_CXFrame) * 2;
  546.   Y := Min(ScreenSize.Y * CharSize.Y + GetSystemMetrics(sm_CYHScroll) +
  547.     GetSystemMetrics(sm_CYCaption), GetSystemMetrics(sm_CYScreen)) +
  548.     GetSystemMetrics(sm_CYFrame) * 2;
  549.   MinMaxInfo^[1].x := X;
  550.   MinMaxInfo^[1].y := Y;
  551.   MinMaxInfo^[3].x := CharSize.X * 16 + GetSystemMetrics(sm_CXVScroll) +
  552.     GetSystemMetrics(sm_CXFrame) * 2;
  553.   MinMaxInfo^[3].y := CharSize.Y * 4 + GetSystemMetrics(sm_CYHScroll) +
  554.     GetSystemMetrics(sm_CYFrame) * 2 + GetSystemMetrics(sm_CYCaption);
  555.   MinMaxInfo^[4].x := X;
  556.   MinMaxInfo^[4].y := Y;
  557.   DoneDeviceContext;
  558. end;
  559.  
  560. { wm_Char message handler }
  561.  
  562. procedure WindowChar(Ch: Char);
  563. begin
  564.   if CheckBreak and (Ch = #3) then Terminate;
  565.   if KeyCount < SizeOf(KeyBuffer) then
  566.   begin
  567.     KeyBuffer[KeyCount] := Ch;
  568.     Inc(KeyCount);
  569.   end;
  570. end;
  571.  
  572. { wm_KeyDown message handler }
  573.  
  574. procedure WindowKeyDown(KeyDown: Byte);
  575. var
  576.   CtrlDown: Boolean;
  577.   I: Integer;
  578. begin
  579.   if CheckBreak and (KeyDown = vk_Cancel) then Terminate;
  580.   CtrlDown := GetKeyState(vk_Control) < 0;
  581.   for I := 1 to ScrollKeyCount do
  582.     with ScrollKeys[I] do
  583.       if (Key = KeyDown) and (Ctrl = CtrlDown) then
  584.       begin
  585.     WindowScroll(SBar, Action, 0);
  586.     Exit;
  587.       end;
  588. end;
  589.  
  590. { wm_SetFocus message handler }
  591.  
  592. procedure WindowSetFocus;
  593. begin
  594.   Focused := True;
  595.   if Reading then ShowCursor;
  596. end;
  597.  
  598. { wm_KillFocus message handler }
  599.  
  600. procedure WindowKillFocus;
  601. begin
  602.   if Reading then HideCursor;
  603.   Focused := False;
  604. end;
  605.  
  606. { wm_Destroy message handler }
  607.  
  608. procedure WindowDestroy;
  609. begin
  610.   FreeMem(ScreenBuffer, ScreenSize.X * ScreenSize.Y);
  611.   Longint(Cursor) := 0;
  612.   Longint(Origin) := 0;
  613.   PostQuitMessage(0);
  614.   Created := False;
  615. end;
  616.  
  617. { CRT window procedure }
  618.  
  619. function CrtWinProc(Window: HWnd; Message, WParam: Word;
  620.   LParam: Longint): Longint;
  621. begin
  622.   CrtWinProc := 0;
  623.   CrtWindow := Window;
  624.   case Message of
  625.     wm_Create: WindowCreate;
  626.     wm_Paint: WindowPaint;
  627.     wm_VScroll: WindowScroll(sb_Vert, WParam, LongRec(LParam).Lo);
  628.     wm_HScroll: WindowScroll(sb_Horz, WParam, LongRec(LParam).Lo);
  629.     wm_Size: WindowResize(LongRec(LParam).Lo, LongRec(LParam).Hi);
  630.     wm_GetMinMaxInfo: WindowMinMaxInfo(PMinMaxInfo(LParam));
  631.     wm_Char: WindowChar(Char(WParam));
  632.     wm_KeyDown: WindowKeyDown(Byte(WParam));
  633.     wm_SetFocus: WindowSetFocus;
  634.     wm_KillFocus: WindowKillFocus;
  635.     wm_Destroy: WindowDestroy;
  636.   else
  637.     CrtWinProc := DefWindowProc(Window, Message, WParam, LParam);
  638.   end;
  639. end;
  640.  
  641. { Text file device driver output function }
  642.  
  643. function CrtOutput(var F: TTextRec): Integer; far;
  644. begin
  645.   if F.BufPos <> 0 then
  646.   begin
  647.     WriteBuf(PChar(F.BufPtr), F.BufPos);
  648.     F.BufPos := 0;
  649.     KeyPressed;
  650.   end;
  651.   CrtOutput := 0;
  652. end;
  653.  
  654. { Text file device driver input function }
  655.  
  656. function CrtInput(var F: TTextRec): Integer; far;
  657. begin
  658.   F.BufEnd := ReadBuf(PChar(F.BufPtr), F.BufSize);
  659.   F.BufPos := 0;
  660.   CrtInput := 0;
  661. end;
  662.  
  663. { Text file device driver close function }
  664.  
  665. function CrtClose(var F: TTextRec): Integer; far;
  666. begin
  667.   CrtClose := 0;
  668. end;
  669.  
  670. { Text file device driver open function }
  671.  
  672. function CrtOpen(var F: TTextRec): Integer; far;
  673. begin
  674.   if F.Mode = fmInput then
  675.   begin
  676.     F.InOutFunc := @CrtInput;
  677.     F.FlushFunc := nil;
  678.   end else
  679.   begin
  680.     F.Mode := fmOutput;
  681.     F.InOutFunc := @CrtOutput;
  682.     F.FlushFunc := @CrtOutput;
  683.   end;
  684.   F.CloseFunc := @CrtClose;
  685.   CrtOpen := 0;
  686. end;
  687.  
  688. { Assign text file to CRT device }
  689.  
  690. procedure AssignCrt(var F: Text);
  691. begin
  692.   with TTextRec(F) do
  693.   begin
  694.     Handle := $FFFF;
  695.     Mode := fmClosed;
  696.     BufSize := SizeOf(Buffer);
  697.     BufPtr := @Buffer;
  698.     OpenFunc := @CrtOpen;
  699.     Name[0] := #0;
  700.   end;
  701. end;
  702.  
  703. { Create CRT window if required }
  704.  
  705. procedure InitWinCrt;
  706. begin
  707.   if not Created then
  708.   begin
  709.     CrtWindow := CreateWindow(
  710.       CrtClass.lpszClassName,
  711.       WindowTitle,
  712.       ws_OverlappedWindow + ws_HScroll + ws_VScroll,
  713.       WindowOrg.X, WindowOrg.Y,
  714.       WindowSize.X, WindowSize.Y,
  715.       0,
  716.       0,
  717.       HInstance,
  718.       nil);
  719.     ShowWindow(CrtWindow, CmdShow);
  720.     UpdateWindow(CrtWindow);
  721.   end;
  722. end;
  723.  
  724. { Destroy CRT window if required }
  725.  
  726. procedure DoneWinCrt;
  727. begin
  728.   if Created then DestroyWindow(CrtWindow);
  729.   Halt(0);
  730. end;
  731.  
  732. { WinCrt unit exit procedure }
  733.  
  734. procedure ExitWinCrt; far;
  735. var
  736.   P: PChar;
  737.   Message: TMsg;
  738.   Title: array[0..127] of Char;
  739. begin
  740.   if Created and (ErrorAddr = nil) then
  741.   begin
  742.     P := WindowTitle;
  743.     WVSPrintF(Title, InactiveTitle, P);
  744.     SetWindowText(CrtWindow, Title);
  745.     EnableMenuItem(GetSystemMenu(CrtWindow, True), sc_Close, mf_Enabled);
  746.     ExitProc := SaveExit;
  747.     CheckBreak := False;
  748.     while GetMessage(Message, 0, 0, 0) do
  749.     begin
  750.       TranslateMessage(Message);
  751.       DispatchMessage(Message);
  752.     end;
  753.   end;
  754. end;
  755.  
  756. begin
  757.   if HPrevInst = 0 then
  758.   begin
  759.     CrtClass.hInstance := HInstance;
  760.     CrtClass.hIcon := LoadIcon(0, idi_Application);
  761.     CrtClass.hCursor := LoadCursor(0, idc_Arrow);
  762.     CrtClass.hbrBackground := GetStockObject(White_Brush);
  763.     RegisterClass(CrtClass);
  764.   end;
  765.   AssignCrt(Input);
  766.   Reset(Input);
  767.   AssignCrt(Output);
  768.   Rewrite(Output);
  769.   GetModuleFileName(HInstance, WindowTitle, SizeOf(WindowTitle));
  770.   SaveExit := ExitProc;
  771.   ExitProc := @ExitWinCrt;
  772. end.
  773.