#include-once
#include <GuiRichEdit.au3>
#include <GUIConstants.au3>
#include <WinAPISys.au3> ; for _WinAPI_SetTimer ; _WinAPI_KillTimer

; the following include is by @melba23
; get it here -> https://www.autoitscript.com/forum/topic/114034-stringsize-m23-new-version-16-aug-11/
#include <stringsize.au3> ; _StringSize()
; #include <ARRAY.AU3>

; the _GUICtrlGetFont() by KaFu, Prog@ndy
; included at the bottom of this script

OnAutoItExitRegister("_EndVintage")

; Default 'screen' dimension in chars (columns and rows)
Global $__g_iColumns = 80 ; width of screen (nr. of chars per line)
Global $__g_iRows = 24 ; height of screen (nr. of lines)
Global $__g_iTabStop = 8 ; Horizontal tab stop step (Historically tab stops where every 8th character)

#cs
	Default Font parameters (a monospaced font is MANDATORY!)
	"The only monospaced TrueType fonts shipped by Microsoft are Courier New, which shipped with Windows 3.1,
	and Lucida Sans Typewriter, which was included in the TrueType Font Pack.
	All other TrueType fonts included with Windows 3.1 and the TrueType Font Pack are proportional fonts."
	https://support.microsoft.com/en-us/help/90057/microsoft-supplied-monospaced-truetype-fonts
#ce
Global $__g_sFontName = "Courier New"
Global $__g_fFontSize = 12
Global $__g_iFontWeight = 400 ; normal
Global $__g_iCharSet = 0 ; see --> _GUICtrlRichEdit_SetFont()

Global $__g_hTimerProc = DllCallbackRegister('__SwitchScreen', 'none', 'hwnd;uint;uint_ptr;dword')
Global $__g_iTimerID ; see --> _WinAPI_KillTimer()

; the screen text buffer
Global $__g_sBuffer = ""
; GUI and 'screen layers' handles
Global $__g_hParentGui, $__g_hMainGui, $__g_ahScreen[3]

; initialize cursor position
Global $__g_iCursorPosX = 1 ; actual cursor horizontal position
Global $__g_iCursorPosY = 1 ; actual cursor vertical position
Global $__g_iCursorPushX = $__g_iCursorPosX ; temp X storage (for a later pull)
Global $__g_iCursorPushY = $__g_iCursorPosY ; temp Y storage (for a later pull)

; initialize text wrap-around default
Global $__g_bWrapAround = True ; (you can change this directly or by the _VDT_SetWrapAround(True/False)

; ANSI Control Sequence Introducer
Global Const $__g_sCSI = Chr(27) & "["

; Unicode shapes associated to control codes [ChrW()]
Global $__g_aControlChars[32] = [ _
		0, 9786, 9787, 9829, 9830, 9827, 9824, 8226, 9688, 9675, 9689, 9794, 9792, 9834, 9835, 9788, _
		9658, 9668, 8597, 8252, 182, 167, 9644, 8616, 8593, 8595, 8594, 8592, 8735, 8596, 9650, 9660]

; possible text attributes:
Global Enum Step * 2 $Bold, $Italic, $Underline, $Concealed, $Inverse, $Blink, $Flash, $VisCtrls
; see the _VDT_Style() function for how to set or unset a text styles

; the BITs of the following byte are used as flags, -> see the _VDT_Style() function for how to set or unset a text styles
Global $__g_dbStyles = 0 ; 0 x 0 0 0 0 0 0 0 0 ; 8 bits as flags 1=true(on), 0=false(off)
;                              ^ ^ ^ ^ ^ ^ ^ ^
;                              | | | | | | | |
;                              | | | | | | | +-> Bold        bit value   1
;                              | | | | | | +---> Italic      bit value   2
;                              | | | | | +-----> Underline   bit value   4
;                              | | | | +-------> Concealed   bit value   8
;                              | | | +---------> Inverse     bit value  16
;                              | | +-----------> Blink       bit value  32
;                              | +-------------> Flash       bit value  64
;                              +---------------> VisCtrls    bit value  128 (visualize control chars)

; used by the _GUICtrlRichEdit_SetCharAttributes function to set or unset an attribute on text
Global $__g_aAttribute[2] = ['-', '+'] ; [0] -> '-' -> False ; [1] -> "+" -> True

; Color names (indexes for the $__g_aColor array)
Global Enum $Black, $Red, $Green, $Yellow, $Blue, $Magenta, $Cyan, $White, $BrightBlack, _
		$BrightRed, $BrightGreen, $BrightYellow, $BrightBlue, $BrightMagenta, $BrightCyan, $BrightWhite

; Set ANSI 16 colors values (0 to 15 basic 16 colors)
Global $__g_aColor[256] ; [16]
$__g_aColor[$Black] = 0x000000 ;         00 = Black          bk
$__g_aColor[$Red] = 0x0000AA ;           01 = Red            rd
$__g_aColor[$Green] = 0x00AA00 ;         02 = Green          gn
$__g_aColor[$Yellow] = 0x00AAAA ;        03 = Yellow         yl
$__g_aColor[$Blue] = 0xAA0000 ;          04 = Blue           bu
$__g_aColor[$Magenta] = 0xAA00AA ;       05 = Magenta        mg
$__g_aColor[$Cyan] = 0xAAAA00 ;          06 = Cyan           cy
$__g_aColor[$White] = 0xAAAAAA ;         07 = White          wt
$__g_aColor[$BrightBlack] = 0x555555 ;   08 = Bright Black   BK
$__g_aColor[$BrightRed] = 0x0000FF ;     09 = Bright Red     RD
$__g_aColor[$BrightGreen] = 0x00FF00 ;   10 = Bright Green   GN
$__g_aColor[$BrightYellow] = 0x00FFFF ;  11 = Bright Yellow  YE
$__g_aColor[$BrightBlue] = 0xFF0000 ;    12 = Bright Blue    BU
$__g_aColor[$BrightMagenta] = 0xFF00FF ; 13 = Bright Magenta MG
$__g_aColor[$BrightCyan] = 0xFFFF00 ;    14 = Bright Cyan    CY
$__g_aColor[$BrightWhite] = 0xFFFFFF ;   15 = Bright White   WT

; Set ANSI 256 colors palette
__SetupANSIPalette() ; (generates the remaining colors in addition to those here above (16 to 255)

; default text colors
Global $__g_iDefaultANSIForeground = $White ; (0 - 15)
Global $__g_iDefaultANSIBackground = $Black ; (0 - 15)
Global $__g_iDefaultForeground = _ANSIcolor($__g_iDefaultANSIForeground) ; $White
Global $__g_iDefaultBackground = _ANSIcolor($__g_iDefaultANSIBackground) ; $Black
; Global $__g_iDefaultForeground = $White
; Global $__g_iDefaultBackground = $Black
Global $__g_iActiveFGColor = $__g_iDefaultForeground ; actual Foreground color
Global $__g_iActiveBGColor = $__g_iDefaultBackground ; actual Background color

; ensure creation of only one TextMode 'control'
Global $__g_bControlExists = False

Func __SetupANSIPalette()
	; Set ANSI colors values (16 to 231)
	Local $aSteps[7] = [16, '00', '5F', '87', 'AF', 'D7', 'FF']
	For $i0 = 1 To 6
		For $i1 = 1 To 6
			For $i2 = 1 To 6
				$__g_aColor[$aSteps[0]] = Dec($aSteps[$i2] & $aSteps[$i1] & $aSteps[$i0])
				$aSteps[0] += 1
			Next
		Next
	Next

	; Set ANSI colors values (232 to 255) grey scale
	For $i0 = 8 To 238 Step 10
		$__g_aColor[$aSteps[0]] = Dec(Hex($i0, 2) & Hex($i0, 2) & Hex($i0, 2))
		$aSteps[0] += 1
	Next
EndFunc   ;==>__SetupANSIPalette

; HotKeySet("{ESC}", "_EndByESC") ; press 'esc' to end

; #FUNCTION# ====================================================================================================================
; Name ..........: _VDT_GUICreate
; Description ...: creates a GUI containing a full GUI window Video Terminal
; Syntax ........: _VDT_GUICreate([$sTitle = "Vintage Terminal"[, $iColumns = $__g_iColumns[, $iRows = $__g_iRows[, $fFontSize = $__g_fFontSize[, $sFontName = $__g_sFontName[, $iDefaultForeground = $__g_iDefaultForeground[, $iDefaultBackground = $__g_iDefaultBackground[, $nStyle = -1[, $nExStyle = -1]]]]]]]]])
;
; Parameters ....: $sTitle              - [optional] String of title for the window
;                  $iColumns            - [optional] Number of wanted columns. Default is 80.
;                  $iRows               - [optional] Number of wanted rows. Default is 24.
;                  $fFontSize           - [optional] Font size. Default is 12.
;                  $sFontName           - [optional] Font name. Default is Courier New. (a monospaced font is mandatory!!)
;                  $iDefaultForeground  - [optional] Foreground color. Default is $__g_iDefaultForeground (if changed it becomes the new default)
;                  $iDefaultBackground  - [optional] Background color. Default is $__g_iDefaultBackground (if changed it becomes the new default)
;                  $nStyle              - [optional] defines the style of the window
;                  $nExStyle            - [optional] defines the extended style of the window
;
; Return values .: a 3-element array containing the following information:
;                                               [0] hWnd of the created window
;                                               [1] Width of the window
;                                               [2] Height of the window
; Author ........: Chimp
; Modified ......:
; Remarks .......: the overall dimension of the window is determined by the following parameters:
;                  number of columns ($iColumns); number of rows ($iRows); Size of font ($fFontSize)
;                  So there are not width and height parameter for the GUI, since it depends and is determined by the 3 above values
;                  Also, if the required font dimension is not available for this font, the most similar available dimension is used instead.
;                  The overall resulting dimensions are however notified to the caller into the returned array.
;
; Related .......:
; Link ..........:
; Example .......: No
; ===============================================================================================================================
Func _VDT_GUICreate($sTitle = Default, $iColumns = $__g_iColumns, $iRows = $__g_iRows, $fFontSize = $__g_fFontSize, $sFontName = $__g_sFontName, $iDefaultForeground = $__g_iDefaultForeground, $iDefaultBackground = $__g_iDefaultBackground, $nStyle = -1, $nExStyle = -1)

	; check if already created
	If $__g_bControlExists = True Then Return

	__VDT_Check_Defaults($iColumns, $iRows, $fFontSize, $sFontName, $iDefaultForeground, $iDefaultBackground)
	; fill the buffer with empty values (spaces) and returns dimensions
	Local $aWinDim = __VDT_CreateBuffer($__g_iColumns, $__g_iRows) ; create the text buffer and returns Width and Height dimensions
	Local $iWidth = $aWinDim[2], $iHeight = $aWinDim[3] ; Screen dimensions

	; create a GUI
	$sTitle = ($sTitle = Default) ? "Vintage Terminal" : $sTitle
	$nExStyle = -1 ? $WS_EX_COMPOSITED : BitOR($nExStyle, $WS_EX_COMPOSITED) ; $WS_EX_COMPOSITED is always included
	$__g_hMainGui = GUICreate($sTitle, $iWidth, $iHeight, -1, -1, $nStyle, $nExStyle)
	__VDT_CreateLayers($__g_hMainGui, 0, 0, $iWidth, $iHeight)

	GUISetState(@SW_HIDE, $__g_hMainGui)
	$__g_bControlExists = True ; only one terminal is allowed
	Local $aArray[3] = [$__g_hMainGui, $iWidth, $iHeight]
	Return $aArray
EndFunc   ;==>_VDT_GUICreate

; nearly same as above, but instead of creating a GUI,
; this creates only the control to be placed on an already existent parent GUI
; #FUNCTION# ====================================================================================================================
; Name ..........: _VDT_GUICtrl_Create
; Description ...:  This creates only the 'Video Terminal Control' and places it on an already existent parent GUI
; Syntax ........: _VDT_GUICtrl_Create($hWnd[, $iLeft = 0[, $iTop = 0[, $iColumns = Default[, $iRows = Default[, $fFontSize =  [, $sFontName = Default[, $iDefaultForeground = Default[, $iDefaultBackground = Default]]]]]]]])
; Parameters ....: $hWnd                - A handle value. the handle of the parent window
;                  $iLeft               - [optional] An integer value. Default is 0. Left position where to place the control on the GUI
;                  $iTop                - [optional] An integer value. Default is 0. Top position   "
;                  $iColumns            - [optional] An integer value. The number of wanted columns (default is the global variable $__g_iColumns) 80
;                  $iRows               - [optional] An integer value. The number of wanted rows (default is the global variable $__g_iRows) 24
;                  $fFontSize           - [optional] A floating value. Default is $__g_sFontSize -> 12
;                  $sFontName           - [optional] A string value. Default is $__g_sFontName -> "Courier New"
;                  $iDefaultForeground  - [optional] An integer value. Default is $__g_iDefaultForeground
;                  $iDefaultBackground  - [optional] An integer value. Default is $__g_iDefaultBackground
; Return values .: a 3-element array containing the following information:
;                                               [0] an array of handles of the created layers
;                                               [1] Width of the control
;                                               [2] Height of the control
; Author ........: Chimp
; Modified ......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......: No
; ===============================================================================================================================
Func _VDT_GUICtrl_Create($hWnd, $iLeft = 0, $iTop = 0, $iColumns = Default, $iRows = Default, $fFontSize = Default, $sFontName = Default, $iDefaultForeground = Default, $iDefaultBackground = Default)
	If $__g_bControlExists = True Then Return
	$__g_hParentGui = $hWnd

	; force the $WS_EX_COMPOSITED ExStyle on the parent GUI
	GUISetStyle(-1, BitOR(GUIGetStyle($hWnd)[1], $WS_EX_COMPOSITED), $hWnd)

	__VDT_Check_Defaults($iColumns, $iRows, $fFontSize, $sFontName, $iDefaultForeground, $iDefaultBackground)

	; fill the buffer with empty values (spaces) and returns dimensions
	Local $aWinDim = __VDT_CreateBuffer($__g_iColumns, $__g_iRows)
	Local $iWidth = $aWinDim[2], $iHeight = $aWinDim[3] ; Screen dimensions
	__VDT_CreateLayers($hWnd, $iLeft, $iTop, $iWidth, $iHeight)

	$__g_bControlExists = True

	; returns the handles of the layers and the size of the newly created control
	Local $aArray[3] = [$__g_ahScreen, $iWidth, $iHeight]
	Return $aArray
EndFunc   ;==>_VDT_GUICtrl_Create

; replace default values with the new required if needed
Func __VDT_Check_Defaults($iColumns, $iRows, $fFontSize, $sFontName, $iDefaultForeground, $iDefaultBackground)

	; if default values are changed then set also global variables accordingly
	$__g_iColumns = (($iColumns = Default) Or (String($iColumns) = "")) ? $__g_iColumns : Number($iColumns)
	$__g_iRows = (($iRows = Default) Or (String($iRows) = "")) ? $__g_iRows : Number($iRows)
	$__g_fFontSize = (($fFontSize = Default) Or (String($fFontSize) = "")) ? $__g_fFontSize : Number($fFontSize)
	$__g_sFontName = (($sFontName = Default) Or (String($sFontName) = "")) ? $__g_sFontName : $sFontName
	$__g_iDefaultForeground = (($iDefaultForeground = Default) Or (String($iDefaultForeground) = "")) ? $__g_iDefaultForeground : Number($iDefaultForeground)
	$__g_iDefaultBackground = (($iDefaultBackground = Default) Or (String($iDefaultBackground) = "")) ? $__g_iDefaultBackground : Number($iDefaultBackground)

	$__g_iActiveFGColor = $__g_iDefaultForeground
	$__g_iActiveBGColor = $__g_iDefaultBackground
EndFunc   ;==>__VDT_Check_Defaults

Func _VDT_ResetToDefaultColors()
	$__g_iActiveFGColor = $__g_iDefaultForeground ; actual Foreground color
	$__g_iActiveBGColor = $__g_iDefaultBackground ; actual Background color
EndFunc   ;==>_VDT_ResetToDefaultColors

; Create sceen buffer and get dimensions
Func __VDT_CreateBuffer($iColumns, $iRows)
	$__g_sBuffer = _StringReplay(_StringReplay(" ", $iColumns) & @CRLF, $iRows - 1) & _StringReplay(" ", $iColumns) ; a string of width * height blank spaces + @crlf
	;
	; _StringSize by @Melba23 (determine the size of the screen according to the font parameters)
	;                --------
	Return _StringSize($__g_sBuffer, $__g_fFontSize, $__g_iFontWeight, 0, $__g_sFontName)
EndFunc   ;==>__VDT_CreateBuffer

Func __VDT_CreateLayers($_hGUI, $iLeft, $iTop, $iWidth, $iHeight)
	; a transparent layer above the rich edit to protect it from clicks and to allow the dragging of the GUI
	$__g_ahScreen[2] = GUICtrlCreateLabel("", $iLeft, $iTop, $iWidth, $iHeight, -1, $GUI_WS_EX_PARENTDRAG)
	GUICtrlSetBkColor(-1, $GUI_BKCOLOR_TRANSPARENT) ;  This is like a glass over the underlying RichEdit
	GUICtrlSetCursor(-1, 2) ; Cursor is an arrow (instead of the default I-beam)
	GUICtrlSetFont(-1, $__g_fFontSize, $__g_iFontWeight, 0, $__g_sFontName)

	; by KaFu, Prog@ndy (get actual font size)
	;    ----  --------
	$__g_fFontSize = Number(_GUICtrlGetFont($__g_ahScreen[2])[0])

	; 2 rich-edit screens (they will be shown alternately to make the Blink and Flash effects)
	$__g_ahScreen[0] = HWnd(_GUICtrlRichEdit_Create($_hGUI, "", $iLeft, $iTop, $iWidth + 4, $iHeight + 4, BitXOR($ES_READONLY, $ES_MULTILINE))) ; layer 0
	_GUICtrlRichEdit_SetRECT($__g_ahScreen[0], 1, 1, $iWidth + 1, $iHeight + 1, True)
	_GUICtrlRichEdit_SetSel($__g_ahScreen[0], 0, -1, True)
	_GUICtrlRichEdit_SetFont($__g_ahScreen[0], $__g_fFontSize, $__g_sFontName)
	;
	$__g_ahScreen[1] = HWnd(_GUICtrlRichEdit_Create($_hGUI, "", $iLeft, $iTop, $iWidth + 4, $iHeight + 4, BitXOR($ES_READONLY, $ES_MULTILINE))) ; layer 1
	_GUICtrlRichEdit_SetRECT($__g_ahScreen[1], 1, 1, $iWidth + 1, $iHeight + 1, True)
	_GUICtrlRichEdit_SetSel($__g_ahScreen[1], 0, -1, True)
	_GUICtrlRichEdit_SetFont($__g_ahScreen[1], $__g_fFontSize, $__g_sFontName)

	; Initialize and clear the screen
	_VDT_CLS()

	; activate the switching of the 2 RichEdit 'screens'
	_VDT_SetTimer()
EndFunc   ;==>__VDT_CreateLayers

; From Htab Vtab (1 based) to absolute position within the screen buffer
Func __GetAbsPos($iHtab = 1, $iVtab = 1, $iScreenWidth = $__g_iColumns)
	Return ($iVtab - 1) * ($iScreenWidth + 1) + $iHtab
EndFunc   ;==>__GetAbsPos

; From Absolute To Htab Vtab (1 based)
Func __GetTabsPos($iAbsolutePos = 1, $iScreenWidth = $__g_iColumns)
	Local $aXY[2]
	$aXY[0] = Mod($iAbsolutePos - 1, $iScreenWidth) + 1 ;  Horizontal position within the Screen (column) $iHtab
	$aXY[1] = Int(($iAbsolutePos - 1) / $iScreenWidth) + 1 ; Vertical position within the Screen (row) $iVtab
	Return $aXY
EndFunc   ;==>__GetTabsPos

; retrieve chars from the screen starting from coordinates x,y
; default retrieve only one char
Func _VDT_PeekChars($iX, $iY, $iZ = 1)
	Return StringMid(_GUICtrlRichEdit_GetText($__g_ahScreen[0]), __GetAbsPos($iX, $iY), $iZ)
EndFunc   ;==>_VDT_PeekChars

; don't show drawing activity (draw behind the shenes)
Func _VDT_PauseRedraw()
	; _VDT_KillTimer() ; also suspend screen switcher
	; _GUICtrlRichEdit_PauseRedraw($__g_ahScreen[0])
	_GUICtrlRichEdit_PauseRedraw($__g_ahScreen[1])
	WinSetState(HWnd($__g_ahScreen[0]), '', @SW_SHOW)
EndFunc   ;==>_VDT_PauseRedraw

; show what's been drawn
Func _VDT_ResumeRedraw()
	;_GUICtrlRichEdit_ResumeRedraw($__g_ahScreen[0])
	_GUICtrlRichEdit_ResumeRedraw($__g_ahScreen[1])
	; _VDT_SetTimer()
EndFunc   ;==>_VDT_ResumeRedraw

; Disable Flash/Blink effect
Func _VDT_PauseSwitching()
	_VDT_KillTimer() ; also suspend screen switcher
	WinSetState(HWnd($__g_ahScreen[0]), '', @SW_SHOW)
EndFunc   ;==>_VDT_PauseSwitching

; Enable Flash/Blink effect
Func _VDT_ResumeSwitching()
	$__g_iTimerID = _WinAPI_SetTimer(0, 0, 500, DllCallbackGetPtr($__g_hTimerProc))
EndFunc   ;==>_VDT_ResumeSwitching

; enables the screens switching
Func _VDT_SetTimer()
	$__g_iTimerID = _WinAPI_SetTimer(0, 0, 500, DllCallbackGetPtr($__g_hTimerProc))
EndFunc   ;==>_VDT_SetTimer

; stops the screens switching
Func _VDT_KillTimer()
	_WinAPI_KillTimer(0, $__g_iTimerID)
EndFunc   ;==>_VDT_KillTimer

; Change or read the WrapAraound setting
Func _VDT_SetWrapAround($vAction = Null)
	If $vAction <> Null Then
		If $vAction = False Then
			$__g_bWrapAround = False
		Else
			$__g_bWrapAround = True
		EndIf
	EndIf
	Return $__g_bWrapAround
EndFunc   ;==>_VDT_SetWrapAround

; #FUNCTION# ====================================================================================================================
; Name ..........: _VDT_Print
; Description ...: Main printing function
; Syntax ........: _VDT_Print([$sString = ""[, $iHtab = $__g_iCursorPosX[, $iVtab = $__g_iCursorPosY[, $iForegroundColor = $__g_iActiveFGColor[, $iBackgroundColor = $__g_iActiveBGColor]]]]])
; Parameters ....: $sString             - [optional] a string value. Default is "". String can include ANSI sequences and ctrl chars
;                  $iHtab               - [optional] column where to start printing
;                  $iVtab               - [optional] row where to start printnting
;                  $iForegroundColor    - [optional] wanted foreground color
;                  $iBackgroundColor    - [optional] Wanted bckground color
;                  $bWrap               - [optional] Default is True, printed Text wrapsaround
;                                                    if is False, the text that exceeds the right margin is simply discarded
; Return values .: None
; Author ........: Chimp
; Modified ......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......: No
; ===============================================================================================================================
Func _VDT_Print($sString = "", $iHtab = $__g_iCursorPosX, $iVtab = $__g_iCursorPosY, $iForegroundColor = $__g_iActiveFGColor, $iBackgroundColor = $__g_iActiveBGColor, $bWrap = $__g_bWrapAround)

	If $iHtab = Default Or $iHtab = "" Then $iHtab = $__g_iCursorPosX
	If $iVtab = Default Or $iVtab = "" Then $iVtab = $__g_iCursorPosY

	Local $iStartingHtab = $iHtab
	Local $sANSI_Escape
	Local $aParameters[1]
	Local $iNumParams

	; step 1 - split string on ansi escape sequences and/or on control chars (if any)
	; -------------------------------------------------------------------------------
	; credits
	; -------
	; RegExp pattern by @jchd (Thanks to @jchd)           https://www.autoitscript.com/forum/topic/192953-regexp-and-ansi-escape-sequences/?do=findComment&comment=1386039
	;                   -----
	; pattern also adapted by @mikell (Thanks to @mikell) https://www.autoitscript.com/forum/topic/192953-regexp-and-ansi-escape-sequences/?do=findComment&comment=1387160
	;                         -------
	Local $aStringChunks = StringRegExp($sString, "(?x)(?(DEFINE) (?<ANSI_Escape> \[ (?:\s*\d*\s*;?)* [[:alpha:]]) )(?| \x1B(?&ANSI_Escape) | [\x01-\x1A\x1C-\x1F] | \x1B(?!(?&ANSI_Escape)) | (?:[^\x01-\x1F] (?!(?&ANSI_Escape)))+ )", 3)

	; remove escape sequences from the string (Thanks to @jchd again)
	; $sString = StringRegExpReplace($sString, "(?x) (\x1B \[ (?:\s*\d*\s*;?)* [[:alpha:]])", "")

	; step 2 - parse the resulting $aStringChunks array
	For $iChunk = 0 To UBound($aStringChunks) - 1
		; check presence of escape sequences or control chars
		$sANSI_Escape = StringReplace($aStringChunks[$iChunk], " ", "") ; clean unneeded (and disturbing)spaces
		If StringLeft($sANSI_Escape, 2) = $__g_sCSI Then ;  it is a CSI (Control Sequence Introducer)
			; get ansi escape sequence parameters
			$aParameters = StringSplit(StringMid(StringTrimRight($sANSI_Escape, 1), 3), ";") ; extract the parameters of this sequence
			$iNumParams = $aParameters[0] ; keep number of parameters
			$aParameters[0] = StringRight($sANSI_Escape, 1) ; gat the final character (put it in [0])
			;
			;   ANSI Escape squence interpreter (http://man7.org/linux/man-pages/man4/console_codes.4.html)
			;                                    https://en.wikipedia.org/wiki/ANSI_escape_code
			;   -------------------------------------------------------------------------------------------
			Select
				Case $aParameters[0] == "a" ; HPR   Move cursor right the indicated # of columns.
					$iHtab += Number($aParameters[1]) + ($aParameters[1] = 0)
					$__g_iCursorPosX = $iHtab

				Case $aParameters[0] == "d" ; VPA   Move cursor to the indicated row, current column.
					$iHtab = Number($aParameters[1])
					$__g_iCursorPosX = $iHtab

				Case $aParameters[0] == "e" ; VPR   Move cursor down the indicated # of rows.
					$iVtab += Number($aParameters[1]) + ($aParameters[1] = 0)
					$__g_iCursorPosY = $iVtab

				Case $aParameters[0] == "f" ; HVP   Move cursor to the indicated row, column.
					ReDim $aParameters[3] ; mandatory 2 parameters
					$iVtab = Number($aParameters[1]) + ($aParameters[1] = 0)
					$__g_iCursorPosY = $iVtab
					$iHtab = Number($aParameters[2]) + ($aParameters[2] = 0)
					$__g_iCursorPosX = $iHtab

				Case $aParameters[0] == "g" ; TBC   Without parameter: clear tab stop at current position.
					; ?
				Case $aParameters[0] == "h" ; SM    Set Mode
					; ?
				Case $aParameters[0] == "l" ; RM    Reset Mode
					; ?
				Case $aParameters[0] == "m" ; SGR   Set attributes.

					For $iParam = 1 To $iNumParams ; UBound($aParameters) - 1

						Switch Number($aParameters[$iParam])
							Case 0 ; reset all attributes to their defaults
								_VDT_SetActiveColors($__g_iDefaultForeground, $__g_iDefaultBackground)
								; _VDT_SetAttribute($Normal)
								_VDT_Style($Bold, False) ; $Bold = False
								_VDT_Style($Italic, False) ; $Italic = False
								_VDT_Style($Underline, False) ; $Underline = False
								_VDT_Style($Concealed, False) ; $Concealed = False
								_VDT_Style($Inverse, False) ; $Inverse = False
								_VDT_Style($Flash, False) ; $Flash = False
								_VDT_Style($Blink, False) ; $Blink = False

								$iBackgroundColor = _VDT_SetActiveBackColor($__g_iDefaultBackground)
								$iForegroundColor = _VDT_SetActiveForeColor($__g_iDefaultForeground)

							Case 1 ; set Bold (or increased intensity)
								_VDT_Style($Bold, True)

							Case 2 ; set Faint (decreased intensity)
								; _VDT_Style($Bold, False)
								;
								;
							Case 3 ; set Italic
								_VDT_Style($Italic, True)

							Case 4 ; set underscore
								_VDT_Style($Underline, True)

							Case 5 ; set blink
								_VDT_Style($Blink, True)

							Case 6 ; Rapid Blink (used as "Flash" effect here instead)
								; https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
								; http://www.pinon-hebert.fr/Knowledge/index.php/Codes_ANSI
								_VDT_Style($Flash, True) ; (emphasized blink)
								; use "25" as blink and/or flash off

							Case 7 ; set reverse video
								_VDT_Style($Inverse, True)

							Case 8 ; concealed (foreground becomes = background)
								_VDT_Style($Concealed, True)

							Case 22 ; bold off
								_VDT_Style($Bold, False)

							Case 23 ; Italic off
								_VDT_Style($Italic, False)

							Case 24 ; underline off
								_VDT_Style($Underline, False)

							Case 25 ; blink off
								_VDT_Style($Blink, False)

							Case 26 ; flash off (custom)
								_VDT_Style($Flash, False) ;

							Case 27 ; reverse video off
								_VDT_Style($Inverse, False)

							Case 28 ; concealed off
								_VDT_Style($Concealed, False)

							Case 30 To 37 ; set foreground color
								;  $iForegroundColor = _VDT_SetActiveForeColor(Number($aParameters[$iParam]) - 30)
								$iForegroundColor = _VDT_SetActiveForeColor(_ANSIcolor(Number($aParameters[$iParam]) - 30))

							Case 38 ; set default foreground color
								;       38;5;#  foreground based on index (0-255)
								;       38;2;#;#;# foreground based on RGB

								If ($iParam + 1) < $iNumParams Then ; there are at least other 2 parameters
									$iParam += 1
									Switch Number($aParameters[$iParam]) ; peek next (sub)Parameter
										Case 5 ; color based on index (0-255)
											$iParam += 1
											; color_index = $aParameters[$iParam]
											$iForegroundColor = _VDT_SetActiveForeColor(_ANSIcolor(Number($aParameters[$iParam]))) ; 0-255
										Case 2
											If ($iParam + 2) < $iNumParams Then ; there are at least other 3 parameters
												$iParam += 3
												; Blue_component = Number($aParameters[$iParam]
												$iForegroundColor = Hex($aParameters[$iParam], 2)
												$iParam -= 1
												; Green_component = Number($aParameters[$iParam]
												$iForegroundColor &= Hex($aParameters[$iParam], 2)
												$iParam -= 1
												; Red_component = Number($aParameters[$iParam]
												$iForegroundColor &= Hex($aParameters[$iParam], 2)
												$iForegroundColor = _VDT_SetActiveForeColor(Dec($iForegroundColor))
												$iParam += 2
											Else
												; wrong number of parameters, 3 are needed for 'Case 2'
											EndIf
									EndSwitch

								Else ; wrong number of parameters, set color to black
									; .... or (better choice) leave colors unchanged
								EndIf

							Case 39 ; set default foreground (using current intensity)

							Case 40 To 47 ; set background color
								$iBackgroundColor = _VDT_SetActiveBackColor(_ANSIcolor(Number($aParameters[$iParam]) - 40))

							Case 48
								;       48;5;#  background based on index (0-255)
								;       48;2;#;#;# background based on RGB

								If ($iParam + 1) < $iNumParams Then ; there are at least other 2 parameters
									$iParam += 1
									Switch Number($aParameters[$iParam]) ; peek next (sub)Parameter
										Case 5 ; color based on index (0-255)
											$iParam += 1
											; color_index = $aParameters[$iParam]
											$iBackgroundColor = _VDT_SetActiveBackColor(_ANSIcolor(Number($aParameters[$iParam]))) ; 0-255
										Case 2
											If ($iParam + 2) < $iNumParams Then ; there are at least other 3 parameters
												$iParam += 3
												; Blue_component = Number($aParameters[$iParam]
												$iBackgroundColor = Hex($aParameters[$iParam], 2)
												$iParam -= 1
												; Green_component = Number($aParameters[$iParam]
												$iBackgroundColor &= Hex($aParameters[$iParam], 2)
												$iParam -= 1
												; Red_component = Number($aParameters[$iParam]
												$iBackgroundColor &= Hex($aParameters[$iParam], 2)
												$iBackgroundColor = _VDT_SetActiveBackColor(Dec($iBackgroundColor))
												$iParam += 2
											Else
												; wrong number of parameters, 3 are needed for 'Case 2'
											EndIf

									EndSwitch

								Else ; wrong number of parameters, set color to black
									; .... or (better choice) leave colors unchanged
								EndIf
							Case 49 ; set default background (using current intensity)

							Case 90 To 97 ; set foreground bright color
								$iForegroundColor = _VDT_SetActiveForeColor(_ANSIcolor(Number($aParameters[$iParam]) - 82))

							Case 100 To 107 ;  ; set background bright color
								$iBackgroundColor = _VDT_SetActiveBackColor(_ANSIcolor(Number($aParameters[$iParam]) - 92))

						EndSwitch
					Next

				Case $aParameters[0] == "n" ; DSR   Status report
					#cs
						Ps = 6  -> Report Cursor Position (CPR) [row;column].
						Result is CSI r ; c R
					#ce
					#cs
						If $aParameters[1] = 6 Then
						Return ($__g_sCSI & $__g_iCursorPosY & "," & $__g_iCursorPosX & "R")
						EndIf
					#ce
				Case $aParameters[0] == "q" ; DECLL Set keyboard LEDs.
					; ESC [ 0 q: clear all LEDs
					; ESC [ 1 q: set Scroll Lock LED
					; ESC [ 2 q: set Num Lock LED
					; ESC [ 3 q: set Caps Lock LED

				Case $aParameters[0] == "r" ; DECSTBM   Set scrolling region; parameters are top and bottom row.

				Case $aParameters[0] == "s" ; Save cursor location.
					_StoreCursor()

				Case $aParameters[0] == "u" ; Restore cursor location.
					_RecallCursor()
					$iHtab = $__g_iCursorPosX
					$iVtab = $__g_iCursorPosY

				Case $aParameters[0] == "`" ; HPA   Move cursor to indicated column in current row.
					$iHtab = Number($aParameters[1])
					$__g_iCursorPosX = $iHtab

				Case $aParameters[0] == "@" ; ICH   Insert the indicated # of blank characters.

				Case $aParameters[0] == "A" ; CUU   Move cursor up the indicated # of rows.
					$iVtab -= Number($aParameters[1]) + ($aParameters[1] = 0)
					$__g_iCursorPosY = $iVtab

				Case $aParameters[0] == "B" ; CUD   Move cursor down the indicated # of rows.
					$iVtab += Number($aParameters[1]) + ($aParameters[1] = 0)
					$__g_iCursorPosY = $iVtab

				Case $aParameters[0] == "C" ; CUF   Move cursor right the indicated # of columns.
					$iHtab += Number($aParameters[1]) + ($aParameters[1] = 0)
					$__g_iCursorPosX = $iHtab

				Case $aParameters[0] == "D" ; CUB   Move cursor left the indicated # of columns.
					$iHtab -= Number($aParameters[1]) + ($aParameters[1] = 0)
					$__g_iCursorPosX = $iHtab

				Case $aParameters[0] == "E" ; CNL   Move cursor down the indicated # of rows, to column 1.
					$iVtab += Number($aParameters[1]) + ($aParameters[1] = 0)
					$__g_iCursorPosY = $iVtab
					$iHtab = 1
					$__g_iCursorPosX = $iHtab

				Case $aParameters[0] == "F" ; CPL   Move cursor up the indicated # of rows, to column 1.
					$iVtab -= Number($aParameters[1]) + ($aParameters[1] = 0)
					$__g_iCursorPosY = $iVtab
					$iHtab = 1
					$__g_iCursorPosX = $iHtab

				Case $aParameters[0] == "G" ; CHA   Move cursor to indicated column in current row.
					$iHtab = Number($aParameters[1])
					$__g_iCursorPosX = $iHtab

				Case $aParameters[0] == "H" ; CUP   Move cursor to the indicated row, column (origin at 1,1).
					ReDim $aParameters[3] ; mandatory 2 parameters
					$iVtab = Number($aParameters[1]) + ($aParameters[1] = 0)
					$__g_iCursorPosY = $iVtab
					$iHtab = Number($aParameters[2]) + ($aParameters[2] = 0)
					$__g_iCursorPosX = $iHtab

				Case $aParameters[0] == "J" ; ED    Erase display (default: from cursor to end of display).
					ReDim $aParameters[2] ; mandatory 1 parameters
					Switch Number($aParameters[1])
						Case 0 ; Pn=0: erases from active position to end of display.
							__Sub_Print(_StringReplay(" ", $__g_iColumns - $iHtab + 1), $iHtab, $iVtab, $__g_iDefaultForeground, $__g_iDefaultBackground)
							If $iVtab < $__g_iRows Then
								For $y = $iVtab + 1 To $__g_iRows
									__Sub_Print(_StringReplay(" ", $__g_iColumns), 1, $y, $__g_iDefaultForeground, $__g_iDefaultBackground)
								Next
							EndIf

						Case 1 ; Pn=1: erases from the beginning of display to active position.
							__Sub_Print(_StringReplay(" ", $iHtab), 1, $iVtab, $__g_iDefaultForeground, $__g_iDefaultBackground)
							If $iVtab > 1 Then
								For $y = 1 To $iVtab - 1
									__Sub_Print(_StringReplay(" ", $__g_iColumns), 1, $y, $__g_iDefaultForeground, $__g_iDefaultBackground)
								Next
							EndIf

						Case 2 ; Pn=2: erases entire display and move cursor to the top-left.
							_VDT_CLS()
							$iHtab = 1
							$iVtab = 1
					EndSwitch

				Case $aParameters[0] == "K" ; EL    Erase line (default: from cursor to end of line).
					__Sub_Print(_StringReplay(" ", $__g_iColumns - $iHtab + 1), $iHtab, $iVtab, $__g_iActiveFGColor, $__g_iActiveBGColor)

				Case $aParameters[0] == "L" ; IL    Insert the indicated # of blank lines.

				Case $aParameters[0] == "M" ; DL    Delete the indicated # of lines.

				Case $aParameters[0] == "P" ; DCH   Delete the indicated # of characters on current line.
					__Sub_Print(_StringReplay(" ", $aParameters[1]), $iHtab, $iVtab, $__g_iActiveFGColor, $__g_iActiveBGColor)

				Case $aParameters[0] == "X" ; ECH   Erase the indicated # of characters on current line.
					__Sub_Print(_StringReplay(" ", $aParameters[1]), $iHtab, $iVtab, $__g_iDefaultForeground, $__g_iDefaultBackground)
			EndSelect
			;
			; is it a single Control character ? (http://jkorpela.fi/chars/c0.html)
		ElseIf StringLen($sANSI_Escape) = 1 And (AscW($sANSI_Escape) >= 0 And AscW($sANSI_Escape) <= 31) Then

			; https://docs.microsoft.com/en-us/host-integration-server/core/character-tables2
			; https://ascii.cl/control-characters.htm
			; http://jkorpela.fi/chars/c0.html

			; control character interpreter
			; ---------------------------------------------------------------------------------------

			; managed control codes are:    chr(07) 0x07  Bell, rings the bell... (Plays Windows' default beep)
			;                               chr(08) 0x08  move cursor 1 char to the left (Backspace)
			;                               chr(09) 0x09  Horizontal tab, move to next tab stop (8 16 24 32 40.....)
			;                               chr(10) 0x0A  Line Feed, move cursor down 1 line (carrage return not performed here)
			;                               chr(11) 0x0B  Vertical tab (the opposite of a line feed as on an RS232 terminal)
			;                               chr(12) 0xOC  Form Feed, page eject
			;                               chr(13) 0xOD  Carriage Return (line feed not performed here)
			;                               chr(24) 0x18  backspace with deletion (Cancel)
			;                               chr(30) 0x1E  (custom) Line feed + partial Carriage Return (CR returns only to previous hTab)
			;                               chr(31) 0x1F  (custom) move cursor 1 char to the right

			If _VDT_Style($VisCtrls) Then ; visualize control codes
				; If (Asc($sANSI_Escape) < Chr(7)) Or (Asc($sANSI_Escape) > Chr(13)) Then
				__Sub_Print(ChrW($__g_aControlChars[AscW($sANSI_Escape)]), $iHtab, $iVtab, $__g_iActiveFGColor, $__g_iActiveBGColor, $bWrap)
				; EndIf
			EndIf

			$aParameters[0] = $sANSI_Escape
			Switch Asc($sANSI_Escape) ; Select
				Case 1

				Case 2

				Case 3

				Case 4

				Case 5

				Case 6

				Case 7 ;  Bell, rings the bell
					Beep(900, 150)

				Case 8 ;  Backspace
					$iHtab -= 1
					$__g_iCursorPosX = $iHtab

				Case 9 ;  Horizontal tab (Historically tab stops were every 8th character)
					If $iHtab >= 0 Then
						$iHtab = $iHtab + (Mod($iHtab, $__g_iTabStop) * -1) + $__g_iTabStop
					Else
						$iHtab = $iHtab + (Mod(Abs($iHtab) - 1, $__g_iTabStop) + 1)
					EndIf
					$__g_iCursorPosX = $iHtab

				Case 10 ; Line Feed @LF (move cursor down by 1 line)
					$iVtab += 1
					$__g_iCursorPosY = $iVtab

				Case 11 ; Vertical tab (move cusros up by 1 line)
					$iVtab -= 1
					$__g_iCursorPosY = $iVtab

				Case 12 ; Form Feed

				Case 13 ; Carriage Return @CR (move cursor to the beginning of this line)
					$iHtab = 1
					$__g_iCursorPosX = $iHtab

				Case 14

				Case 15

				Case 16

				Case 17

				Case 18

				Case 19

				Case 20

				Case 21

				Case 22

				Case 23

				Case 24 ; backspace with deletion (Cancel)
					$iHtab -= 1
					__Sub_Print(" ", $iHtab, $iVtab, $__g_iActiveFGColor, $__g_iActiveBGColor)
					$__g_iCursorPosX = $iHtab

				Case 25

				Case 26

				Case 27

				Case 28

				Case 29

				Case 30 ; (custom) LF + a partial CR (Carriage Return stops below previous HTab)
					$iVtab += 1
					$iHtab = $iStartingHtab
					$__g_iCursorPosX = $iHtab
					$__g_iCursorPosY = $iVtab

				Case 31 ; move cursor to the right by 1 char ->
					$iHtab += 1
					$__g_iCursorPosX = $iHtab

			EndSwitch

		Else ; print the text
			__Sub_Print(StringReplace($aStringChunks[$iChunk], ChrW(0), ""), $iHtab, $iVtab, $iForegroundColor, $iBackgroundColor, $bWrap)
			$iHtab = $__g_iCursorPosX
			$iVtab = $__g_iCursorPosY

		EndIf
	Next
EndFunc   ;==>_VDT_Print

; manage the portion of text and/or the wraparound of the text to be placed on the terminal
Func __Sub_Print($sString = "", $iHtab = $__g_iCursorPosX, $iVtab = $__g_iCursorPosY, $iForegroundColor = $__g_iActiveFGColor, $iBackgroundColor = $__g_iActiveBGColor, $bWrap = True)

	Local $sExceeding = ""
	Local $iStringFullLen = StringLen($sString)
	Local $iStringLen = $iStringFullLen
	If Not $iStringLen Then Return ; no string to print

	Local $iStringEnd = $iHtab + $iStringLen - 1

	$__g_iCursorPosX = $iHtab + $iStringLen
	$__g_iCursorPosY = $iVtab

	; -----------------------------------------------------------------------
	; if $bWrap = False keep only the text portion that fall into the screen
	; if $bWrap = True then the part on excess is wrapped to next line(s)
	; (parts of text falling outside the screen will be managed by recursion)
	; -----------------------------------------------------------------------

	If (Not $bWrap) And ( _ ; check if the string exceeds the right edge
			$iHtab > $__g_iColumns) Then Return ;

	If _ ; check if all the string falls outside the printable area
			$iVtab > $__g_iRows Or _ ; below the bottom
			$iVtab < 1 Or _ ; over the top edge
			$iStringEnd < 1 _ ; last char of string is still on the left of the left edge
			Then Return

	; adjust string if only a part has to be Printed

	; (a) string begins on the left of the left edge
	If $iHtab < 1 Then ; remove the part outside on the left    ...|..........|
		$sString = StringRight($sString, $iStringEnd) ; case     st|ring
		$iStringLen = StringLen($sString)
		$iHtab = 1
	EndIf

	; (b) string begins in the screen but is wider of the screen  |      str|ing
	;                                                             +---------+...
	If $iStringEnd > $__g_iColumns Then ; removes the exceeding part on the right

		; to wordwrap by recursion we keep exceeding part for later use
		$sExceeding = StringRight($sString, $iStringEnd - $__g_iColumns)

		$sString = StringTrimRight($sString, $iStringEnd - $__g_iColumns)
		$iStringLen = StringLen($sString)
	EndIf
	; ---------------------------------------------------------------

	Local $iAnchor = __GetAbsPos($iHtab, $iVtab) - 1
	Local $iActive = $iAnchor + $iStringLen

	__PokeText(0, $sString, $iAnchor, $iActive, $iForegroundColor, $iBackgroundColor) ; Screen 0 normal text (common to all)

	Select ; evaluate what to print on the second screen based on the various styles set

		Case _VDT_Style($Blink) ;  Print only on layer 1 ; it alternates On and Off.

			If _VDT_Style($Flash) Then ; blink + flash
				__PokeText(1, _StringReplay(" ", StringLen($sString)), $iAnchor, $iActive, $iBackgroundColor, $iForegroundColor) ; clear the portion on screen 1

			Else ; only blink
				__PokeText(1, _StringReplay(" ", StringLen($sString)), $iAnchor, $iActive, $iForegroundColor, $iBackgroundColor) ; clear the portion on screen 1
			EndIf

		Case _VDT_Style($Flash) ; only flash. Alternate foreground with background on each of both screens
			__PokeText(1, $sString, $iAnchor, $iActive, $iBackgroundColor, $iForegroundColor)

		Case Else ; normal text
			__PokeText(1, $sString, $iAnchor, $iActive, $iForegroundColor, $iBackgroundColor)

	EndSelect

	; *** recurse if part of the string have to be wrapped on next line ***
	If $bWrap And $sExceeding <> "" Then
		$iHtab = 1
		$iVtab += 1
		$__g_iCursorPosX = $iHtab
		$__g_iCursorPosY = $iVtab
		__Sub_Print($sExceeding, $iHtab, $iVtab, $iForegroundColor, $iBackgroundColor) ; ===>> recursive call
	EndIf

EndFunc   ;==>__Sub_Print


; Place string on the "screen" buffer (on the RichEdit controls)
Func __PokeText($iLayer, $sString, $iAnchor, $iActive, $iForeColor, $iBackColor)

	; Automatically set or unset the reverse effect based on the _VDT_Style($Inverse) boolean value
	Local $aForeBack[2] = [$iForeColor, $iBackColor]
	$iForeColor = $aForeBack[_VDT_Style($Inverse)]
	$iBackColor = $aForeBack[Not _VDT_Style($Inverse)]

	; select the part of the screen buffer to be replaced with the incoming $sString
	_GUICtrlRichEdit_SetSel($__g_ahScreen[$iLayer], $iAnchor, $iActive, False)
	_GUICtrlRichEdit_ReplaceText($__g_ahScreen[$iLayer], $sString, False)

	; reselect again the just replaced text so to set styles
	_GUICtrlRichEdit_SetSel($__g_ahScreen[$iLayer], $iAnchor, $iActive, False)

	; set styles for the incoming text
	_GUICtrlRichEdit_SetFont($__g_ahScreen[$iLayer], $__g_fFontSize, $__g_sFontName, $__g_iCharSet) ; font

	Local $iLocalBackColor = $iBackColor
	Local $iLocalForeColor = $iForeColor

	; bold is managed as higher-light (true bold creates problems)
	If _VDT_Style($Bold) Then
		If $iLocalForeColor <= 0xAAAAAA Then
			$iLocalForeColor = $iLocalForeColor + 0x555555
		Else
		EndIf
	EndIf

	_GUICtrlRichEdit_SetCharBkColor($__g_ahScreen[$iLayer], $iLocalBackColor)

	; foreground color
	If _VDT_Style($Concealed) Then
		; if $Concealed is true then print with forecolor same as backcolor to 'hide' this text
		_GUICtrlRichEdit_SetCharColor($__g_ahScreen[$iLayer], $iLocalBackColor)
	Else
		_GUICtrlRichEdit_SetCharColor($__g_ahScreen[$iLayer], $iLocalForeColor)
	EndIf

	; set or unset italic, underline, according to the state of the respective variables
	; (since bold creates problems, is managed as HighLight here above)
	_GUICtrlRichEdit_SetCharAttributes($__g_ahScreen[$iLayer], _ ; $__g_aAttribute[_VDT_Style($Bold)] & 'bo' & _ ; bold creates problems
			$__g_aAttribute[_VDT_Style($Italic)] & 'it' & _ ; italic
			$__g_aAttribute[_VDT_Style($Underline)] & 'un') ; underline

	_GUICtrlRichEdit_Deselect($__g_ahScreen[$iLayer])
EndFunc   ;==>__PokeText

; svae the cursor position
Func _StoreCursor($sAction = "Push")
	Local Static $__g_iCursorPushX = $__g_iCursorPosX
	Local Static $__g_iCursorPushY = $__g_iCursorPosY

	If $sAction = "Push" Then
		$__g_iCursorPushX = $__g_iCursorPosX
		$__g_iCursorPushY = $__g_iCursorPosY
	EndIf

	Local $aXY[2] = [$__g_iCursorPushX, $__g_iCursorPushY]
	Return $aXY

EndFunc   ;==>_StoreCursor

; restore the cursor position
Func _RecallCursor()
	Local $aXY = _StoreCursor("Pull")
	$__g_iCursorPosX = $aXY[0]
	$__g_iCursorPosY = $aXY[1]

EndFunc   ;==>_RecallCursor

#cs
	; if you pass a number 0-255 it returns a predefined color from the $__g_aColor[] array.
	; if the number is > 255 and <= 0xFFFFFF it returns the same number, while if the passed
	; number is out of range it return 0 ($Black)and sets @error
	Func __PeekColor($iColor)
	MsgBox(0,"Debug",  "obsolete: __PeekColor(" & $iColor & ")")
	$iColor = Number($iColor)
	If $iColor >= 0 And $iColor < UBound($__g_aColor) Then
	Return $__g_aColor[$iColor] ; predefined colors (0-255)
	ElseIf _IsRGB($iColor) Then
	Return $iColor ; value is <= 0xFFFFFF (256 - 0xFFFFFF)
	Else
	Return SetError(1, 0, 0) ; if out of range return Black and set error
	EndIf
	EndFunc   ;==>__PeekColor
#ce

; passing 3 rgb components it returns a color code
; like 0xBBGGRR (blue green red)
; single base color rage is from 0 to 255 (00 to FF)
Func _RGB($R, $G, $B)
	If $R > 255 Then $R = 255
	If $R < 0 Then $R = 0

	If $G > 255 Then $G = 255
	If $G < 0 Then $G = 0

	If $B > 255 Then $B = 255
	If $B < 0 Then $B = 0

	; returns dec(0xBBGGRR)
	Return (Dec(Hex($B, 2) & Hex($G, 2) & Hex($R, 2)))
EndFunc   ;==>_RGB

; constrain color range from 0x000000 to 0xFFFFFF
Func _ChkColor($Color)
	If $Color < 0 Then Return 0
	If $Color > 0xFFFFFF Then Return 16777215
	Return $Color
EndFunc   ;==>_ChkColor

; returns the color code of the passed ANSI color number (8bit) 0- 255
Func _ANSIcolor($ColorCode)
	If _IsByte($ColorCode) Then
		; ConsoleWrite("-> " & $ColorCode & @TAB & '0x' & Hex($__g_aColor[$ColorCode]) & @CRLF)
		Return '0x' & Hex($__g_aColor[$ColorCode], 6)
	Else
		; ConsoleWrite("-> " & $ColorCode & @TAB & "???" & @CRLF)
		Return SetError(1, 0, "")
	EndIf
EndFunc   ;==>_ANSIcolor

; clear the screen (fill screen buffer with spaces)
; (for 'crazy' effects you could also select another char instead of the space and custom colors)
Func _VDT_CLS($sFillChr = " ", $iForegroundColor = $__g_iActiveFGColor, $iBackgroundColor = $__g_iActiveBGColor) ; clear the screen

	For $iScreen = 0 To 1 ; act on both screens 0 and 1

		If $sFillChr = " " Then
			; fill screens with blanks
			_GUICtrlRichEdit_SetText($__g_ahScreen[$iScreen], $__g_sBuffer)
		Else
			; fill screens with custom char
			_GUICtrlRichEdit_SetText($__g_ahScreen[$iScreen], StringReplace($__g_sBuffer, " ", $sFillChr))
		EndIf
		_GUICtrlRichEdit_SetSel($__g_ahScreen[$iScreen], 0, -1, True) ; select whole screen

		; set RichEdit styles
		_GUICtrlRichEdit_SetFont($__g_ahScreen[$iScreen], $__g_fFontSize, $__g_sFontName, $__g_iCharSet) ; Set Font
		_GUICtrlRichEdit_SetCharColor($__g_ahScreen[$iScreen], $iForegroundColor) ; __PeekColor($iForegroundColor)) ; Set Foreground default color
		_GUICtrlRichEdit_SetCharBkColor($__g_ahScreen[$iScreen], $iBackgroundColor) ; __PeekColor($iBackgroundColor)) ; Set Background default color

		_GUICtrlRichEdit_SetSel($__g_ahScreen[$iScreen], 0, 0, False)
	Next

	; put cursor at home
	$__g_iCursorPosX = 1 ; $iHtab
	$__g_iCursorPosY = 1 ; $iVtab

EndFunc   ;==>_VDT_CLS

; Set new active fore/back colors
; Default:      -> restore default color
; Empty string: -> if "" or out of range leave active color unchanged
Func _VDT_SetActiveColors($iForeColor = Default, $iBackColor = Default)
	#cs
		If $iForeColor = Default Then $iForeColor = $__g_iDefaultForeground
		If $iForeColor < $Black Or $iForeColor > 255 Or String($iForeColor) = "" Then $iForeColor = $__g_iActiveFGColor

		If $iBackColor = Default Then $iBackColor = $__g_iDefaultBackground
		If $iBackColor < $Black Or $iBackColor > 255 Or String($iBackColor) = "" Then $iBackColor = $__g_iActiveBGColor

		$__g_iActiveFGColor = _VDT_SetActiveForeColor($iForeColor) ; $__g_iDefaultForeground = __PeekColor($iForeColor)
		$__g_iActiveBGColor = _VDT_SetActiveBackColor($iBackColor) ; $__g_iDefaultBackground = __PeekColor($iBackColor)
	#ce
	If $iForeColor = Default Then $iForeColor = $__g_iDefaultForeground
	If $iBackColor = Default Then $iBackColor = $__g_iDefaultBackground
	_VDT_SetActiveForeColor($iForeColor) ; $__g_iDefaultForeground = __PeekColor($iForeColor)
	_VDT_SetActiveBackColor($iBackColor) ; $__g_iDefaultBackground = __PeekColor($iBackColor)

	Local $aDefaultColors = [$__g_iActiveFGColor, $__g_iActiveBGColor]

	Return $aDefaultColors
EndFunc   ;==>_VDT_SetActiveColors

; Set new active foreground color
Func _VDT_SetActiveForeColor($iForeColor = $__g_iActiveFGColor)
	If $iForeColor = Default Or $iForeColor = "" Then ; Or $iForeColor = "" Then
		$iForeColor = $__g_iActiveFGColor ; $__g_iDefaultForeground ;
	EndIf
	#cs
		If $iForeColor = "" Then ; leave foreground color unchanged
		$iForeColor = $__g_iActiveFGColor
		EndIf
	#ce

	$__g_iActiveFGColor = $iForeColor

	Return $__g_iActiveFGColor
EndFunc   ;==>_VDT_SetActiveForeColor

; Set new active background color
Func _VDT_SetActiveBackColor($iBackColor = $__g_iActiveBGColor)
	If $iBackColor = Default Or $iBackColor = "" Then ; Or $iBackColor = "" Then
		$iBackColor = $__g_iActiveBGColor ; $__g_iDefaultBackground ;
	EndIf

	#cs
		If $iBackColor = "" Then ; leave background color unchanged
		$iBackColor = $__g_iActiveBGColor
		EndIf
	#ce

	$__g_iActiveBGColor = $iBackColor

	Return $__g_iActiveBGColor
EndFunc   ;==>_VDT_SetActiveBackColor

; if you pass the second parameter as True or False it Set or Unset the passed style.
; passing only first parameter (without the second), it returns True or False according to the actual setting of the passed style
Func _VDT_Style($iStyle, $vAction = Null)
	If $vAction = Null Then Return BitAND($__g_dbStyles, $iStyle) <> 0
	If $vAction = True Then $__g_dbStyles = BitOR($__g_dbStyles, $iStyle)
	If $vAction = False Then $__g_dbStyles = BitAND($__g_dbStyles, BitNOT($iStyle))
	Return $__g_dbStyles
EndFunc   ;==>_VDT_Style

; check if is within color ranges
Func _IsRGB($iColor)
	Return $iColor >= 0x000000 And $iColor <= 0xFFFFFF
EndFunc   ;==>_IsRGB

; Check if is a byte
Func _IsByte($iByte)
	Return $iByte >= 0 And $iByte <= 255
EndFunc   ;==>_IsByte

; move the TextMode GUI
Func _VDT_GUIMoveTo($iX = 5, $iY = 5, $_hGUI = $__g_hMainGui)
	If IsHWnd($_hGUI) Then WinMove($_hGUI, "", $iX, $iY)
EndFunc   ;==>_VDT_GUIMoveTo

; psition cursor to indicated coordinates
Func _VDT_SetCursorPos($iHtab, $iVtab)
	$__g_iCursorPosX = $iHtab
	$__g_iCursorPosY = $iVtab
EndFunc   ;==>_VDT_SetCursorPos

; if ESC and active GUI is this then exit
Func _EndByESC()
	; If WinActive("[ACTIVE]") = $__g_hMainGui Or WinActive("[ACTIVE]") = $__g_hParentGui Then _EndVintage()
EndFunc   ;==>_EndByESC

; This function alternates the visualization of the 2 screens
Func __SwitchScreen($hWnd, $iMsg, $__g_iTimerID, $iTime)
	#forceref $hWnd, $iMsg, $__g_iTimerID, $iTime

	Local Static $bStatus = True

	$bStatus = Not $bStatus
	If $bStatus Then
		WinSetState(HWnd($__g_ahScreen[0]), '', @SW_HIDE)
		; $iVisibleLayer = 1
	Else
		WinSetState(HWnd($__g_ahScreen[0]), '', @SW_SHOWNOACTIVATE)
		; $iVisibleLayer = 0
	EndIf
EndFunc   ;==>__SwitchScreen

; https://www.autoitscript.com/forum/topic/121847-convert-text-string-from-codepage-437-or-850-to-1252/
Func _StringToCodepage($ansi, $codepage)
	#cs
		Local $struct = DllStructCreate("byte[" & StringLen($ansi) * 2 + 4 & "]") ;platz für UTF16
		$string = _WinAPI_MultiByteToWideCharEx($ansi, DllStructGetPtr($struct), Number($codepage), $MB_PRECOMPOSED) ; $MB_USEGLYPHCHARS)   ;Ansi-String in Codepage umwandeln
		Return BinaryToString(DllStructGetData($struct, 1), 2)
	#ce
	Return _WinAPI_MultiByteToWideChar($ansi, $codepage, 0, True)

EndFunc   ;==>_StringToCodepage

Func _EndVintage()
	_WinAPI_KillTimer(0, $__g_iTimerID)
	DllCallbackFree($__g_hTimerProc)

	_GUICtrlRichEdit_Destroy($__g_ahScreen[0])
	_GUICtrlRichEdit_Destroy($__g_ahScreen[1])

	Exit
EndFunc   ;==>_EndVintage

; returns one or more chars replicated n times
; Example: ConsoleWrite(_StringReplay('*', 5) & @CRLF)
Func _StringReplay($sChars = "", $iRepeats = 0)
	$sChars = String($sChars)
	$iRepeats = Int(Abs(Number($iRepeats)))
	Return StringReplace(StringFormat('%' & $iRepeats & 's', ""), " ", $sChars)
EndFunc   ;==>_StringReplay

; some links about ANSI escape sequences:
; http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
; https://www.npmjs.com/package/ansi-escape-sequences
; http://wiki.call-cc.org/eggref/4/ansi-escape-sequences
;
; https://github.com/sindresorhus/ansi-escapes  <--- mnemonic functions
; https://github.com/chalk/ansi-styles  <-- javascript encoder
; https://github.com/chalk/chalk
;
; https://misc.flogisoft.com/bash/tip_colors_and_formatting     <-- for testing
; http://www.termsys.demon.co.uk/vtansi.htm

; ------------------------------------------------------
; Following functions are ANSI Escape sequences encoders
; (CSI means Control Sequence Introducer)
; those can be used to 'embed' ansi escape sequences
; in a string or also te be sent to the terminal to
; set or unset some "rendition"
; ------------------------------------------------------
; ---------------------------------------------------------------------------------------
; Encoder for 4 bit colors (0-15)
; ---------------------------------------------------------------------------------------
; Set the forgraund and background colors
; using ANSI color codes 0 - 15
Func _CSI_Colors($iForeColor = $__g_iDefaultANSIForeground, $iBackColor = $__g_iDefaultANSIBackground)

	Local $sAnsi = ""

	If $iForeColor = Default Then
		$iForeColor = $__g_iDefaultANSIForeground
	ElseIf String($iForeColor) = "" Then ; leave active foreground unchanged
		$iForeColor = _ANSIcolorSearch($__g_iActiveFGColor)
		If @error Then
			$iForeColor = $__g_iDefaultANSIForeground
		EndIf
	EndIf

	If $iBackColor = Default Then
		$iBackColor = $__g_iDefaultANSIBackground
	ElseIf String($iBackColor) = "" Then
		$iBackColor = _ANSIcolorSearch($__g_iActiveBGColor)
		If @error Then
			$iBackColor = $__g_iDefaultANSIBackground
		EndIf
	EndIf

	Local $sAnsiFG
	If $iForeColor >= 0 And $iForeColor <= 15 Then
		$sAnsiFG = _CSI_ForeColor($iForeColor, False)
	Else
		$sAnsiFG = ''
	EndIf

	Local $sAnsiBG
	If $iBackColor >= 0 And $iBackColor <= 15 Then
		$sAnsiBG = _CSI_BackColor($iBackColor, False)
	Else
		$sAnsiBG = ''
	EndIf
	If $sAnsiFG <> "" And $sAnsiBG <> "" Then
		$sAnsi = $__g_sCSI & $sAnsiFG & ";" & $sAnsiBG & "m"
	ElseIf String($sAnsiFG) = "" Then
		If $sAnsiBG <> "" Then $sAnsi = $__g_sCSI & $sAnsiBG & "m"
	Else
		$sAnsi = $__g_sCSI & $sAnsiFG & "m"
	EndIf
	Return $sAnsi
EndFunc   ;==>_CSI_Colors

; Set only the forgraund color
Func _CSI_ForeColor($iForeColor = $__g_iDefaultANSIForeground, $bEncodeAnsi = True)
	Local $sAnsi = ""
	If $iForeColor = Default Then
		$iForeColor = $__g_iDefaultANSIForeground
	ElseIf String($iForeColor) = "" Then
		$iForeColor = _ANSIcolorSearch($__g_iActiveFGColor)
		If @error Then
			$iForeColor = $__g_iDefaultANSIForeground
		EndIf
	EndIf

	If $iForeColor >= 0 And $iForeColor <= 7 Then
		$sAnsi &= String($iForeColor + 30)
	ElseIf $iForeColor >= 8 And $iForeColor <= 15 Then
		$sAnsi &= String($iForeColor + 82)
	EndIf

	If $bEncodeAnsi Then $sAnsi = $__g_sCSI & $sAnsi & "m"

	Return $sAnsi
EndFunc   ;==>_CSI_ForeColor

; Set only the background color
Func _CSI_BackColor($iBackColor = $__g_iDefaultANSIBackground, $bEncodeAnsi = True)
	Local $sAnsi = ""
	If $iBackColor = Default Then
		$iBackColor = $__g_iDefaultANSIBackground
	ElseIf String($iBackColor) = "" Then
		$iBackColor = _ANSIcolorSearch($__g_iActiveBGColor)
		If @error Then
			$iBackColor = $__g_iDefaultANSIBackground
		EndIf
	EndIf

	If $iBackColor >= 0 And $iBackColor <= 7 Then
		$sAnsi = String($iBackColor + 40)
	ElseIf $iBackColor >= 8 And $iBackColor <= 15 Then
		$sAnsi = String($iBackColor + 92)
	EndIf

	If $bEncodeAnsi Then $sAnsi = $__g_sCSI & $sAnsi & "m"

	Return $sAnsi
EndFunc   ;==>_CSI_BackColor
; ---------------------------------------------------------------------------------------
; Encoder for 8 bit colors (n 0-255)		FG -> ESC[38;5;<n>m		BG -> ESC[48;5;<n>m
; ---------------------------------------------------------------------------------------
Func _CSI_Colors_8bit($iForeColor, $iBackColor)
	If (Not _IsByte($iForeColor)) Or (Not _IsByte($iBackColor)) Then Return SetError(1, 0, "")
	Local $sAnsi = ""
	$sAnsi = $__g_sCSI & "38;5;" & $iForeColor & ";" & "48;5;" & $iBackColor & "m"
	Return $sAnsi
EndFunc   ;==>_CSI_Colors_8bit

Func _CSI_ForeColor_8bit($iForeColor)
	If Not _IsByte($iForeColor) Then Return SetError(1, 0, "")
	Local $sAnsi = ""
	$sAnsi = $__g_sCSI & "38;5;" & $iForeColor & "m"
	Return $sAnsi
EndFunc   ;==>_CSI_ForeColor_8bit

Func _CSI_BackColor_8bit($iBackColor)
	If Not _IsByte($iBackColor) Then Return SetError(1, 0, "")
	Local $sAnsi = ""
	$sAnsi = $__g_sCSI & "48;5;" & $iBackColor & "m"
	Return $sAnsi
EndFunc   ;==>_CSI_BackColor_8bit

; --------------------------------------------------------------------------------------- ; Dec(Hex('0x' & StringMid(Hex($value,6),1,2)))
; Encoder for 24 bit colors     FG: ESC[ 38;2;<r>;<g>;<b>m	  BG: ESC[ 48;2;<r>;<g>;<b>m
; ---------------------------------------------------------------------------------------
Func _CSI_Colors_24bit($iForeColor, $iBackColor)
	If (Not _IsRGB($iForeColor)) Or (Not _IsRGB($iBackColor)) Then Return SetError(1, 0, "")
	Local $sAnsi = ""
	$sAnsi = $__g_sCSI
	$sAnsi &= "38;2" ; foreground
	$sAnsi &= ';' & Dec(Hex('0x' & StringMid(Hex($iForeColor, 6), 1, 2))) ; red
	$sAnsi &= ';' & Dec(Hex('0x' & StringMid(Hex($iForeColor, 6), 3, 2))) ; green
	$sAnsi &= ';' & Dec(Hex('0x' & StringMid(Hex($iForeColor, 6), 5, 2))) ; blue
	$sAnsi &= ';' & "48;2" ; backgroung
	$sAnsi &= ';' & Dec(Hex('0x' & StringMid(Hex($iBackColor, 6), 1, 2))) ; red
	$sAnsi &= ';' & Dec(Hex('0x' & StringMid(Hex($iBackColor, 6), 3, 2))) ; green
	$sAnsi &= ';' & Dec(Hex('0x' & StringMid(Hex($iBackColor, 6), 5, 2))) ; blue
	$sAnsi &= 'm'
	Return $sAnsi

EndFunc   ;==>_CSI_Colors_24bit

Func _CSI_ForeColor_24bit($iForeColor)
	If Not _IsRGB($iForeColor) Then Return SetError(1, 0, "")
	Local $sAnsi = ""
	$sAnsi = $__g_sCSI
	$sAnsi &= "38;2" ; foreground
	$sAnsi &= ';' & Dec(Hex('0x' & StringMid(Hex($iForeColor, 6), 1, 2))) ; red
	$sAnsi &= ';' & Dec(Hex('0x' & StringMid(Hex($iForeColor, 6), 3, 2))) ; green
	$sAnsi &= ';' & Dec(Hex('0x' & StringMid(Hex($iForeColor, 6), 5, 2))) ; blue
	$sAnsi &= 'm'
	Return $sAnsi

EndFunc   ;==>_CSI_ForeColor_24bit

Func _CSI_BackColor_24bit($iBackColor)
	If Not _IsRGB($iBackColor) Then Return SetError(1, 0, "")
	$sAnsi = $__g_sCSI
	$sAnsi &= "48;2" ; backgroung
	$sAnsi &= ';' & Dec(Hex('0x' & StringMid(Hex($iBackColor, 6), 1, 2))) ; red
	$sAnsi &= ';' & Dec(Hex('0x' & StringMid(Hex($iBackColor, 6), 3, 2))) ; green
	$sAnsi &= ';' & Dec(Hex('0x' & StringMid(Hex($iBackColor, 6), 5, 2))) ; blue
	$sAnsi &= 'm'
	Return $sAnsi

EndFunc   ;==>_CSI_BackColor_24bit

; ---------------------------------------------------------------------------------------
; Set/unset the bold attribute (use true or false to set/unset)
Func _CSI_Bold($bSet = True) ; True - False
	Local $sAnsi = ""
	Select
		Case $bSet = True
			$sAnsi = $__g_sCSI & "1m"
		Case $bSet = False
			$sAnsi = $__g_sCSI & "22m"
	EndSelect
	Return $sAnsi
EndFunc   ;==>_CSI_Bold

; Set/unset the italic attribute (use true or false to set/unset)
Func _CSI_Italic($bSet = True) ; True - False
	Local $sAnsi = ""
	Select
		Case $bSet = True
			$sAnsi = $__g_sCSI & "3m"
		Case $bSet = False
			$sAnsi = $__g_sCSI & "23m"
	EndSelect
	Return $sAnsi
EndFunc   ;==>_CSI_Italic

; Set/unset the underline attribute (use true or false to set/unset)
Func _CSI_Underline($bSet = True) ; True - False
	Local $sAnsi = ""
	Select
		Case $bSet = True
			$sAnsi = $__g_sCSI & "4m"
		Case $bSet = False
			$sAnsi = $__g_sCSI & "24m"
	EndSelect
	Return $sAnsi
EndFunc   ;==>_CSI_Underline

; Set/unset the blink attribute (use true or false to set/unset)
Func _CSI_Blink($bSet = True) ; True - False
	Local $sAnsi = ""
	Select
		Case $bSet = True
			$sAnsi = $__g_sCSI & "5m"
		Case $bSet = False
			$sAnsi = $__g_sCSI & "25m"
	EndSelect
	Return $sAnsi
EndFunc   ;==>_CSI_Blink

; Set/unset the flash attribute (use true or false to set/unset)
; note: this is a custom "rendition"
;                 ------
Func _CSI_Flash($bSet = True) ; True - False
	Local $sAnsi = ""
	Select
		Case $bSet = True
			$sAnsi = $__g_sCSI & "6m"
		Case $bSet = False
			$sAnsi = $__g_sCSI & "26m" ; custom
	EndSelect
	Return $sAnsi
EndFunc   ;==>_CSI_Flash

; Set/unset the reverse attribute (use true or false to set/unset)
Func _CSI_Reverse($bSet = True) ; True - False
	Local $sAnsi = ""
	Select
		Case $bSet = True
			$sAnsi = $__g_sCSI & "7m"
		Case $bSet = False
			$sAnsi = $__g_sCSI & "27m"
	EndSelect
	Return $sAnsi
EndFunc   ;==>_CSI_Reverse

; Set/unset the concealed attribute (use true or false to set/unset)
Func _CSI_Concealed($bSet = True) ; True - False
	Local $sAnsi = ""
	Select
		Case $bSet = True
			$sAnsi = $__g_sCSI & "8m"
		Case $bSet = False
			$sAnsi = $__g_sCSI & "28m"
	EndSelect
	Return $sAnsi
EndFunc   ;==>_CSI_Concealed

Func _CSI_ResetStyles()
	Local $sAnsi = $__g_sCSI & "0m"
	Return $sAnsi
EndFunc   ;==>_CSI_ResetStyles

; Set the absolute position of the cursor. x0 y0 is the top left of the screen. (x1 y1)
Func _CSI_cursorTo($x = "", $y = "")
	Local $sAnsi = ""

	If Not IsNumber($x) Then Return ""
	If Not IsNumber($y) Then
		$ansi = $__g_sCSI & $x & "G"
	Else
		$ansi = $__g_sCSI & $y & ";" & $x & "H"
	EndIf

	Return $ansi

EndFunc   ;==>_CSI_cursorTo


; Set the position of the cursor relative to its current position.
Func _CSI_cursorMove($x = "", $y = "")
	Local $sAnsi = ""

	If Not IsNumber($x) Then Return ""

	If $x < 0 Then
		$sAnsi = $__g_sCSI & $x & "D"
	ElseIf $x > 0 Then
		$sAnsi = $__g_sCSI & $x & "C"
	EndIf

	If $y < 0 Then
		$sAnsi &= $__g_sCSI & $y & "A"
	ElseIf $y > 0 Then
		$sAnsi &= $__g_sCSI & $y & "B"
	EndIf

	Return $sAnsi

EndFunc   ;==>_CSI_cursorMove

; Move cursor up a specific amount of rows. Default is 1.
Func _CSI_cursorUp($count = 1)
	Local $ansi = ""
	$count = Int($count)
	$ansi = $__g_sCSI & $count & "A"
	Return $ansi
EndFunc   ;==>_CSI_cursorUp

; Move cursor down a specific amount of rows. Default is 1.
Func _CSI_cursorDown($count = 1)
	Local $ansi = ""
	$count = Int($count)
	$ansi = $__g_sCSI & $count & "B"
	Return $ansi
EndFunc   ;==>_CSI_cursorDown

; Move cursor forward a specific amount of rows. Default is 1.
Func _CSI_cursorForward($count = 1)
	Local $ansi = ""
	$count = Int($count)
	$ansi = $__g_sCSI & $count & "C"
	Return $ansi
EndFunc   ;==>_CSI_cursorForward

; Move cursor backward a specific amount of rows. Default is 1.
Func _CSI_cursorBackward($count = 1)
	Local $ansi = ""
	$count = Int($count)
	$ansi = $__g_sCSI & $count & "D"
	Return $ansi
EndFunc   ;==>_CSI_cursorBackward

; Move cursor to the specified column (same line) : left side.
Func _CSI_cursorColumn($count = 1)
	Local $ansi = ""
	$count = Int($count) + ($count = 0)
	$ansi = $__g_sCSI & $count & "G"
	Return $ansi
EndFunc   ;==>_CSI_cursorColumn

; Save cursor position.
Func _CSI_cursorSavePosition()
	Local $ansi = $__g_sCSI & "s"
	Return $ansi
EndFunc   ;==>_CSI_cursorSavePosition

; Restore saved cursor position.
Func _CSI_cursorRestorePosition()
	Local $ansi = $__g_sCSI & "u"
	Return $ansi
EndFunc   ;==>_CSI_cursorRestorePosition

; Get cursor position.
Func _CSI_cursorGetPosition()
	Local $ansi = $__g_sCSI & "6n"
	Return $ansi
EndFunc   ;==>_CSI_cursorGetPosition

; Move cursor to the next line.
Func _CSI_cursorNextLine()
	Local $ansi = $__g_sCSI & "E"
	Return $ansi
EndFunc   ;==>_CSI_cursorNextLine

; Move cursor to the previous line.
Func _CSI_cursorPrevLine()
	Local $ansi = $__g_sCSI & "F"
	Return $ansi
EndFunc   ;==>_CSI_cursorPrevLine

; Hide cursor.
Func _CSI_cursorHide()
EndFunc   ;==>_CSI_cursorHide

; Show cursor.
Func _CSI_cursorShow()
EndFunc   ;==>_CSI_cursorShow

; Erase from the current cursor position up the specified amount of rows.
Func _CSI_eraseLines($count)
	Local $ansi = ""
	For $i = 0 To $count
		$ansi &= _CSI_eraseLine() & $i < $count - 1 ? _CSI_cursorUp() : ""
	Next
	If $count Then $ansi &= _CSI_cursorColumn()
	Return $ansi
EndFunc   ;==>_CSI_eraseLines

; Erase from the current cursor position to the end of the current line.
Func _CSI_eraseEndLine()
	Local $ansi = $__g_sCSI & "K"
	Return $ansi
EndFunc   ;==>_CSI_eraseEndLine

; Erase from the current cursor position to the start of the current line.
Func _CSI_eraseStartLine()
	Local $ansi = $__g_sCSI & "1K"
	Return $ansi
EndFunc   ;==>_CSI_eraseStartLine

; Erase the entire current line.
Func _CSI_eraseLine()
	Local $ansi = $__g_sCSI & "2K"
	Return $ansi
EndFunc   ;==>_CSI_eraseLine

; Erase the screen from the current line down to the bottom of the screen.
Func _CSI_eraseDown()
	Local $ansi = $__g_sCSI & "J"
	Return $ansi
EndFunc   ;==>_CSI_eraseDown

; Erase the screen from the current line up to the top of the screen.
Func _CSI_eraseUp()
	Local $ansi = $__g_sCSI & "1J"
	Return $ansi
EndFunc   ;==>_CSI_eraseUp

; Erase the screen and move the cursor to the top left position.
Func _CSI_eraseScreen()
	Local $ansi = $__g_sCSI & "2J"
	Return $ansi
EndFunc   ;==>_CSI_eraseScreen

; Scroll display up one line.
Func _CSI_scrollUp()
	Local $ansi = $__g_sCSI & "S"
	Return $ansi
EndFunc   ;==>_CSI_scrollUp

; Scroll display down one line.
Func _CSI_scrollDown()
	Local $ansi = $__g_sCSI & "T"
	Return $ansi
EndFunc   ;==>_CSI_scrollDown

; Clear the terminal screen.
Func _CSI_clearScreen()
	Local $ansi = $__g_sCSI & "2J"
	Return $ansi
EndFunc   ;==>_CSI_clearScreen

; Output a beeping sound.
Func _CSI_beep()
	Return Chr(7)
EndFunc   ;==>_CSI_beep

; Create a clickable link.
Func _CSI_link($text, $url)
	; ToDo
EndFunc   ;==>_CSI_link

; Display an image.
; Currently only supported on iTerm2 >=3
Func _CSI_image($input, $options)
	; ToDo
EndFunc   ;==>_CSI_image

Func _ANSIcolorSearch($iANSI_color)
	For $iNDX = 0 To UBound($__g_aColor) - 1
		If $__g_aColor[$iNDX] = $iANSI_color Then Return SetError(0, 0, $iNDX)
	Next
	Return SetError(1, 0, -1)
EndFunc   ;==>_ANSIcolorSearch

; === The End ===

; #FUNCTION# ====================================================================================================================
; https://www.autoitscript.com/forum/topic/124526-_guictrlgetfont/
; Name...........: _GUICtrlGetFont
; Description ...: Gets the font of a GUI Control
; Syntax.........: _GUICtrlGetFont( [$hWnd] )
; Parameters ....: $hWnd        - [optional] ControlID or Handle of the control. Default is last created GUICtrl... (-1)
;
; Return values .: Success      - Array[5] with options of font:
;                                 [0] - FontSize (~ approximation)
;                                 [1] - Font weight (400 = normal).
;                                 [2] - italic:2 underlined:4 strike:8 char format (styles added together, 2+4 = italic and underlined).
;                                 [3] - The name of the font to use.
;                                 [4] - Font quality to select (PROOF_QUALITY=2 is default in AutoIt).
;
;                  Failure      - Array[5] with empty fields, @error set to nonzero
;
; Author ........: KaFu, Prog@ndy
;
; Comments.......: The FontSize returned is an approximation of the actual fontsize used for the control.
;                  The height of the font returned by GetObject is the height of the font's character cell or character in logical units.
;                  The character height value (also known as the em height) is the character cell height value minus the internal-leading value.
;                  The font mapper interprets the value specified in lfHeight. The result returned by the font mapper is not easily reversible
;                  The FontSize calculated below is an approximation of the actual size used for the analyzed control, qualified enough to use
;                  in another call to the font mapper resulting in the same font size as the the original font.
; MSDN.. ........: Windows Font Mapping: http://msdn.microsoft.com/en-us/library/ms969909(loband).aspx
; ===============================================================================================================================
Func _GUICtrlGetFont($hWnd = -1)
	Local $aReturn[5], $hObjOrg

	If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd)
	If Not IsHWnd($hWnd) Then Return SetError(1, 0, $aReturn)

	Local $hFONT = _SendMessage($hWnd, $WM_GETFONT)
	If Not $hFONT Then Return SetError(2, 0, $aReturn)

	Local $hDC = _WinAPI_GetDC($hWnd)
	$hObjOrg = _WinAPI_SelectObject($hDC, $hFONT)
	Local $tFONT = DllStructCreate($tagLOGFONT)
	Local $aRet = DllCall('gdi32.dll', 'int', 'GetObjectW', 'ptr', $hFONT, 'int', DllStructGetSize($tFONT), 'ptr', DllStructGetPtr($tFONT))
	If @error Or $aRet[0] = 0 Then
		_WinAPI_SelectObject($hDC, $hObjOrg)
		_WinAPI_ReleaseDC($hWnd, $hDC)
		Return SetError(3, 0, $aReturn)
	EndIf

	; Need to extract FontFacename separately  => DllStructGetData($tFONT, 'FaceName') is only valid if FontFacename has been set explicitly!
	$aRet = DllCall("gdi32.dll", "int", "GetTextFaceW", "handle", $hDC, "int", 0, "ptr", 0)
	Local $nCount = $aRet[0]
	Local $tBuffer = DllStructCreate("wchar[" & $aRet[0] & "]")
	Local $pBuffer = DllStructGetPtr($tBuffer)
	$aRet = DllCall("Gdi32.dll", "int", "GetTextFaceW", "handle", $hDC, "int", $nCount, "ptr", $pBuffer)
	If @error Then
		_WinAPI_SelectObject($hDC, $hObjOrg)
		_WinAPI_ReleaseDC($hWnd, $hDC)
		Return SetError(4, 0, $aReturn)
	EndIf
	$aReturn[3] = DllStructGetData($tBuffer, 1) ; FontFacename

	$aReturn[0] = Round(((-1 * DllStructGetData($tFONT, 'Height')) * 72 / _WinAPI_GetDeviceCaps($hDC, 90)), 1) ; $LOGPIXELSY = 90 => DPI aware ; 0.25 = Magic Number, don't ask...

	_WinAPI_SelectObject($hDC, $hObjOrg)
	_WinAPI_ReleaseDC($hWnd, $hDC)

	$aReturn[1] = DllStructGetData($tFONT, 'Weight')
	$aReturn[2] = 2 * (True = DllStructGetData($tFONT, 'Italic')) + 4 * (True = DllStructGetData($tFONT, 'Underline')) + 8 * (True = DllStructGetData($tFONT, 'StrikeOut'))
	$aReturn[4] = DllStructGetData($tFONT, 'Quality')

	Return $aReturn

EndFunc   ;==>_GUICtrlGetFont
