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.

58
demandé sur alexis 2008-11-15 06:29:09

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.

28
répondu S.Lott 2014-06-17 09:54:34

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
répondu tsvikas 2011-07-19 14:23:32

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
14
répondu K. Brafford 2008-11-20 00:32:05

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)
13
répondu W. Russell 2015-08-18 15:48:39

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()
10
répondu wroscoe 2016-12-11 06:31:18

vous pourriez regarder comment pygame gère ceci pour voler quelques idées.

5
répondu Rizwan Kassim 2008-11-15 03:49:45

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)
5
répondu K. Brafford 2008-11-16 17:48:25

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?

0
répondu chbchb55 2017-05-23 11:54:50

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

0
répondu ullix 2018-03-19 15:34:29