web-dev-qa-db-fra.com

Interrogation du clavier (détection d'une frappe) en python

Comment interroger le clavier depuis une application python de la console? Plus précisément, j'aimerais faire quelque chose de similaire avec beaucoup d'autres activités d'E/S (sélection de socket, 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 de faire cela sous Pythonic sous Windows? En outre, la portabilité vers Linux ne serait pas mauvaise, bien que ce ne soit pas obligatoire.

58
K. Brafford

L'approche standard consiste à utiliser le module select .

Cependant, cela ne fonctionne pas sous Windows. Pour cela, vous pouvez utiliser l'interrogation au clavier du module msvcrt .

Cela se fait souvent avec plusieurs threads - un par périphérique "surveillé", plus les processus d'arrière-plan qui pourraient devoir être interrompus par le périphérique.

29
S.Lott

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
17
Stefan

Ok, puisque ma tentative d’afficher ma solution dans un commentaire a échoué, voici ce que j’essayais de dire. Je pouvais faire exactement ce que je voulais à partir de Python natif (sous Windows, pas ailleurs) avec le code suivant:

import msvcrt 

def kbfunc(): 
   x = msvcrt.kbhit()
   if x: 
      ret = ord(msvcrt.getch()) 
   else: 
      ret = 0 
   return ret
14
K. Brafford

Une solution utilisant le module curses. Imprimer une valeur numérique correspondant à chaque touche enfoncé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 __== '__main__':
    curses.wrapper(main)
14
W. Russell

Aucune de ces réponses n'a bien fonctionné pour moi. Ce paquetage, 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()
10
wroscoe

Vous pouvez regarder comment pygame gère ceci pour voler quelques idées.

5
Rizwan Kassim

D'après les 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 C DLL appelé PyKeyboardAccess.dll et accéder aux fonctions crt conio en exportant 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é à 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)
5
K. Brafford

J'utilise ceci pour vérifier si vous appuyez sur une touche, je ne peux 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', supposée fonctionner sous Linux, Windows, Mac mais je ne pouvais pas que cela fonctionne.

1
ullix

Si vous combinez time.sleep, threading.Thread et sys.stdin.read, vous pouvez facilement attendre un laps de temps spécifié avant de continuer.

t = threading.Thread(target=sys.stdin.read(1) args=(1,))
t.start()
time.sleep(5)
t.join()

Vous pouvez également placer cela dans une fonction comme

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 retourne rien, vous devriez plutôt utiliser le module de pool de multitraitement que vous pouvez trouver ici: comment obtenir la valeur de retour d'un thread en python?

0
chbchb55

J'ai rencontré une implémentation multi-plateforme de kbhit à http://home.wlu.edu/~levys/software/kbhit.py (modifications apportées pour supprimer le code non pertinent):

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 != []

Assurez-vous de read() le (s) caractère (s) en attente - la fonction retournera True jusqu'à ce que vous le fassiez!

0
ivan_pozdeev