1
0
PB-ConsoleHelpers/VirtualTerminal.pbi
2021-07-01 21:24:06 +02:00

216 lines
7.9 KiB
Plaintext

;{- Code Header
; ==- Basic Info -================================
; Name: VirtualTerminal.pbi
; Version: N/A
; Author: Herwin Bozet
;
; ==- Compatibility -=============================
; Compiler version: PureBasic 5.70 (x86/x64)
; Operating system: Windows 10 21H1 (Previous versions untested)
;
; ==- Links & License -===========================
; License: Unlicense
;}
;- Compiler directives
XIncludeFile "./Console.pbi"
XIncludeFile "./AinsiEscapeCode.pbi"
;- Module declaration
DeclareModule VirtualTerminal
;-> Macros
;-> > Console.pbi macros
Macro IsConsoleApp() : Console::#IsConsoleApp : EndMacro
Macro GetOutputHandle() : Console::GetOutputHandle() : EndMacro
Macro GetInputHandle() : Console::GetInputHandle() : EndMacro
Macro GetErrorHandle() : Console::GetErrorHandle() : EndMacro
;-> > Platform-dependant Macros
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
Macro EnableVirtualTerminalProcessing() : Console::EnableVirtualTerminalProcessing() : EndMacro
Macro DisableVirtualTerminalProcessing() : Console::DisableVirtualTerminalProcessing() : EndMacro
CompilerElse
Declare.b EnableVirtualTerminalProcessing()
Declare.b DisableVirtualTerminalProcessing()
CompilerEndIf
;-> > Generic Macros
Macro WriteOutput(Message) : Print(Message) : EndMacro
Macro WriteOutputN(Message) : PrintN(Message) : EndMacro
Macro WriteErrorN(Message) : ConsoleError(Message) : EndMacro
;-> > Ainsi Escape Code Macros
;-> > > Cursor
Macro CursorUp() : VirtualTerminal::WriteOutput(#ESC$ + AinsiEscapeCode::#CUU$) : EndMacro
Macro CursorDown() : VirtualTerminal::WriteOutput(#ESC$ + AinsiEscapeCode::#CUD$) : EndMacro
Macro CursorRight() : VirtualTerminal::WriteOutput(#ESC$ + AinsiEscapeCode::#CUF$) : EndMacro
Macro CursorLeft() : VirtualTerminal::WriteOutput(#ESC$ + AinsiEscapeCode::#CUB$) : EndMacro
Macro CursorNextLine(Amount) : VirtualTerminal::WriteOutput(#ESC$ + AinsiEscapeCode::#CNL$) : EndMacro
Macro CursorPreviousLine(Amount) : VirtualTerminal::WriteOutput(#ESC$ + AinsiEscapeCode::#CPL$) : EndMacro
Macro CursorUpBy(Amount) : VirtualTerminal::WriteOutput(#ESC$ + AinsiEscapeCode::#CSI$ + Str(Amount) + AinsiEscapeCode::#CUU$) : EndMacro
Macro CursorDownBy(Amount) : VirtualTerminal::WriteOutput(#ESC$ + AinsiEscapeCode::#CSI$ + Str(Amount) + AinsiEscapeCode::#CUD$) : EndMacro
Macro CursorRightBy(Amount) : VirtualTerminal::WriteOutput(#ESC$ + AinsiEscapeCode::#CSI$ + Str(Amount) + AinsiEscapeCode::#CUF$) : EndMacro
Macro CursorLeftBy(Amount) : VirtualTerminal::WriteOutput(#ESC$ + AinsiEscapeCode::#CSI$ + Str(Amount) + AinsiEscapeCode::#CUB$) : EndMacro
Macro CursorLineDownBy(Amount) : VirtualTerminal::WriteOutput(#ESC$ + AinsiEscapeCode::#CSI$ + Str(Amount) + AinsiEscapeCode::#CNL$) : EndMacro
Macro CursorLineUpBy(Amount) : VirtualTerminal::WriteOutput(#ESC$ + AinsiEscapeCode::#CSI$ + Str(Amount) + AinsiEscapeCode::#CPL$) : EndMacro
Macro CursorToColumn(ColumnNumber) : VirtualTerminal::WriteOutput(#ESC$ + AinsiEscapeCode::#CSI$ + Str(ColumnNumber) + AinsiEscapeCode::#CHA$) : EndMacro
Macro CursorToLine(LineNumber) : VirtualTerminal::WriteOutput(#ESC$ + AinsiEscapeCode::#CSI$ + Str(LineNumber) + AinsiEscapeCode::#VPA$) : EndMacro
Macro CursorTo(X, Y) : VirtualTerminal::WriteOutput(#ESC$ + AinsiEscapeCode::#CSI$ + Str(Y) + ";" + Str(X) + AinsiEscapeCode::#CUP$) : EndMacro
Macro CursorFlip() : VirtualTerminal::WriteOutput(#ESC$ + AinsiEscapeCode::#RI$) : EndMacro
Macro CursorSave() : VirtualTerminal::WriteOutput(#ESC$ + AinsiEscapeCode::#DECSC$) : EndMacro
Macro CursorRestore() : VirtualTerminal::WriteOutput(#ESC$ + AinsiEscapeCode::#DECSR$) : EndMacro
;-> > > Others
Macro ClearDisplay(Mode = AinsiEscapeCode::#ED_0) : VirtualTerminal::WriteOutput(#ESC$ + AinsiEscapeCode::#CSI$ + Str(Mode) + AinsiEscapeCode::#ED$) : EndMacro
Macro ClearDisplayToEnd() : VirtualTerminal::ClearDisplay(AinsiEscapeCode::#ED_0) : EndMacro
Macro ClearDisplayToStart() : VirtualTerminal::ClearDisplay(AinsiEscapeCode::#ED_1) : EndMacro
Macro ClearDisplayFull() : VirtualTerminal::ClearDisplay(AinsiEscapeCode::#ED_2) : EndMacro
Macro ClearDisplayAbsolute() : VirtualTerminal::ClearDisplay(AinsiEscapeCode::#ED_3) : EndMacro
;-> > > Window
Macro SetWindowTitleAndIcon(Title) : VirtualTerminal::WriteOutput(#ESC$ + AinsiEscapeCode::#OSC$ + "0;" + Left(Title, 255) + AinsiEscapeCode::#BEL$) : EndMacro
Macro SetWindowTitle(Title) : VirtualTerminal::WriteOutput(#ESC$ + AinsiEscapeCode::#OSC$ + "2;" + Left(Title, 255) + AinsiEscapeCode::#BEL$) : EndMacro
;-> Procedure Declaration (See the "Platform-dependant Macros" section)
Declare.b GetCursorPosition(*CursorPosition.Console::CursorPosition, TimeoutMs.i = 1)
Declare.i GetTerminalWidth(RestorePosition.b = #True)
Declare.i GetTerminalHeight(RestorePosition.b = #True)
EndDeclareModule
;- Module Definition
Module VirtualTerminal
;-> Compiler Directives
EnableExplicit
;-> Procedure Definition
CompilerIf Not #PB_Compiler_OS = #PB_OS_Windows
; FIXME: May not work if piped, not sure !
Procedure.b EnableVirtualTerminalProcessing() : ProcedureReturn #True : EndIf
Procedure.b DisableVirtualTerminalProcessing() : ProcedureReturn #True : EndIf
CompilerEndIf
Procedure.b GetCursorPosition(*CursorPosition.Console::CursorPosition, TimeoutMs.i = 1)
Protected StartTime.q
Protected Input$ = #Null$
If *CursorPosition
WriteOutput(#ESC$ + AinsiEscapeCode::#CSI$ + AinsiEscapeCode::#DECXCPR$)
; Waiting for stuff to come in...
StartTime = ElapsedMilliseconds()
Repeat
Input$ = Inkey()
Until Input$ <> #Null$ Or ((TimeoutMs <> -1 And (ElapsedMilliseconds() - StartTime > TimeoutMs)) Or (TimeoutMs = -1))
Repeat
Protected NewChar$ = Inkey()
If NewChar$ <> #Null$
Input$ = Input$ + NewChar$
Else
Break
EndIf
ForEver
Protected.i ResponseCodeStart = FindString(Input$, "[") + 1
Input$ = Mid(Input$, ResponseCodeStart, FindString(Input$, "R", ResponseCodeStart) - ResponseCodeStart)
If FindString(Input$, ";") >= 2
*CursorPosition\Y = Val(StringField(Input$, 1, ";"))
*CursorPosition\X = Val(StringField(Input$, 2, ";"))
ProcedureReturn #True
EndIf
EndIf
ProcedureReturn #False
EndProcedure
Procedure.i GetTerminalWidth(RestorePosition.b = #True)
Define OriginalCursorPosition.Console::CursorPosition
Define MeasuringCursorPosition.Console::CursorPosition
If RestorePosition
VirtualTerminal::GetCursorPosition(@OriginalCursorPosition)
EndIf
VirtualTerminal::CursorTo(32767, 0)
VirtualTerminal::GetCursorPosition(@MeasuringCursorPosition)
If RestorePosition
VirtualTerminal::CursorTo(OriginalCursorPosition\X, OriginalCursorPosition\Y)
EndIf
ProcedureReturn MeasuringCursorPosition\X
EndProcedure
Procedure.i GetTerminalHeight(RestorePosition.b = #True)
Define OriginalCursorPosition.Console::CursorPosition
Define MeasuringCursorPosition.Console::CursorPosition
If RestorePosition
VirtualTerminal::GetCursorPosition(@OriginalCursorPosition)
EndIf
VirtualTerminal::CursorTo(0, 32767)
VirtualTerminal::GetCursorPosition(@MeasuringCursorPosition)
If RestorePosition
VirtualTerminal::CursorTo(OriginalCursorPosition\X, OriginalCursorPosition\Y)
EndIf
ProcedureReturn MeasuringCursorPosition\Y
EndProcedure
EndModule
;- Tests
CompilerIf #PB_Compiler_IsMainFile
EnableExplicit
If OpenConsole("Console.pbi")
If Not VirtualTerminal::EnableVirtualTerminalProcessing()
VirtualTerminal::WriteErrorN("Unable to activate virtual terminal processing, output is likely piped !")
CloseConsole()
End 2
EndIf
Else
Debug "Can't open console !"
End 1
EndIf
VirtualTerminal::ClearDisplay(AinsiEscapeCode::#ED_2)
VirtualTerminal::CursorTo(0, 0)
PrintN("-==- Title Bar -==-")
Print("Size: "+VirtualTerminal::GetTerminalWidth()+"x"+VirtualTerminal::GetTerminalHeight())
;Print("Press enter key to exit...")
Debug Input()
;FreeMemory(*Buffer)
VirtualTerminal::DisableVirtualTerminalProcessing()
CloseConsole()
End 0
CompilerEndIf