Scruter le clavier (détecter une touche) en python
Comment puis-je sonder le clavier à partir d'une application console python? Plus précisément, je voudrais faire quelque chose de semblable à cela, au milieu de beaucoup d'autres activités d'e/S (prise sélectionne, d'accès au port série, etc.):
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
Quelle est la bonne façon pythonique de faire cela sur Windows? En outre, la portabilité vers Linux ne serait pas mauvaise, bien que ce ne soit pas nécessaire.
9 réponses
l'approche standard consiste à utiliser le module sélectionner .
cependant, cela ne fonctionne pas sur Windows. Pour cela, vous pouvez utiliser le sondage clavier du module msvcrt .
souvent, cela se fait avec plusieurs threads -- Un Par périphérique étant "observé" plus les processus de fond qui pourraient avoir besoin d'être interrompus par le périphérique.
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, depuis ma tentative de poster ma solution dans un commentaire manqué, voici ce que j'essayais de dire. Je pouvais faire exactement ce que je voulais de natif Python (sur Windows, pas n'importe où ailleurs) avec le code suivant:
import msvcrt
def kbfunc():
x = msvcrt.kbhit()
if x:
ret = ord(msvcrt.getch())
else:
ret = 0
return ret
une solution utilisant le module malédictions. Impression d'une valeur numérique correspondant à chaque touche pressée:
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 __name__ == '__main__':
curses.wrapper(main)
aucune de ces réponses n'a bien fonctionné pour moi. Ce paquet, pynput, fait exactement ce dont j'ai besoin.
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()
vous pourriez regarder comment pygame gère ceci pour voler quelques idées.
des commentaires:
import msvcrt # built-in module
def kbfunc():
return ord(msvcrt.getch()) if msvcrt.kbhit() else 0
Merci pour l'aide. J'ai fini par écrire un livre appelé PyKeyboardAccess.dll et accès aux fonctions crt conio, exportation de cette routine:
#include <conio.h>
int kb_inkey () {
int rc;
int key;
key = _kbhit();
if (key == 0) {
rc = 0;
} else {
rc = _getch();
}
return rc;
}
et j'y accède en python en utilisant le module ctypes (intégré dans python 2.5):
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)
Si vous combinez le temps.le sommeil, le filetage.Fil, et sys.stdin.lire vous pouvez facilement attendre un certain temps pour la saisie, puis continuer, de plus, cela devrait être compatible avec toutes les plateformes.
t = threading.Thread(target=sys.stdin.read(1) args=(1,))
t.start()
time.sleep(5)
t.join()
vous pouvez aussi le placer dans une fonction comme so
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
bien que cela ne retournera rien donc à la place vous devriez utiliser le module de piscine multiprocessing que vous pouvez trouver ici: comment obtenir le retour la valeur à partir d'un fil en python?
Je l'utilise pour vérifier les presses à clés, ne peut pas être beaucoup plus simple:
#!/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)
alors que curses ne fonctionne pas sous windows, il existe une version "unicurses", qui est censée fonctionner sous Linux, Windows, Mac mais je n'ai pas pu faire en sorte que cela fonctionne