mirror of
https://github.com/danieleteti/delphimvcframework.git
synced 2024-11-16 00:05:53 +01:00
435 lines
10 KiB
ObjectPascal
435 lines
10 KiB
ObjectPascal
// ***************************************************************************
|
|
//
|
|
// Delphi MVC Framework
|
|
//
|
|
// Copyright (c) 2010-2024 Daniele Teti and the DMVCFramework Team
|
|
//
|
|
// https://github.com/danieleteti/delphimvcframework
|
|
//
|
|
// ***************************************************************************
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
// *************************************************************************** }
|
|
|
|
unit MVCFramework.Console;
|
|
|
|
|
|
{$I dmvcframework.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
System.SysUtils
|
|
,System.SyncObjs
|
|
{$IFDEF MSWINDOWS}
|
|
,WinApi.Windows
|
|
{$ENDIF}
|
|
{$IFDEF LINUX}
|
|
{$ENDIF}
|
|
;
|
|
|
|
type
|
|
// https://stackoverflow.com/questions/17125440/c-win32-console-color
|
|
// https://docs.microsoft.com/en-us/dotnet/api/system.consolecolor?view=netcore-3.1
|
|
TConsoleColor = (Black = 0, // The color black.
|
|
DarkBlue = 1, // The color dark blue.
|
|
DarkGreen = 2, // The color dark green.
|
|
DarkCyan = 3, // The color dark cyan (dark blue-green).
|
|
DarkRed = 4, // The color dark red.
|
|
DarkMagenta = 5, // The color dark magenta (dark purplish-red).
|
|
DarkYellow = 6, // The color dark yellow (ochre).
|
|
Gray = 7, // The color gray.
|
|
DarkGray = 8, // The color dark gray.
|
|
Blue = 9, // The color blue.
|
|
Green = 10, // The color green.
|
|
Cyan = 11, // The color Cyan(Blue - green).
|
|
Red = 12, // The color red.
|
|
Magenta = 13, // The color magenta (purplish-red).
|
|
Yellow = 14, // The color yellow.
|
|
White = 15 // The color white.
|
|
);
|
|
|
|
EMVCConsole = class(Exception)
|
|
|
|
end;
|
|
|
|
TMVCConsoleSize = record
|
|
Columns: Word;
|
|
Rows: Word;
|
|
end;
|
|
|
|
procedure ResetConsole;
|
|
procedure TextColor(const color: TConsoleColor);
|
|
procedure TextBackground(const color: TConsoleColor);
|
|
procedure GotoXY(const X, Y: Byte);
|
|
function GetConsoleSize: TMVCConsoleSize;
|
|
function GetConsoleBufferSize: TMVCConsoleSize;
|
|
procedure ClrScr;
|
|
function GetCh: Char;
|
|
procedure WaitForReturn;
|
|
procedure SaveColors;
|
|
procedure RestoreSavedColors;
|
|
procedure SetDefaultColors;
|
|
function ConsoleAttr: Integer;
|
|
procedure SetConsoleAttr(const TextAttr: Integer);
|
|
function TextAttr: Word;
|
|
procedure SetTextAttr(const TextAttr: Word);
|
|
function BackgroundAttr: Word;
|
|
procedure SetBackgroundAttr(const BackgroundAttr: Word);
|
|
procedure HideCursor;
|
|
procedure ShowCursor;
|
|
procedure CenterInScreen(const Text: String);
|
|
|
|
|
|
function ColorName(const color: TConsoleColor): String;
|
|
|
|
implementation
|
|
|
|
uses
|
|
System.TypInfo;
|
|
|
|
const
|
|
ESC = Chr(27);
|
|
|
|
var
|
|
GForeGround, GSavedForeGround: Int16;
|
|
GBackGround, GSavedBackGround: Int16;
|
|
GOutHandle: THandle = INVALID_HANDLE_VALUE;
|
|
GInputHandle: THandle = INVALID_HANDLE_VALUE;
|
|
GIsConsoleAllocated: Boolean = False;
|
|
GLock: TObject = nil;
|
|
|
|
|
|
|
|
function ColorName(const color: TConsoleColor): String;
|
|
begin
|
|
Result := GetEnumName(TypeInfo(TConsoleColor), Ord(color));
|
|
end;
|
|
|
|
|
|
{$IFDEF LINUX}
|
|
procedure HideCursor;
|
|
begin
|
|
|
|
end;
|
|
|
|
procedure ShowCursor;
|
|
begin
|
|
|
|
end;
|
|
|
|
procedure Init; inline;
|
|
begin
|
|
|
|
end;
|
|
|
|
procedure WaitForReturn;
|
|
begin
|
|
ReadLn;
|
|
end;
|
|
|
|
procedure UpdateMode;
|
|
begin
|
|
|
|
end;
|
|
|
|
function GetCh: Char;
|
|
begin
|
|
raise EMVCConsole.Create('Not Implemented');
|
|
end;
|
|
|
|
procedure GotoXY(const X, Y: Byte);
|
|
begin
|
|
raise EMVCConsole.Create('Not Implemented');
|
|
end;
|
|
|
|
function GetConsoleSize: TMVCConsoleSize;
|
|
begin
|
|
raise EMVCConsole.Create('Not Implemented');
|
|
end;
|
|
|
|
function GetConsoleBufferSize: TMVCConsoleSize;
|
|
begin
|
|
raise EMVCConsole.Create('Not Implemented');
|
|
end;
|
|
|
|
procedure ClrScr;
|
|
begin
|
|
raise EMVCConsole.Create('Not Implemented');
|
|
end;
|
|
|
|
{$ENDIF}
|
|
{$IFDEF MSWINDOWS}
|
|
|
|
{.$IF not Defined(RIOORBETTER)}
|
|
const
|
|
ATTACH_PARENT_PROCESS = DWORD(-1);
|
|
function AttachConsole(dwProcessId: DWORD): BOOL; stdcall; external kernel32 name 'AttachConsole';
|
|
{.$ENDIF}
|
|
|
|
procedure WinCheck(const Value: LongBool);
|
|
begin
|
|
if not Value then
|
|
raise EMVCConsole.CreateFmt('GetLastError() = %d', [GetLastError]);
|
|
end;
|
|
|
|
procedure Init;
|
|
begin
|
|
if not GIsConsoleAllocated then
|
|
begin
|
|
TMonitor.Enter(GLock);
|
|
try
|
|
if not GIsConsoleAllocated then
|
|
begin
|
|
// Attempt to attach to the parent (if there is already a console allocated)
|
|
if not IsConsole then
|
|
begin
|
|
if not AttachConsole(ATTACH_PARENT_PROCESS) then
|
|
AllocConsole; // No console allocated, create a new one
|
|
end;
|
|
GOutHandle := GetStdHandle(STD_OUTPUT_HANDLE);
|
|
if GOutHandle = INVALID_HANDLE_VALUE then
|
|
raise EMVCConsole.CreateFmt('Cannot Get STD_OUTPUT_HANDLE - GetLastError() = %d', [GetLastError]);
|
|
GIsConsoleAllocated := True;
|
|
end;
|
|
finally
|
|
TMonitor.Exit(GLock);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure InternalShowCursor(const ShowCursor: Boolean);
|
|
var
|
|
info: CONSOLE_CURSOR_INFO;
|
|
begin
|
|
Init;
|
|
GetConsoleCursorInfo(GOutHandle, info);
|
|
info.bVisible := ShowCursor;
|
|
SetConsoleCursorInfo(GOutHandle, info);
|
|
end;
|
|
|
|
procedure WaitForReturn;
|
|
begin
|
|
Init;
|
|
while GetCh <> #13 do;
|
|
end;
|
|
|
|
procedure ClrScr;
|
|
var
|
|
lSize: TMVCConsoleSize;
|
|
dwConSize: UInt32;
|
|
lStartCoord: _COORD;
|
|
lCharsWritten: UInt32;
|
|
lConsoleScreenBufferInfo: _CONSOLE_SCREEN_BUFFER_INFO;
|
|
begin
|
|
Init;
|
|
// https://docs.microsoft.com/en-us/windows/console/clearing-the-screen
|
|
lSize := GetConsoleBufferSize;
|
|
dwConSize := lSize.Columns * lSize.Rows;
|
|
lStartCoord.X := 0;
|
|
lStartCoord.Y := 0;
|
|
if not FillConsoleOutputCharacter(GOutHandle, ' ', dwConSize, lStartCoord, lCharsWritten) then
|
|
raise EMVCConsole.CreateFmt('Cannot fill console with blank char - GetLastError() = %d', [GetLastError]);
|
|
|
|
if not GetConsoleScreenBufferInfo(GOutHandle, lConsoleScreenBufferInfo) then
|
|
raise EMVCConsole.CreateFmt('Cannot GetConsoleScreenBufferInfo - GetLastError() = %d', [GetLastError]);
|
|
|
|
if not FillConsoleOutputAttribute(GOutHandle, lConsoleScreenBufferInfo.wAttributes, dwConSize, lStartCoord,
|
|
lCharsWritten) then
|
|
raise EMVCConsole.CreateFmt('Cannot FillConsoleOutputAttribute - GetLastError() = %d', [GetLastError]);
|
|
|
|
GotoXY(0, 0);
|
|
end;
|
|
|
|
function GetConsoleSize: TMVCConsoleSize;
|
|
var
|
|
lConsoleScreenBufferInfo: _CONSOLE_SCREEN_BUFFER_INFO;
|
|
begin
|
|
if not GetConsoleScreenBufferInfo(GOutHandle, lConsoleScreenBufferInfo) then
|
|
raise EMVCConsole.CreateFmt('Cannot Get Console Size - GetLastError() = %d', [GetLastError]);
|
|
Result.Columns := lConsoleScreenBufferInfo.srWindow.Right - lConsoleScreenBufferInfo.srWindow.Left + 1;
|
|
Result.Rows := lConsoleScreenBufferInfo.srWindow.Bottom - lConsoleScreenBufferInfo.srWindow.Top + 1;
|
|
end;
|
|
|
|
procedure EnsureStdInput;
|
|
begin
|
|
if GInputHandle = INVALID_HANDLE_VALUE then
|
|
begin
|
|
GInputHandle := GetStdHandle(STD_INPUT_HANDLE);
|
|
if GInputHandle = INVALID_HANDLE_VALUE then
|
|
begin
|
|
raise EMVCConsole.CreateFmt('Cannot Get STD_INPUT_HANDLE - GetLastError() = %d', [GetLastError]);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function GetCh: Char;
|
|
var
|
|
lMode, lCC: DWORD;
|
|
C: Char;
|
|
begin
|
|
Init;
|
|
EnsureStdInput;
|
|
C := #0;
|
|
WinCheck(GetConsoleMode(GInputHandle, lMode));
|
|
WinCheck(SetConsoleMode(GInputHandle, lMode and (not(ENABLE_LINE_INPUT or ENABLE_ECHO_INPUT))));
|
|
try
|
|
lCC := 0;
|
|
WinCheck(ReadConsole(GInputHandle, @C, SizeOf(Char), lCC, nil));
|
|
finally
|
|
WinCheck(SetConsoleMode(GInputHandle, lMode));
|
|
end;
|
|
Result := C;
|
|
end;
|
|
|
|
function GetConsoleBufferSize: TMVCConsoleSize;
|
|
var
|
|
lConsoleScreenBufferInfo: _CONSOLE_SCREEN_BUFFER_INFO;
|
|
begin
|
|
if not GetConsoleScreenBufferInfo(GOutHandle, lConsoleScreenBufferInfo) then
|
|
raise EMVCConsole.CreateFmt('Cannot Get Console Buffer Size - GetLastError() = %d', [GetLastError]);
|
|
Result.Columns := lConsoleScreenBufferInfo.dwSize.X;
|
|
Result.Rows := lConsoleScreenBufferInfo.dwSize.Y;
|
|
end;
|
|
|
|
procedure UpdateMode;
|
|
begin
|
|
Init;
|
|
SetConsoleTextAttribute(GOutHandle, Ord(GForeGround) or Ord(GBackGround));
|
|
end;
|
|
|
|
procedure GotoXY(const X, Y: Byte);
|
|
var
|
|
lCoord: _COORD;
|
|
begin
|
|
Init;
|
|
lCoord.X := X;
|
|
lCoord.Y := Y;
|
|
if not SetConsoleCursorPosition(GOutHandle, lCoord) then
|
|
begin
|
|
raise EMVCConsole.Create('Invalid Coordinates');
|
|
end;
|
|
end;
|
|
|
|
procedure HideCursor;
|
|
begin
|
|
InternalShowCursor(False);
|
|
end;
|
|
|
|
procedure ShowCursor;
|
|
begin
|
|
InternalShowCursor(True);
|
|
end;
|
|
|
|
{$ENDIF}
|
|
|
|
{ ******************************************* }
|
|
{ * HIGH LEVEL FUNCTION - no IFDEF required * }
|
|
{ ******************************************* }
|
|
|
|
procedure CenterInScreen(const Text: String);
|
|
begin
|
|
Init;
|
|
GotoXY(GetConsoleSize.Columns div 2 - Length(Text) div 2, GetConsoleSize.Rows div 2 - 1);
|
|
Write(Text)
|
|
end;
|
|
|
|
procedure ResetConsole;
|
|
begin
|
|
SetDefaultColors;
|
|
end;
|
|
|
|
procedure TextColor(const color: TConsoleColor);
|
|
begin
|
|
GForeGround := Ord(color);
|
|
UpdateMode;
|
|
// write(ESC + GetColorString);
|
|
end;
|
|
|
|
procedure TextBackground(const color: TConsoleColor);
|
|
begin
|
|
GBackGround := Ord(color) shl 4;
|
|
UpdateMode;
|
|
// write(ESC + GetColorString);
|
|
end;
|
|
|
|
procedure SetDefaultColors;
|
|
begin
|
|
GForeGround := Ord(TConsoleColor.DarkGray);
|
|
GBackGround := Ord(TConsoleColor.Black);
|
|
UpdateMode;
|
|
end;
|
|
|
|
procedure SaveColors;
|
|
begin
|
|
Init;
|
|
GSavedForeGround := GForeGround;
|
|
GSavedBackGround := GBackGround;
|
|
end;
|
|
|
|
procedure RestoreSavedColors;
|
|
begin
|
|
GForeGround := GSavedForeGround;
|
|
GBackGround := GSavedBackGround;
|
|
UpdateMode;
|
|
end;
|
|
|
|
function ConsoleAttr: Integer;
|
|
begin
|
|
Result := GForeGround;
|
|
Result := (Result shl 16) or GBackGround;
|
|
end;
|
|
|
|
procedure SetConsoleAttr(const TextAttr: Integer);
|
|
var
|
|
lAttr: Integer;
|
|
begin
|
|
lAttr := TextAttr;
|
|
GBackGround := lAttr and $0000FFFF;
|
|
GForeGround := lAttr shr 16;
|
|
UpdateMode;
|
|
end;
|
|
|
|
function TextAttr: Word;
|
|
begin
|
|
Result := GForeGround;
|
|
end;
|
|
|
|
procedure SetTextAttr(const TextAttr: Word);
|
|
begin
|
|
GForeGround := TextAttr;
|
|
UpdateMode;
|
|
end;
|
|
|
|
function BackgroundAttr: Word;
|
|
begin
|
|
Result := GBackGround;
|
|
end;
|
|
|
|
procedure SetBackgroundAttr(const BackgroundAttr: Word);
|
|
begin
|
|
GBackGround := BackgroundAttr;
|
|
UpdateMode;
|
|
end;
|
|
|
|
initialization
|
|
|
|
Glock := TObject.Create;
|
|
|
|
finalization
|
|
|
|
Glock.Free;
|
|
|
|
end.
|