How to question: process display until user presses a key

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
carlsomo
Posts: 91
Joined: 02 Oct 2012 17:21

How to question: process display until user presses a key

#1 Post by carlsomo » 25 Jan 2013 23:35

Let's say you wish to run a process until the user presses any key
While waiting for the event you wish a process to keep running, ie. dispalay a running timer

Code: Select all

call :SetCR CR
set timestart=%time%
:loop
call :calculatetime %timestart% timefromzero
<nul set/p=%timefromzero%!CR!
call :keypressedOrNot?
if %errorlevel% equ 1 goto :loop
echo(timer stopped at %timefromzero%
exit/b

:keypressedOrNot?
rem OK what code goes here?
rem Bios Int 16h,funtion 01h in exe format?? for MSDOS command line?
exit/b

:calculatetime
rem time format code here - not a big problem
exit/b

:setCR
rem CR code here
exit/b

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

Re: How to question: process display until user presses a ke

#2 Post by Aacini » 25 Jan 2013 23:59

You may use my GetKey.exe auxiliary program:

GetKey.exe description wrote:Get a key from keyboard and return its value in ERRORLEVEL.

GetKey [/N]

Ascii characters are returned as positive values, extended keys as negative values.

If /N switch is given, no wait for a key: immediately return zero if no key was pressed.

/N switch is useful to control actively interactive programs; for example, a program may repeat a loop until a key is pressed:

Code: Select all

:loop
   rem Do a repetitive process here
   GetKey /N
if %errorlevel% equ 0 goto loop
Look for 3- GetKey.exe.hex at this topic.

Antonio

carlsomo
Posts: 91
Joined: 02 Oct 2012 17:21

Re: How to question: process display until user presses a ke

#3 Post by carlsomo » 26 Jan 2013 00:34

That is exactly what I did and by the way I use your getkey.exe program all the time and I cannot thank you enough for that. I write numerous user interaction DOS snippets and it comes in very handy where set/p and choice just do not offer the same control over what uncontrollable users can do to mess things up, like using doskey functions inside of set/p and the limitations of choice.exe. I used to create getkey.com with echo staements but it won't work on Win64 platforms:

@echo hD1X-s0P_kUHP0UxGWX4ax1y1ieimnfeinklddmemkjanmndnadmndnpbbn>getkey.com
@echo hhpbbnpljhoxolnhaigidpllnbkdnhlkfhlflefblffahfUebdfahhfkokh>>getkey.com
@echo l/QnKE@HB61H.>>getkey.com

Unfortunatey, your getkey.exe /n pauses during the timer display for up to 2 seconds at a time and thus the timer display is jerky and not uniform. I don't know why for sure. I have disabled most background services during testing but it remains a problem and I cannot expect users to only run in safe mode. Perhaps a streamlined version that merely checks the keyboard buffer ie. kbhit().exe and returns right away? hint hint. Here is my code for Timer.cmd. The /Stopwatch option uses your getkey.exe. The simple command 'Timer 10 secs' shows how the timer counts down from 10 seconds smoothly. I cannot get the stopwatch feature to count up without hiccups 'Timer /s'

Code: Select all

::Timer.cmd [/P] TimeVal [[TimeSpec] or [/S=StopWatch]] [Beep or Bell]
@echo off&goto :Start
:Timer
echo(Description: Extremely Accurate Timer with Precise Clock and optional Beeper
echo(
echo(USAGE: %~nx0 [/P=] TimeVal [[TimeSpec] or [StopWatch]] [Beep or Bell]
echo(Countdown timer with optional bell ringer. Bell should be the last parameter
echo(Optional beep after Timeval [secs/mins/hours] [beep] ; seconds is default
echo(Timeval may be specified as interger, ie. 120 seconds or 120 sec or 120 s
echo(Timeval may be specified as a floating point, ie. 1.75 hours or 1.75 h
echo(Timespec may consist of starting or 1st chars of hrs mins or secs, h m or s
echo(Timeval may be specified in time format, ie. 1:20:00 ; 1 hour and 20 minutes
echo(When colons are used:
echo(   Digits after the last colon are considered seconds
echo(   Digits after '.' are hundredths of a second, ie 0:1.75 ; 1 and 3/4 seconds
echo(Regardless of format, precision is allowed for 2 digits after the '.'
echo(
echo(Stopwatch mode:
echo(   Counter counts up from zero until a key is pressed or /P=Process ends
echo(   Total elapsed time is displayed to consule unless a process is running
echo(   If timing a process the /P=Process [parameters] format must be followed
echo(   TimeVal is considered a variable that is set to the elapsed time HH:MM:SS.hh
echo(   If TimeVal.exe, .bat, .cmd is passed the process will be run with start/stop
echo(       times echo'd to the console, subject to optional redirection to a file
echo(   Returns elapsed time down to the second in errorlevel in HHMMSS format
echo(   Examples:
echo(       Timer /S=[StopwatchVar] - ^(Must use /s for stopwatch mode^)
echo(            Timer will run until key press and place elapsed time in TimeVar
echo(            if Timevar is not specified the result is in variable 'Stopwatch'
echo(       Timer /P="My Process.exe" "prameters" ^>"My Timing File.log"
echo(            Timer will call the process with parameters and report start and
echo(            stop times, total proccess time and errorlevel returned by process
echo(            The variable: 'My Process.exe' will contain elapsed time
echo(            Quotes must be used if Process or Parameters contain spaces and the
echo(            Parameters must immediately follow 'Process.exe'
echo(
echo(This program uses the CPU clock checked every 1-3 hundredths of a second
echo(depending on CPU background acticity so minimize background for the most
echo(precision possible
endlocal&exit /b %errorlevel%

:Start timer
set time1=%time: =%
set "debug=>nul"
::set "debug="
setlocal enabledelayedexpansion enableextensions
set "process="
set "StopWatch="
call :parse %*
if /i %errorlevel% lss 0 goto :Timer
if defined process exit/b %errorlevel%
if defined StopWatch exit/b %errorlevel%
echo/from parse: secs=%secs% mil2=%mil2% %debug%
for /f "tokens=1-4 delims=:." %%a in ("%time1%") do (
  set hour1=%%a&set min1=%%b&set sec1=%%c&set "mil1=%%d"
)
if /i %min1:~0,1% equ 0 set "min1=%min1:~1%"
if /i %sec1:~0,1% equ 0 set "sec1=%sec1:~1%"
if /i %mil1:~0,1% equ 0 set "mil1=%mil1:~1%"
set /a sec1+=(%hour1%*3600)+(%min1%*60)
set /a secs+=%sec1%
::check for midnight crossing (twice)
if /i %secs% geq 86400 set /a secs-=86400
set /a hour2=%secs% / 3600
set /a min2=(%secs%-(%hour2%*3600)) / 60
set /a sec2=(%secs%-(%hour2%*3600)) %% 60
if /i %mil1% neq 0 if /i %random:~-1% gtr 5 set /a mil1-=1
set/a mil2+=%mil1%
if /i %mil2% gtr 100 (
  set/a secs+=1&set/a mil2-=100
  if /i %sec2% lss 59 (set/a sec2+=1) else (
    set/a sec2=0&if /i %min2% lss 59 (set/a min2+=1) else (
      set/a min2=0&if /i %hour2% lss 23 (set/a hour2+=1) else (
        set/a hour2=0&if %secs% geq 86400 set/a secs-=86400
      )
    )
  )
)
if /i 1%sec2% lss 20 set "sec2=0%sec2%"
if /i 1%min2% lss 20 set "min2=0%min2%"
if /i 1%mil2% lss 20 set "mil2=0%mil2%"
set "time2=%hour2%:%min2%:%sec2%.%mil2%"
if /i 1%hour2% lss 20 set "hour2=0%hour2%"
set "HHMMSS=%hour2%%min2%%sec2%"
if not defined debug goto :end
:wait
  set timen=%time: =%
  if /i %timen% %eq% %time2% (
    set "beep=00"
    set "hsecs=.!beep!"
  ) else (
    call :time_diff %timen% %time2% timeleft
    set "hsecs=!timeleft:~-3!"
    set "timeleft=!timeleft:~0,-3!
  )
  set/a thours=!timeleft!/3600
  set/a tmins=!timeleft!/60 - !thours!*60
  set/a tsecs=!timeleft! - !tmins!*60 - !thours!*3600
  if /i 1!thours! lss 20 set thours=0!thours!
  if /i 1!tmins! lss 20 set tmins=0!tmins!
  if /i 1!tsecs! lss 20 set "tsecs=0!tsecs!"
  <nul set/p="REMAINING TIME: !thours!:!tmins!:!tsecs!!hsecs!%CR%">con
  echo/REMAINING TIME: !thours!:!tmins!:!tsecs!!hsecs! %debug%
  if "!beep!"=="00" goto :beep
goto :wait
:beep
if not defined bell goto :end
echo((|choice /n>nul 2>&1
:end
echo(
endlocal&exit /b %HHMMSS%

:parse timer.cmd secs tim beep
echo/in parse %* %debug%
if "%~1%"=="" exit/b -1
if /i %~1 equ /? exit/b -1
if /i %~1 equ /P call :Process %*&exit/b !errorlevel!
call :CR CR 27
if /i %~1 equ /S call :StopWatch %*&exit/b !errorlevel!
set "eq=geq"
set/a error=0
set "colon="
set "dot="
set "mils="
set "seconds=%~1"
set/a minutes=0
set/a hours=0
set/a mil2=0
echo/seconds=%seconds% now find:%debug%
echo(%seconds%|find ":"%debug%
if %errorlevel% equ 0 set "colon=:"
echo(%seconds%|find "."%debug%
echo/find.errorlevel=%errorlevel% %debug%
if /i %errorlevel% equ 0 (
  set "dot=."
  if /i "%seconds:~0,1%" equ "." set "seconds=0%seconds%
)
if defined dot (
  for /f "tokens=1-2* delims=. " %%A in ("%seconds%") do (
    set seconds=%%A&set mil2=%%B&set "ERR=%%C"
  )
  if defined ERR set error=-1&goto :ERROR
  echo/in dot: seconds=!seconds! mil2=!mil2!.. %debug%
  if not defined mil2 set/a mil2=0
  if not "!mil2!"=="0" (
    echo/ if /i 1!mil2! lss 20 then set mil2*=10 %debug%
    if /i 1!mil2!0 lss 200 set/a mil2*=10
    echo/mil2=!mil2! %debug%
    echo/if /i "!mil2:~0,1!" equ "0" set "mil2=!mil2:~1!" %debug%
    if /i "!mil2:~0,1!" equ "0" set "mil2=!mil2:~1!"
    call :IsInteger !mil2! 100&set error=!errorlevel!&if /i !error! neq 0 goto :ERROR
  )
)
if defined colon (
  for /f "tokens=1-4 delims=: " %%a in ("!seconds!") do (
    set a=%%a&set b=%%b&set c=%%c&set "d=%%d"
  )
  echo/!a!:!b!:!c!;!d! %debug%
  if defined d set error=-1&goto :ERROR
  call :IsInteger !a! 60&set/a error=!errorlevel!
  if /i !error! lss 0 goto :ERROR
  if not defined b set/a seconds=!a!&goto :bell
  if /i !error! gtr 0 goto :ERROR
  call :IsInteger !b! 60&set/a error=!errorlevel!
  if /i !error! neq 0 goto :ERROR
  set/a seconds=!b!&set/a minutes=!a!
  if not defined c goto :bell
  call :IsInteger !c! 60&set/a error=!errorlevel!
  if /i !error! neq 0 goto :ERROR
  set/a seconds=!c!&set/a minutes=!b!&set/a hours=!a!
)
:bell
set "tim=%~2"
echo/In Bell: tim=%tim% seconds=%seconds% mil2=%mil2% colon=%colon% dot=%dot% %debug%
if not defined colon (
  call :IsInteger %seconds%&set/a error=!errorlevel!
  if /i !error! lss 0 goto :ERROR
  if defined tim (
    echo/tim defined as %tim% %debug%
    set "tim=%tim:~0,1%"
    if /i [!tim!] equ [m] (
      set /a minutes=%seconds%&set/a seconds=0
      if defined dot (
        echo/set/a seconds=%mil2%*60/100andset/a mil2=%mil2%*60 %% 100 %debug%
        set/a seconds=!mil2!*60/100 &set/a mil2=%mil2%*60 %% 100
        echo/seconds=!seconds! %debug%
      )
    ) else if /i [!tim!] equ [h] (
      set /a hours=%seconds%&set/a seconds=0
      if defined dot (
        echo/set/a seconds=%mil2%*3600/100andset/a mil2=%mil2%*3600 %% 100 %debug%
        set/a seconds=%mil2%*3600/100&set/a mil2=%mil2%*3600 %% 100
      )
    )
  )
)
echo/set/a secs=%seconds%+%minutes%*60+%hours%*3600 %debug%
set/a secs=%seconds%+%minutes%*60+%hours%*3600
echo/secs=%secs% tim=%tim% %debug%
echo(%*|find /i "be">nul
if /i %errorlevel% equ 0 (set bell=1) else (set bell=)
:ERROR
if /i %error% gtr 0 set/a error=-%error%
if %error% equ -1 echo(ERROR:Invalid Timeval format
if %error% equ -2 echo(ERROR:Invalid Process or path
exit /b %error%

:CR CR
setlocal
set "num=%~2"
if defined num (if /i "%num%" gtr "80" set/a num=80) else (set/a num=80)
for /f "tokens=1 delims=# " %%a in ('"prompt #$H# &echo on &for %%b in (1) do rem"') do (
  for /l %%i in (1,1,%num%) do (call set "bkspc=%%a%%bkspc%%")
)
endlocal&call set %~1=%bkspc%&exit /b 0

:IsInteger value  ; returns -1 if not integer, else 0 if lss %~2, 1 if geq
if "%~1"=="" exit/b -1
setlocal
set "compare=%~2"
set/a Integer=0
for /f "tokens=1* delims=0123456789" %%I IN ("%~1") do set "Integer=%%I"
if /i "%Integer%" neq "0" (set/a Integer=-1) else (
  if defined compare if /i %~1 geq %compare% set/a Integer=1
)
endlocal&exit/b %Integer%

:Process
shift
set "process=%~1"
if not defined process set/a error=-2&goto :ERROR
echo(Process  call for: %~1 %~2 %~3 %~4 %~5 %~6 %~7 %~8 %~9
if not exist %process% (
  set "process=%~$PATH:1"
  if defined process goto :Begin_process
  set error=-2&goto :ERROR
)
:Begin_process
setlocal
set time1=%time%
echo(Starting time for: %process%: %time1%
call "%process%" %~2 %~3 %~4 %~5 %~6 %~7 %~8 %~9
echo(Error Level  from: %process%: %errorlevel%
set time2=%time%
echo(Ending  time  for: %process%: %time2%
call :Time_Diff %time1% %time2% time_diff
echo(Elapsed time  for: %~1: %time_diff%
endlocal&call set %~1=%time_diff%&exit /b %errorlevel%

:StopWatch
set "StopWatch=%~2"
if not defined StopWatch set "StopWatch=StopWatch"
echo(Starting Time: %time1%
:GO
call :time_diff %time1% %time% StopWatch
<nul set/p="ELAPSED TIMER: %StopWatch%%CR%"
GetKey.exe /n
if %errorlevel% equ 0 goto :GO
echo(
echo(Total Elapsed Time:  %StopWatch%
exit/b %errorlevel%

:Time_Diff
setlocal
set "time2=%~2"
set "time1=%~1"
for /f "tokens=1-4 delims=:." %%a in ("%time1%") do (
  set hour1=%%a&set min1=%%b&set sec1=%%c&set "mil1=%%d"
)
if /i [%mil1:~0,1%] equ [0] set mil1=%mil1:~1%
if /i [%hour1:~0,1%] equ [0] set hour1=%hour1:~1%
if not defined hour1 set /a hour1=0
if /i [%min1:~0,1%] equ [0] set min1=%min1:~1%
if not defined min1 set /a min1=0
if /i [%sec1:~0,1%] equ [0] set sec1=%sec1:~1%
if not defined sec1 set /a sec1=0
for /f "tokens=1-4 delims=:." %%a in ("%time2%") do (
  set hour2=%%a&set min2=%%b&set sec2=%%c&set "mil2=%%d"
)
if /i [%mil2:~0,1%] equ [0] set mil2=%mil2:~1%
if /i [%hour2:~0,1%] equ [0] set hour2=%hour2:~1%
if not defined hour2 set /a hour2=0
if /i [%min2:~0,1%] equ [0] set min2=%min2:~1%
if not defined min2 set /a min2=0
if /i [%sec2:~0,1%] equ [0] set sec2=%sec2:~1%
if not defined sec2 set /a sec2=0
set /a sec1+=(%hour1%*3600)+(%min1%*60)
set /a sec1*=100
set /a sec1+=%mil1%
set /a sec2+=(%hour2%*3600)+(%min2%*60)
set /a sec2*=100
set /a sec2+=%mil2%
set /a seconds=%sec2%-%sec1%
set /a mils=%seconds% %% 100
set /a plus=0
set /a seconds/=100
set "sign="
if /i %seconds% lss 0 set seconds=%seconds:-=%& set "sign=-"
if /i %mils% lss 0 set mils=%mils:-=%&set "sign=-"
if /i %mils% geq 50 set /a plus+=1
if /i 1%mils% lss 20 set mils=0%mils%
set EnVar=%sign%%seconds%.%mils%
set /a seconds+=%plus%
set seconds=%sign%%seconds%
:end
endlocal&call set "%~3=%EnVar%"&exit /b %seconds%

Post Reply