Study about moving the cursor up

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
jeb
Expert
Posts: 914
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Study about moving the cursor up

#1 Post by jeb » 20 Jul 2013 06:47

Hi,

I played long time with cursor movement, I'm able to use the backspace or also the CR character to move the cursor back in a line.

I can also move the cursor up without clearing the screen, but until now I haven't found a good solution with pure batch.

Currently the solution needs an embedded jscript to use SendKeys, but it has many drawbacks, like that it uses a SET/P (or cmd/k is also possible) for key input.
That's a bit nasty for games like snake, as it blocks the user input.
Also it can be disturbed by the user with keypresses.

The key idea is to use the ability of SET/p (or cmd), that you can jump back the cursor to the beginning with pressing the ESC key.
Unfortunately I can't get it working with pipes or something else.
SET/P seems to disable any output, if the input comes from a stream or redirection.
CMD would work here, but I can't send any ESC over a pipe or redirection.

But perhaps somebody have a good idea to solve this old problem. :D

Here is a simple proof on concept

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 :thread2

:thread1
cls
echo Line1
call :wait
call :wait
call :Send 27
echo   Line2
echo Line3
echo Line4
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
set /p var=
rem 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)));


jeb

npocmaka_
Posts: 481
Joined: 24 Jun 2013 17:10
Location: Bulgaria
Contact:

Re: Study about moving the cursor up

#2 Post by npocmaka_ » 20 Jul 2013 11:40

oooh..
Multi-threading in batch....

Samir
Posts: 345
Joined: 16 Jul 2013 12:00
Location: HSV
Contact:

Re: Study about moving the cursor up

#3 Post by Samir » 20 Jul 2013 17:00

npocmaka_ wrote:oooh..
Multi-threading in batch....
das pimpness 8)

dbenham
Expert
Posts: 2270
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Study about moving the cursor up

#4 Post by dbenham » 20 Jul 2013 17:29

@jeb - I cannot figure out the sequence of what in hell is going on with your example :!: :?
When does thread2 terminate? You only have one SET /P, yet multiple SEND commands. Where do they all go? What controls which line is chosen to backtrack to? Is it a timing issue that could be machine dependent?

@npocmaka_ - The posted snake game is highly dependent on the "multi-threading" that you are referring to. A controller process to receive keyboard input, and a game process to handle the logic and write "graphics" to the screen. The two processes communicate via files. The controller sends entered key data to the game, and the game sends commands (modes) to the controller.


Dave Benham

jeb
Expert
Posts: 914
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: Study about moving the cursor up

#5 Post by jeb » 21 Jul 2013 01:03

It's obviously 8)

Thread1 is for the output, thread2 to bring the cursor back.

First thread1 outputs line1
Then it waits (simply two times with ping).
So it's safe (more or less) that thread2 will start set/p, after Line1 but before Line2 ist printed.

Then an ESC is sent from thread1 to thread2 via SendKeys, this seems to make nothing, but it initializes SET/p so the next ESC will take an effect.
Thread1 will print now "Line2", "Line3", "Line4".

Then the next SendKeys ESC brings the cursor back to the initial position (of the set), so the cursor is now back in front of Line2.
And then the next SendKey 13 (CR) terminates the set/p and thread2 exits.

Now thread1 can draw the dots.

That's all :D

jeb

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

Re: Study about moving the cursor up

#6 Post by carlos » 21 Jul 2013 02:22

jeb, I thing almost two methods for do this:

calling a c script using tiny c:

gotoxy.c

Code: Select all

#include <windows.h>
int main(int argc, char ** argv) {
if (3 == argc) {
HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(out, (COORD){
(SHORT) strtoul(argv[2], (char **) NULL, 10),
(SHORT) strtoul(argv[1], (char **) NULL, 10)});
}   
return 0;
}


tcc.exe -run gotoxy.c 10 20

also you can compile it and call to gotoxy.exe

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

Re: Study about moving the cursor up

#7 Post by penpen » 21 Jul 2013 12:31

I fear it is not possible to send special keys via pipe using the cmd shell, or command.com environment.
If nothing important was changed since MS-DOS 6.22, piped bytes with value 0x00 will be interpreted by set /p as an end of line.
I assume nothing changed, because <nul set /p "=." still works.

Example:
Java style content of test.txt: "1111\r\n2\u000022\r\n3333\r\n"
test.bat:

Code: Select all

setlocal enableDelayedExpansion
(
  for /l %%a in (1,1,10) do (
   set "INPUT="
   set /p "INPUT="
   echo !INPUT!
  )
)  < a.txt
endlocal

The special keys are all coded by a leading 0-byte so they may be passed to a set via pipe or redirection, but ignored (as a line end). Even if the second byte may be read somehow, it should be interpreted as a more or less "normal" ascii character with no special function.

penpen

dbenham
Expert
Posts: 2270
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Study about moving the cursor up

#8 Post by dbenham » 21 Jul 2013 14:31

@jeb - Thanks for the explanation of your code - that clears things up for me. It is interesting. But the situation does seem hopeless. :(

It does seem the only way to get SET /P to re-position the cursor is via either a physical key press, or else an external (not native batch) program that emulates a key press. Obviously a physical key press does us no good. And if we are to use an external program, then it makes more sense to set the cursor position directly via the method Carlos suggested, or else Aacini's handy utilities for cursor manipulation.

You confused me by your statement that "I can't send any ESC over a pipe or redirection". I have no trouble passing Esc (0x1B) over pipe or via redirection. But what I can't do is redirect or pipe any SendKeys output. It seems to ignore pipes and redirection entirely. I'm thinking it must be communicating with the console window at a lower level. So if we can't redirect or pipe SendKeys output, I shouldn't think we could ever emulate SendKeys via pipes or redirection either.


Dave Benham

aGerman
Expert
Posts: 3669
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Study about moving the cursor up

#9 Post by aGerman » 21 Jul 2013 17:53

[OT]
After a lot of soul-searching I finally decided to post the following but marked as off-topic. Why? Because I know jeb is looking for a pure Batch solution. However I fear I can't help, sorry buddy :(

Perhaps my solution is acceptable for those who try to achieve a cursor positionig with "on-board tools". In the past the DEBUG tool was often used to assemble a small .com file for a certain purpose. But on x64 systems they can't be run.
I was looking for an alternative way. On most Windows computers you'll find the .NET Framework nowadays. To my amazement, it comes with command line compilers for C# and VB (csc.exe, vbc.exe). This opens a new possibility ...

Code: Select all

@echo off &setlocal

REM Pathes for source code and executable file.
set "src="%temp%\gotoxy.cs""
set "gotoxy="%temp%\gotoxy.exe""

REM Find csc.exe (C# compiler).
set "csc="&pushd "%SystemRoot%\Microsoft.NET\Framework"
for /d %%i in ("v*") do (dir /a-d /b "%%~fi\csc.exe" >nul 2>&1 && set "csc="%%~fi\csc.exe"")
popd
if not defined csc (echo C# compiler not found.&pause&goto :eof)

REM Write C# source code.
>%src% (
  echo(using System; class GotoXY {public static int Main(string[] args^) {if (args.Length == 2^) {
  echo(try {int x=int.Parse(args[0]^); int y=int.Parse(args[1]^); Console.SetCursorPosition(x, y^); return 0;}
  echo(catch {return 1;}} else {return 1;}}}
)

REM Compile, delete source code.
%csc% /nologo /target:exe /out:%gotoxy% %src%
del %src%

REM Use the compiled exe file - e.g. write the returned errorlevel to a certain position (column 10, line 2).
%gotoxy% 9 1
echo %errorlevel%

REM Clean up.
del %gotoxy%

pause

Regards
aGerman
[/OT]

Squashman
Expert
Posts: 4107
Joined: 23 Dec 2011 13:59

Re: Study about moving the cursor up

#10 Post by Squashman » 21 Jul 2013 18:41

I like aGerman's approach. I think sometimes we are confining ourselves to writing pure batch when of course we can write hybrid scripts. I know everyone wants to hold onto their dear old XP installs but upgrading above XP also gives us more batch commands and other built-in options like Powershell and other .net capabilities.

foxidrive
Expert
Posts: 6033
Joined: 10 Feb 2012 02:20

Re: Study about moving the cursor up

#11 Post by foxidrive » 21 Jul 2013 20:27

Nice find, aGerman - I like hybrid scripts too, particularly when it makes the script easier to follow and simpler.

Samir
Posts: 345
Joined: 16 Jul 2013 12:00
Location: HSV
Contact:

Re: Study about moving the cursor up

#12 Post by Samir » 21 Jul 2013 22:13

I think hybrid scripting is pretty much the way to go when faced with problems that can't be solved in pure-batch. Unless there's a backward compatibility issue that would be best addressed by pure batch, hybrid scripting opens up a lot of possibilities. 8)

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

Re: Study about moving the cursor up

#13 Post by penpen » 22 Jul 2013 06:05

Great idea, i've never thought of using C#/batch hybrid script, although i like hybrid scripts.
This is more or less a matter of taste, but prefer to avoid creating temp source files via echo.
The code then is more readable (in my opinion), and no characters have to be escaped.
And i changed the for loop of the above script, as it doesn't find the most recent C# compiler on my pc:

Code: Select all

// // >nul 2> nul & @goto :main
/*
:main
@echo off
setlocal
cls

REM Pathes for source code and executable file.
set "src="%temp%\gotoxy.cs""
set "gotoxy="%temp%\gotoxy.exe""

REM Find csc.exe (C# compiler).
set "csc="&pushd "%SystemRoot%\Microsoft.NET\Framework"
for /f "tokens=* delims=" %%i in ('dir /b /o:n "v*"') do (
   dir /a-d /b "%%~fi\csc.exe" >nul 2>&1 && set "csc="%%~fi\csc.exe""
)
popd
if not defined csc (echo C# compiler not found.&pause&goto :eof)
echo csc=%csc%

REM Compile source code.
%csc% /nologo /target:exe /out:%gotoxy% "%~f0"

REM Use the compiled exe file - e.g. write the returned errorlevel to a certain position (column 10, line 2).
%gotoxy% 9 2
echo %errorlevel%

REM Clean up.
del %gotoxy%

pause
goto :eof
*/

using System;

class GotoXY {
   public static int Main(string[] args) {
      if (args.Length == 2) {
         try {
            int x=int.Parse(args[0]);
            int y=int.Parse(args[1]);
            Console.SetCursorPosition(x, y);
            return 0;
         }
         catch {
            return 1;
         }
      }
      else {
         return 1;
      }
   }
}


penpen

dbenham
Expert
Posts: 2270
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Study about moving the cursor up

#14 Post by dbenham » 22 Jul 2013 09:18

Not surprisingly, the standard enterprise PC image within my office has the .NET command line compilers removed. The technique is cool, but has its limits.


Dave Benham

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

Re: Study about moving the cursor up

#15 Post by carlos » 22 Jul 2013 13:13

this is the executable of gotoxy for build using batch:

Code: Select all

@Echo Off
Rem Script made using BHX { code.google.com/p/bhx }
SetLocal EnableExtensions
For %%# In ("gotoxy.ex_") Do Set "bin=%%~f#"
For %%# In ("gotoxy.exe") Do Set "exp=%%~f#"
Del /A /F "%bin%" "%bin%.da" "%exp%" >Nul 2>&1
For %%# In (
4D5343460000000071020000000000002C000000000000000301010001000000
00000000470000000100010000060000000000000000F542F2212000676F746F
78792E657865009F43F7D222020006434BD553CF6B1341147E9BAE12AB497310
AF4EA05E83E8A99043A05D144C719654112FED9A1DE3E2FE08BB13A9374B5508
21D0FE07FE05EAC1C3462F2D7AB087DE3C78925CC4157AF0220629AC6F76C734
29A2513CE88337DF9B37DFBC7DDFCCECE2F50D980200153D8E014248AD02BFB6
7BE8F9D3CFF3F0ECD86E3154AABBC5A55B56409ABED7F00D87D40DD7F538B9C1
88DF7289E59285CB35E278262BE572D3B3B206D500AA4A66AC6E1F66A68E2B47
C7724F0A380827B23B1167D2BE010E10CEA6F9FC53487425C4C2280E2135AC57
9E40EBEF5A19EBCEFE64BDC4D92A17FA15186A81F16310ADAD944C831B82A248
ED9951B1C3BBDAFAD33EAFB4DFAFED6531D808C571757250ACC0DCEB99070F71
167E8EE398469F306C6BFB9D232AAEAD6F657BD398D07B62BBDEC9EAD15B0CD6
5F9DD8EE17B607859B6D6DF09DA91E663E3EC4FCBAB627B4B4FB3D017A7771A0
D368332575B47D1A75413EC98F62D87999B4AB26ED42DA551769494CC32C7E94
866A320A1934BA9A943A199D421D2929BA94A454590A86A56834977C419E4B7C
A64C2A095625528915894B12AF495C2093FC33FF9AAD9083F83E49DF6D7324B7
837195FC78EF26E61FA1BF90EB6F10DFA17F40FF4226E7DC66BECBECF3E74AA6
6DE3F402E3356E5E345CD36638AD313EEFB98167B3F9961F783EF5028B5B9E8B
4BDAAAC5A9EFD559108013DCA9FB5C9608B8CFBD96881CE6D49B7731585E6E30
EE18966BF88D00E70CF7FE87F7F5B7ED1B
) Do >>"%bin%.da" (Echo For b=1 To Len^("%%#"^) Step 2
Echo WScript.StdOut.Write Chr^(CByte^("&H"^&Mid^("%%#",b,2^)^)^)
Echo Next)
Cscript.exe /B /E:vbs "%bin%.da" >"%bin%"
Expand.exe "%bin%" "%exp%" >Nul 2>&1
Del /A /F "%bin%" "%bin%.da" >Nul 2>&1
Goto :Eof


Post Reply