it-swarm.com.de

Abfragen der Tastatur (Erkennen eines Tastendrucks) in Python

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.

58
K. Brafford

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.

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, 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
14
K. Brafford

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)
14
W. Russell

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()
10
wroscoe

Sie können sich anschauen, wie pygame damit umgeht, um einige Ideen zu stehlen.

5
Rizwan Kassim

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)
5
K. Brafford

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

1
ullix

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?

0
chbchb55

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!

0
ivan_pozdeev