Page 1 of 2
Multi-line menu with options selection via DOSKEY
Posted: 31 May 2014 21:41
by Aacini
The creation of a multi-line menu that allows to select options via arrow keys has been an old request in Batch files. This type of selection menu may be developed with the aid of
auxiliary programs, like GetKey to get the selection keys and a combination of CursorPos/ColorShow to deselect the current option and highlight the new one; however, such a program is somewhat complex.
I devised a simpler method to achieve such selection menu using DOSKEY program. This DOS command store the lines executed in the command-line (like inputs to SET /P command) and store they in a
history that may be displayed in the form of a selection menu when F7 key is pressed. This way, the method consist in:
- Clear previous DOSKEY history.
- Execute several SET /P commands that read the menu options, so the DOSKEY history is filled with them.
- Send a F7 key to the keyboard.
- Execute a SET /P "OPTION=Prompt: "; the input to this command will be completed via the selection menu of DOSKEY.
Code: Select all
@if (@CodeSection == @Batch) @then
@echo off
setlocal EnableDelayedExpansion
rem Multi-line menu with options selection via DOSKEY
rem Antonio Perez Ayala
rem Define the options
set numOpts=0
for %%a in (First Second Third Fourth Fifth) do (
set /A numOpts+=1
set "option[!numOpts!]=%%a Option"
)
set /A numOpts+=1
set "option[!numOpts!]=exit"
rem Clear previous doskey history
doskey /REINSTALL
rem Fill doskey history with menu options
cscript //nologo /E:JScript "%~F0" EnterOpts
for /L %%i in (1,1,%numOpts%) do set /P "var="
:nextOpt
cls
echo MULTI-LINE MENU WITH OPTIONS SELECTION
echo/
rem Send a F7 key to open the selection menu
cscript //nologo /E:JScript "%~F0"
set /P "var=Select the desired option: "
echo/
if "%var%" equ "exit" goto :EOF
echo Option selected: "%var%"
pause
goto nextOpt
@end
var wshShell = WScript.CreateObject("WScript.Shell"),
envVar = wshShell.Environment("Process"),
numOpts = parseInt(envVar("numOpts"));
if ( WScript.Arguments.Length ) {
// Enter menu options
for ( var i=1; i <= numOpts; i++ ) {
wshShell.SendKeys(envVar("option["+i+"]")+"{ENTER}");
}
} else {
// Enter a F7 to open the menu
wshShell.SendKeys("{F7}");
}
Output example of previous program:
There is a strange point about this program: the DOSKEY /REINSTALL command clear the history only when it is executed
the first time. If previous program is executed a second time in the same cmd.exe session, the DOSKEY history is
not cleared, so menu options are wrong. I read DOSKEY documentation in Microsoft and SS64 sites and didn't found any reference about this problem. I tested this program in Windows 8, so I don't know if this problem also appear in other versions...
Antonio
Re: Multi-line menu with options selection via DOSKEY
Posted: 01 Jun 2014 00:51
by foxidrive
You're a clever fellow Antonio.
Re: Multi-line menu with options selection via DOSKEY
Posted: 01 Jun 2014 02:18
by carlos
Aacini: Very good idea.
Edit: for clear the buffer of command history set to 0 and then to the number of elements of the menu:
Code: Select all
rem Clear the command history
doskey /LISTSIZE=0
doskey /LISTSIZE=%numOpts%
or simple set the size to the number of elements of the menu:
also, i add the home key for the menu appears selected with the first option:
after F7:
doskey handle two buffers, the buffer of the doskey macros, and the buffer of the commands history. Apparently doskey /reinstall not works, it reset any buffer. Also /history show anything even when you see commands with F7.
Re: Multi-line menu with options selection via DOSKEY
Posted: 15 Feb 2017 16:10
by Sponge Belly
Hello All!
Here’s an alternative approach I cobbled together:
Code: Select all
@echo off & setlocal enableextensions disabledelayedexpansion
(call;)
title Menu Demo
mode con lines=15 cols=20
(set lf=^
%= DO NOT DELETE =%
)
set ^"nl=^^^%lf%%lf%^%lf%%lf%^"
set ^"\n=^^^%lf%%lf%^%lf%%lf%^^"
cls
echo(Choose an Option:%nl%%\n%
1. Calculator%nl%%\n%
2. Disk Cleanup%nl%%\n%
3. Notepad%nl%%\n%
4. Paint%nl%%\n%
5. WordPad%nl%%\n%
0. Quit
:readKey
set "opt=" & for /f skip^=1^ delims^=^ eol^= %%A in ('
replace ? . /u /w
') do if not defined opt set "opt=%%A"
set opt | findstr /ix "opt=[012345]" >nul || goto readKey
if %opt% equ 0 goto end
for /f "tokens=1,2 delims=:" %%A in (
^"1:calc%nl%2:cleanmgr%nl%3:notepad%nl%4:mspaint%nl%5:wordpad^"
) do if %opt% equ %%A (
start "" "%%B.exe"
goto end
)
:end
endlocal & goto :EOF
Run the program from Windows/File Explorer. All key presses except 0-5 will be ignored.
Enjoy!
- SBPS: Thanks to Carlos for the Read Key with REPLACE technique.
Re: Multi-line menu with options selection via DOSKEY
Posted: 16 Feb 2017 02:13
by guimenez
Is there anyway to disable the left and right cursor?
Because if i press does, it hide the menu and show line by line.
Thanks
Re: Multi-line menu with options selection via DOSKEY
Posted: 18 Feb 2017 09:21
by Aacini
Sponge Belly wrote:Hello All!
Here’s an alternative approach I cobbled together:
Run the program from Windows/File Explorer. All key presses except 0-5 will be ignored.
Enjoy!
- SBPS: Thanks to Carlos for the Read Key with REPLACE technique.
Mmmm... As far as I know, the REPLACE technique can
not read arrow keys either. Your example code could be done in a simpler way via CHOICE command...
Antonio
Re: Multi-line menu with options selection via DOSKEY
Posted: 09 Jul 2019 14:30
by bakemonogatari
Hello, can someone put an example of this script that would launch Explorer.exe after validating (with the Enter key) the choice "0: First option"? this would allow me to understand how to do the same for the other options. Thank you.
Re: Multi-line menu with options selection via DOSKEY
Posted: 11 Jul 2019 22:15
by Aacini
I reviewed this program and fixed the problem about the reinitialization of DOSKEY history. It works correctly now.
Then, I wrote an example of a menu to start real programs. When the programs are console applications, everything is OK. However, when the programs are GUI applications, then may be a synchronization problem between the AppActivate method used to select again the cmd.exe window, and the SendKeys method used to assemble the menu. I inserted a delay between the two methods. However, there are problems now and then even if the delay is as large as 500 msec. I can't find a
reliable method to achieve this goal...
Code: Select all
@if (@CodeSection == @Batch) @then
@echo off
setlocal EnableDelayedExpansion
if "%~1" equ "newCmd" goto newCmd
rem Multi-line menu with options selection via DOSKEY
rem Antonio Perez Ayala
rem Set title for AppActivate
title Select option
rem Define the options
set numOpts=0
for %%a in ("Calculator=calc" "Notepad=notepad" "Paint=mspaint" "Explorer=explorer") do (
for /F "tokens=1,2 delims==" %%b in (%%a) do (
set /A numOpts+=1
set "option[!numOpts!]=%%b"
set "app[%%b]=%%c"
)
)
set /A numOpts+=1
set "option[!numOpts!]=Quit"
rem Options selection loop
:nextOpt
cmd /C "%~F0" newCmd
if errorlevel 1 goto nextOpt
goto :EOF
:newCmd
rem Clear previous doskey history
doskey /REINSTALL
rem Fill doskey history with menu options
cscript //nologo /E:JScript "%~F0" %numOpts%
for /L %%i in (1,1,%numOpts%) do set /P "="
cls
echo MULTI-LINE MENU WITH OPTIONS SELECTION
echo/
rem Send a F7 key to open the selection menu
cscript //nologo /E:JScript "%~F0"
rem Read the option
set /P "option=Select the desired option: "
echo/
set "continue=1"
if defined app[%option%] (
start !app[%option%]!
) else (
set "continue=0"
)
exit %continue%
@end
var wshShell = WScript.CreateObject("WScript.Shell"),
envVar = wshShell.Environment("Process");
// Select the cmd.exe window
wshShell.AppActivate("Select option");
WScript.Sleep(300);
if ( WScript.Arguments.Length ) {
// Send menu options to fill the menu
var numOpts = parseInt(WScript.Arguments(0));
for ( var i=1; i <= numOpts; i++ ) {
wshShell.SendKeys(envVar("option["+i+"]")+"{ENTER}");
}
} else {
// Send a F7 to open the menu
wshShell.SendKeys("{F7}");
}
Antonio
Re: Multi-line menu with options selection via DOSKEY
Posted: 02 Aug 2019 10:53
by bakemonogatari
thanks
Re: Multi-line menu with options selection via DOSKEY
Posted: 16 Aug 2019 12:22
by Szecska
@Sponge Belly
Code: Select all
@echo off & setlocal enableextensions disabledelayedexpansion
(call;)
title Menu Demo
mode con lines=15 cols=20
(set lf=^
%= DO NOT DELETE =%
)
set ^"nl=^^^%lf%%lf%^%lf%%lf%^"
set ^"\n=^^^%lf%%lf%^%lf%%lf%^^"
cls
echo(Choose an Option:%nl%%\n%
1. Calculator%nl%%\n%
2. Disk Cleanup%nl%%\n%
3. Notepad%nl%%\n%
4. Paint%nl%%\n%
5. WordPad%nl%%\n%
0. Quit
:readKey
set "opt=" & for /f skip^=1^ delims^=^ eol^= %%A in ('
replace ? . /u /w
') do if not defined opt set "opt=%%A"
set opt | findstr /ix "opt=[012345]" >nul || goto readKey
if %opt% equ 0 goto end
for /f "tokens=1,2 delims=:" %%A in (
^"1:calc%nl%2:cleanmgr%nl%3:notepad%nl%4:mspaint%nl%5:wordpad^"
) do if %opt% equ %%A (
start "" "%%B.exe"
goto end
)
:end
endlocal & goto :EOF
Your script behaves strangely if you run it from a pendrive.
It stucks at the character reading command and the same happens if you try the xcopy method on a FAT32 formatted pendrive.
I dont really know why it's happening,I guess it has to do something with the fs.
I managed to fix the issue with this:
Code: Select all
@echo off & setlocal enableextensions disabledelayedexpansion
for %%P in (%CD%) do set "OriginalDrive=%%~dP"
if not !OriginalDrive!==%SystemDrive% %SystemDrive%
REM Rest of the original code here
Szecska
Re: Multi-line menu with options selection via DOSKEY
Posted: 18 Aug 2019 04:53
by Aacini
@Szecska,
As I
said before, you may get the same result in a much simpler way using a
choice /N /C 123450 command; I don't see any reason to use the replace.exe method here...
IMHO these replace.exe-based examples should be moved to the replace.exe explanation method thread. Those "option selection" methods that just read a key are
not similar to the
visual change in the selected menu option that is performed
via arrow keys when doskey.exe command is used in the way described in this thread...
Antonio
Re: Multi-line menu with options selection via DOSKEY
Posted: 20 Aug 2019 15:50
by carlos
Szecska the replace method was a way of get an input where choice was not present in the windows. I not remeber from which version of windows it was included, maybe windows 8 ?
I'm interested anyways in the cause of fail using fat32 filesystem, maybe use:
will work ?
Re: Multi-line menu with options selection via DOSKEY
Posted: 31 Aug 2019 15:28
by Szecska
@Aacini
I found a strange thing lately,with this script:
Code: Select all
@echo off
:null
PowerShell Exit($host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown').VirtualKeyCode);
echo %errorlevel%
goto null
this can detect arrow keys, but only as
%&'( (key 37,38,39,40)
So far this is the closest thing I could find for arrow key detection but its painfully slow.
Re: Multi-line menu with options selection via DOSKEY
Posted: 31 Aug 2019 16:31
by aGerman
Code: Select all
powershell -nop -ep Bypass -c "while($true){$ki=$host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');$vk=$ki.VirtualKeyCode;if(($ki.Character -eq 0) -and ((37..40) -contains $vk)){exit($vk-36);}}"
Maybe that's what you're looking for. Returns errorlevel 1-4.
Steffen
Re: Multi-line menu with options selection via DOSKEY
Posted: 01 Sep 2019 11:07
by Aacini
Szecska wrote: ↑31 Aug 2019 15:28
@Aacini
I found a strange thing lately,with this script:
Code: Select all
@echo off
:null
PowerShell Exit($host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown').VirtualKeyCode);
echo %errorlevel%
goto null
this can detect arrow keys, but only as
%&'( (key 37,38,39,40)
So far this is the closest thing I could find for arrow key detection but its painfully slow.
The method to read arrow keys in an efficient way using Powershell (and also move cursor and show text in color) is described at
Read arrow keys and show color text in an efficient way thread...
PS - (All of) You should note that all this last discussion have
no relation to the method to use Doskey program proposed in
this thread...
Antonio