Page 1 of 1

Vt escape codes and cursor hide / show

Posted: 15 Oct 2020 15:42
by T3RRY
I've been using these for controlling various aspects of output for a while now, and somehow missed that Hide / show cursor sequences are effective in cmd.exe

A short demo script utilizing %\E[%?25l to hide the cursor

Code: Select all

@Echo off
If Not "%~1" == "" (Exit /B)Else CLS
(For /F %%a in ('echo prompt $E ^| cmd')do (Set "\E[=%%a["&Set "\E=%%a")
%= Ascii Escape Character. Do Not Modify. =%)
(Set LF=^


%= LineFeed - Do Not Modify =%)
 Echo/%\E[%?25l
 Set "Roll=(For /F "Delims=" %%R in ('Set /A "D=!random! %%6 + 1"')Do (Set "#=%%R"&(!D[%%R]!)))"
 Set "Roll.Anim=For %%n in (1 2) Do if %%n==2 ((If "!Repeat!"=="" Set "Repeat=15")&For /L %%x in (1 1 !Repeat!) do (%ROLL% & %Roll% & (For /L %%D in (1 1 Delay)Do Call "%~F0" 1) & CLS))Else Set "
 Set "DefArr=For %%n in (1 2)Do if %%n==2 ((For /F "Tokens=1,2 Delims==" %%v in ('2^> Nul Set #[')Do Set "%%~v=" & Set "#{i}=0") & For %%G in (!list!)Do (Set /a "#{i}=!#{i}!+1" & Set "#[!#{i}!]=%%~G"))Else Set List="
 Set "Select=CLS&(Title Enter a number [2-12] or [E]xit & Set "Guess=" & (For %%n in (1 2)Do If not !Guess! GTR 1 (For /F "Delims=" %%G in ('Choice /N /C:E0123456789')Do If "%%G"=="E" (TITLE & Echo/%\E[%?25h & Endlocal & Exit /B 0) Else (<nul Set /P "=%%G"& Set "Guess=!Guess!%%G")))& (if !Guess! GTR 12 (Goto :Guess)))& (If "!Guess:~0,1!"=="0" (Set "Guess=!Guess:~1,1!"))& (If !Guess! LEQ 1 Goto :Guess) & CLS"
 Set "Total=(Set /A "Sum=#"&Echo/You rolled: [%\E[%33m!Sum!%\E[%0m])& (If "!Guess!" == "!Sum!" (Echo/Congrats)Else (Echo/Your Guess: [%\E[%31m!Guess!%\E[%0m] was wrong.)) & Pause > Nul & CLS & Goto :Guess )"
 Setlocal EnableDelayedExpansion
 %DefArr:#=D% "Echo/%\E[%31m---!LF!!LF! o!LF!!LF!---%\E[%0m!LF!" "Echo/%\E[%32m---!LF!  o!LF!!LF!o!LF!---%\E[%0m!LF!" "Echo/%\E[%33m---!LF!o!LF! o !LF!  o!LF!---%\E[%0m!LF!" "Echo/%\E[%34m---!LF!o o!LF!!LF!o o!LF!---%\E[%0m!LF!" "Echo/%\E[%35m---!LF!o o!LF! o!LF!o o!LF!---%\E[%0m!LF!" "Echo/%\E[%36m---!LF!o o!LF!o o!LF!o o!LF!---%\E[%0m!LF!"
:Guess
 %Select%
 %Roll.Anim:Delay=5%Repeat=20
 %Roll:#=R[1]%&%Roll:#=R[2]%
 %Total:#=R[1]+R[2]%

Re: Vt escape codes and cursor hide / show

Posted: 15 Oct 2020 16:23
by ShadowThief
Everything that's listed here will work: https://docs.microsoft.com/en-us/window ... -sequences

Re: Vt escape codes and cursor hide / show

Posted: 15 Oct 2020 17:23
by T3RRY
ShadowThief wrote:
15 Oct 2020 16:23
Everything that's listed here will work: https://docs.microsoft.com/en-us/window ... -sequences
yet to figure out how to get cursor position using the ESC[6n Query myself.

Re: Vt escape codes and cursor hide / show

Posted: 15 Oct 2020 21:08
by ShadowThief
T3RRY wrote:
15 Oct 2020 17:23
ShadowThief wrote:
15 Oct 2020 16:23
Everything that's listed here will work: https://docs.microsoft.com/en-us/window ... -sequences
yet to figure out how to get cursor position using the ESC[6n Query myself.
The closest I've been able to get so far is

Code: Select all

echo [5;2H[6n
set /p cpos=
echo Cursor at %cpos:~2,-1%
but that requires the user to press enter when the ^[[5;2R is displayed. Any time I try to redirect the echo to a text file or run it through a for loop, it sends the initial ANSI sequence instead.
https://github.com/PowerShell/PSReadLine/issues/799 suggests that I should be able to just read in the data from the console, but I can't seem to pick it up programmatically since it gets sent to CON (I think) instead of STDIN or STDERR.

Re: Vt escape codes and cursor hide / show

Posted: 16 Oct 2020 02:37
by T3RRY
ShadowThief wrote:
15 Oct 2020 21:08
The closest I've been able to get so far is

Code: Select all

echo [5;2H[6n
set /p cpos=
echo Cursor at %cpos:~2,-1%
but that requires the user to press enter when the ^[[5;2R is displayed. Any time I try to redirect the echo to a text file or run it through a for loop, it sends the initial ANSI sequence instead.
https://github.com/PowerShell/PSReadLine/issues/799 suggests that I should be able to just read in the data from the console, but I can't seem to pick it up programmatically since it gets sent to CON (I think) instead of STDIN or STDERR.
That's gotten me closer - It does indeed go to con:

Code: Select all

@Echo off(For /F %%a in ('echo prompt $E ^| cmd')do (Set "/E=%%a[")
%= Ascii Escape Character. Do Not Modify. =%)
 <nul Set /P "=/%/E%5;2H."
 Set "catchPos=(<Con Set /P"Cpos=%/E%6n") & (Set "Cpos=!Cpos:~2,-1!")&Echo/!Cpos!"
 Setlocal EnableDelayedExpansion
 %catchpos%
Pause > Nul
I haven't devised a means to redirect or pipe the output in a non blocking way as yet

Re: Vt escape codes and cursor hide / show

Posted: 16 Oct 2020 04:30
by miskox
What I remember from using DEC Video Terminals (VT 420 and VT 520): Correct sequence is:

Code: Select all

CSI   Pl ; Pc H

CSI = ESC + [
So you should
set ESC to 27decimal
echo %esc%[4;2HThis is test.
to set cursor position. This should work.

EDIT: this works for me:

(instead of X I patched it with 0x1B) - you could use viewtopic.php?f=3&t=5326 )

Code: Select all

@echo off
cls
set ESC=X
echo %esc%[4;2HThis is test.
echo.
echo.
echo.
echo.
echo.
echo.
echo.
echo.
echo.
echo.

(windows 10, version 1903, build 18362.1082), x64, slovenian)

Saso

Re: Vt escape codes and cursor hide / show

Posted: 16 Oct 2020 05:47
by T3RRY
miskox wrote:
16 Oct 2020 04:30
What I remember from using DEC Video Terminals (VT 420 and VT 520): Correct sequence is:

Code: Select all

CSI   Pl ; Pc H

CSI = ESC + [
So you should
set ESC to 27decimal
echo %esc%[4;2HThis is test.
to set cursor position. This should work.

EDIT: this works for me:

Code: Select all

@echo off
cls
set ESC=X
echo %esc%[4;2HThis is test.
echo.
echo.
echo.
echo.
echo.
echo.
echo.
echo.
echo.
echo.

(windows 10, version 1903, build 18362.1082), x64, slovenian)

Saso
I'm not certain what your trying to add to the conversation here. ESC[l;cH is already known as the sequence syntax for setting cursor position line;column - as well as being described well in the documentation already referenced:
ShadowThief wrote:
15 Oct 2020 16:23
Everything that's listed here will work: https://docs.microsoft.com/en-us/window ... -sequences
As for :
miskox wrote:
16 Oct 2020 04:30
(instead of X I patched it with 0x1B) - you could use viewtopic.php?f=3&t=5326 )
The following is a suitable way to define the ESC control character. two variables are defined, one for sequences requiring [, one for squences that don't require [

Code: Select all

(For /F %%a in ('echo prompt $E ^| cmd')do (Set "\E[=%%a["&Set "\E=%%a")
The discussion around ESC[6n is about capturing the current position when the value is unknown, Idealy in a manner that is non blocking and doesn't result in output to the console.
The reason I myself am intersted in this is to develop a means of positional control using Escape sequences:

ESCA Cursor Up
ESCB Cursor Down
ESCC Cursor Forward (Right)
ESCD Cursor Backward (Left)

Without having to resort to intermediary values to adjust line/column positions, but simply test the current cursor postion against a table of permitted values for the axis of movement.

Re: Vt escape codes and cursor hide / show

Posted: 16 Oct 2020 05:53
by miskox
There is a post that cursor positiooning is not working.

Saso

Re: Vt escape codes and cursor hide / show

Posted: 16 Oct 2020 06:01
by penpen
You might find viewtopic.php?f=3&t=9454 usefull:
It contains a c# solution and a pure batch solution to get the cursor position and the device attribute.


penpen

Re: Vt escape codes and cursor hide / show

Posted: 16 Oct 2020 06:12
by T3RRY
miskox wrote:
16 Oct 2020 05:53
There is a post that cursor positiooning is not working.

Saso
Post #3 ? Perhaps a simple misunderstanding. Get Cursor position using ESC[6n

That's is: get the current cursor position using escape code DECXCPR to query the state of the cursor position, and Set it to a variable.
This is a differs from setting the cursor position using the CUP escape code.

The issue with assigning the result of the querry to a varible stems from it being returned via the con stream - it cant be read directly from stdout, nor have I found means of redirecting it that allows it to be captured in a non blocking manner

Re: Vt escape codes and cursor hide / show

Posted: 16 Oct 2020 07:43
by T3RRY
penpen wrote:
16 Oct 2020 06:01
You might find viewtopic.php?f=3&t=9454 usefull:
It contains a c# solution and a pure batch solution to get the cursor position and the device attribute.


penpen
Brilliant! As always, the wheel has already been invented, by smarter minds than mine. Macro adapted :

Code: Select all

@echo off
(Set \n=^^^
%=Do not modify=%
)
for /F "delims=#" %%a in ('"prompt #$E# & for %%a in (1) do rem"') do set "\E=%%a"
<Nul Set /p "=%\E%[20;20H"
Set GetPos=For %%n in (1 2)Do if %%n==2 (%\n%
 For /L %%l in (2 1 12)Do (%\n%
  If not "!Char!" == "R" (%\n%
   ^<nul set /p "=%\E%[6n" %\n%
   FOR /L %%# in (1 1 %%l) DO pause ^< CON ^> NUL%\n%
    Set "Char=;"%\n%
    for /F "tokens=1 skip=1 delims=*" %%C in ('"REPLACE /W ? . < con"') DO (%\n%
     Set "char=%%C"%\n%
    )%\n%
   If "!Cpos!" == "" (Set "Cpos=!Char!")Else set "Cpos=!Cpos!!char:R=!"%\n%
  )%\n%
 )%\n%
)Else set "Cpos=" ^&Set "Char="
Setlocal EnableDelayedExpansion
%GetPos%
 <Nul Set /P "=!Cpos!"
Endlocal
exit /b
A proof of concept regarding Positional movement by comparing a move from a current position in a given direction with a list of allowed move positions:

Code: Select all

==========================================================================================================
::: * Proof of concept script for moving cursor along a permitted path only using ASCII escape codes * :::
==========================================================================================================
@echo off & CLS  & CD "%userprofile%"
Rem [* Ensure safe temporary working directory - Failed Redirections can cause issues in the working directory *]
 If exist "%TEMP%\%~n0\Guard" (RMDIR "%TEMP%\%~n0\Guard" /S /Q 2> Nul || (Echo/Cleanup failed & Exit /B 1))
 Timeout 2 > Nul & CLS
 If not exist "%TEMP%\%~n0\Guard" MD "%TEMP%\%~n0\Guard"
 PUSHD "%TEMP%\%~n0\Guard" || (Echo/Safe working directory required & Exit /B)
(Set \n=^^^
%=Do not modify=%
)

 for /F "delims=#" %%a in ('"prompt #$E# & for %%a in (1) do rem"') do set "\E=%%a"
Rem [* max expected return length is 11 characters: "^]]###;###R". R is disregarded. only 10 iterations required *]
Rem [* Additional redirections or piping within the CHKmove macro or any (code block) it's used in may cause failure. *]
Set CHKmove=(Set "Opos=!Cpos!" ^& set "Cpos=" ^&Set "Char=" ^& For %%n in (1 2)Do if %%n==2 (%\n%
 For /L %%l in (2 1 12)Do (%\n%
  If not "!Char!" == "R" (%\n%
   ^<nul set /p "=%\E%[6n" %\n%
   FOR /L %%# in (1 1 %%l) DO pause ^< CON ^> NUL%\n%
   Set "Char=;"%\n%
   for /F "tokens=1 skip=1 delims=*" %%C in ('"REPLACE /W ? . < con"') DO (Set "char=%%C")%\n%
   If "!Cpos!" == "" (Set "Cpos=!Char!")Else set "Cpos=!Cpos!!char:R=!"%\n%
  )%\n%
 )%\n%
 Set "_V=F"^&(For %%G in (!Valid!)Do If /I "%%~G" == "!Cpos!" (Set "_V=T"))%\n%
))
Rem [* 'Valid' variable is used as the source of valid positions to compare against in CHKmove macro *]
 Set Valid="20;21" "20;22" "20;23" "20;24" "20;25" "19;25" "18;25" "17;25" "16;25"  "15;25" "15;24" "15;23" "15;22" "15;21" "15;21" "16;21" "17;21" "18;21" "19;21"
Rem [* On [E]xit: restor cursor - return to previous WD - Delete scripts TEMP folder - End the local Environment *]
 Set "CLEANUP=ECHO/%\E%[?25h%\E%[21;1HDone. & POPD & RMDIR "%TEMP%\%~n0\Guard" /S /Q 2> Nul & Endlocal & Exit /B"
 Set "RestorePos=(set "Cpos=!Opos!"& <Nul Set /P "=%\E%[!Opos!H%\E%[!Col!mx%\E%[0m" &Set "_V=T")"
Setlocal EnableDelayedExpansion
 For %%v in (!Valid!) Do <Nul Set /P "=%\E%[%%~vH%\E%[90m.%\E%[0m"
Rem [* Hide cursor; Set and display Intial position *]
 <Nul Set /p "=%\E%[?25l%\E%[20;21Hx"&Set "Cpos=20;21"
Rem [* Directional 'cursor move' sequences *]
 Set "D="&Set "W=%\E%D%\E%A"& Set "A=%\E%D%\E%D"& Set "S=%\E%B%\E%D"
 Set "Col=30"
:loop
 If %COL% EQU 37 Set "Col=30"
 Set /A "Col+=1" & TITLE Move: [WASD] Exit: [E]
Rem [* User input attempt move *]
 For /F "Delims=" %%O in ('Choice /N /C:WASDE')Do If "%%O" == "E" (%CLEANUP%)Else ( <Nul Set /p "=!%%O!")
Rem [* move cursor using escape codes; test if position is valid -T:Display move -F:Restore Cursor to last saved valid position *]
 %CHKmove% & If "!_V!"=="T" (<Nul Set /p "=%\E%[!Col!mx%\E%[0m") Else (%RestorePos%)
Goto :loop