Study about moving the cursor up

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
Aacini
Expert
Posts: 1914
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: Study about moving the cursor up

#16 Post by Aacini » 23 Jul 2013 20:37

I always have thought that the term "pure Batch solution" is imprecise and subject to interpretation. For example, CHOICE.EXE program is NOT Windows XP native, so some Win XP users may refuse to download it although many other users are willing to download and use it with no problems; in this case the important question is: why these users accept it as "pure Batch"? Perhaps because choice IS a native command in posterior Win versions, although the choice.exe file that must be downloaded for Win XP is NOT the same choice command of posterior Win versions. "Yes, but it is called the same and works in the same way", someone may said. If this point is a matter of same name and design, would you accept a choice.exe program with the same design written by me? "Oh, no: personal developments are NOT pure Batch solutions!". Really? Did you know who developed the choice program you download for Win XP? There are at least 2 different versions of it! (and this story may be as long as you want)... But I am going off-topic too much!

I want to present a solution for "moving the cursor up" problem that may be taken as "pure Batch solution" (depending on what I stated before) that consists in using escape sequences of ANSI.SYS, the device driver included in all DOS versions from the very beginning until Windows XP. The usage of this driver is very simple; for example:

Code: Select all

@echo off
ren %WinDir%\System32\config.nt config.nt.bak 2>nul
(
echo DOSONLY
echo dos=high, umb
echo device=%SystemRoot%\System32\himem.sys
echo device=%SystemRoot%\System32\ansi.sys /x
echo files=40
) > %WinDir%\System32\config.nt
for /F %%a in ('echo prompt $E ^| cmd') do set ESC=%%a
cls
dir
rem Move the cursor to top of screen and show a line
command /C echo %ESC%[1;1H+====================+
rem Show some words in different colors
command /C echo +  At %ESC%[31;1mtop %ESC%[32;1mof %ESC%[34;1mscreen  %ESC%[0m+
echo +====================+

This solution is particularly good because it also provides several useful screen management features, like show text in color, insert empty lines, scroll a window, etc. I tested previous program in Windows XP and works very well. For Windows Vista and above, you may download ANSICON program that provides the same functionality of original ANSI.SYS driver; look for detailed instructions on how to download and install it at this link.

Antonio

penpen
Expert
Posts: 2009
Joined: 23 Jun 2013 06:15
Location: Germany

Re: Study about moving the cursor up

#17 Post by penpen » 24 Jul 2013 05:05

If MS hasn't changed it, some ANSI.SYS functions may be still disabled using cmd.exe:
http://support.microsoft.com/kb/101875/en-us

So for full support you have to use command.com.

But using it has the advantage that %SystemRoot%\System32\config.nt remains unchanged, if you don't want t change it:
Create the config.nt Aacini wrote in the same folder as the batch program.
Then create a shortcut to command.com.
After that open the shortcut properties, change to Program tab click Advanced, and
finally use config.nt only as config name.

penpen

carlos
Expert
Posts: 503
Joined: 20 Aug 2010 13:57
Location: Chile
Contact:

Re: Study about moving the cursor up

#18 Post by carlos » 24 Jul 2013 07:31

I remember time time ago write a function using ansi.sys for print text using the same background and foreground color.
But, i decline using ansi.sys because for work with it windows xp you need touch files in system32 folder (and it can fail if the user use a limited account), and is hard restore the files if batch file end because a some error.

this is the code anyways:
(note this code not works in a 64 bits system)

Code: Select all

::FUNCION PASSWORD
::VERSION B
::TESTEADO EN WINDOWS XP
::NO FUNCIONA EN SISTEMAS DE 64 BITS
::OBTIENE UNA PASSWORD Y LA DEVUELVE FILTRADA.
::SOLO SE PERMITEN LETRAS Y NUMEROS.
::ME HE DIVERTIDO CREANDO ESTA FUNCION PUES NUNCA HABIA JUGADO CON ANSI.SYS
::PENSE QUE NO SE PODIA EN XP Y SI SE PUEDE
::CON ANSI.SYS CAMBIO EL COLOR DE FONDO Y DE LETRAS A NEGRO
::AUTOR: CARLOS


 @ECHO OFF
SETLOCAL ENABLEEXTENSIONS
PUSHD "%TEMP%"
(SET PASSWORD=)

SET NOMBRE=CONFIG.NT
SET ARCHIVO=%Windir%\SYSTEM32\%NOMBRE%
SET ARCHIVO_RESPALDO=%ARCHIVO%.BAK
IF EXIST "%ARCHIVO_RESPALDO%" DEL /F /Q /A "%ARCHIVO_RESPALDO%" >NUL 2>&1
IF EXIST "%ARCHIVO%" TYPE "%ARCHIVO%" > "%ARCHIVO_RESPALDO%"
IF EXIST "%ARCHIVO%" DEL /F /Q /A "%ARCHIVO%" >NUL 2>&1

FOR %%A IN (
"DOSONLY"
"DOS=HIGH, UMB"
"FILES=40"
"DEVICE=%WINDIR%\SYSTEM32\ANSI.SYS /X"
) DO ECHO:%%~A>>"%ARCHIVO%"

DEL /F /Q /A "ESC.KEY" >NUL 2>&1
FOR %%A IN (
"N ESC.KEY"
"E 0000 1B"
"R CX"
"0001"
"W 0"
"Q"
) DO ECHO:%%~A>>"ESC.KEY"

TYPE ESC.KEY | DEBUG >NUL 2>&1
FOR /F %%A IN (ESC.KEY) DO (SET ESCAPE=%%A)
DEL /F /Q /A "ESC.KEY" >NUL 2>&1
DEL /F /Q /A "PWL.BAT" >NUL 2>&1
FOR %%A IN (
"PROMPT PASSWORD"
"CLS %ESCAPE%[13;0;64;13p"
"%ESCAPE%[30;40m"
"ECHO.%ESCAPE%[6A"
"IF ERRORLEVEL 0 IF NOT ERRORLEVEL 1 TYPE CON >PWL.DAT"
"EXIT"
) DO ECHO:%%~A>>"PWL.BAT"

COMMAND.COM /CPWL.BAT
CLS
DEL /F /Q /A "PWL.BAT" >NUL 2>&1
FOR /F "TOKENS=* EOL=%ESCAPE%" %%A IN (PWL.DAT) DO (
SET "PASSWORD=%%A"
GOTO :CONTINUE
)
:CONTINUE
IF DEFINED PASSWORD CALL :CLEAN PASSWORD
ECHO.SU PASSWORD ES :%PASSWORD%

::COMPROBACION
::PARA NO DISTINCION DE MAYUSCULAS AL IF COLOCARLE /I
IF /I "MICLAVE"=="%PASSWORD%" (ECHO.TU CLAVE ES MICLAVE) ELSE (
ECHO.TU CLAVE NO ES MICLAVE
)
DEL /F /Q /A "PWL.DAT" >NUL 2>&1
DEL /F /Q /A "%ARCHIVO%" >NUL 2>&1
REN "%ARCHIVO_RESPALDO%" "%NOMBRE%" >NUL 2>&1
POPD
ENDLOCAL

PAUSE
CLS
GOTO :EOF

:::::::::::::::::::::::::::::::::::::::::::::::::::::::
:CLEAN
:::::::::::::::::::::::::::::::::::::::::::::::::::::::
::Autor Carlos
::version 1.0 more restricted
  SETLOCAL ENABLEDELAYEDEXPANSION
  IF NOT DEFINED %~1 (GOTO:_CLEANE) || (GOTO:_CLEANE)
  SET "CONTENT=!%~1!"
  IF NOT DEFINED CONTENT (GOTO:EOF)
  SET /A COUNT=0
  :_LOOP
    SET "CHAR=!CONTENT:~%COUNT%,1!"
    IF NOT DEFINED CHAR (GOTO:_ENDLOOP)
    SET ADD=FALSE
    FOR %%A IN (0 1 2 3 4 5 6 7 8 9) DO (
      IF [^!CHAR!] EQU [%%A] (SET ADD=TRUE)
    )
    FOR %%A IN (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) DO (
      IF /I [^!CHAR!] EQU [%%A] (SET ADD=TRUE)
    )
    IF /I [!ADD!] EQU [TRUE] (
      SET "STRING=!STRING!!CHAR!"
    )
    SET /A COUNT +=1
    GOTO:_LOOP
  :_ENDLOOP
    ENDLOCAL&&SET "%~1=%STRING%"
    GOTO:EOF
  :_CLEANE
    ECHO.CLEAN FUNCTION RECEIVE A DEFINED VARIABLE.
    PAUSE
    GOTO:EOF
:::::::::::::::::::::::::::::::::::::::::::::::::::::::

einstein1969
Expert
Posts: 960
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: Study about moving the cursor up

#19 Post by einstein1969 » 01 Sep 2013 13:07

Hi to all, Hi Jeb

I found this very interesting! I have not much know of Dos Batch, but i use it.

My current project is a front-end/wrapper for x264 in batch and in this project there a part that use a lot of variables.

I need to look value of variable and navigate on screen is the best i wish. I need to navigate via TAB. Each variable has a list of value and i need to choose and the SPACE is a good key.

For each set of variable i need a set of value. But i need to have multiple sets to figure out on the screen.

I think that this is possible whit this moving up or other

This script is a start , a demo . I used trick , fake to get result.

But i have a few of questions

Code: Select all

@if (@X)==(@Y) @end /* Harmless hybrid line that begins a JScript comment
@echo off
if "%~1"=="intern" (
   call %2
   exit
)

setlocal & setlocal EnableDelayedExpansion

rem coordinate start from 0, need to adjust!!

call :init-virtual-monitor

:thread1

   set /a X1=40, Y1=20

   for /l %%i in (1,1,250) do (

      set /a "x1=X1-3+!random! %% 6","Y1 = Y1 -1 + (!random! %% 2)"

      if !x1! lss 0 set /a x1=69
      if !y1! lss 0 set /a y1=39
      
      call :virtual-echo !x1! !y1! "\____"
   )   

   call :virtual-echo 30 5 "===================="
   call :virtual-echo 30 6 "|                  |"
   call :virtual-echo 30 7 "===================="
   
   call :gotoxy 32 6
   
   call :begin-insert-getkey-mode

   call :wait
   call :wait
   set /p "x=Enter x: "

   rem call :getkey & rem echo %key% !key!

   For /L %%i in (1,1,35) do echo(

   echo X=!x!

   rem call :Send 13


rem echo end1
exit /b

:thread2
set /p var=
rem Thread2 ends now
exit /b

############### High level

:echost
  set /a y=%random% %% 20 + 1
  call :ruotadx %y%
  call :virtual-echo 1 %y% %%st[%y%]%%
exit /b

:ruotadx y
  for /F "delims=" %%P in ("st[%1]") DO set "st[%1]=...!%%P!"
  for /F "delims=" %%P in ("st[%1]:~0,30") DO set "st[%1]=!%%P!"
exit /b


###############

############### Low level

:virtual-echo xcord ycord text [/n]
  rem per faster output we can make a queue and order it and print it in time (50-100ms)
  call :gotoXY %1 %2
  call :echo-no-nl %3
  rem update screen buffer

  set "string=%~3"
  call:strLen string len
  set /a len=len+%1
 
  for /F "delims=" %%P in ("sb%2:~!len!") do set "resto=!%%P!"

  for /F "delims=" %%P in ("sb%2:~0,%1") do set "sb%2=!%%P!%~3!resto!"

exit /b

:begin-insert-getkey-mode
   rem there is a way to end thread2 using a pipe? or a quicly method?
   set /a tmpY=!virtual_y!-1
   call :gotoxy !virtual_x! !tmpY!
   call :Send 13
   set /a tmpY=!virtual_y!+1
   for /F "delims=" %%P in ("sb!tmpY!:~0,!virtual_x!") do set "stringa=!%%P!"
   call ::echo-no-nl "!stringa!"   
exit /b

:gotoXY x y
  rem check the current virtual position and choose for absolute or relative positioning. For now use absolute
  call :Send 27
  rem start from 1 = %2 - 1
  for /l %%i in (1,1,%2) do (echo()
  rem controllare coordinata
  for /F "delims=" %%P in ("sb%2:~0,%1") do set "stringa=!%%P!"
  rem call :echo-no-nl "!stringa!"
  %echo-no-nl-macro_%!stringa!
  set /a virtual_X=%1,virtual_Y=%2
exit /b


:echo-no-nl string
  rem bug seven space
  rem http://stackoverflow.com/questions/13488592/in-dos-how-to-set-p-with-a-string-starting-with-spaces
  rem per i file : http://stackoverflow.com/questions/9864620/in-batch-how-do-i-create-spaces-at-the-beginning-of-a-input-prompt-string
  <nul set /p "var=.%BS%%~1"
exit /b

:GetKey
  call :begin-insert-getkey-mode
  set "key="
  for /F "usebackq delims=" %%L in (`xcopy /L /w "%~f0" "%~f0" 2^>NUL`) do (
    if not defined key set "key=%%L"
  )
  set "key=%key:~-1%"
exit /b

:Send
  cscript //E:JScript //nologo "%~f0" %1
exit /b

:wait
  ping localhost -n 2 > nul
exit /b 0

:init-virtual-monitor

   mode con: cols=80 lines=50

   :: Define BS to contain a backspace
   for /f %%A in ('"prompt $H&for %%B in (1) do rem"') do set "BS=%%A"
   
   set echo-no-nl-macro_=^<nul set /p var=.%BS%

   call :virtual-cls
   start /b "" "%~f0" intern :thread2
   call :wait
     call :Send 27
   for /L %%# in (0 1 39) do echo !sb%%#!
   call :Send 27
   set /a virtual_insert_mode=0
exit /b

:virtual-cls
   cls
   rem FARE: get linee colonne "mode con" ora fisse a 40
   rem                                  012345678|012345678|012345678|012345678|012345678|012345678|012345678|012345678| 
   for /L %%# in (0 1 0) do  set "sb%%#=         +         +         +         +         +         +         +        |"
   for /L %%# in (1 1 39) do set "sb%%#=                                                                              |"
   set /a virtual_X=0,virtual_Y=0
exit /b


:strLen -- returns the length of a string via binary search, maximum length 1023
::      -- %~1: in - varible name of a string variable
::      -- %~2: out- string length
SETLOCAL
set str=A!%~1!&  rem keep the A up front to ensures we get the length and not the upper bond
                 rem it also avoids trouble in case of empty string
set len=0
set /a n=1024
set /a n^>^>=1, len+=n
 if !str:~%len%!. == . set /a len-=n
set /a n^>^>=1, len+=n
 if !str:~%len%!. == . set /a len-=n
set /a n^>^>=1, len+=n
 if !str:~%len%!. == . set /a len-=n
set /a n^>^>=1, len+=n
 if !str:~%len%!. == . set /a len-=n
set /a n^>^>=1, len+=n
 if !str:~%len%!. == . set /a len-=n
set /a n^>^>=1, len+=n
 if !str:~%len%!. == . set /a len-=n
set /a n^>^>=1, len+=n
 if !str:~%len%!. == . set /a len-=n
set /a n^>^>=1, len+=n
 if !str:~%len%!. == . set /a len-=n
set /a n^>^>=1, len+=n
 if !str:~%len%!. == . set /a len-=n
set /a n^>^>=1, len+=n
 if !str:~%len%!. == . set /a len-=n
( ENDLOCAL & REM RETURN VALUES
    IF "%~2" NEQ "" SET %~2=%len%
)
GOTO:EOF

//
***jscript part****/

var WshShell = WScript.CreateObject("WScript.Shell");
var args=WScript.Arguments;

WshShell.SendKeys(String.fromCharCode(args.Item(0)));


Output

Code: Select all

         +        \____________\____   +         +         +   \_______       |
                          \________                                  \____    |
                          \_\\____                                \_\_____    |
                        \___\_____                                 \____      |
                          \_\_____                                 \____      |
                          \_\_====================                 \____      |
                            \_| Enter x: 123     |               \\\____      |
                             \====================                  \____     |
                              \_______                              \____     |
                          \_\________                              \____      |
                           \____\\____                           \____        |
                             \_________                          \_____       |
                           \____\\_____                         \____         |
                         \____  \____                           \____         |
                           \____ \\_____                        \____         |
                              \______________                      \____      |
 \____                           \_____\____                      \_______    |
   \\____                         \____\_\____                                |
   \____                          \____ \_____________                        |
     \\____                         \_______       \____                      |
        \____                        \____            \____   \____           |
      \_________                                         \__\_\____           |
            \____                                          \___\____          |
        \_\____                                              \__\\______      |
             \____                                           \__\_______      |
               \\______                                        \____\_____    |
 \____           \____                                         \____          |
    \____         \_\_____                                        \____       |
  \____               \____                                    \\____         |
\_______              \____                                  \__________      |
      \______          \____                                         \____    |
      \\\____           \\____                                     \\____     |
        \______           \____                                   \____       |
          \____           \____                                 \____         |
        \____           \____________                            \\\____      |
      \__________              \____                                \____     |
          \_______             \____                              \\\____     |
             \____              \____                           \____         |
           \_______________     \_\____                         \____         |
                    \____       \_\____                       \____           |


X=123

E:\x264\provini>


I have used a virtual screen buffer for now because i need to restart the thread2 and cls the screen. But there is another method?

I think to use e INSERT mode like "vi". In insert mode the thread2 is off.

There is a method for close thread2 via pipe? or escape for set/p temporarily?

There is a method for go ahead the cursor in the screen without clear the text below?

EDIT:

I have modify your script and have subst the set /p of thread2 with a echo(>nul and seem that work in same way!

Why?

Code: Select all

@if (@X)==(@Y) @end /* Harmless hybrid line that begins a JScript comment
@echo off
if "%~1"=="intern" (
   call %2
   exit
)
start /b "" "%~f0" intern :thread1
start /b "" "%~f0" intern :thread2

goto :eof

:thread1
cls
echo Line1
call :wait
call :wait
call :Send 27
echo   Line2
echo Line3
echo Line4
echo Line5
echo Line6
call :wait
call :Send 27
for /L %%n in ( 1 1 10) DO (
   <nul set /p "=."
   call :wait
)
call :Send 13
exit /b

:thread2
call :wait
rem set /p var=
echo(>nul
echo Thread2 ends now
exit /b

:Send
cscript //E:JScript //nologo "%~f0" %1
exit /b

:wait
ping localhost -n 2 > nul
exit /b 0

//
***jscript part****/

var WshShell = WScript.CreateObject("WScript.Shell");
var args=WScript.Arguments;

WshShell.SendKeys(String.fromCharCode(args.Item(0)));


EDIT2: Mistake! Ok there is a main thread !

Post Reply