home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 9 / 09.iso / l / l040 / 13.ddi / RTLWIN.ZIP / WINCRT.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1992-10-28  |  18.7 KB  |  776 lines

  1.  
  2. {*******************************************************}
  3. {                                                       }
  4. {       Turbo Pascal Runtime Library                    }
  5. {       Windows CRT Interface Unit                      }
  6. {                                                       }
  7. {       Copyright (c) 1991,92 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.   SetTextColor(DC, GetSysColor(color_WindowText));
  164.   SetBkColor(DC, GetSysColor(color_Window));
  165. end;
  166.  
  167. { Release device context }
  168.  
  169. procedure DoneDeviceContext;
  170. begin
  171.   SelectObject(DC, SaveFont);
  172.   if Painting then
  173.     EndPaint(CrtWindow, PS) else
  174.     ReleaseDC(CrtWindow, DC);
  175. end;
  176.  
  177. { Show caret }
  178.  
  179. procedure ShowCursor;
  180. begin
  181.   CreateCaret(CrtWindow, 0, CharSize.X, 2);
  182.   SetCaretPos((Cursor.X - Origin.X) * CharSize.X,
  183.     (Cursor.Y - Origin.Y) * CharSize.Y + CharAscent);
  184.   ShowCaret(CrtWindow);
  185. end;
  186.  
  187. { Hide caret }
  188.  
  189. procedure HideCursor;
  190. begin
  191.   DestroyCaret;
  192. end;
  193.  
  194. { Update scroll bars }
  195.  
  196. procedure SetScrollBars;
  197. begin
  198.   SetScrollRange(CrtWindow, sb_Horz, 0, Max(1, Range.X), False);
  199.   SetScrollPos(CrtWindow, sb_Horz, Origin.X, True);
  200.   SetScrollRange(CrtWindow, sb_Vert, 0, Max(1, Range.Y), False);
  201.   SetScrollPos(CrtWindow, sb_Vert, Origin.Y, True);
  202. end;
  203.  
  204. { Terminate CRT window }
  205.  
  206. procedure Terminate;
  207. begin
  208.   if Focused and Reading then HideCursor;
  209.   Halt(255);
  210. end;
  211.  
  212. { Set cursor position }
  213.  
  214. procedure CursorTo(X, Y: Integer);
  215. begin
  216.   Cursor.X := Max(0, Min(X, ScreenSize.X - 1));
  217.   Cursor.Y := Max(0, Min(Y, ScreenSize.Y - 1));
  218. end;
  219.  
  220. { Scroll window to given origin }
  221.  
  222. procedure ScrollTo(X, Y: Integer);
  223. begin
  224.   if Created then
  225.   begin
  226.     X := Max(0, Min(X, Range.X));
  227.     Y := Max(0, Min(Y, Range.Y));
  228.     if (X <> Origin.X) or (Y <> Origin.Y) then
  229.     begin
  230.       if X <> Origin.X then SetScrollPos(CrtWindow, sb_Horz, X, True);
  231.       if Y <> Origin.Y then SetScrollPos(CrtWindow, sb_Vert, Y, True);
  232.       ScrollWindow(CrtWindow,
  233.     (Origin.X - X) * CharSize.X,
  234.     (Origin.Y - Y) * CharSize.Y, nil, nil);
  235.       Origin.X := X;
  236.       Origin.Y := Y;
  237.       UpdateWindow(CrtWindow);
  238.     end;
  239.   end;
  240. end;
  241.  
  242. { Scroll to make cursor visible }
  243.  
  244. procedure TrackCursor;
  245. begin
  246.   ScrollTo(Max(Cursor.X - ClientSize.X + 1, Min(Origin.X, Cursor.X)),
  247.     Max(Cursor.Y - ClientSize.Y + 1, Min(Origin.Y, Cursor.Y)));
  248. end;
  249.  
  250. { Return pointer to location in screen buffer }
  251.  
  252. function ScreenPtr(X, Y: Integer): PChar;
  253. begin
  254.   Inc(Y, FirstLine);
  255.   if Y >= ScreenSize.Y then Dec(Y, ScreenSize.Y);
  256.   ScreenPtr := @ScreenBuffer[Y * ScreenSize.X + X];
  257. end;
  258.  
  259. { Update text on cursor line }
  260.  
  261. procedure ShowText(L, R: Integer);
  262. begin
  263.   if L < R then
  264.   begin
  265.     InitDeviceContext;
  266.     TextOut(DC, (L - Origin.X) * CharSize.X,
  267.       (Cursor.Y - Origin.Y) * CharSize.Y,
  268.       ScreenPtr(L, Cursor.Y), R - L);
  269.     DoneDeviceContext;
  270.   end;
  271. end;
  272.  
  273. { Write text buffer to CRT window }
  274.  
  275. procedure WriteBuf(Buffer: PChar; Count: Word);
  276. var
  277.   L, R: Integer;
  278.  
  279. procedure NewLine;
  280. begin
  281.   ShowText(L, R);
  282.   L := 0;
  283.   R := 0;
  284.   Cursor.X := 0;
  285.   Inc(Cursor.Y);
  286.   if Cursor.Y = ScreenSize.Y then
  287.   begin
  288.     Dec(Cursor.Y);
  289.     Inc(FirstLine);
  290.     if FirstLine = ScreenSize.Y then FirstLine := 0;
  291.     FillChar(ScreenPtr(0, Cursor.Y)^, ScreenSize.X, ' ');
  292.     ScrollWindow(CrtWindow, 0, -CharSize.Y, nil, nil);
  293.     UpdateWindow(CrtWindow);
  294.   end;
  295. end;
  296.  
  297. begin
  298.   InitWinCrt;
  299.   L := Cursor.X;
  300.   R := Cursor.X;
  301.   while Count > 0 do
  302.   begin
  303.     case Buffer^ of
  304.       #32..#255:
  305.     begin
  306.       ScreenPtr(Cursor.X, Cursor.Y)^ := Buffer^;
  307.       Inc(Cursor.X);
  308.       if Cursor.X > R then R := Cursor.X;
  309.       if Cursor.X = ScreenSize.X then NewLine;
  310.     end;
  311.       #13:
  312.     NewLine;
  313.       #8:
  314.     if Cursor.X > 0 then
  315.     begin
  316.       Dec(Cursor.X);
  317.       ScreenPtr(Cursor.X, Cursor.Y)^ := ' ';
  318.       if Cursor.X < L then L := Cursor.X;
  319.     end;
  320.       #7:
  321.         MessageBeep(0);
  322.     end;
  323.     Inc(Buffer);
  324.     Dec(Count);
  325.   end;
  326.   ShowText(L, R);
  327.   if AutoTracking then TrackCursor;
  328. end;
  329.  
  330. { Write character to CRT window }
  331.  
  332. procedure WriteChar(Ch: Char);
  333. begin
  334.   WriteBuf(@Ch, 1);
  335. end;
  336.  
  337. { Return keyboard status }
  338.  
  339. function KeyPressed: Boolean;
  340. var
  341.   M: TMsg;
  342. begin
  343.   InitWinCrt;
  344.   while PeekMessage(M, 0, 0, 0, pm_Remove) do
  345.   begin
  346.     if M.Message = wm_Quit then Terminate;
  347.     TranslateMessage(M);
  348.     DispatchMessage(M);
  349.   end;
  350.   KeyPressed := KeyCount > 0;
  351. end;
  352.  
  353. { Read key from CRT window }
  354.  
  355. function ReadKey: Char;
  356. begin
  357.   TrackCursor;
  358.   if not KeyPressed then
  359.   begin
  360.     Reading := True;
  361.     if Focused then ShowCursor;
  362.     repeat WaitMessage until KeyPressed;
  363.     if Focused then HideCursor;
  364.     Reading := False;
  365.   end;
  366.   ReadKey := KeyBuffer[0];
  367.   Dec(KeyCount);
  368.   Move(KeyBuffer[1], KeyBuffer[0], KeyCount);
  369. end;
  370.  
  371. { Read text buffer from CRT window }
  372.  
  373. function ReadBuf(Buffer: PChar; Count: Word): Word;
  374. var
  375.   Ch: Char;
  376.   I: Word;
  377. begin
  378.   I := 0;
  379.   repeat
  380.     Ch := ReadKey;
  381.     case Ch of
  382.       #8:
  383.     if I > 0 then
  384.     begin
  385.       Dec(I);
  386.       WriteChar(#8);
  387.     end;
  388.       #32..#255:
  389.     if I < Count - 2 then
  390.     begin
  391.       Buffer[I] := Ch;
  392.       Inc(I);
  393.       WriteChar(Ch);
  394.     end;
  395.     end;
  396.   until (Ch = #13) or (CheckEOF and (Ch = #26));
  397.   Buffer[I] := Ch;
  398.   Inc(I);
  399.   if Ch = #13 then
  400.   begin
  401.     Buffer[I] := #10;
  402.     Inc(I);
  403.     WriteChar(#13);
  404.   end;
  405.   TrackCursor;
  406.   ReadBuf := I;
  407. end;
  408.  
  409. { Set cursor position }
  410.  
  411. procedure GotoXY(X, Y: Integer);
  412. begin
  413.   CursorTo(X - 1, Y - 1);
  414. end;
  415.  
  416. { Return cursor X position }
  417.  
  418. function WhereX: Integer;
  419. begin
  420.   WhereX := Cursor.X + 1;
  421. end;
  422.  
  423. { Return cursor Y position }
  424.  
  425. function WhereY: Integer;
  426. begin
  427.   WhereY := Cursor.Y + 1;
  428. end;
  429.  
  430. { Clear screen }
  431.  
  432. procedure ClrScr;
  433. begin
  434.   InitWinCrt;
  435.   FillChar(ScreenBuffer^, ScreenSize.X * ScreenSize.Y, ' ');
  436.   Longint(Cursor) := 0;
  437.   Longint(Origin) := 0;
  438.   SetScrollBars;
  439.   InvalidateRect(CrtWindow, nil, True);
  440.   UpdateWindow(CrtWindow);
  441. end;
  442.  
  443. { Clear to end of line }
  444.  
  445. procedure ClrEol;
  446. begin
  447.   InitWinCrt;
  448.   FillChar(ScreenPtr(Cursor.X, Cursor.Y)^, ScreenSize.X - Cursor.X, ' ');
  449.   ShowText(Cursor.X, ScreenSize.X);
  450. end;
  451.  
  452. { wm_Create message handler }
  453.  
  454. procedure WindowCreate;
  455. begin
  456.   Created := True;
  457.   GetMem(ScreenBuffer, ScreenSize.X * ScreenSize.Y);
  458.   FillChar(ScreenBuffer^, ScreenSize.X * ScreenSize.Y, ' ');
  459.   if not CheckBreak then
  460.     EnableMenuItem(GetSystemMenu(CrtWindow, False), sc_Close,
  461.       mf_Disabled + mf_Grayed);
  462. end;
  463.  
  464. { wm_Paint message handler }
  465.  
  466. procedure WindowPaint;
  467. var
  468.   X1, X2, Y1, Y2: Integer;
  469. begin
  470.   Painting := True;
  471.   InitDeviceContext;
  472.   X1 := Max(0, PS.rcPaint.left div CharSize.X + Origin.X);
  473.   X2 := Min(ScreenSize.X,
  474.     (PS.rcPaint.right + CharSize.X - 1) div CharSize.X + Origin.X);
  475.   Y1 := Max(0, PS.rcPaint.top div CharSize.Y + Origin.Y);
  476.   Y2 := Min(ScreenSize.Y,
  477.     (PS.rcPaint.bottom + CharSize.Y - 1) div CharSize.Y + Origin.Y);
  478.   while Y1 < Y2 do
  479.   begin
  480.     TextOut(DC, (X1 - Origin.X) * CharSize.X, (Y1 - Origin.Y) * CharSize.Y,
  481.       ScreenPtr(X1, Y1), X2 - X1);
  482.     Inc(Y1);
  483.   end;
  484.   DoneDeviceContext;
  485.   Painting := False;
  486. end;
  487.  
  488. { wm_VScroll and wm_HScroll message handler }
  489.  
  490. procedure WindowScroll(Which, Action, Thumb: Integer);
  491. var
  492.   X, Y: Integer;
  493.  
  494. function GetNewPos(Pos, Page, Range: Integer): Integer;
  495. begin
  496.   case Action of
  497.     sb_LineUp: GetNewPos := Pos - 1;
  498.     sb_LineDown: GetNewPos := Pos + 1;
  499.     sb_PageUp: GetNewPos := Pos - Page;
  500.     sb_PageDown: GetNewPos := Pos + Page;
  501.     sb_Top: GetNewPos := 0;
  502.     sb_Bottom: GetNewPos := Range;
  503.     sb_ThumbPosition: GetNewPos := Thumb;
  504.   else
  505.     GetNewPos := Pos;
  506.   end;
  507. end;
  508.  
  509. begin
  510.   X := Origin.X;
  511.   Y := Origin.Y;
  512.   case Which of
  513.     sb_Horz: X := GetNewPos(X, ClientSize.X div 2, Range.X);
  514.     sb_Vert: Y := GetNewPos(Y, ClientSize.Y, Range.Y);
  515.   end;
  516.   ScrollTo(X, Y);
  517. end;
  518.  
  519. { wm_Size message handler }
  520.  
  521. procedure WindowResize(X, Y: Integer);
  522. begin
  523.   if Focused and Reading then HideCursor;
  524.   ClientSize.X := X div CharSize.X;
  525.   ClientSize.Y := Y div CharSize.Y;
  526.   Range.X := Max(0, ScreenSize.X - ClientSize.X);
  527.   Range.Y := Max(0, ScreenSize.Y - ClientSize.Y);
  528.   Origin.X := Min(Origin.X, Range.X);
  529.   Origin.Y := Min(Origin.Y, Range.Y);
  530.   SetScrollBars;
  531.   if Focused and Reading then ShowCursor;
  532. end;
  533.  
  534. { wm_GetMinMaxInfo message handler }
  535.  
  536. procedure WindowMinMaxInfo(MinMaxInfo: PMinMaxInfo);
  537. var
  538.   X, Y: Integer;
  539.   Metrics: TTextMetric;
  540. begin
  541.   InitDeviceContext;
  542.   GetTextMetrics(DC, Metrics);
  543.   CharSize.X := Metrics.tmMaxCharWidth;
  544.   CharSize.Y := Metrics.tmHeight + Metrics.tmExternalLeading;
  545.   CharAscent := Metrics.tmAscent;
  546.   X := Min(ScreenSize.X * CharSize.X + GetSystemMetrics(sm_CXVScroll),
  547.     GetSystemMetrics(sm_CXScreen)) + GetSystemMetrics(sm_CXFrame) * 2;
  548.   Y := Min(ScreenSize.Y * CharSize.Y + GetSystemMetrics(sm_CYHScroll) +
  549.     GetSystemMetrics(sm_CYCaption), GetSystemMetrics(sm_CYScreen)) +
  550.     GetSystemMetrics(sm_CYFrame) * 2;
  551.   MinMaxInfo^[1].x := X;
  552.   MinMaxInfo^[1].y := Y;
  553.   MinMaxInfo^[3].x := CharSize.X * 16 + GetSystemMetrics(sm_CXVScroll) +
  554.     GetSystemMetrics(sm_CXFrame) * 2;
  555.   MinMaxInfo^[3].y := CharSize.Y * 4 + GetSystemMetrics(sm_CYHScroll) +
  556.     GetSystemMetrics(sm_CYFrame) * 2 + GetSystemMetrics(sm_CYCaption);
  557.   MinMaxInfo^[4].x := X;
  558.   MinMaxInfo^[4].y := Y;
  559.   DoneDeviceContext;
  560. end;
  561.  
  562. { wm_Char message handler }
  563.  
  564. procedure WindowChar(Ch: Char);
  565. begin
  566.   if CheckBreak and (Ch = #3) then Terminate;
  567.   if KeyCount < SizeOf(KeyBuffer) then
  568.   begin
  569.     KeyBuffer[KeyCount] := Ch;
  570.     Inc(KeyCount);
  571.   end;
  572. end;
  573.  
  574. { wm_KeyDown message handler }
  575.  
  576. procedure WindowKeyDown(KeyDown: Byte);
  577. var
  578.   CtrlDown: Boolean;
  579.   I: Integer;
  580. begin
  581.   if CheckBreak and (KeyDown = vk_Cancel) then Terminate;
  582.   CtrlDown := GetKeyState(vk_Control) < 0;
  583.   for I := 1 to ScrollKeyCount do
  584.     with ScrollKeys[I] do
  585.       if (Key = KeyDown) and (Ctrl = CtrlDown) then
  586.       begin
  587.     WindowScroll(SBar, Action, 0);
  588.     Exit;
  589.       end;
  590. end;
  591.  
  592. { wm_SetFocus message handler }
  593.  
  594. procedure WindowSetFocus;
  595. begin
  596.   Focused := True;
  597.   if Reading then ShowCursor;
  598. end;
  599.  
  600. { wm_KillFocus message handler }
  601.  
  602. procedure WindowKillFocus;
  603. begin
  604.   if Reading then HideCursor;
  605.   Focused := False;
  606. end;
  607.  
  608. { wm_Destroy message handler }
  609.  
  610. procedure WindowDestroy;
  611. begin
  612.   FreeMem(ScreenBuffer, ScreenSize.X * ScreenSize.Y);
  613.   Longint(Cursor) := 0;
  614.   Longint(Origin) := 0;
  615.   PostQuitMessage(0);
  616.   Created := False;
  617. end;
  618.  
  619. { CRT window procedure }
  620.  
  621. function CrtWinProc(Window: HWnd; Message, WParam: Word;
  622.   LParam: Longint): Longint;
  623. begin
  624.   CrtWinProc := 0;
  625.   CrtWindow := Window;
  626.   case Message of
  627.     wm_Create: WindowCreate;
  628.     wm_Paint: WindowPaint;
  629.     wm_VScroll: WindowScroll(sb_Vert, WParam, LongRec(LParam).Lo);
  630.     wm_HScroll: WindowScroll(sb_Horz, WParam, LongRec(LParam).Lo);
  631.     wm_Size: WindowResize(LongRec(LParam).Lo, LongRec(LParam).Hi);
  632.     wm_GetMinMaxInfo: WindowMinMaxInfo(PMinMaxInfo(LParam));
  633.     wm_Char: WindowChar(Char(WParam));
  634.     wm_KeyDown: WindowKeyDown(Byte(WParam));
  635.     wm_SetFocus: WindowSetFocus;
  636.     wm_KillFocus: WindowKillFocus;
  637.     wm_Destroy: WindowDestroy;
  638.   else
  639.     CrtWinProc := DefWindowProc(Window, Message, WParam, LParam);
  640.   end;
  641. end;
  642.  
  643. { Text file device driver output function }
  644.  
  645. function CrtOutput(var F: TTextRec): Integer; far;
  646. begin
  647.   if F.BufPos <> 0 then
  648.   begin
  649.     WriteBuf(PChar(F.BufPtr), F.BufPos);
  650.     F.BufPos := 0;
  651.     KeyPressed;
  652.   end;
  653.   CrtOutput := 0;
  654. end;
  655.  
  656. { Text file device driver input function }
  657.  
  658. function CrtInput(var F: TTextRec): Integer; far;
  659. begin
  660.   F.BufEnd := ReadBuf(PChar(F.BufPtr), F.BufSize);
  661.   F.BufPos := 0;
  662.   CrtInput := 0;
  663. end;
  664.  
  665. { Text file device driver close function }
  666.  
  667. function CrtClose(var F: TTextRec): Integer; far;
  668. begin
  669.   CrtClose := 0;
  670. end;
  671.  
  672. { Text file device driver open function }
  673.  
  674. function CrtOpen(var F: TTextRec): Integer; far;
  675. begin
  676.   if F.Mode = fmInput then
  677.   begin
  678.     F.InOutFunc := @CrtInput;
  679.     F.FlushFunc := nil;
  680.   end else
  681.   begin
  682.     F.Mode := fmOutput;
  683.     F.InOutFunc := @CrtOutput;
  684.     F.FlushFunc := @CrtOutput;
  685.   end;
  686.   F.CloseFunc := @CrtClose;
  687.   CrtOpen := 0;
  688. end;
  689.  
  690. { Assign text file to CRT device }
  691.  
  692. procedure AssignCrt(var F: Text);
  693. begin
  694.   with TTextRec(F) do
  695.   begin
  696.     Handle := $FFFF;
  697.     Mode := fmClosed;
  698.     BufSize := SizeOf(Buffer);
  699.     BufPtr := @Buffer;
  700.     OpenFunc := @CrtOpen;
  701.     Name[0] := #0;
  702.   end;
  703. end;
  704.  
  705. { Create CRT window if required }
  706.  
  707. procedure InitWinCrt;
  708. begin
  709.   if not Created then
  710.   begin
  711.     CrtWindow := CreateWindow(
  712.       CrtClass.lpszClassName,
  713.       WindowTitle,
  714.       ws_OverlappedWindow + ws_HScroll + ws_VScroll,
  715.       WindowOrg.X, WindowOrg.Y,
  716.       WindowSize.X, WindowSize.Y,
  717.       0,
  718.       0,
  719.       HInstance,
  720.       nil);
  721.     ShowWindow(CrtWindow, CmdShow);
  722.     UpdateWindow(CrtWindow);
  723.   end;
  724. end;
  725.  
  726. { Destroy CRT window if required }
  727.  
  728. procedure DoneWinCrt;
  729. begin
  730.   if Created then DestroyWindow(CrtWindow);
  731.   Halt(0);
  732. end;
  733.  
  734. { WinCrt unit exit procedure }
  735.  
  736. procedure ExitWinCrt; far;
  737. var
  738.   P: PChar;
  739.   Message: TMsg;
  740.   Title: array[0..127] of Char;
  741. begin
  742.   ExitProc := SaveExit;
  743.   if Created and (ErrorAddr = nil) then
  744.   begin
  745.     P := WindowTitle;
  746.     WVSPrintF(Title, InactiveTitle, P);
  747.     SetWindowText(CrtWindow, Title);
  748.     EnableMenuItem(GetSystemMenu(CrtWindow, False), sc_Close, mf_Enabled);
  749.     CheckBreak := False;
  750.     while GetMessage(Message, 0, 0, 0) do
  751.     begin
  752.       TranslateMessage(Message);
  753.       DispatchMessage(Message);
  754.     end;
  755.   end;
  756. end;
  757.  
  758. begin
  759.   if HPrevInst = 0 then
  760.   begin
  761.     CrtClass.hInstance := HInstance;
  762.     CrtClass.hIcon := LoadIcon(0, idi_Application);
  763.     CrtClass.hCursor := LoadCursor(0, idc_Arrow);
  764.     CrtClass.hbrBackground := color_Window + 1;
  765.     RegisterClass(CrtClass);
  766.   end;
  767.   AssignCrt(Input);
  768.   Reset(Input);
  769.   AssignCrt(Output);
  770.   Rewrite(Output);
  771.   GetModuleFileName(HInstance, WindowTitle, SizeOf(WindowTitle));
  772.   OemToAnsi(WindowTitle, WindowTitle);
  773.   SaveExit := ExitProc;
  774.   ExitProc := @ExitWinCrt;
  775. end.
  776.