
130834
28.12.2016
Choice Zusatztool, ENTER und ESC? (Batch)
Hey Leute, heute wieder eine Frage der unmöglichen Art, bitte überzeugt mich von Gegenteil.
Ich entwickle gerade schon wieder irgendwas, Und es hat eine ASDW Steuerung, die ich mit dem Choice befehl Abfrage.
Momentan wird Bestätigung durch D ausgeführt.
Leider etwas unpraktisch, wie auch immer.
Ich würde jetzt gerne ENTER als Gültigen Wert haben, um meine Menüs damit zu erweitern.
Die Frage wurde bestimmt schon gestellt,
die Suche hat aber jedoch nur ergeben das dem User der fragte eine
PM damit geschickt wurde ( Ganz toll gemacht, Lösungen sind ja nicht für alle da /Sarkasmus )
und das die Frage oft mit "unmöglich" beantwortet wurde.
Da ich sowieso 2000 Zusatztools verwende, um das ganze einiger Massen gut aussehen zu lassen, brauche ich keine riesige 50-Zeilen-Pure-Batch-Lösung.
Es wäre außerdem auch schön den ESC Key verwenden zu können, ist aber nicht nötig.
Danke im voraus, schönen Abend
lg clragon
Ich entwickle gerade schon wieder irgendwas, Und es hat eine ASDW Steuerung, die ich mit dem Choice befehl Abfrage.
Momentan wird Bestätigung durch D ausgeführt.
Leider etwas unpraktisch, wie auch immer.
Ich würde jetzt gerne ENTER als Gültigen Wert haben, um meine Menüs damit zu erweitern.
Die Frage wurde bestimmt schon gestellt,
die Suche hat aber jedoch nur ergeben das dem User der fragte eine
PM damit geschickt wurde ( Ganz toll gemacht, Lösungen sind ja nicht für alle da /Sarkasmus )
und das die Frage oft mit "unmöglich" beantwortet wurde.
Da ich sowieso 2000 Zusatztools verwende, um das ganze einiger Massen gut aussehen zu lassen, brauche ich keine riesige 50-Zeilen-Pure-Batch-Lösung.
Es wäre außerdem auch schön den ESC Key verwenden zu können, ist aber nicht nötig.
Danke im voraus, schönen Abend
lg clragon
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Content-ID: 324970
Url: https://administrator.de/forum/choice-zusatztool-enter-und-esc-batch-324970.html
Ausgedruckt am: 15.05.2025 um 04:05 Uhr
23 Kommentare
Neuester Kommentar
Hallo clragon.
Ich erspare mir mal Kommentare, die du dir selbst denken kannst ...
Cmdwiz - cmd helper tools
Gotoxy
Cmdgfx - draw graphic primitives (polygons,circles etc) in cmd line window
Das Tool im ersten Link sollte sein, was du suchst.
Oder selbst kompilieren:
getkey.c
Compiler und IDE
test.bat
Grüße
rubberman
Ich erspare mir mal Kommentare, die du dir selbst denken kannst ...
Cmdwiz - cmd helper tools
Gotoxy
Cmdgfx - draw graphic primitives (polygons,circles etc) in cmd line window
Das Tool im ersten Link sollte sein, was du suchst.
Oder selbst kompilieren:
getkey.c
// getkey.c
#include <stdlib.h>
#include <errno.h>
#include <conio.h>
// Funktion um Tastatureingabe in einen numerischen Wert zu konvertieren
int key()
{
int ret = _getch();
return (ret == 0 || ret == 224) ? 256 + _getch() : ret;
}
// Funktion um 2 Elemente eines int-Arrays zu vergleichen (für qsort und bsearch)
int compare(const void *a, const void *b)
{
return *(int*)a - *(int*)b;
}
// Einsprungfunktion des Programms
int main(int argc, char *argv)
{
// Wenn kein Argument übergeben wurde, auf Tasatureingabe warten, Wert zurückgeben und Programm beenden
if (argc == 1)
return key();
// anderenfalls ...
int ret = 0;
long conv = 0L;
char *endptr = NULL;
int *valid = malloc((argc - 1) * sizeof(int)); // Speicher für die übergebenen Argumente reservieren
if (valid == NULL)
return -1;
// übergebene Argumente in numerische Werte konvertieren
for (int i = 1; i < argc; ++i)
{
conv = strtol(argv[i], &endptr, 0);
if (errno || *endptr || conv < 1L || conv > 511L)
{
free(valid);
return -1;
}
valid[i - 1] = (int)conv;
}
// Werte für eine effiziente Suche sortieren
qsort(valid, argc - 1, sizeof(int), compare);
// in einer Schleife Tastatureingaben mit den übergebenen Werten vergleich
do
{
ret = key();
} while (bsearch(&ret, valid, argc - 1, sizeof(int), compare) == NULL); // iterieren, solange keine Übereinstimmung gefunden wurde
free(valid); // reservierten Speicher freigeben
return ret; // Wert zurückgeben und Programm beenden
}
test.bat
@echo off &setlocal
REM Enter (CR) (ASCII 13) 13
REM Escape (ASCII 27) 27
REM Pfeil rechts (256 + Scancode 77) 333
REM Pfeil links (256 + Scancode 75) 331
REM Pfeil oben (256 + Scancode 72) 328
REM Pfeil unten (256 + Scancode 80) 336
echo Enter, Escape, Pfeiltasten
getkey 13 27 333 331 328 336
echo %errorlevel%
pause
echo(
echo Beliebige Taste
setlocal EnableDelayedExpansion
for /l %%i in () do (
getkey
echo !errorlevel!
)
Grüße
rubberman
Ist aber nicht Open-Source
Ist doch egal, oder würde es dir was nützen den Sourcecode zu kennen? Es ist definitiv Freeware.und meiner Meinung nach etwas zu gross
Kann man nicht behaupten, wenn man nicht weiß wie's funktioniert. Kleiner sind pure Batchlösungen, aber da stört dich ja wieder, dass es ein paar Zeilen Code zu viel werden könnten ^^warum zur Hölle sollte ich mich damit beschäftigen 64 und 32 bit zu unterscheiden
Ist ja nun kein Problem.if exist "%systemroot%\syswow64\cmd.exe" (set "editv=EditV64.exe") else set "editv=EditV32.exe"
%editv% foo
Weiß nicht ob es ähnliche Tools gibt. Um aus einem Kindprozess Variablen im Elternprozess zu verändern, muss man aber schon etwas Magie anwenden. I.d.R. so etwas wie DLL Injection. Da hier keine DLL im Spiel ist, ist es vermutlich Inline ASM. Also, ob was Nachgebasteltes signifikant kleiner wäre, ist fraglich. In jedem Fall hätte man aber wieder 2 Tools (je nach dem, ob der laufende cmd.exe Prozess 32 oder 64 Bit ist), da man in den Speicherbereich des laufenden Prozesses eingreifen muss.
Grüße
rubberman
invalid conversion from 'void*' to 'int*'
Du hast ein C++ Projekt erstellt, bzw. einen C++ Compiler verwendet. Warum?Abhilfe:
int *valid = (int*)malloc((argc - 1) * sizeof(int));
conio.h: No such file or Directory
Der von mir verlinkte Compiler hat diesen Header (der Windows-spezifisch ist, aber hier benötigt wird).Wenn bei dem von dir verwendeten Compiler der Header fehlt, kannst du ihn nicht für diesen Code nutzen.
step by step
Projekt heißt bei dir natürlich nicht "HelloWorld" sondern "getkey" und den Beispielcode in der main.c ersetzt du mit dem aus meinem Post. Du kannst oben im Menü "Release" statt "Debug" als Build Target auswählen, um das Overhead im Code zu minimieren und damit die Programmdatei klein zu halten.
Grüße
rubberman
Hab mal noch Option /i (als erstes Argument zu übergeben) hinzugefügt. Damit kannst du festlegen, dass Groß-/Kleinbuchstaben gleich behandelt werden. Der übergebene ASCII Wert wird zurückgegeben (unabhängig ob es der des Groß- oder des Kleinbuchstaben war).
// getkey.c
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <errno.h>
#include <conio.h>
// Struktur mit dem ursprünglich übergebenen Wert und dem Suchwert (der dem ASCII Wert des Kleinbuchstaben entspricht, wenn Groß-/Kleinschreibung ignoriert werden soll)
typedef struct tag_KEYINFO { int origin; int search; } KEYINFO;
// Funktion um Tastatureingabe in einen numerischen Wert zu konvertieren
int key(const int ignorecase)
{
int ret = _getch();
if (ret == 0 || ret == 224)
return 256 + _getch();
return (ignorecase != 0) ? tolower(ret) : ret;
}
// Funktion um 2 Werte zu vergleichen (für qsort() und bsearch())
int compare(const KEYINFO *a, const KEYINFO *b)
{
return a->search - b->search;
}
// Einsprungfunktion des Programms
int main(int argc, char *argv)
{
// Wenn kein Argument übergeben wurde, auf Tasatureingabe warten, Wert zurückgeben und Programm beenden
if (argc == 1)
return key(0);
// anderenfalls ... feststellen, ob Option /i übergeben werden
int ignorecase = 0;
if (_stricmp(argv[1], "/i") == 0)
{
if (argc < 3)
return -1;
ignorecase = 1;
}
KEYINFO *valid = NULL, *found = NULL, current = {0};
int offset = 1 + ignorecase;
if ((valid = (KEYINFO*)malloc((argc - offset) * sizeof(KEYINFO))) == NULL) // Speicher für die konvertierten Argumente reservieren
return -1;
// übergebene Argumente in numerische Werte konvertieren
for (int i = offset; i < argc; ++i)
{
char *endptr = NULL;
long conv = strtol(argv[i], &endptr, 0);
if (errno || *endptr || conv < 1L || conv > 511L)
{
free(valid);
return -1;
}
valid[i - offset].origin = (int)conv;
valid[i - offset].search = (ignorecase != 0 && conv < 256L) ? tolower((int)conv) : (int)conv;
}
// Werte für eine effiziente Suche sortieren
qsort(valid, argc - offset, sizeof(KEYINFO), (int(*)(const void*,const void*))compare);
// in einer Schleife Tastatureingaben mit den übergebenen Werten vergleich
do
{
current.search = key(ignorecase);
} while ((found = (KEYINFO*)bsearch(¤t, valid, argc - offset, sizeof(KEYINFO), (int(*)(const void*,const void*))compare)) == NULL); // iterieren, solange keine Übereinstimmung gefunden wurde
int ret = found->origin; // Rückgabewert kopieren (bevor er durch free() invalid wird)
free(valid); // reservierten Speicher freigeben
return ret; // Wert zurückgeben und Programm beenden
}
@echo off &setlocal
echo y/Y oder n/N
getkey /i 89 78
echo %errorlevel%
pause
// getkey.c
#ifdef _WIN32_WINNT
# undef _WIN32_WINNT
#endif
#define _WIN32_WINNT 0x0501
#define WIN32_LEAN_AND_MEAN
#define NOUSER
#define NOSERVICE
#define NOMCX
#define NOIME
#define NOKERNEL
#include <windows.h>
#include <locale.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <errno.h>
#include <conio.h>
// Struktur mit dem ursprünglich übergebenen Wert und dem Suchwert (der dem ASCII Wert des Kleinbuchstaben entspricht, wenn Groß-/Kleinschreibung ignoriert werden soll)
typedef struct tag_KEYINFO
{
int origin;
int search;
} KEYINFO;
// Struktur zur Verwendung als Argument für die Threadfunktion
typedef struct tag_THREADARG
{
int ret; // Rückgabewert
int ignorecase; // 1 wenn Groß-/Kleinschreibung ignoriert werden soll
KEYINFO *valid; // konvertierte Werte
size_t vlength; // Anzahl konvertierter Werte
} THREADARG;
// Funktion um 2 Werte zu vergleichen (für qsort() und bsearch())
int compare(const KEYINFO *a, const KEYINFO *b);
// Funktion um Tastatureingabe in einen numerischen Wert zu konvertieren
void key(THREADARG *const p_arg);
// Threadfunktion (gibt nur dann zurück, wenn eine Übereinstimmung zwischen Eingabe und Vorgabewerten gefunden wird)
DWORD WINAPI check(THREADARG *const p_arg);
// Einsprungfunktion des Programms
int main(int argc, char *argv)
{
// Lacale-Einstellungen der Umgebung übernehemen
setlocale(LC_ALL, "");
THREADARG t_arg = {0};
// Wenn kein Argument übergeben wurde, auf Tasatureingabe warten, Wert zurückgeben und Programm beenden
if (argc == 1)
{
key(&t_arg);
return t_arg.ret;
}
// anderenfalls ...
DWORD timeout = INFINITE;
int offset = 1;
char *endptr = NULL;
long conv = 0L;
// feststellen, ob Option /i oder /t übergeben wurde
for (int i = 1; i < 3 && *argv[i] == '/'; ++i)
{
if (_stricmp(argv[i], "/i") == 0)
{
t_arg.ignorecase = 1;
++offset;
}
else if (_strnicmp(argv[i], "/t:", 3U) == 0)
{
if (argv[i][3U] == '\0')
return -1;
conv = strtol(&argv[i][3U], &endptr, 0);
if (errno || *endptr || conv < 0L || conv > 9999L)
return -1;
++offset;
timeout = conv * 1000U;
}
if (argc < offset + 1)
return -1;
}
t_arg.vlength = argc - offset;
if ((t_arg.valid = (KEYINFO*)malloc(t_arg.vlength * sizeof(KEYINFO))) == NULL) // Speicher für die konvertierten Argumente reservieren
return -1;
// übergebene Argumente in numerische Werte konvertieren
for (int i = offset; i < argc; ++i)
{
conv = strtol(argv[i], &endptr, 0);
if (errno || *endptr || conv < 1L || conv > 65791L)
{
free(t_arg.valid);
return -1;
}
t_arg.valid[i - offset].origin = (int)conv;
t_arg.valid[i - offset].search = (t_arg.ignorecase != 0 && conv < 65536L) ? towlower((wint_t)conv) : (int)conv;
}
// Default-Rückgabewert, wenn der Thread timeout ist
int defaultret = t_arg.valid.origin;
// Werte für eine effiziente Suche sortieren
qsort(t_arg.valid, argc - offset, sizeof(KEYINFO), (int(*)(const void*,const void*))compare);
HANDLE t_handle = CreateThread(NULL, 0U, (LPTHREAD_START_ROUTINE)check, &t_arg, 0U, NULL); // Thread starten
DWORD waitret = WaitForSingleObject(t_handle, timeout); // 'timeout' Millisekunden auf Beenden des Threads warten
CloseHandle(t_handle); // Threadhandle schließen
free(t_arg.valid); // reservierten Speicher freigeben
return (waitret == 0U) ? t_arg.ret : defaultret; // Wert zurückgeben und Programm beenden
}
int compare(const KEYINFO *a, const KEYINFO *b)
{
return a->search - b->search;
}
void key(THREADARG *const p_arg)
{
int ret = _getwch();
if (ret == 0 || ret == 224)
p_arg->ret = 65536 + _getwch();
else
p_arg->ret = (p_arg->ignorecase != 0) ? towlower(ret) : ret;
}
DWORD WINAPI check(THREADARG *const p_arg)
{
KEYINFO *found = NULL, current = {0};
// in einer Schleife Tastatureingaben mit den übergebenen Werten vergleich
do
{
key(p_arg);
current.search = p_arg->ret;
} while ((found = (KEYINFO*)bsearch(¤t, p_arg->valid, p_arg->vlength, sizeof(KEYINFO), (int(*)(const void*,const void*))compare)) == NULL); // iterieren, solange keine Übereinstimmung gefunden wurde
p_arg->ret = found->origin;
return 0U;
}
getkey [/i] [/t:s] [x1 [x2 [...xn]]]
/i Ignoriere Groß-/Kleinschreibung
/t:s Timeout nach s Sekunden, x1 wird als Default zurückgegeben
x1...xn Zugehörige Werte für die gültigen Tastatureingaben:
Unicode Code Point des Zeichens oder
(65536 + Scancode) für Tasten die kein Zeichen spezifizieren
Rückgabewert:
* bei Fehler -1
* wenn kein Wert spezifiziert wurde, der Wert einer beliebigen Tastatureingabe
* wenn Werte spezifiziert wurden, zugehöriger Wert zur Tastatureingabe
* bei Timeout, erster übergebener Wert
Ich sag mal so ...
Die ersten Computer- und Programmiersprachenentwickler lebten auf ihrer eigenen Weltscheibe. Auf der gab es nur ASCII Zeichen, also auch nur Buchstaben von A-Z. Klar war Speicher knapp und Operationen langsam. Man hat aber von vorn herein versäumt mal in die Zukunft zu blicken und den ganzen Spaß sinnvoll erweiterbar zu halten.
Also hat man Krücken gebaut, mit denen wir uns bis heute herumschlagen dürfen. Code Pages, um das 8. Bit eines Bytes zu nutzen, aber die Werte mal so und mal anders zu interpretieren. Bestes Beispiel ist das Windows Consolefenster. Umlaute dort, sind ganz andere Zeichen als in deinem Texteditor.
Darüber hinaus geht die Entwicklung in 2 Richtungen. *nixoide Betriebssysteme setzen auf UTF-8. Je nachdem, wie viele Bytes für einen Unicode Code Point benötigt wird, ist ein Zeichen dort unterschiedlich breit. Derzeit begrenzt der Standard die Breite auf 4 Bytes, heißt aber nicht, dass man das nicht ändern könnte, wenn zukünftig eine größere Breite benötigt würde.
Nicht so Windows. Erst mal ist man davon ausgegangen, dass 2 Bytes ausreichen (UCS-2 bzw. "Basic Multilingual Plane"). Also arbeitet Windows intern mit Zeichen, die grundsätzlich eine Breite von 2 Bytes haben. Als man gemerkt hat, dass man damit aber immer noch nicht alle Zeichen abbilden kann, hat man zu UTF-16 gewechselt. Auch hier sind Zeichen grundsätzlich immer noch 2 Bytes breit. Wenn's nicht mehr ausreicht, kombiniert man weitere 2 Bytes zu einem Surrogate Pair zusammen. Was passiert, wenn auch das nicht mehr reicht, wissen die Götter.
Worauf ich hinaus will ... Man kann sich auf die Weltscheibe der Pioniere begeben, läuft aber Gefahr vom Rand zu fallen. Mit den hierzulande gebräuchlichen Umlauten steht man schon mit einem Bein daneben. Auch wenn man mit den CRT Funktionen erst die halbe Miete schafft (UCS-2), steht man aber schon wesentlich sicherer. Das ist der Grund, warum ich das noch einmal geändert habe. Mit 1 Byte kann man 256, mit 2 Bytes 65536 unterschiedliche Werte darstellen. Um nicht Gefahr zu laufen, dass es Überschneidungen zwischen Code Points von Zeichen mit den Scan Codes der anderen Tasten gibt, muss nun eben 65536 zum Scancode addiert werden. Ich sehe da kein Problem. Zudem hast du immer die Möglichkeit das Tool ohne Argumente aufzurufen, um an den Wert einer bestimmten Tastatureingabe zu kommen.
Hier hat sich mal jemand Mühe gegeben eine Tabelle zu kreieren.
Die Seite lädt endlos Zeichen am Ende nach. Ich hab jetzt nicht getestet wie weit es geht, aktuell 128172 Zeichen laut Wikipedia. Die Code Points sind dort Hexadezimal angegeben. Kannst du übrigens auch so übergeben, wenn du ein 0x voranstellst. %=exitcode% statt %errorlevel% zeigt dir auch den Rückgabewert hexadezimal an. Naja, nur nebenbei ...
Die ersten Computer- und Programmiersprachenentwickler lebten auf ihrer eigenen Weltscheibe. Auf der gab es nur ASCII Zeichen, also auch nur Buchstaben von A-Z. Klar war Speicher knapp und Operationen langsam. Man hat aber von vorn herein versäumt mal in die Zukunft zu blicken und den ganzen Spaß sinnvoll erweiterbar zu halten.
Also hat man Krücken gebaut, mit denen wir uns bis heute herumschlagen dürfen. Code Pages, um das 8. Bit eines Bytes zu nutzen, aber die Werte mal so und mal anders zu interpretieren. Bestes Beispiel ist das Windows Consolefenster. Umlaute dort, sind ganz andere Zeichen als in deinem Texteditor.
Darüber hinaus geht die Entwicklung in 2 Richtungen. *nixoide Betriebssysteme setzen auf UTF-8. Je nachdem, wie viele Bytes für einen Unicode Code Point benötigt wird, ist ein Zeichen dort unterschiedlich breit. Derzeit begrenzt der Standard die Breite auf 4 Bytes, heißt aber nicht, dass man das nicht ändern könnte, wenn zukünftig eine größere Breite benötigt würde.
Nicht so Windows. Erst mal ist man davon ausgegangen, dass 2 Bytes ausreichen (UCS-2 bzw. "Basic Multilingual Plane"). Also arbeitet Windows intern mit Zeichen, die grundsätzlich eine Breite von 2 Bytes haben. Als man gemerkt hat, dass man damit aber immer noch nicht alle Zeichen abbilden kann, hat man zu UTF-16 gewechselt. Auch hier sind Zeichen grundsätzlich immer noch 2 Bytes breit. Wenn's nicht mehr ausreicht, kombiniert man weitere 2 Bytes zu einem Surrogate Pair zusammen. Was passiert, wenn auch das nicht mehr reicht, wissen die Götter.
Worauf ich hinaus will ... Man kann sich auf die Weltscheibe der Pioniere begeben, läuft aber Gefahr vom Rand zu fallen. Mit den hierzulande gebräuchlichen Umlauten steht man schon mit einem Bein daneben. Auch wenn man mit den CRT Funktionen erst die halbe Miete schafft (UCS-2), steht man aber schon wesentlich sicherer. Das ist der Grund, warum ich das noch einmal geändert habe. Mit 1 Byte kann man 256, mit 2 Bytes 65536 unterschiedliche Werte darstellen. Um nicht Gefahr zu laufen, dass es Überschneidungen zwischen Code Points von Zeichen mit den Scan Codes der anderen Tasten gibt, muss nun eben 65536 zum Scancode addiert werden. Ich sehe da kein Problem. Zudem hast du immer die Möglichkeit das Tool ohne Argumente aufzurufen, um an den Wert einer bestimmten Tastatureingabe zu kommen.
Und was ist der Unicode Code Point?
Der Wert den ein Zeichen im Unicode Standard hat.Hier hat sich mal jemand Mühe gegeben eine Tabelle zu kreieren.
Die Seite lädt endlos Zeichen am Ende nach. Ich hab jetzt nicht getestet wie weit es geht, aktuell 128172 Zeichen laut Wikipedia. Die Code Points sind dort Hexadezimal angegeben. Kannst du übrigens auch so übergeben, wenn du ein 0x voranstellst. %=exitcode% statt %errorlevel% zeigt dir auch den Rückgabewert hexadezimal an. Naja, nur nebenbei ...
mit ^ escapen
Das hat nix mit dem Tool zu tun und ist Kommandozeilen-Verhalten in Batch. Ja, geht natürlich.%exitcode%
Nee, %=exitcode%. Eine dieser merkwürdigen Variablen mit = am Anfang, die cmd.exe produziert und die man nicht selbst definieren kann.Also 0x10020 ist ein Ausrufezeichen?
Ein Ausrufezeichen hat dezimal den Wert 33, hexadezimal 0x21. (Vorangestellte Nullen kannst du weglassen.)Die Tabelle ist so zu lesen, dass du jeweils die letzte 0 in der Zeile durch das 0-F der Spalte ersetzt.
Die ersten Computer-Pioniere waren also Idioten.
Fachidioten. Experten auf ihrem Gebiet, haben aber nicht über den Tellerrand geschaut.Werd ich denn überhaupt einer Zahl unter 65536 über den Weg laufen?
Alle Tasten die ein Zeichen repräsentieren, ergeben einen Wert <65536. Im Unterschied zu vorher können sie aber jetzt auch >255 sein (€ = 8364 = 0x20AC).