How do I disable user input in a batch-file? - batch-file

Here's the code:
#echo off
color 0a
set /p object="Name an object (article included): "
set /p person="Name a person: "
set /p place="Name a place: "
echo %person% decided it was a good idea to take %object% to %place%. It was not.
set /p DUMMY=Hit Enter to proceed.
I would like to make it so that when the Hit Enter to proceed part shows up, you can't type anything, until you pressed Enter.

Ok. Perhaps you may be wrong when you said "it's possible the program will break" when the user enter "anything" as response in a set /P command. Anyway, this code do what you want:
#echo off
setlocal EnableDelayedExpansion
rem Get a CR
for /F %%a in ('copy /Z "%~F0" NUL') do set "CR=%%a"
set /P "=Hit Enter to proceed. " < NUL
:getKey
set "key="
for /F "delims=" %%K in ('xcopy /W "%~F0" "%~F0" 2^>NUL') do (
if not defined key set "key=%%K"
)
if "!key:~-1!" neq "!CR!" goto getKey
echo/
echo Proceeding...

Related

Is it possible to shadowtype in cmd?

Pretty straight forward question. Is it possible to shadow-type in cmd? ( I mean typing in the cmd window without it showing what you've typed ) Like when you're setting a password for a user with net user J.Doe * for example. Is it possible to immitate that with commands?
A 100% Batch solution i made, which accept backspace to remove a char, accept the enter key to valid the password and automatically count the password length.
#echo off&cls
::The password
set "$Mdp=toto1234"
::La longeur du Mot de passe
set "$Long=-1"
for /F "delims=" %%c in ('cmd /D /U /C echo %$Mdp% ^| find /V ""') do (set /a $Long+=1)
::Les autres variables
set "$l="
set "$l1="
set "$C=0"
:test
if %$c%==%$Long% goto:Pastrouve
set "$T="
cls&echo Entrer votre MDP : %$l1%
For /F "delims=" %%# In ('Xcopy /W "%~f0" "%~f0" 2^>Nul') Do If Not Defined $T Set "$T=%%#"
set "$testenter=%$T:~-1%"
if not defined $Testenter goto:Pastrouve
if %$T:~-1%== (
if not %$C%==0 (
Set "$l=%$l:~0,-1%"
set "$l1=%$l1:~0,-1%"
set /a $C-=1)
) else (
Set "$l=%$l%%$T:~-1%"
set "$l1=%$l1%*"
set /a $C+=1)
if "%$l%"=="%$Mdp%" goto:trouve
goto:test
:trouve
echo Pass OK
Pause >NUL & exit/b
:Pastrouve
echo PASS NOT OK
Pause>NUL & exit/b
And the same using BAT/Powershell
#echo off&cls
set $MDP=toto1234
for /f "delims=" %%a in ('powershell -c "$rep=read-host Entrer_votre_MDP -AsSecureString;$password = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($rep));write $password"') do set $rep=%%a
if %$MDP%==%$rep% (echo PASS OK) else (echo PASS NOT OK)
exit/b

Batch choice alternative for detecting key without pause

The question is: is here any way to detect keypress in batch without pausing entire script for scripts like chat, games etc? For now I know about useful command called xcopy. I use it to detect and extract pressed key such as Enter. But it pauses entire script and waits for confirmation, while chose may not pause script, but unable to do silent invalid key as well as detecting specific ones
It's not simple with pure batch, but possible.
This is a sample that uses two threads.
The first thread :keyCheck waits for a key.
The second thread :mainFunc counts until a key is pressed.
#echo off
setlocal DisableDelayedExpansion
set "func=%~0"
for /F "delims=\" %%X in ("%func:*\=%") do set "func=%%X"
if ":" == "%func:~0,1%" (
goto %func%
)
( "%~d0\:keyCheck\..%~pnx0" ) > lock.tmp | "%~d0\:mainFunc\..%~pnx0"
echo Ende
exit /b
REM *** Thread1 - waiting for key
:keyCheck
for /f skip^=1^ delims^=^ eol^= %%A in ('replace.exe ? . /u /w') do for /f delims^=^ eol^= %%B in ("%%A") do (
set key=%%B
)
exit /b
REM *** Thread2 - Counting up
:mainFunc
setlocal EnableDelayedExpansion
for /F %%# in ('copy /Z "%~dpf0" NUL') do set "CR=%%#"
set "lastTime="
set cnt=0
:loop
set /a cnt+=1
set /p "=Stop with any key !cnt! !CR!" < nul
call :waitOrStop
goto :loop
:waitOrStop
REM Check if a key was pressed, then the lock is released
(
(
rem
) 2> lock.tmp && (
echo(
exit
)
) 2> nul
set "now=%time:~-2%"
if "!now!" NEQ "!lastTime!" (
set "lastTime=!now!"
exit /b
)
goto :waitOrStop
While it is not at all straightforward, the site Dostips.com has a full implementation of the game "Snake" using nothing but Batch, including non-blocking input.
Essentially, the batchfile spawns a second command prompt, which is blocking on input. When input is received, it is routed to the first, "main" program which polls the input file.
Like I said, not straightforward or simple, but it is do-able.
Although possible, there is not a simple way to do that using pure Batch commands. The simplest way is use a third party .exe program specifically designed to do so, like my GetKey.exe auxiliary file. This program get a key from keyboard and returns via ERRORLEVEL a value that indicate the key pressed. All keys are processed: ASCII characters are returned as positive values and extended keys (function keys, cursor control keys, etc) as negative values. If /N switch is given, GetKey.exe no waits: if a key was not pressed the value returned is zero.
This is a very simple example program that use GetKey.exe auxiliary file:
#echo off
setlocal EnableDelayedExpansion
rem Simple example of GetKey.exe auxiliary program to detect keys pressed
rem Get a Return (ASCII 13) CR character
for /F %%a in ('copy /Z "%~F0" NUL') do set "CR=%%a"
cls
echo Press a key at any moment; press ESC key to end
echo/
set i=0
:loop
set /A i+=1
set /P "=%i%!CR!" < NUL
GetKey /N
if %errorlevel% equ 0 goto loop
echo/
echo Key pressed: %errorlevel%
if %errorlevel% neq 27 goto loop
You may download GetKey.exe auxiliary program from this site; you may also download SHOWKEYCODES.BAT program that show the codes returned by GetKey.exe for all keys in keyboard, including Shift-, Ctrl- and Alt- combinations.
PS - If you are reluctant to use a third-party .exe program, just think that the original choice command is also an .exe file with a 35 KB size, but my GetKey.exe file is just 1536 bytes size. You may review several of my auxiliary .exe files and the replies posted by users of these programs at the same link.
Another multithread method, this time using Xcopy to capture input.
Handles all ASCII printable characters in the range 32 ~ 126, as well as TAB, Carriage Return and Backspace.
#Echo off
REM on relaunch, directs execution to the target label.
If not "%~1"=="" Goto:%1
REM initialize variables for the controller launcher
Set "QuitKey={BACKSPACE}"
Set "SignalFile=%TEMP%\%~n0_signal.dat"
REM Pipe the output of the function XCOPYCONTROLLER to Game to facilitate non blocking input.
Start /Wait /B "" "%~F0" XCOPYCONTROLLER 1>"%SignalFile%" | "%~F0" GAME <"%SignalFile%" 2> nul
REM end of controller launcher. Game has been quit.
Endlocal & Goto:Eof
:GAME
REM enable EDE environment to facilitate the use of posion characters.
REM More advanced gameloops use an infinite for /l loop to iterate through game logic
REM as it is parsed more efficiently by cmd.exe's interpreter.
REM such loops Require EDE to expand variables with their current value.
Setlocal EnableDelayedExpansion
:GAMELOOP
REM your game loop goes here.
Cls
Set /p "key="
If Defined key Title Lastkey= "!Key!". Press !Quitkey! to exit
Echo(%TIME%
If "!Key!"=="quit" EXIT
Set "key="
Goto:GAMELOOP
=======================================================
:XCOPYCONTROLLER by T3RRY
Setlocal EnableExtensions DISABLEdelayedExpansion
REM define unprintable characters
(Set LF=^
%= Do Not Modify. Linefeed Variable =%)
%= Escape =% for /f "Delims=" %%e in ('Echo Prompt $E^|cmd') Do Set "\E=%%e"
%= Tab =% for /f "delims= " %%T in ('robocopy /L . . /njh /njs' )do set "TAB=%%T"
%= Carriage Return =% for /f %%C in ('copy /Z "%~dpf0" nul') do set "CR=%%C"
%= BackSpace =% for /F "delims=#" %%B in ('"prompt #$H# &echo on &for %%b in (1) do rem"') do Set "BS=%%B"
Set "BS=%BS:~0,1%"
%= SUB =% copy nul sub.tmp /a > nul
for /F %%a in (sub.tmp) DO (
set "sub=%%a"
)
del sub.tmp
(TITLE )
<nul Set /P "=Press any Key to start"
REM Environment handling allows use of ! key
For /l %%C in () do (
Set "Key="
for /f "delims=" %%A in ('%SystemRoot%\System32\xcopy.exe /w "%~f0" "%~f0" 2^>nul') do If not Defined Key (
set "key=%%A"
Setlocal ENABLEdelayedExpansion
set "key=!KEY:~-1!"
If "!key!" == "!QuitKey!" (
<nul Set /P "=quit"
EXIT
) Else If "!Key!" == "%BS%" (
If "!QuitKey!" == "{BACKSPACE}" (
<nul Set /P "=quit"
EXIT
)
<nul Set /p "={BACKSPACE}"
) Else If "!Key!" == "!CR!" (
If "!QuitKey!" == "{ENTER}" (
<nul Set /P "=quit"
EXIT
)
<nul Set /p "={ENTER}"
) Else If "!Key!" == "!TAB!" (
If "!QuitKey!" == "{TAB}" (
<nul Set /P "=quit"
EXIT
)
<nul Set /p "={TAB}"
) Else (%= Echo without Linefeed. Allows output of = Key and Space =%
1> %~n0txt.tmp (echo(!Key!!sub!)
copy %~n0txt.tmp /a %~n0txt2.tmp /b > nul
type %~n0txt2.tmp
del %~n0txt.tmp %~n0txt2.tmp
)
Endlocal
)
)

What does this batch code exactly do?

I just surfed internet to find a function in batch, which colorizes the text. This is the code:
:Color
:: v20 deprecated.
:: Arguments: hexColor text [\n]
:: Supported in windows XP, 7, 8.
:: In XP extended ascii characters are printed as dots.
:: For print quotes, use empty text.
SetLocal enableExtensions EnableDelayedExpansion
Set "Text=%~2"
If Not Defined Text (Set Text=^")
Subst `: "!Temp!" >Nul &`: &Cd \
If Not Exist `.7 (
Echo(|(Pause >Nul &Findstr "^" >`)
Set /P "=." >>` <Nul
For /F "delims=;" %%# In (
'"Prompt $H;&For %%_ In (_) Do Rem"') Do (
Set /P "=%%#%%#%%#" <Nul >`.3
Set /P "=%%#%%#%%#%%#%%#" <Nul >`.5
Set /P "=%%#%%#%%#%%#%%#%%#%%#" <Nul >`.7))
Set /P "LF=" <` &Set "LF=!LF:~0,1!"
For %%# in ("!LF!") Do For %%_ In (
\ / :) Do Set "Text=!Text:%%_=%%~#%%_%%~#!"
For /F delims^=^ eol^= %%# in ("!Text!") Do (
If #==#! SetLocal DisableDelayedExpansion
If \==%%# (Findstr /A:%~1 . \` Nul
Type `.3) Else If /==%%# (Findstr /A:%~1 . /.\` Nul
Type `.5) Else (Echo %%#\..\`>`.dat
Findstr /F:`.dat /A:%~1 .
Type `.7))
If "\n"=="%~3" (Echo()
Goto :Eof
Can anyone please explain how is this working? I would really want to know what does each phrase do and how it participates in printing out color text.
P.S. I know most of the stuff what's happening there, I just don't know how it makes the console print out text in color and why does it create files in %Temp% directory.
I would like for the explanation to be step by step and easy to understand please.
Thank you!
I'm not sure what is going on but the easiest way for me is with powershell:
Put this at the top after #echo off
setlocal EnableDelayedExpansion
for /F "tokens=1,2 delims=#" %%a in ('"prompt #$H#$E# & echo on & for %%b in (1) do rem"') do (
set "DEL=%%a"
)
rem Prepare a file "X" with only one dot
<nul > X set /p ".=."
(It will create a file "x" that will stick around. Anoying but nothing much.
Then put this at the complete bottom of the script.
:colorEcho
set "param=^%~2" !
set "param=!param:"=\"!"
findstr /p /A:%1 "." "!param!\..\X" nul
<nul set /p ".=%DEL%%DEL%%DEL%%DEL%%DEL%%DEL%%DEL%"
exit /b
Then use this format to make colored text:
call :ColorEcho 81 "text" &echo.
the 81 is the color code for cmd. In the command prompt run color /? and you'll find the color codes there. The first one is the background the second is the text.

Typing text with not yet (but will be) defined variables in batch

So i want to create typing text for a Turn Based RPG (in batch), where you have a person controlling almost everything that interacts with the players.
I want it so when everyone's turn is over, it will display what everyone did, but in a dramatic way.
Now some of us know
for %%i in (h e l l o) do (set /p a=%%i<nul & ping 0.0.0.0 -n 2.5>nul 2>&1)
but I want to have a variable do this using
set /p Write=<Write.txt
so i can have something like for %%i in (%write%) do (set /p a=%%i<nul & ping 0.0.0.0 -n 2.5>nul 2>&1)
to make it write one letter at a time.
Thanks!
The Batch file below use an interesting trick I borrowed from this post that convert the Ascii (1-byte) characters into Unicode 2-bytes characters via /U switch of cmd.exe (inserting a zero-byte between characters), and then split the zero-bytes in individual lines via find command:
#echo off
setlocal
echo Hello, World!> Write.txt
for /F %%a in ('echo prompt $H^| cmd') do set "BS=%%a"
for /F "delims=" %%i in ('cmd /D /U /C type Write.txt ^| find /V ""') do (
set /P "=X%BS%%%i" < NUL
ping localhost -n 2 > NUL
)
EDIT: New version added
I modified previous code to show several lines in the right way; it also use JScript's sleep method in order to use variable delay intervals between each character, this point results in an output appearing in a more dramatic way.
#if (#CodeSection == #Batch) #then
#echo off
(
echo Hello, World!
echo The World is ending!
) > Write.txt
for /F %%a in ('echo prompt $H^| cmd') do set "BS=%%a"
for /F "delims=" %%a in (Write.txt) do (
for /F "delims=" %%i in ('cmd /D /U /C set /P "=%%a"^<NUL ^| find /V ""') do (
set /P "=X%BS%%%i" < NUL
REM ping localhost -n 3 > NUL
cscript //nologo //E:JScript "%~F0"
)
echo/
)
goto :EOF
#end
// JScript section: wait a random number of milliseconds between 0 and 300
WScript.Sleep(300*Math.random());
This is a version of Ghost typer that uses a variable, to display text on a screen in a way that a person might type it.
#echo off
:: Ghost typer - variable version
:: shows text in a variable on the screen in a way that a person might type it.
:: Do not use " in the text to be printed, replace them with '
:: Adjust speed variable - higher numbers increase typing speed - default=3
set speed=6
:: backspace variable is used in the printing routine
for /f %%a in ('"prompt $H&for %%b in (1) do rem"') do set "BS=%%a"
set "line=Your dog was eaten by a red winged dragon!"
call :begin
set "line=Two sloths ate all your chocolate!"
call :begin
set "line=A genie appears, and grants you 4 wishes...."
call :begin
set "line=How many woodchucks does it take?"
call :begin
pause>nul
goto :EOF
:begin
set num=0
:type
call set "letter=%%line:~%num%,1%%"
set "delay=%random%%random%%random%%random%%random%%random%%random%"
set "delay=%delay:~-6%"
if not "%letter%"=="" set /p "=a%bs%%letter%" <nul
for /L %%b in (1,%speed%,%delay%) do rem
if "%letter%"=="" echo.&goto :EOF
set /a num+=1
goto :type
To print the characters one by one of an arbitrary string, you could use the following:
#echo off
rem define string to print:
set "WRITE=Hello world!"
setlocal EnableDelayedExpansion
for /L %%I in (0,1,8191) do (
set "CHAR=!WRITE:~%%I,1!"
rem if "!WRITE:~%%I,2!"=="!CHAR! " set "CHAR=!CHAR! "
if "!CHAR!"=="" goto :SKIP
< nul set /P "DUMMY=!CHAR!"
> nul 2>&1 ping 127.0.0.1 -n 2
)
:SKIP
endlocal
As you will notice, the SPACE within the string in WRITE is not printed, because set /P does not print any (leading) spaces in the prompt string. To work around this, remove the rem in front of the if inside of the for loop. Actually this previews the next character and appends it to the current one in case it is a space, as set /P prints trailing spaces.
#echo off
setlocal enabledelayedexpansion
for /f %%A in ('"prompt $H &echo on &for %%B in (1) do rem"') do set BS=%%A
set /P string=<write.txt
call :StrLen "%string%" _len1
for /L %%A in (0,1,%_len1%) do (
set "substring=!string:~%%A,1!"
set /p "=.%BS%!substring!" <nul
> nul 2>&1 ping 127.0.0.1 -n 1
)
echo.
pause
GOTO :EOF
REM Subroutine to return the length of a string variable
:StrLen [string] [len-var]
set "_str=A%~1" & set "_len=0"
for /L %%A in (12,-1,0) do (set /a "_len|=1<<%%A" & for %%B in (!_len!) do if "!_str:~%%B,1!"=="" set /a "_len&=~1<<%%A")
set /a %~2=%_len%
exit /b

How to make a batch SET /P statememt not require an enter

I'm making my own console based off batch because I want more then what cmd offers but have the key features that batch has.
One of the most important things is to prompt the user for the command:
:prompt
#echo off
title JDOS command line
echo.
echo.
SET /P command="%FDIR%>"
rem SECTIONS/COMMANDS
rem /I means the if statement is not case-sensitive. USE IT AT ALL TIMES!
if /I "%command%"=="add" goto add
if /I "%command%"=="subtract" goto subtract
goto prompt
(This is just a small portion of all the options but you get the idea)
:add
title Calculator/Add
SET /P Add_A=Please enter the first number:
SET /P Add_B=Please enter the second number:
SET /A sum=%Add_A% + %Add_B%
echo The sum is %sum%
timeout /t 10 >nul
goto prompt
But this is timewasting and sort of idiotic (at least in my opinion).
So, can I execute goto add without the user pressing enter ?
Edit:
I'm thinking an approach similar to CHOICE but with the option to have more than 1 key be pressed (so for example instead of 1/2/3/4/ it would be restart/shutdown/lock/logoff/
I modified my accepted answer at this post and adjusted it for this request. Here it is:
#echo off
setlocal EnableDelayedExpansion
set "commands=add subtract"
for %%a in (%commands%) do set "com[%%a]=1"
for /F %%a in ('echo prompt $H ^| cmd') do set "BS=%%a"
for /F %%a in ('copy /Z "%~F0" NUL') do set "CR=%%a"
set "command="
:nextKey
set "key="
for /F "delims=" %%K in ('xcopy /W "%~F0" "%~F0" 2^>NUL') do if not defined key set "key=%%K"
if "!key:~-1!" equ "!CR!" goto endCommand
if "!key:~-1!" equ "!BS!" (
if defined command (
set "command=%command:~0,-1%"
set /P "=.!BS!!BS! !BS!!BS!" < NUL
)
) else if "!key:~-1!" neq " " (
set "command=%command%!key:~-1!"
set /P "=!key:~-1!" < NUL
if defined com[!command!] goto endCommand
)
goto nextKey
:endCommand
echo/
echo/
echo command read: "%command%"
Note: The mechanism used in this method does not allow to insert spaces! This code should be modified in large parts in order to read spaces.

Resources