Wie kann ich die Tastatur von einer Konsole-Python-App abfragen? Im Einzelnen würde ich gerne etwas ähnliches tun, inmitten vieler anderer E/A-Aktivitäten (Socket-Selects, serieller Portzugriff usw.):
while 1:
# doing amazing Pythonic embedded stuff
# ...
# periodically do a non-blocking check to see if
# we are being told to do something else
x = keyboard.read(1000, timeout = 0)
if len(x):
# ok, some key got pressed
# do something
Was ist der richtige Pythonic-Weg, um dies unter Windows zu tun? Die Portabilität zu Linux wäre auch nicht schlecht, obwohl dies nicht erforderlich ist.
Der Standardansatz ist die Verwendung des Moduls select .
Dies funktioniert jedoch nicht unter Windows. Dazu können Sie die Tastaturabfrage des Moduls msvcrt verwenden.
Dies geschieht häufig mit mehreren Threads - einer pro Gerät wird "überwacht" und den Hintergrundprozessen, die möglicherweise vom Gerät unterbrochen werden müssen.
import sys
import select
def heardEnter():
i,o,e = select.select([sys.stdin],[],[],0.0001)
for s in i:
if s == sys.stdin:
input = sys.stdin.readline()
return True
return False
Ok, da mein Versuch, meine Lösung in einem Kommentar zu posten, fehlgeschlagen ist, habe ich Folgendes versucht. Mit dem folgenden Code konnte ich genau das tun, was ich von nativem Python wollte (unter Windows jedoch nicht woanders):
import msvcrt
def kbfunc():
x = msvcrt.kbhit()
if x:
ret = ord(msvcrt.getch())
else:
ret = 0
return ret
Eine Lösung mit dem Curses-Modul. Drucken eines numerischen Werts für jede gedrückte Taste:
import curses
def main(stdscr):
# do not wait for input when calling getch
stdscr.nodelay(1)
while True:
# get keyboard input, returns -1 if none available
c = stdscr.getch()
if c != -1:
# print numeric value
stdscr.addstr(str(c) + ' ')
stdscr.refresh()
# return curser to start position
stdscr.move(0, 0)
if __== '__main__':
curses.wrapper(main)
Keine dieser Antworten hat für mich gut funktioniert. Dieses Paket, pynput, macht genau das, was ich brauche.
https://pypi.python.org/pypi/pynput
from pynput.keyboard import Key, Listener
def on_press(key):
print('{0} pressed'.format(
key))
def on_release(key):
print('{0} release'.format(
key))
if key == Key.esc:
# Stop listener
return False
# Collect events until released
with Listener(
on_press=on_press,
on_release=on_release) as listener:
listener.join()
Sie können sich anschauen, wie pygame damit umgeht, um einige Ideen zu stehlen.
Aus den Kommentaren:
import msvcrt # built-in module
def kbfunc():
return ord(msvcrt.getch()) if msvcrt.kbhit() else 0
Danke für die Hilfe. Am Ende habe ich ein C DLL mit dem Namen PyKeyboardAccess.dll geschrieben und auf die crt conio-Funktionen zugegriffen, wobei diese Routine exportiert wurde:
#include <conio.h>
int kb_inkey () {
int rc;
int key;
key = _kbhit();
if (key == 0) {
rc = 0;
} else {
rc = _getch();
}
return rc;
}
Und ich greife in Python mit dem Modul ctypes (in Python 2.5 integriert) darauf zu:
import ctypes
import time
#
# first, load the DLL
#
try:
kblib = ctypes.CDLL("PyKeyboardAccess.dll")
except:
raise ("Error Loading PyKeyboardAccess.dll")
#
# now, find our function
#
try:
kbfunc = kblib.kb_inkey
except:
raise ("Could not find the kb_inkey function in the dll!")
#
# Ok, now let's demo the capability
#
while 1:
x = kbfunc()
if x != 0:
print "Got key: %d" % x
else:
time.sleep(.01)
Ich verwende dies zur Überprüfung auf Tastendruck, kann nicht viel einfacher sein:
#!/usr/bin/python3
# -*- coding: UTF-8 -*-
import curses, time
def main(stdscr):
"""checking for keypress"""
stdscr.nodelay(True) # do not wait for input when calling getch
return stdscr.getch()
while True:
print("key:", curses.wrapper(main)) # prints: 'key: 97' for 'a' pressed
# '-1' on no presses
time.sleep(1)
Während Flüche nicht unter Windows funktionieren, gibt es eine "Unicurses" -Version, die angeblich unter Linux, Windows und Mac arbeitet, aber ich konnte dies nicht zum Laufen bringen
Wenn Sie time.sleep, threading.Thread und sys.stdin.read kombinieren, können Sie leicht eine bestimmte Eingabedauer warten und dann fortfahren Auch dies sollte plattformübergreifend kompatibel sein.
t = threading.Thread(target=sys.stdin.read(1) args=(1,))
t.start()
time.sleep(5)
t.join()
Sie könnten dies auch in eine Funktion einordnen
def timed_getch(self, bytes=1, timeout=1):
t = threading.Thread(target=sys.stdin.read, args=(bytes,))
t.start()
time.sleep(timeout)
t.join()
del t
Obwohl dies nichts zurückgibt, sollten Sie stattdessen das Multiprocessing-Pool-Modul verwenden, das Sie hier finden: Wie kann ich den Rückgabewert von einem Thread in Python erhalten?
Ich habe eine plattformübergreifende Implementierung von kbhit
unter http://home.wlu.edu/~levys/software/kbhit.py gefunden (Änderungen vorgenommen, um irrelevanten Code zu entfernen):
import os
if os.name == 'nt':
import msvcrt
else:
import sys, select
def kbhit():
''' Returns True if a keypress is waiting to be read in stdin, False otherwise.
'''
if os.name == 'nt':
return msvcrt.kbhit()
else:
dr,dw,de = select.select([sys.stdin], [], [], 0)
return dr != []
Stellen Sie sicher, dass Sie die wartenden Zeichen read()
eingeben - die Funktion gibt True
so lange zurück, bis Sie dies tun!