2021-07-01 21:24:06 +02:00
|
|
|
;{- Code Header
|
|
|
|
; ==- Basic Info -================================
|
|
|
|
; Name: VirtualTerminal.pbi
|
|
|
|
; Version: N/A
|
|
|
|
; Author: Herwin Bozet
|
|
|
|
;
|
|
|
|
; ==- Links & License -===========================
|
|
|
|
; License: Unlicense
|
2021-07-01 22:31:17 +02:00
|
|
|
; GitHub: https://github.com/aziascreations/PB-ConsoleHelpers
|
2021-07-01 21:24:06 +02:00
|
|
|
;}
|
|
|
|
|
|
|
|
;- Compiler directives
|
|
|
|
|
|
|
|
XIncludeFile "./Console.pbi"
|
|
|
|
XIncludeFile "./AinsiEscapeCode.pbi"
|
|
|
|
|
|
|
|
|
|
|
|
;- Module declaration
|
|
|
|
|
|
|
|
DeclareModule VirtualTerminal
|
|
|
|
;-> Macros
|
|
|
|
|
|
|
|
;-> > Console.pbi macros
|
|
|
|
|
2021-07-01 22:31:17 +02:00
|
|
|
;Macro CursorPosition : Console::CursorPosition : EndMacro
|
|
|
|
|
2021-07-01 21:24:06 +02:00
|
|
|
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 CursorSave() : VirtualTerminal::WriteOutput(#ESC$ + AinsiEscapeCode::#DECSC$) : EndMacro
|
|
|
|
Macro CursorRestore() : VirtualTerminal::WriteOutput(#ESC$ + AinsiEscapeCode::#DECSR$) : EndMacro
|
|
|
|
|
2021-07-01 22:31:17 +02:00
|
|
|
; Does not appear to work properly in cmd.exe
|
|
|
|
Macro CursorFlip() : VirtualTerminal::WriteOutput(#ESC$ + AinsiEscapeCode::#RI$) : EndMacro
|
|
|
|
|
|
|
|
;-> > > Screen Buffer
|
|
|
|
Macro ScrollUpBy(Amount = 1) : VirtualTerminal::WriteOutput(#ESC$ + AinsiEscapeCode::#CSI$ + Str(Amount) + AinsiEscapeCode::#SU$) : EndMacro
|
|
|
|
Macro ScrollDownBy(Amount = 1) : VirtualTerminal::WriteOutput(#ESC$ + AinsiEscapeCode::#CSI$ + Str(Amount) + AinsiEscapeCode::#SD$) : EndMacro
|
|
|
|
Macro ScrollUp() : VirtualTerminal::ScrollUpBy() : EndMacro
|
|
|
|
Macro ScrollDown() : VirtualTerminal::ScrollDownBy() : EndMacro
|
|
|
|
|
|
|
|
;-> > > Others ?
|
2021-07-01 21:24:06 +02:00
|
|
|
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
|
|
|
|
|
2021-07-01 22:31:17 +02:00
|
|
|
Macro ClearLineDisplay(Mode = AinsiEscapeCode::#EL_0) : VirtualTerminal::WriteOutput(#ESC$ + AinsiEscapeCode::#CSI$ + Str(Mode) + AinsiEscapeCode::#EL$) : EndMacro
|
|
|
|
Macro ClearLineToEnd() : VirtualTerminal::ClearLineDisplay(AinsiEscapeCode::#EL_0) : EndMacro
|
|
|
|
Macro ClearLineToStart() : VirtualTerminal::ClearLineDisplay(AinsiEscapeCode::#EL_1) : EndMacro
|
|
|
|
Macro ClearLineFull() : VirtualTerminal::ClearLineDisplay(AinsiEscapeCode::#EL_2) : EndMacro
|
|
|
|
|
2021-07-01 21:24:06 +02:00
|
|
|
;-> > > 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)
|
|
|
|
|
2021-07-01 22:31:17 +02:00
|
|
|
; May mess up some terminals (ConEmu with cmd doesn't like it at all...)
|
2021-07-01 21:24:06 +02:00
|
|
|
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
|
|
|
|
|
2021-07-01 22:31:17 +02:00
|
|
|
Define TerminalWidth.i = VirtualTerminal::GetTerminalWidth(#False)
|
|
|
|
Define TerminalHeight.i = VirtualTerminal::GetTerminalHeight(#False)
|
|
|
|
|
2021-07-01 21:24:06 +02:00
|
|
|
VirtualTerminal::ClearDisplay(AinsiEscapeCode::#ED_2)
|
|
|
|
VirtualTerminal::CursorTo(0, 0)
|
|
|
|
|
2021-07-01 22:31:17 +02:00
|
|
|
VirtualTerminal::WriteOutput(RSet("", TerminalWidth, "#"))
|
|
|
|
VirtualTerminal::WriteOutput(LSet("# Application Title", TerminalWidth-1) + "#")
|
|
|
|
VirtualTerminal::WriteOutput(RSet("", TerminalWidth, "#"))
|
|
|
|
|
|
|
|
VirtualTerminal::CursorTo(0, TerminalHeight - 2)
|
|
|
|
|
|
|
|
VirtualTerminal::WriteOutput(RSet("", TerminalWidth, "#"))
|
|
|
|
VirtualTerminal::WriteOutput(LSet("# Footer text", TerminalWidth-1) + "#")
|
|
|
|
VirtualTerminal::WriteOutput(RSet("", TerminalWidth, "#"))
|
|
|
|
VirtualTerminal::CursorTo(0, 4)
|
|
|
|
|
|
|
|
|
2021-07-01 21:24:06 +02:00
|
|
|
|
2021-07-01 22:31:17 +02:00
|
|
|
Print("Press enter key to exit...")
|
|
|
|
Input()
|
2021-07-01 21:24:06 +02:00
|
|
|
|
|
|
|
VirtualTerminal::DisableVirtualTerminalProcessing()
|
|
|
|
CloseConsole()
|
|
|
|
End 0
|
|
|
|
CompilerEndIf
|