首页  编辑  

一个CRT Unit

Tags: /超级猛料/Console.控制台程序/   Date Created:

Author: Attila Szomor

{$IFDEF VER130}

{$DEFINE NEW_STYLES}

{$ENDIF}

{$IFDEF VER140}

{$DEFINE NEW_STYLES}

{$ENDIF}

{..$Define HARD_CRT}{Redirect STD_...}

{..$Define CRT_EVENT}{CTRL-C,...}

{$DEFINE MOUSE_IS_USED} {Handle mouse or not}

{..$Define OneByOne}{Block or byte style write}

unit CRT32 ;

interface

{$IFDEF Win32}

const

  { CRT modes of original CRT unit }

 BW40 = 0 ; { 40x25 B/W on Color Adapter }

 CO40 = 1 ; { 40x25 Color on Color Adapter }

 BW80 = 2 ; { 80x25 B/W on Color Adapter }

 CO80 = 3 ; { 80x25 Color on Color Adapter }

 Mono = 7 ; { 80x25 on Monochrome Adapter }

 Font8x8 = 256 ; { Add-in for ROM font }

  { Mode constants for 3.0 compatibility of original CRT unit }

 C40 = CO40 ;

 C80 = CO80 ;

  { Foreground and background color constants of original CRT unit }

 Black = 0 ;

 Blue = 1 ;

 Green = 2 ;

 Cyan = 3 ;

 Red = 4 ;

 Magenta = 5 ;

 Brown = 6 ;

 LightGray = 7 ;

  { Foreground color constants of original CRT unit }

 DarkGray = 8 ;

 LightBlue = 9 ;

 LightGreen = 10 ;

 LightCyan = 11 ;

 LightRed = 12 ;

 LightMagenta = 13 ;

 Yellow = 14 ;

 White = 15 ;

  { Add-in for blinking of original CRT unit }

 Blink = 128 ;

  {  }

  {  New constans there are not in original CRT unit }

  {  }

 MouseLeftButton = 1 ;

 MouseRightButton = 2 ;

 MouseCenterButton = 4 ;

var

  { Interface variables of original CRT unit }

 CheckBreak : Boolean ; { Enable Ctrl-Break }

 CheckEOF : Boolean ; { Enable Ctrl-Z }

 DirectVideo : Boolean ; { Enable direct video addressing }

 CheckSnow : Boolean ; { Enable snow filtering }

 LastMode : Word ; { Current text mode }

 TextAttr : Byte ; { Current text attribute }

 WindMin : Word ; { Window upper left coordinates }

 WindMax : Word ; { Window lower right coordinates }

  {  }

  {  New variables there are not in original CRT unit }

  {  }

 MouseInstalled : boolean ;

 MousePressedButtons : word ;

  { Interface functions & procedures of original CRT unit }

procedure AssignCrt ( var F : Text );

function KeyPressed : Boolean ;

function ReadKey : char ;

procedure TextMode ( Mode : Integer );

procedure Window ( X1 , Y1 , X2 , Y2 : Byte );

procedure GotoXY ( X , Y : Byte );

function WhereX : Byte ;

function WhereY : Byte ;

procedure ClrScr ;

procedure ClrEol ;

procedure InsLine ;

procedure DelLine ;

procedure TextColor ( Color : Byte );

procedure TextBackground ( Color : Byte );

procedure LowVideo ;

procedure HighVideo ;

procedure NormVideo ;

procedure Delay ( MS : Word );

procedure Sound ( Hz : Word );

procedure NoSound ;

{ New functions & procedures there are not in original CRT unit }

procedure FillerScreen ( FillChar : Char );

procedure FlushInputBuffer ;

function GetCursor : Word ;

procedure SetCursor ( NewCursor : Word );

function MouseKeyPressed : Boolean ;

procedure MouseGotoXY ( X , Y : Integer );

function MouseWhereY : Integer ;

function MouseWhereX : Integer ;

procedure MouseShowCursor ;

procedure MouseHideCursor ;

{ These functions & procedures are for inside use only }

function MouseReset : Boolean ;

procedure WriteChrXY ( X , Y : Byte ; Chr : char );

procedure WriteStrXY ( X , Y : Byte ; Str : PChar ; dwSize : Integer );

procedure OverwriteChrXY ( X , Y : Byte ; Chr : char );

{$ENDIF Win32}

implementation

{$IFDEF Win32}

uses Windows , SysUtils ;

type

 POpenText = ^ TOpenText ;

 TOpenText = function ( var F : Text ; Mode : Word ): Integer ; far ;

var

 IsWinNT : boolean ;

 PtrOpenText : POpenText ;

 hConsoleInput : THandle ;

 hConsoleOutput : THandle ;

 ConsoleScreenRect : TSmallRect ;

 StartAttr : word ;

 LastX , LastY : byte ;

 SoundDuration : integer ;

 SoundFrequency : integer ;

 OldCP : integer ;

 MouseRowWidth , MouseColWidth : word ;

 MousePosX , MousePosY : smallInt ;

 MouseButtonPressed : boolean ;

 MouseEventTime : TDateTime ;

  {  }

  {  This function handles the Write and WriteLn commands }

  {  }

function TextOut ( var F : Text ): Integer ; far ;

{$IFDEF OneByOne}

var

 dwSize : DWORD ;

  {$ENDIF}

begin

  with TTExtRec ( F ) do

  begin

    if BufPos > 0 then

    begin

     LastX := WhereX ;

     LastY := WhereY ;

      {$IFDEF OneByOne}

     dwSize := 0 ;

      while ( dwSize < BufPos ) do

      begin

       WriteChrXY ( LastX , LastY , BufPtr [ dwSize ]);

       Inc ( dwSize );

      end ;

      {$ELSE}

     WriteStrXY ( LastX , LastY , BufPtr , BufPos );

     FillChar ( BufPtr ^, BufPos + 1 , #0 );

      {$ENDIF}

     BufPos := 0 ;

    end ;

  end ;

 Result := 0 ;

end ;

{  }

{  This function handles the exchanging of Input or Output }

{  }

function OpenText ( var F : Text ; Mode : Word ): Integer ; far ;

var

 OpenResult : integer ;

begin

 OpenResult := 102 ; { Text not assigned }

  if Assigned ( PtrOpenText ) then

  begin

   TTextRec ( F ). OpenFunc := PtrOpenText ;

   OpenResult := PtrOpenText ^( F , Mode );

    if OpenResult = 0 then

    begin

      if Mode = fmInput then

       hConsoleInput := TTextRec ( F ). Handle

      else

      begin

       hConsoleOutput := TTextRec ( F ). Handle ;

       TTextRec ( Output ). InOutFunc := @ TextOut ;

       TTextRec ( Output ). FlushFunc := @ TextOut ;

      end ;

    end ;

  end ;

 Result := OpenResult ;

end ;

{  }

{  Fills the current window with special character }

{  }

procedure FillerScreen ( FillChar : Char );

var

 Coord : TCoord ;

 dwSize , dwCount : DWORD ;

 Y : integer ;

begin

 Coord . X := ConsoleScreenRect . Left ;

 dwSize := ConsoleScreenRect . Right - ConsoleScreenRect . Left + 1 ;

  for Y := ConsoleScreenRect . Top to ConsoleScreenRect . Bottom do

  begin

   Coord . Y := Y ;

   FillConsoleOutputAttribute ( hConsoleOutput , TextAttr , dwSize , Coord , dwCount );

   FillConsoleOutputCharacter ( hConsoleOutput , FillChar , dwSize , Coord , dwCount );

  end ;

 GotoXY ( 1 , 1 );

end ;

{  }

{  Write one character at the X,Y position }

{  }

procedure WriteChrXY ( X , Y : Byte ; Chr : char );

var

 Coord : TCoord ;

 dwSize , dwCount : DWORD ;

begin

 LastX := X ;

 LastY := Y ;

  case Chr of

    #13 : LastX := 1 ;

    #10 :

      begin

       LastX := 1 ;

       Inc ( LastY );

      end ;

  else

    begin

     Coord . X := LastX - 1 + ConsoleScreenRect . Left ;

     Coord . Y := LastY - 1 + ConsoleScreenRect . Top ;

     dwSize := 1 ;

     FillConsoleOutputAttribute ( hConsoleOutput , TextAttr , dwSize , Coord , dwCount );

     FillConsoleOutputCharacter ( hConsoleOutput , Chr , dwSize , Coord , dwCount );

     Inc ( LastX );

    end ;

  end ;

  if ( LastX + ConsoleScreenRect . Left ) > ( ConsoleScreenRect . Right + 1 ) then

  begin

   LastX := 1 ;

   Inc ( LastY );

  end ;

  if ( LastY + ConsoleScreenRect . Top ) > ( ConsoleScreenRect . Bottom + 1 ) then

  begin

   Dec ( LastY );

   GotoXY ( 1 , 1 );

   DelLine ;

  end ;

 GotoXY ( LastX , LastY );

end ;

{  }

{  Write string into the X,Y position }

{  }

(* !!! The WriteConsoleOutput does not write into the last line !!!

 Procedure WriteStrXY(X,Y: byte; Str: PChar; dwSize: integer );

 {$IfDef OneByOne}

   Var

     dwCount: integer;

 {$Else}

   Type

     PBuffer= ^TBuffer;

     TBUffer= packed array [0..16384] of TCharInfo;

   Var

     I: integer;

     dwCount: DWORD;

     WidthHeight,Coord: TCoord;

     hTempConsoleOutput: THandle;

     SecurityAttributes: TSecurityAttributes;

     Buffer: PBuffer;

     DestinationScreenRect,SourceScreenRect: TSmallRect;

 {$EndIf}

 Begin

   If dwSize>0 Then Begin

     {$IfDef OneByOne}

       LastX:=X;

       LastY:=Y;

       dwCount:=0;

       While dwCount < dwSize Do Begin

         WriteChrXY(LastX,LastY,Str[dwCount]);

         Inc(dwCount);

       End;

     {$Else}

       SecurityAttributes.nLength:=SizeOf(SecurityAttributes)-SizeOf(DWORD);

       SecurityAttributes.lpSecurityDescriptor:=NIL;

       SecurityAttributes.bInheritHandle:=TRUE;

       hTempConsoleOutput:=CreateConsoleScreenBuffer(

        GENERIC_READ OR GENERIC_WRITE,

        FILE_SHARE_READ OR FILE_SHARE_WRITE,

        @SecurityAttributes,

        CONSOLE_TEXTMODE_BUFFER,

        NIL

       );

       If dwSize<=(ConsoleScreenRect.Right-ConsoleScreenRect.Left+1) Then Begin

         WidthHeight.X:=dwSize;

         WidthHeight.Y:=1;

       End Else Begin

         WidthHeight.X:=ConsoleScreenRect.Right-ConsoleScreenRect.Left+1;

         WidthHeight.Y:=dwSize DIV WidthHeight.X;

         If (dwSize MOD WidthHeight.X) > 0 Then Inc(WidthHeight.Y);

       End;

       SetConsoleScreenBufferSize(hTempConsoleOutput,WidthHeight);

       DestinationScreenRect.Left:=0;

       DestinationScreenRect.Top:=0;

       DestinationScreenRect.Right:=WidthHeight.X-1;

       DestinationScreenRect.Bottom:=WidthHeight.Y-1;

       SetConsoleWindowInfo(hTempConsoleOutput,FALSE,DestinationScreenRect);

       Coord.X:=0;

       For I:=1 To WidthHeight.Y Do Begin

         Coord.Y:=I-0;

         FillConsoleOutputAttribute(hTempConsoleOutput,TextAttr,WidthHeight.X,Coord,dwCount);

         FillConsoleOutputCharacter(hTempConsoleOutput,' '     ,WidthHeight.X,Coord,dwCount);

       End;

       WriteConsole(hTempConsoleOutput,Str,dwSize,dwCount,NIL);

       {  }

       New(Buffer);

       Coord.X:= 0;

       Coord.Y:= 0;

       SourceScreenRect.Left:=0;

       SourceScreenRect.Top:=0;

       SourceScreenRect.Right:=WidthHeight.X-1;

       SourceScreenRect.Bottom:=WidthHeight.Y-1;

       ReadConsoleOutputA(hTempConsoleOutput,Buffer,WidthHeight,Coord,SourceScreenRect);

       Coord.X:=X-1;

       Coord.Y:=Y-1;

       DestinationScreenRect:=ConsoleScreenRect;

       WriteConsoleOutputA(hConsoleOutput,Buffer,WidthHeight,Coord,DestinationScreenRect);

       GotoXY((dwSize MOD WidthHeight.X)-1,WidthHeight.Y+1);

       Dispose(Buffer);

       {  }

       CloseHandle(hTempConsoleOutput);

     {$EndIf}

   End;

 End;

*)

procedure WriteStrXY ( X , Y : Byte ; Str : PChar ; dwSize : Integer );

{$IFDEF OneByOne}

var

 dwCount : integer ;

  {$ELSE}

var

 I : integer ;

 LineSize , dwCharCount , dwCount , dwWait : DWORD ;

 WidthHeight : TCoord ;

 OneLine : packed array [ 0 .. 131 ] of char ;

 Line , TempStr : PChar ;

  procedure NewLine ;

  begin

   LastX := 1 ;

   Inc ( LastY );

    if ( LastY + ConsoleScreenRect . Top ) > ( ConsoleScreenRect . Bottom + 1 ) then

    begin

     Dec ( LastY );

     GotoXY ( 1 , 1 );

     DelLine ;

    end ;

   GotoXY ( LastX , LastY );

  end ;

  {$ENDIF}

begin

  if dwSize > 0 then

  begin

    {$IFDEF OneByOne}

   LastX := X ;

   LastY := Y ;

   dwCount := 0 ;

    while dwCount < dwSize do

    begin

     WriteChrXY ( LastX , LastY , Str [ dwCount ]);

     Inc ( dwCount );

    end ;

    {$ELSE}

   LastX := X ;

   LastY := Y ;

   GotoXY ( LastX , LastY );

   dwWait := dwSize ;

   TempStr := Str ;

    while ( dwWait > 0 ) and ( Pos ( #13#10 , StrPas ( TempStr )) = 1 ) do

    begin

     Dec ( dwWait , 2 );

     Inc ( TempStr , 2 );

     NewLine ;

    end ;

    while ( dwWait > 0 ) and ( Pos ( #10 , StrPas ( TempStr )) = 1 ) do

    begin

     Dec ( dwWait );

     Inc ( TempStr );

     NewLine ;

    end ;

    if dwWait > 0 then

    begin

      if dwSize <= ( ConsoleScreenRect . Right - ConsoleScreenRect . Left - LastX + 1 ) then

      begin

       WidthHeight . X := dwSize + LastX - 1 ;

       WidthHeight . Y := 1 ;

      end

      else

      begin

       WidthHeight . X := ConsoleScreenRect . Right - ConsoleScreenRect . Left + 1 ;

       WidthHeight . Y := dwSize div WidthHeight . X ;

        if ( dwSize mod WidthHeight . X ) > 0 then Inc ( WidthHeight . Y );

      end ;

      for I := 1 to WidthHeight . Y do

      begin

       FillChar ( OneLine , SizeOf ( OneLine ), #0 );

       Line := @ OneLine ;

       LineSize := WidthHeight . X - LastX + 1 ;

        if LineSize > dwWait then LineSize := dwWait ;

       Dec ( dwWait , LineSize );

       StrLCopy ( Line , TempStr , LineSize );

       Inc ( TempStr , LineSize );

       dwCharCount := Pos ( #13#10 , StrPas ( Line ));

        if dwCharCount > 0 then

        begin

         OneLine [ dwCharCount - 1 ] := #0 ;

         OneLine [ dwCharCount ] := #0 ;

         WriteConsole ( hConsoleOutput , Line , dwCharCount - 1 , dwCount , nil );

         Inc ( Line , dwCharCount + 1 );

         NewLine ;

         LineSize := LineSize - ( dwCharCount + 1 );

        end

        else

        begin

         dwCharCount := Pos ( #10 , StrPas ( Line ));

          if dwCharCount > 0 then

          begin

           OneLine [ dwCharCount - 1 ] := #0 ;

           WriteConsole ( hConsoleOutput , Line , dwCharCount - 1 , dwCount , nil );

           Inc ( Line , dwCharCount );

           NewLine ;

           LineSize := LineSize - dwCharCount ;

          end ;

        end ;

        if LineSize <> 0 then

        begin

         WriteConsole ( hConsoleOutput , Line , LineSize , dwCount , nil );

        end ;

        if dwWait > 0 then

        begin

         NewLine ;

        end ;

      end ;

    end ;

    {$ENDIF}

  end ;

end ;

{  }

{  Empty the buffer }

{  }

procedure FlushInputBuffer ;

begin

 FlushConsoleInputBuffer ( hConsoleInput );

end ;

{  }

{  Get size of current cursor }

{  }

function GetCursor : Word ;

var

 CCI : TConsoleCursorInfo ;

begin

 GetConsoleCursorInfo ( hConsoleOutput , CCI );

 GetCursor := CCI . dwSize ;

end ;

{  }

{  Set size of current cursor }

{  }

procedure SetCursor ( NewCursor : Word );

var

 CCI : TConsoleCursorInfo ;

begin

  if NewCursor = $0000 then

  begin

   CCI . dwSize := GetCursor ;

   CCI . bVisible := False ;

  end

  else

  begin

   CCI . dwSize := NewCursor ;

   CCI . bVisible := True ;

  end ;

 SetConsoleCursorInfo ( hConsoleOutput , CCI );

end ;

{  }

{ --- Begin of Interface functions & procedures of original CRT unit --- }

procedure AssignCrt ( var F : Text );

begin

 Assign ( F , '' );

 TTextRec ( F ). OpenFunc := @ OpenText ;

end ;

function KeyPressed : Boolean ;

var

 NumberOfEvents : DWORD ;

 NumRead : DWORD ;

 InputRec : TInputRecord ;

 Pressed : boolean ;

begin

 Pressed := False ;

 GetNumberOfConsoleInputEvents ( hConsoleInput , NumberOfEvents );

  if NumberOfEvents > 0 then

  begin

    if PeekConsoleInput ( hConsoleInput , InputRec , 1 , NumRead ) then

    begin

      if ( InputRec . EventType = KEY_EVENT ) and

        ( InputRec {$IFDEF NEW_STYLES} . Event {$ENDIF} . KeyEvent . bKeyDown ) then

      begin

       Pressed := True ;

        {$IFDEF MOUSE_IS_USED}

       MouseButtonPressed := False ;

        {$ENDIF}

      end

      else

      begin

        {$IFDEF MOUSE_IS_USED}

        if ( InputRec . EventType = _MOUSE_EVENT ) then

        begin

          with InputRec {$IFDEF NEW_STYLES} . Event {$ENDIF} . MouseEvent do

          begin

           MousePosX := dwMousePosition . X ;

           MousePosY := dwMousePosition . Y ;

            if dwButtonState = FROM_LEFT_1ST_BUTTON_PRESSED then

            begin

             MouseEventTime := Now ;

             MouseButtonPressed := True ;

              {If (dwEventFlags AND DOUBLE_CLICK)<>0 Then Begin}

              {End;}

            end ;

          end ;

        end ;

       ReadConsoleInput ( hConsoleInput , InputRec , 1 , NumRead );

        {$ELSE}

       ReadConsoleInput ( hConsoleInput , InputRec , 1 , NumRead );

        {$ENDIF}

      end ;

    end ;

  end ;

 Result := Pressed ;

end ;

function ReadKey : char ;

var

 NumRead : DWORD ;

 InputRec : TInputRecord ;

begin

  repeat

    repeat

    until KeyPressed ;

   ReadConsoleInput ( hConsoleInput , InputRec , 1 , NumRead );

  until InputRec {$IFDEF NEW_STYLES} . Event {$ENDIF} . KeyEvent . AsciiChar > #0 ;

 Result := InputRec {$IFDEF NEW_STYLES} . Event {$ENDIF} . KeyEvent . AsciiChar ;

end ;

procedure TextMode ( Mode : Integer );

begin

end ;

procedure Window ( X1 , Y1 , X2 , Y2 : Byte );

begin

 ConsoleScreenRect . Left := X1 - 1 ;

 ConsoleScreenRect . Top := Y1 - 1 ;

 ConsoleScreenRect . Right := X2 - 1 ;

 ConsoleScreenRect . Bottom := Y2 - 1 ;

 WindMin := ( ConsoleScreenRect . Top shl 8 ) or ConsoleScreenRect . Left ;

 WindMax := ( ConsoleScreenRect . Bottom shl 8 ) or ConsoleScreenRect . Right ;

  {$IFDEF WindowFrameToo}

 SetConsoleWindowInfo ( hConsoleOutput , True , ConsoleScreenRect );

  {$ENDIF}

 GotoXY ( 1 , 1 );

end ;

procedure GotoXY ( X , Y : Byte );

var

 Coord : TCoord ;

begin

 Coord . X := X - 1 + ConsoleScreenRect . Left ;

 Coord . Y := Y - 1 + ConsoleScreenRect . Top ;

  if not SetConsoleCursorPosition ( hConsoleOutput , Coord ) then

  begin

   GotoXY ( 1 , 1 );

   DelLine ;

  end ;

end ;

function WhereX : Byte ;

var

 CBI : TConsoleScreenBufferInfo ;

begin

 GetConsoleScreenBufferInfo ( hConsoleOutput , CBI );

 Result := TCoord ( CBI . dwCursorPosition ). X + 1 - ConsoleScreenRect . Left ;

end ;

function WhereY : Byte ;

var

 CBI : TConsoleScreenBufferInfo ;

begin

 GetConsoleScreenBufferInfo ( hConsoleOutput , CBI );

 Result := TCoord ( CBI . dwCursorPosition ). Y + 1 - ConsoleScreenRect . Top ;

end ;

procedure ClrScr ;

begin

 FillerScreen ( ' ' );

end ;

procedure ClrEol ;

var

 Coord : TCoord ;

 dwSize , dwCount : DWORD ;

begin

 Coord . X := WhereX - 1 + ConsoleScreenRect . Left ;

 Coord . Y := WhereY - 1 + ConsoleScreenRect . Top ;

 dwSize := ConsoleScreenRect . Right - Coord . X + 1 ;

 FillConsoleOutputAttribute ( hConsoleOutput , TextAttr , dwSize , Coord , dwCount );

 FillConsoleOutputCharacter ( hConsoleOutput , ' ' , dwSize , Coord , dwCount );

end ;

procedure InsLine ;

var

 SourceScreenRect : TSmallRect ;

 Coord : TCoord ;

 CI : TCharInfo ;

 dwSize , dwCount : DWORD ;

begin

 SourceScreenRect := ConsoleScreenRect ;

 SourceScreenRect . Top := WhereY - 1 + ConsoleScreenRect . Top ;

 SourceScreenRect . Bottom := ConsoleScreenRect . Bottom - 1 ;

 CI . AsciiChar := ' ' ;

 CI . Attributes := TextAttr ;

 Coord . X := SourceScreenRect . Left ;

 Coord . Y := SourceScreenRect . Top + 1 ;

 dwSize := SourceScreenRect . Right - SourceScreenRect . Left + 1 ;

 ScrollConsoleScreenBuffer ( hConsoleOutput , SourceScreenRect , nil , Coord , CI );

 Dec ( Coord . Y );

 FillConsoleOutputAttribute ( hConsoleOutput , TextAttr , dwSize , Coord , dwCount );

end ;

procedure DelLine ;

var

 SourceScreenRect : TSmallRect ;

 Coord : TCoord ;

 CI : TCharinfo ;

 dwSize , dwCount : DWORD ;

begin

 SourceScreenRect := ConsoleScreenRect ;

 SourceScreenRect . Top := WhereY + ConsoleScreenRect . Top ;

 CI . AsciiChar := ' ' ;

 CI . Attributes := TextAttr ;

 Coord . X := SourceScreenRect . Left ;

 Coord . Y := SourceScreenRect . Top - 1 ;

 dwSize := SourceScreenRect . Right - SourceScreenRect . Left + 1 ;

 ScrollConsoleScreenBuffer ( hConsoleOutput , SourceScreenRect , nil , Coord , CI );

 FillConsoleOutputAttribute ( hConsoleOutput , TextAttr , dwSize , Coord , dwCount );

end ;

procedure TextColor ( Color : Byte );

begin

 LastMode := TextAttr ;

 TextAttr := ( Color and $0F ) or ( TextAttr and $F0 );

 SetConsoleTextAttribute ( hConsoleOutput , TextAttr );

end ;

procedure TextBackground ( Color : Byte );

begin

 LastMode := TextAttr ;

 TextAttr := ( Color shl 4 ) or ( TextAttr and $0F );

 SetConsoleTextAttribute ( hConsoleOutput , TextAttr );

end ;

procedure LowVideo ;

begin

 LastMode := TextAttr ;

 TextAttr := TextAttr and $F7 ;

 SetConsoleTextAttribute ( hConsoleOutput , TextAttr );

end ;

procedure HighVideo ;

begin

 LastMode := TextAttr ;

 TextAttr := TextAttr or $08 ;

 SetConsoleTextAttribute ( hConsoleOutput , TextAttr );

end ;

procedure NormVideo ;

begin

 LastMode := TextAttr ;

 TextAttr := StartAttr ;

 SetConsoleTextAttribute ( hConsoleOutput , TextAttr );

end ;

procedure Delay ( MS : Word );

{

Const

 Magic= $80000000;

var

StartMS,CurMS,DeltaMS: DWORD;

}

begin

 Windows . SleepEx ( MS , False ); // Windows.Sleep(MS);

  {

 StartMS:= GetTickCount;

 Repeat

   CurMS:= GetTickCount;

   If CurMS >= StartMS Then

      DeltaMS:= CurMS - StartMS

   Else DeltaMS := (CurMS + Magic) - (StartMS - Magic);

 Until MS<DeltaMS;

 }

end ;

procedure Sound ( Hz : Word );

begin

  {SetSoundIOPermissionMap(LocalIOPermission_ON);}

 SoundFrequency := Hz ;

  if IsWinNT then

  begin

   Windows . Beep ( SoundFrequency , SoundDuration )

  end

  else

  begin

    asm

       mov  BX,Hz

       cmp  BX,0

       jz   @2

       mov  AX,$34DD

       mov  DX,$0012

       cmp  DX,BX

       jnb  @2

       div  BX

       mov  BX,AX

        { Sound is On ? }

       in   Al,$61

       test Al,$03

       jnz  @1

        { Set Sound On }

       or   Al,03

       out  $61,Al

        { Timer Command }

       mov  Al,$B6

       out  $43,Al

        { Set Frequency }

   @1: mov  Al,Bl

       out  $42,Al

       mov  Al,Bh

       out  $42,Al

   @2:

    end ;

  end ;

end ;

procedure NoSound ;

begin

  if IsWinNT then

  begin

   Windows . Beep ( SoundFrequency , 0 );

  end

  else

  begin

    asm

        { Set Sound On }

       in   Al,$61

       and  Al,$FC

       out  $61,Al

    end ;

  end ;

  {SetSoundIOPermissionMap(LocalIOPermission_OFF);}

end ;

{ --- End of Interface functions & procedures of original CRT unit --- }

{  }

procedure OverwriteChrXY ( X , Y : Byte ; Chr : char );

var

 Coord : TCoord ;

 dwSize , dwCount : DWORD ;

begin

 LastX := X ;

 LastY := Y ;

 Coord . X := LastX - 1 + ConsoleScreenRect . Left ;

 Coord . Y := LastY - 1 + ConsoleScreenRect . Top ;

 dwSize := 1 ;

 FillConsoleOutputAttribute ( hConsoleOutput , TextAttr , dwSize , Coord , dwCount );

 FillConsoleOutputCharacter ( hConsoleOutput , Chr , dwSize , Coord , dwCount );

 GotoXY ( LastX , LastY );

end ;

{  --------------------------------------------------  }

{  Console Event Handler }

{  }

{$IFDEF CRT_EVENT}

function ConsoleEventProc ( CtrlType : DWORD ): Bool ; stdcall ; far ;

var

 S : {$IFDEF Win32} ShortString {$ELSE} string {$ENDIF} ;

  Message : PChar ;

begin

  case CtrlType of

   CTRL_C_EVENT : S := 'CTRL_C_EVENT' ;

   CTRL_BREAK_EVENT : S := 'CTRL_BREAK_EVENT' ;

   CTRL_CLOSE_EVENT : S := 'CTRL_CLOSE_EVENT' ;

   CTRL_LOGOFF_EVENT : S := 'CTRL_LOGOFF_EVENT' ;

   CTRL_SHUTDOWN_EVENT : S := 'CTRL_SHUTDOWN_EVENT' ;

  else

   S := 'UNKNOWN_EVENT' ;

  end ;

 S := S + ' detected, but not handled.' ;

  Message := @ S ;

 Inc ( Message );

 MessageBox ( 0 , Message , 'Win32 Console' , MB_OK );

 Result := True ;

end ;

{$ENDIF}

function MouseReset : Boolean ;

begin

 MouseColWidth := 1 ;

 MouseRowWidth := 1 ;

 Result := True ;

end ;

procedure MouseShowCursor ;

const

 ShowMouseConsoleMode = ENABLE_MOUSE_INPUT ;

var

 cMode : DWORD ;

begin

 GetConsoleMode ( hConsoleInput , cMode );

  if ( cMode and ShowMouseConsoleMode ) <> ShowMouseConsoleMode then

  begin

   cMode := cMode or ShowMouseConsoleMode ;

   SetConsoleMode ( hConsoleInput , cMode );

  end ;

end ;

procedure MouseHideCursor ;

const

 ShowMouseConsoleMode = ENABLE_MOUSE_INPUT ;

var

 cMode : DWORD ;

begin

 GetConsoleMode ( hConsoleInput , cMode );

  if ( cMode and ShowMouseConsoleMode ) = ShowMouseConsoleMode then

  begin

   cMode := cMode and ( $FFFFFFFF xor ShowMouseConsoleMode );

   SetConsoleMode ( hConsoleInput , cMode );

  end ;

end ;

function MouseKeyPressed : Boolean ;

{$IFDEF MOUSE_IS_USED}

const

 MouseDeltaTime = 200 ;

var

 ActualTime : TDateTime ;

 HourA , HourM , MinA , MinM , SecA , SecM , MSecA , MSecM : word ;

 MSecTimeA , MSecTimeM : longInt ;

 MSecDelta : longInt ;

  {$ENDIF}

begin

 MousePressedButtons := 0 ;

  {$IFDEF MOUSE_IS_USED}

 Result := False ;

  if MouseButtonPressed then

  begin

   ActualTime := NOW ;

   DecodeTime ( ActualTime , HourA , MinA , SecA , MSecA );

   DecodeTime ( MouseEventTime , HourM , MinM , SecM , MSecM );

   MSecTimeA := ( 3600 * HourA + 60 * MinA + SecA ) * 100 + MSecA ;

   MSecTimeM := ( 3600 * HourM + 60 * MinM + SecM ) * 100 + MSecM ;

   MSecDelta := Abs ( MSecTimeM - MSecTimeA );

    if ( MSecDelta < MouseDeltaTime ) or ( MSecDelta > ( 8784000 - MouseDeltaTime )) then

    begin

     MousePressedButtons := MouseLeftButton ;

     MouseButtonPressed := False ;

     Result := True ;

    end ;

  end ;

  {$ELSE}

 Result := False ;

  {$ENDIF}

end ;

procedure MouseGotoXY ( X , Y : Integer );

begin

  {$IFDEF MOUSE_IS_USED}

 mouse_event ( MOUSEEVENTF_ABSOLUTE or MOUSEEVENTF_MOVE ,

   X - 1 , Y - 1 , WHEEL_DELTA , GetMessageExtraInfo ());

 MousePosY := ( Y - 1 ) * MouseRowWidth ;

 MousePosX := ( X - 1 ) * MouseColWidth ;

  {$ENDIF}

end ;

function MouseWhereY : Integer ;

{$IFDEF MOUSE_IS_USED}

{Var

 lppt, lpptBuf: TMouseMovePoint;}

{$ENDIF}

begin

  {$IFDEF MOUSE_IS_USED}

  {GetMouseMovePoints(

   SizeOf(TMouseMovePoint), lppt, lpptBuf,

   7,GMMP_USE_DRIVER_POINTS

 );

 Result:=lpptBuf.Y DIV MouseRowWidth;}

 Result := ( MousePosY div MouseRowWidth ) + 1 ;

  {$ELSE}

 Result := - 1 ;

  {$ENDIF}

end ;

function MouseWhereX : Integer ;

{$IFDEF MOUSE_IS_USED}

{Var

 lppt, lpptBuf: TMouseMovePoint;}

{$ENDIF}

begin

  {$IFDEF MOUSE_IS_USED}

  {GetMouseMovePoints(

   SizeOf(TMouseMovePoint), lppt, lpptBuf,

   7,GMMP_USE_DRIVER_POINTS

 );

 Result:=lpptBuf.X DIV MouseColWidth;}

 Result := ( MousePosX div MouseColWidth ) + 1 ;

  {$ELSE}

 Result := - 1 ;

  {$ENDIF}

end ;

{  }

procedure Init ;

const

 ExtInpConsoleMode = ENABLE_WINDOW_INPUT or ENABLE_PROCESSED_INPUT or ENABLE_MOUSE_INPUT ;

 ExtOutConsoleMode = ENABLE_PROCESSED_OUTPUT or ENABLE_WRAP_AT_EOL_OUTPUT ;

var

 cMode : DWORD ;

 Coord : TCoord ;

 OSVersion : TOSVersionInfo ;

 CBI : TConsoleScreenBufferInfo ;

begin

 OSVersion . dwOSVersionInfoSize := SizeOf ( TOSVersionInfo );

 GetVersionEx ( OSVersion );

  if OSVersion . dwPlatformId = VER_PLATFORM_WIN32_NT then

   IsWinNT := True

  else

   IsWinNT := False ;

 PtrOpenText := TTextRec ( Output ). OpenFunc ;

  {$IFDEF HARD_CRT}

 AllocConsole ;

 Reset ( Input );

 hConsoleInput := GetStdHandle ( STD_INPUT_HANDLE );

 TTextRec ( Input ). Handle := hConsoleInput ;

 ReWrite ( Output );

 hConsoleOutput := GetStdHandle ( STD_OUTPUT_HANDLE );

 TTextRec ( Output ). Handle := hConsoleOutput ;

  {$ELSE}

 Reset ( Input );

 hConsoleInput := TTextRec ( Input ). Handle ;

 ReWrite ( Output );

 hConsoleOutput := TTextRec ( Output ). Handle ;

  {$ENDIF}

 GetConsoleMode ( hConsoleInput , cMode );

  if ( cMode and ExtInpConsoleMode ) <> ExtInpConsoleMode then

  begin

   cMode := cMode or ExtInpConsoleMode ;

   SetConsoleMode ( hConsoleInput , cMode );

  end ;

 TTextRec ( Output ). InOutFunc := @ TextOut ;

 TTextRec ( Output ). FlushFunc := @ TextOut ;

 GetConsoleScreenBufferInfo ( hConsoleOutput , CBI );

 GetConsoleMode ( hConsoleOutput , cMode );

  if ( cMode and ExtOutConsoleMode ) <> ExtOutConsoleMode then

  begin

   cMode := cMode or ExtOutConsoleMode ;

   SetConsoleMode ( hConsoleOutput , cMode );

  end ;

 TextAttr := CBI . wAttributes ;

 StartAttr := CBI . wAttributes ;

 LastMode := CBI . wAttributes ;

 Coord . X := CBI . srWindow . Left ;

 Coord . Y := CBI . srWindow . Top ;

 WindMin := ( Coord . Y shl 8 ) or Coord . X ;

 Coord . X := CBI . srWindow . Right ;

 Coord . Y := CBI . srWindow . Bottom ;

 WindMax := ( Coord . Y shl 8 ) or Coord . X ;

 ConsoleScreenRect := CBI . srWindow ;

 SoundDuration := - 1 ;

 OldCp := GetConsoleOutputCP ;

 SetConsoleOutputCP ( 1250 );

  {$IFDEF CRT_EVENT}

 SetConsoleCtrlHandler (@ ConsoleEventProc , True );

  {$ENDIF}

  {$IFDEF MOUSE_IS_USED}

 SetCapture ( hConsoleInput );

 KeyPressed ;

  {$ENDIF}

 MouseInstalled := MouseReset ;

 Window ( 1 , 1 , 80 , 25 );

 ClrScr ;

end ;

{  }

procedure Done ;

begin

  {$IFDEF CRT_EVENT}

 SetConsoleCtrlHandler (@ ConsoleEventProc , False );

  {$ENDIF}

 SetConsoleOutputCP ( OldCP );

 TextAttr := StartAttr ;

 SetConsoleTextAttribute ( hConsoleOutput , TextAttr );

 ClrScr ;

 FlushInputBuffer ;

  {$IFDEF HARD_CRT}

 TTextRec ( Input ). Mode := fmClosed ;

 TTextRec ( Output ). Mode := fmClosed ;

 FreeConsole ;

  {$ELSE}

 Close ( Input );

 Close ( Output );

  {$ENDIF}

end ;

initialization

 Init ;

finalization

 Done ;

  {$ENDIF win32}

end .