Gibt es eine Möglichkeit, ein einzelnes Zeichen aus der Benutzereingabe zu lesen? Zum Beispiel drücken sie eine Taste am Terminal und es wird zurückgegeben (ähnlich getch()
). Ich weiß, dass es in Windows eine Funktion dafür gibt, aber ich möchte etwas, das plattformübergreifend ist.
260
msvcrt.getch
durch zu ersetzenmsvcrt.getwch
, wie dort vorgeschlagen.Antworten:
Hier ist ein Link zu einer Site, auf der angegeben ist, wie Sie ein einzelnes Zeichen unter Windows, Linux und OSX lesen können: http://code.activestate.com/recipes/134892/
quelle
ImportError
Ausnahme wie eine Art if-Anweisung verwendet wird. Warum nicht platform.system () aufrufen, um das Betriebssystem zu überprüfen?liest grundsätzlich 1 Byte aus STDIN.
Wenn Sie die Methode verwenden müssen, die nicht auf das wartet
\n
, können Sie diesen Code wie in der vorherigen Antwort vorgeschlagen verwenden:( entnommen aus http://code.activestate.com/recipes/134892/ )
quelle
Das in zwei Antworten wörtlich zitierte ActiveState- Rezept ist überarbeitet. Es kann darauf reduziert werden:
quelle
0
.Ebenfalls einen Versuch wert ist die Readchar- Bibliothek, die teilweise auf dem in anderen Antworten erwähnten ActiveState-Rezept basiert.
Installation:
Verwendungszweck:
Getestet unter Windows und Linux mit Python 2.7.
Unter Windows nur die Tasten, die Buchstaben oder ASCII - Steuercodes Karte unterstützt ( Backspace, Enter, Esc, Tab, Ctrl+ Schreiben ). Auf GNU / Linux (auf genauen Terminal abhängig, vielleicht?) Erhalten Sie auch Insert, Delete, Pg Up, Pg Dn, Home, Endund Tasten ... aber dann gibt es Probleme , diese speziellen Schlüssel von einer Trennung .F nEsc
Caveat: Wie bei den meisten (? Alle) Antworten hier, Signaltasten wie Ctrl+ C, Ctrl+ Dund Ctrl+ Zgefangen und zurück (wie
'\x03'
,'\x04'
und'\x1a'
jeweils); Es kann schwierig sein, Ihr Programm abzubrechen.quelle
Eine alternative Methode:
Aus diesem Blogbeitrag .
quelle
| os.O_NONBLOCK
. Andernfalls können Sie es in eine Schleife einfügen (eine gute Idee, ein wenig in der Schleife zu schlafen, um ein Drehen zu verhindern).while True
dannwhile 1
.Dieser Code, der hier basiert , löst KeyboardInterrupt und EOFError korrekt aus, wenn Ctrl+ Coder Ctrl+ Dgedrückt werden.
Sollte unter Windows und Linux funktionieren. Eine OS X-Version ist von der Originalquelle verfügbar.
quelle
Die (derzeit) am besten bewertete Antwort (mit dem ActiveState-Code) ist zu kompliziert. Ich sehe keinen Grund, Klassen zu verwenden, wenn eine bloße Funktion ausreichen sollte. Im Folgenden finden Sie zwei Implementierungen, die dasselbe erreichen, jedoch mit besser lesbarem Code.
Beide Implementierungen:
Version 1: lesbar und einfach
Version 2: Wiederholte Importe und Ausnahmebehandlung vermeiden:
[BEARBEITEN] Ich habe einen Vorteil des ActiveState-Codes verpasst. Wenn Sie vorhaben, Zeichen mehrmals zu lesen, werden durch diesen Code die (vernachlässigbaren) Kosten für die Wiederholung des Windows-Imports und die Behandlung von ImportError-Ausnahmen auf Unix-ähnlichen Systemen vermieden. Während Sie sich wahrscheinlich mehr Gedanken über die Lesbarkeit von Code machen sollten als über diese vernachlässigbare Optimierung, gibt es hier eine Alternative (sie ähnelt Louis 'Antwort, aber getChar () ist in sich geschlossen), die genauso funktioniert wie der ActiveState-Code und besser lesbar ist:
Beispielcode, der eine der oben genannten Versionen von getChar () ausführt:
quelle
Dies kann ein Anwendungsfall für einen Kontextmanager sein. Abgesehen von den Zulassungen für das Windows-Betriebssystem ist hier mein Vorschlag:
quelle
self
in__enter__
und habenread
Methode , dass die Renditensys.stdin.read(1)
, dann könnte man mehrere Charaktere in einem Kontext lesen.Versuchen Sie Folgendes : http://home.wlu.edu/~levys/software/kbhit.py Es ist nicht blockierend (das heißt, Sie können eine while-Schleife haben und einen Tastendruck erkennen, ohne ihn anzuhalten) und plattformübergreifend.
Ein Beispiel dafür:
Oder Sie können das getch-Modul von PyPi verwenden . Dies würde jedoch die while-Schleife blockieren
quelle
Dies ist NICHT BLOCKIEREND, liest eine Taste und speichert sie in keypress.key.
in Ihrem Programm
quelle
Die Antworten hier waren informativ, aber ich wollte auch eine Möglichkeit, Tastendrücke asynchron zu erhalten und Tastendrücke in separaten Ereignissen abzufeuern, alles auf threadsichere, plattformübergreifende Weise. PyGame war mir auch zu aufgebläht. Also habe ich Folgendes gemacht (in Python 2.7, aber ich vermute, es ist leicht portierbar), das ich hier teilen würde, falls es für andere nützlich wäre. Ich habe dies in einer Datei namens keyPress.py gespeichert.
Die Idee ist, dass Sie entweder einfach anrufen können
keyPress.getKey()
, um eine Taste von der Tastatur zu lesen, und sie dann zurückgeben können.Wenn Sie etwas mehr als das wollen, habe ich ein
KeyCapture
Objekt gemacht. Sie können eine über so etwas wie erstellenkeys = keyPress.KeyCapture()
.Dann gibt es drei Dinge, die Sie tun können:
addEvent(functionName)
übernimmt jede Funktion, die einen Parameter akzeptiert. Jedes Mal, wenn eine Taste gedrückt wird, wird diese Funktion mit der Zeichenfolge dieser Taste als Eingabe aufgerufen. Diese werden in einem separaten Thread ausgeführt, sodass Sie alles blockieren können, was Sie möchten, und die Funktionalität des KeyCapturer nicht beeinträchtigt oder die anderen Ereignisse verzögert werden.get()
Gibt einen Schlüssel auf dieselbe blockierende Weise wie zuvor zurück. Es wird jetzt hier benötigt, da die Schlüssel jetzt über dasKeyCapture
Objekt erfasst werden. DieskeyPress.getKey()
würde zu einem Konflikt mit diesem Verhalten führen und beide würden einige Schlüssel übersehen, da jeweils nur ein Schlüssel erfasst werden kann. Angenommen, der Benutzer drückt 'a', dann 'b', Sie rufen anget()
, der Benutzer drückt 'c'. Dieserget()
Aufruf gibt sofort 'a' zurück. Wenn Sie ihn erneut aufrufen, wird 'b' und dann 'c' zurückgegeben. Wenn Sie es erneut aufrufen, wird es blockiert, bis eine andere Taste gedrückt wird. Dies stellt sicher, dass Sie keine Schlüssel verpassen, auf Wunsch blockierend. Auf diese Weise ist es ein bisschen anders alskeyPress.getKey()
zuvorWenn Sie das Verhalten von
getKey()
zurück wollen,get(lossy=True)
ist wieget()
, außer dass es nur Tasten zurückgibt, die nach dem Anruf an gedrückt wurdenget()
. Im obigen Beispielget()
würde blockiert, bis der Benutzer 'c' drückt, und wenn Sie es erneut aufrufen, wird es blockiert, bis eine andere Taste gedrückt wird.getAsync()
ist ein bisschen anders. Es wurde für etwas entwickelt, das viel verarbeitet, dann gelegentlich zurückkommt und überprüft, welche Tasten gedrückt wurden. Somit wirdgetAsync()
eine Liste aller seit dem letzten Aufruf gedrückten TastengetAsync()
in der Reihenfolge von der ältesten gedrückten bis zur zuletzt gedrückten Taste zurückgegeben. Es wird auch nicht blockiert, was bedeutet, dassgetAsync()
ein Leerzeichen zurückgegeben[]
wird , wenn seit dem letzten Aufruf von keine Tasten gedrückt wurden .Um tatsächlich mit der Erfassung von Schlüsseln zu beginnen, müssen Sie
keys.startCapture()
mit Ihrem oben erstelltenkeys
Objekt anrufen .startCapture
ist nicht blockierend und startet einfach einen Thread, der nur die Tastendrücke aufzeichnet, und einen anderen Thread, um diese Tastendrücke zu verarbeiten. Es gibt zwei Threads, um sicherzustellen, dass der Thread, der Tastendrücke aufzeichnet, keine Tasten übersieht.Wenn Sie die Erfassung von Schlüsseln beenden möchten, können Sie anrufen
keys.stopCapture()
und die Erfassung von Schlüsseln wird beendet. Da das Erfassen eines Schlüssels jedoch eine Blockierungsoperation ist, erfassen die Thread-Erfassungsschlüssel nach dem Aufruf möglicherweise einen weiteren SchlüsselstopCapture()
.Um dies zu verhindern, können Sie einen oder mehrere optionale Parameter
startCapture(functionName, args)
an eine Funktion übergeben, die nur prüft, ob eine Taste gleich 'c' ist, und dann beendet wird. Es ist wichtig, dass diese Funktion nur sehr wenig bewirkt, bevor beispielsweise ein Schlaf hier dazu führt, dass wir Schlüssel verpassen.Wenn
stopCapture()
diese Funktion jedoch aufgerufen wird, werden die Tastenerfassungen sofort gestoppt, ohne dass versucht wird, weitere zu erfassen, und alleget()
Anrufe werden sofort mit "Keine" zurückgegeben, wenn noch keine Tasten gedrückt wurden.Auch da
get()
undgetAsync()
speichern alle vorherigen Tasten gedrückt (bis Sie sie abrufen), können Sie anrufenclearGetList()
undclearAsyncList()
die Schlüssel vorher gedrückt zu vergessen.Beachten Sie, dass
get()
,getAsync()
und Ereignisse sind unabhängig, so dass , wenn eine Taste gedrückt wird: 1. Ein Anruf ,get()
dass wartet, mit verlustbehafteten auf, wird diese Taste zurück. Die anderen wartenden Anrufe (falls vorhanden) warten weiter. 2. Diese Taste wird in der Warteschlange der Get-Schlüssel gespeichert, sodassget()
bei Verlust die älteste Taste zurückgegeben wird, dieget()
noch nicht zurückgegeben wurde . 3. Alle Ereignisse werden mit dieser Taste als Eingabe ausgelöst. 4. Diese Taste wird in der Liste dergetAsync()
Schlüssel gespeichert, in der diese Liste zurückgegeben und beim nächsten Aufruf an auf eine leere Liste gesetzt wirdgetAsync()
Wenn dies alles zu viel ist, ist hier ein Beispiel für einen Anwendungsfall:
Nach dem einfachen Test, den ich gemacht habe, funktioniert es gut für mich, aber ich nehme auch gerne andere Rückmeldungen entgegen, wenn ich etwas verpasst habe.
Ich habe das auch hier gepostet .
quelle
Ein Kommentar in einer der anderen Antworten erwähnte den cbreak-Modus, der für Unix-Implementierungen wichtig ist, da Sie im Allgemeinen nicht möchten, dass ^ C (
KeyboardError
) von getchar verbraucht wird (wie es der Fall ist, wenn Sie das Terminal auf den Raw-Modus setzen, wie von die meisten anderen Antworten).Ein weiteres wichtiges Detail ist, dass Sie, wenn Sie ein Zeichen und nicht ein Byte lesen möchten , 4 Bytes aus dem Eingabestream lesen sollten, da dies die maximale Anzahl von Bytes ist, aus denen ein einzelnes Zeichen in UTF-8 (Python 3+) besteht ). Das Lesen nur eines einzelnen Bytes führt zu unerwarteten Ergebnissen für Mehrbytezeichen wie z. B. Tastaturpfeile.
Hier ist meine geänderte Implementierung für Unix:
quelle
Versuchen Sie dies mit Pygame:
quelle
pygame.error: video system not initialized
Das Rezept des ActiveState scheint einen kleinen Fehler für "Posix" -Systeme zu enthalten, der eine
Ctrl-C
Unterbrechung verhindert (ich verwende einen Mac). Wenn ich den folgenden Code in mein Skript einfüge:Ich werde niemals in der Lage sein, das Skript mit zu beenden
Ctrl-C
, und ich muss mein Terminal töten, um zu entkommen.Ich glaube, die folgende Zeile ist die Ursache und auch zu brutal:
Abgesehen davon wird das Paket
tty
nicht wirklich benötigt,termios
es reicht aus, um damit umzugehen.Unten ist der verbesserte Code, der für mich funktioniert (
Ctrl-C
unterbricht), mit der zusätzlichengetche
Funktion, die das Zeichen während der Eingabe wiedergibt:Verweise:
quelle
Das
curses
Paket in Python kann verwendet werden, um mit nur wenigen Anweisungen in den "Raw" -Modus für die Zeicheneingabe vom Terminal zu wechseln. Die Hauptverwendung von Curses besteht darin, den Bildschirm für die Ausgabe zu übernehmen, was möglicherweise nicht das ist, was Sie wollen. Dieses Code-Snippet verwendetprint()
stattdessen Anweisungen, die verwendet werden können. Sie müssen jedoch wissen, wie Flüche die an die Ausgabe angehängten Zeilenenden ändern.quelle
Wenn ich etwas Kompliziertes mache, benutze ich Flüche, um Schlüssel zu lesen. Aber oft möchte ich nur ein einfaches Python 3-Skript, das die Standardbibliothek verwendet und Pfeiltasten lesen kann. Deshalb mache ich Folgendes:
quelle
Meine Lösung für Python3, unabhängig von Pip-Paketen.
quelle
Ich glaube, dass dies eine der elegantesten Lösungen ist.
und dann im Code verwenden:
quelle
Die akzeptierte Antwort lief für mich nicht so gut (ich würde eine Taste halten, nichts würde passieren, dann würde ich eine andere Taste drücken und es würde funktionieren).
Nachdem Sie das Modul Flüche kennengelernt haben, scheint es wirklich der richtige Weg zu sein. Und es ist jetzt für Windows über Windows -Cursor (über Pip verfügbar) verfügbar, sodass Sie plattformunabhängig programmieren können. Hier ist ein Beispiel, das von diesem netten Tutorial auf YouTube inspiriert wurde :
Speichern Sie es mit einer
.py
Erweiterung oder führen Sie escurses.wrapper(getkey)
im interaktiven Modus aus.quelle
Hier beantwortet: raw_input in Python ohne Enter
Verwenden Sie diesen Code-
Referenz: https://github.com/unfor19/mg-tools/blob/master/mgtools/get_key_pressed.py
quelle
Wenn Sie nur einen einzigen Tastendruck registrieren möchten, auch wenn der Benutzer ihn mehrmals gedrückt hat oder die Taste länger gedrückt hat. Um zu vermeiden, dass mehrere Eingaben gedrückt werden, verwenden Sie die while-Schleife und übergeben Sie sie.
quelle
Wenn Sie nur den Bildschirm halten möchten, damit Sie das Ergebnis auf dem Terminal sehen können, schreiben Sie einfach
am Ende des Codes und es wird den Bildschirm halten
quelle
Der eingebaute raw_input sollte helfen.
quelle