delphimvcframework/sources/MVCFramework.Console.pas

362 lines
8.6 KiB
ObjectPascal
Raw Normal View History

// ***************************************************************************
//
// Delphi MVC Framework
//
// Copyright (c) 2010-2023 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.
//
// *************************************************************************** }
2017-10-16 22:57:27 +02:00
unit MVCFramework.Console;
interface
uses
System.SysUtils
{$IFDEF MSWINDOWS}
,WinApi.Windows
{$ENDIF}
{$IFDEF LINUX}
{$ENDIF}
;
2017-10-16 22:57:27 +02:00
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;
2017-10-16 22:57:27 +02:00
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;
2020-06-18 14:49:06 +02:00
procedure SaveColors;
procedure RestoreSavedColors;
procedure Init;
procedure SetDefaults;
function ConsoleAttr: Integer;
procedure SetConsoleAttr(const TextAttr: Integer);
function TextAttr: Word;
procedure SetTextAttr(const TextAttr: Word);
function BackgroundAttr: Word;
procedure SetBackgroundAttr(const BackgroundAttr: Word);
function ColorName(const color: TConsoleColor): String;
2017-10-16 22:57:27 +02:00
implementation
uses
System.TypInfo;
2017-10-16 22:57:27 +02:00
const
ESC = Chr(27);
var
GForeGround, GSavedForeGround: Int16;
GBackGround, GSavedBackGround: Int16;
GOutHandle: THandle = INVALID_HANDLE_VALUE;
GInputHandle: THandle = INVALID_HANDLE_VALUE;
2017-10-16 22:57:27 +02:00
function ColorName(const color: TConsoleColor): String;
2017-10-16 22:57:27 +02:00
begin
Result := GetEnumName(TypeInfo(TConsoleColor), Ord(color));
2017-10-16 22:57:27 +02:00
end;
2020-06-18 14:49:06 +02:00
{$IFDEF LINUX}
procedure WaitForReturn;
begin
ReadLn;
end;
procedure Init; inline;
begin
end;
2017-10-16 22:57:27 +02:00
procedure UpdateMode;
2017-10-16 22:57:27 +02:00
begin
2017-10-16 22:57:27 +02:00
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;
2017-10-16 22:57:27 +02:00
function GetConsoleBufferSize: TMVCConsoleSize;
begin
raise EMVCConsole.Create('Not Implemented');
end;
2017-10-16 22:57:27 +02:00
procedure ClrScr;
begin
raise EMVCConsole.Create('Not Implemented');
end;
2017-10-16 22:57:27 +02:00
{$ENDIF}
{$IFDEF MSWINDOWS}
procedure WinCheck(const Value: LongBool);
begin
if not Value then
raise EMVCConsole.CreateFmt('GetLastError() = %d', [GetLastError]);
end;
procedure WaitForReturn;
begin
while GetCh <> #13 do;
end;
procedure ClrScr;
2017-10-16 22:57:27 +02:00
var
lSize: TMVCConsoleSize;
dwConSize: UInt32;
lStartCoord: _COORD;
lCharsWritten: UInt32;
lConsoleScreenBufferInfo: _CONSOLE_SCREEN_BUFFER_INFO;
2017-10-16 22:57:27 +02:00
begin
// 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]);
2017-10-16 22:57:27 +02:00
if not FillConsoleOutputAttribute(GOutHandle, lConsoleScreenBufferInfo.wAttributes, dwConSize, lStartCoord,
lCharsWritten) then
raise EMVCConsole.CreateFmt('Cannot FillConsoleOutputAttribute - GetLastError() = %d', [GetLastError]);
2017-10-16 22:57:27 +02:00
GotoXY(0, 0);
2017-10-16 22:57:27 +02:00
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;
2017-10-16 22:57:27 +02:00
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
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 Init;
begin
GOutHandle := GetStdHandle(STD_OUTPUT_HANDLE);
if GOutHandle = INVALID_HANDLE_VALUE then
raise EMVCConsole.CreateFmt('Cannot Get STD_OUTPUT_HANDLE - GetLastError() = %d', [GetLastError]);
end;
procedure UpdateMode;
2017-10-16 22:57:27 +02:00
begin
SetConsoleTextAttribute(GOutHandle, Ord(GForeGround) or Ord(GBackGround));
2017-10-16 22:57:27 +02:00
end;
procedure GotoXY(const X, Y: Byte);
var
lCoord: _COORD;
2017-10-16 22:57:27 +02:00
begin
lCoord.X := X;
lCoord.Y := Y;
if not SetConsoleCursorPosition(GOutHandle, lCoord) then
begin
raise EMVCConsole.Create('Invalid Coordinates');
end;
2017-10-16 22:57:27 +02:00
end;
{$ENDIF}
procedure ResetConsole;
2017-10-16 22:57:27 +02:00
begin
// write(ESC + '[0m');
GForeGround := Ord(TConsoleColor.DarkGray);
GBackGround := Ord(TConsoleColor.Black);
UpdateMode;
2017-10-16 22:57:27 +02:00
end;
procedure TextColor(const color: TConsoleColor);
2017-10-16 22:57:27 +02:00
begin
GForeGround := Ord(color);
UpdateMode;
// write(ESC + GetColorString);
2017-10-16 22:57:27 +02:00
end;
procedure TextBackground(const color: TConsoleColor);
2017-10-16 22:57:27 +02:00
begin
GBackGround := Ord(color) shl 4;
UpdateMode;
// write(ESC + GetColorString);
2017-10-16 22:57:27 +02:00
end;
procedure SetDefaults;
2017-10-16 22:57:27 +02:00
begin
GForeGround := Ord(TConsoleColor.White);
GBackGround := Ord(TConsoleColor.Black);
UpdateMode;
2017-10-16 22:57:27 +02:00
end;
2020-06-18 14:49:06 +02:00
procedure SaveColors;
begin
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;
2020-06-18 14:49:06 +02:00
2017-10-16 22:57:27 +02:00
initialization
if IsConsole then
begin
Init;
SetDefaults;
end;
2017-10-16 22:57:27 +02:00
finalization
end.