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%