Seite 1 von 1
Tastendruck abfangen
Verfasst: Donnerstag 26. August 2010, 07:21
von mcdaniels
Hallo und guten Morgen!
Ich möchte gerne einen Tastendruck abfangen. Konkret geht es mir hier um die Cursortasten, die in der Python-Shell (natürlich nach gestartetem Programm) abgefangen werden sollen.
Quasi sowas in die Richtung:
Wenn Event -> Tastaturcode so und so: mach das ...
das ganze natürlich ohne mit input auf eine Eingabe zu warten, der dann mit Return zu bestätigen ist.
Per Suche konnte ich bislang hauptsächlich Problemlösungen bezogen auf die GUI Programmierung finden.
Wird wohl auf
rauslaufen.
Hm.. Gerade das hier gefunden:
http://www.python-forum.de/viewtopic.ph ... =sys.stdin
Schaut wohl nicht so gut aus...
Danke und LG
Re: Tastendruck abfangen
Verfasst: Donnerstag 26. August 2010, 08:13
von BlackJack
@mcdaniels: Nein, das schaut leider wirklich nicht so gut aus. Da gibt's keinen allgemeinen, plattformübergreifenden Weg.
Unter Linux wäre die Antwort wohl das `curses`-Modul aus der Standardbibliothek, beziehungsweise `urwid` wenn es auch etwas zusätzlich Installierbares sein darf. Die `curses`-API ist nicht so der Hit.
Re: Tastendruck abfangen
Verfasst: Donnerstag 26. August 2010, 09:17
von snafu
Die folgende portable Funktion sollte genau das tun, was du haben möchtest. Das Drücken einer Pfeiltaste ergibt unter Unix eine Escape-Sequenz von 3 Zeichen. Dementsprechend müsstest du `length` anpassen. Probier halt einfach aus, ob bei einem zweiten Aufruf sofort eine Ausgabe kommt (das bedeutet: Ergebnis ist länger als 1 Zeichen) oder ob du wieder was neues eingeben kannst (Ergebnis ist genau 1 Zeichen lang).
Code: Alles auswählen
try:
# windows
import msvcrt
except ImportError:
msvcrt = None
import sys
import termios
import tty
def getch(length=1):
"""
Read a key press and return the result. Nothing is echoed to the
console.
Note that on Windows a special function key press will return its
keycode. `Control-C` cannot be read there.
On Unices it will return one char by default. Thus, when reading
a special function key, whose resulting escape sequence could be
longer than one char, the `length` value might be changed, since
otherwise the remaining characters would be returned by the next
calls until stdin is "empty".
"""
if msvcrt:
char = msvcrt.getch()
if char in ('\000', '\xe0'):
# special key -> need a second call to get keycode
char = msvcrt.getch()
return char
else:
old = termios.tcgetattr(sys.stdin)
try:
tty.setraw(sys.stdin)
return sys.stdin.read(length)
finally:
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old)
Re: Tastendruck abfangen
Verfasst: Donnerstag 26. August 2010, 09:49
von snafu
Übrigens, eventuell mache ich mir mal die Mühe, die möglichen Tasten(-kombinationen) plattformübergreifend mit Konstanten zu wrappen, damit man dafür nicht extra `pygame` installieren muss. Bedarf ist ja offenbar da und ich glaube, es gibt noch kein Modul dafür.
BTW: Weiß jemand einen sauberen Weg, um zu erkennen, ob noch Zeichen in STDIN sind? Mit `select` habe ich es nicht hinbekommen.
Re: Tastendruck abfangen
Verfasst: Donnerstag 26. August 2010, 10:39
von mcdaniels
Hey snafu!
Dumme Frage, läuft das auch unter Python 3.x?
Traceback (most recent call last):
File "<pyshell#81>", line 1, in <module>
getch(y)
File "/home/user/tastenabfangen.py", line 32, in getch
old = termios.tcgetattr(sys.stdin)
TypeError: argument must be an int, or have a fileno() method.
LG
Re: Tastendruck abfangen
Verfasst: Donnerstag 26. August 2010, 10:56
von snafu
Liefert jetzt auch bei Pfeiltasten ohne weiteres Zutun das korrekte Ergebnis. Python 3.x Kompatibilität möge man sich anpassen. Ich verwende jetzt zumindest Dateideskriptoren, anstatt einen `fileno()`-Aufruf zu erwarten, der bei Python 2.x ja funktioniert.
Code: Alles auswählen
try:
# windows
import msvcrt
except ImportError:
msvcrt = None
import errno
import fcntl
import os
import sys
import termios
import tty
def getch():
"""
Read a key press and return the result. Nothing is echoed to the
console.
Note that on Windows a special function key press will return its
keycode. `Control-C` cannot be read there.
On Unices pressing a special key will return its escape sequence.
"""
if msvcrt:
char = msvcrt.getch()
if char in ('\000', '\xe0'):
# special key -> need a second call to get keycode
char = msvcrt.getch()
return char
else:
stdin = sys.stdin.fileno()
old = termios.tcgetattr(stdin)
try:
tty.setraw(stdin)
char = sys.stdin.read(1)
finally:
termios.tcsetattr(stdin, termios.TCSADRAIN, old)
old = fcntl.fcntl(stdin, fcntl.F_GETFL)
try:
fcntl.fcntl(stdin, fcntl.F_SETFL, old | os.O_NONBLOCK)
try:
char += sys.stdin.read()
except IOError, e:
if e.errno == errno.EAGAIN:
# there was no more than one char to read
pass
else:
raise
finally:
fcntl.fcntl(stdin, fcntl.F_SETFL, old)
return char
Re: Tastendruck abfangen
Verfasst: Donnerstag 26. August 2010, 11:02
von mcdaniels
Python 3.x Kompatibilität möge man sich anpassen
O lala, so weit bin ich lange noch nicht

Re: Tastendruck abfangen
Verfasst: Donnerstag 26. August 2010, 14:16
von jerch
snafu hat geschrieben:BTW: Weiß jemand einen sauberen Weg, um zu erkennen, ob noch Zeichen in STDIN sind? Mit `select` habe ich es nicht hinbekommen.
Ja das geht mit select und poll. siehe
http://www.python-forum.de/viewtopic.php?f=11&t=20555
Auch ist Deine getch()-Funktion etwas seltsam, warum liest Du erst blockierend und nochmal nicht blockierend?
Um das plattformübergreifend zu implementieren, müsste man eine Art Keyhandler schreiben, der die entsprechenden Keycodes aus STDIN auswertet. Und genau hier liegt die Crux, aufgrund des Wildwuchses an Terminals sind die Keycodes sehr verschieden und man müsste zuvor den Terminaltypen abfragen, um die richtigen Keycodes zu suchen. Wenn Du das alles implementiert hast, hast Du quasi die Hälfte von curses nachgebaut

Re: Tastendruck abfangen
Verfasst: Donnerstag 26. August 2010, 19:53
von mcdaniels
Guten Abend!
Nundenn, ich lege die Tastenabfrage somit lieber mal auf Eis und widme mich weiterhin den Basics
LG