Python las ein einzelnes Zeichen vom Benutzer

260

Gibt es eine Möglichkeit, ein einzelnes Zeichen aus der Benutzereingabe zu lesen? Zum Beispiel drücken sie eine Taste am Terminal und es wird zurückgegeben (ähnlich getch()). Ich weiß, dass es in Windows eine Funktion dafür gibt, aber ich möchte etwas, das plattformübergreifend ist.

Evan Fosmark
quelle
1
Unter Windows stieß ich auf das gleiche Problem wie in dieser Frage . Die Lösung besteht darin, das msvcrt.getchdurch zu ersetzen msvcrt.getwch, wie dort vorgeschlagen.
A. Roy
Die Lösung besteht darin, das Getch-Modul "pip install getch" zu installieren. Verwenden Sie für Python2 den Befehl "pip2 install files.pythonhosted.org/packages/56/f7/… ". Diese Lösung funktioniert auch unter Termux (Android).
Petr Mach

Antworten:

189

Hier ist ein Link zu einer Site, auf der angegeben ist, wie Sie ein einzelnes Zeichen unter Windows, Linux und OSX lesen können: http://code.activestate.com/recipes/134892/

class _Getch:
    """Gets a single character from standard input.  Does not echo to the
screen."""
    def __init__(self):
        try:
            self.impl = _GetchWindows()
        except ImportError:
            self.impl = _GetchUnix()

    def __call__(self): return self.impl()


class _GetchUnix:
    def __init__(self):
        import tty, sys

    def __call__(self):
        import sys, tty, termios
        fd = sys.stdin.fileno()
        old_settings = termios.tcgetattr(fd)
        try:
            tty.setraw(sys.stdin.fileno())
            ch = sys.stdin.read(1)
        finally:
            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
        return ch


class _GetchWindows:
    def __init__(self):
        import msvcrt

    def __call__(self):
        import msvcrt
        return msvcrt.getch()


getch = _Getch()
tehvan
quelle
18
Code scheint kurz genug zu sein, dass Sie ihn einfach einschließen könnten, aber +1, um so schnell eine gute (plattformübergreifende) Antwort zu finden.
John Mulder
4
Behandelt es nicht-lateinische (z. B. kyrillische) Buchstaben gut? Ich habe ein Problem damit und kann nicht herausfinden, ob es mein Fehler ist oder nicht.
Phlya
7
Mir gefällt nicht, wie die ImportErrorAusnahme wie eine Art if-Anweisung verwendet wird. Warum nicht platform.system () aufrufen, um das Betriebssystem zu überprüfen?
Seismoid
10
@ Seismoid: Um Vergebung zu bitten wird im Allgemeinen als besser angesehen, siehe stackoverflow.com/questions/12265451/…
dirkjot
4
Funktioniert nicht unter OS X: "old_settings = termios.tcgetattr (fd)" "termios.error: (25, 'Unangemessenes ioctl für Gerät')"
Anzeigename
79
sys.stdin.read(1)

liest grundsätzlich 1 Byte aus STDIN.

Wenn Sie die Methode verwenden müssen, die nicht auf das wartet \n, können Sie diesen Code wie in der vorherigen Antwort vorgeschlagen verwenden:

class _Getch:
    """Gets a single character from standard input.  Does not echo to the screen."""
    def __init__(self):
        try:
            self.impl = _GetchWindows()
        except ImportError:
            self.impl = _GetchUnix()

    def __call__(self): return self.impl()


class _GetchUnix:
    def __init__(self):
        import tty, sys

    def __call__(self):
        import sys, tty, termios
        fd = sys.stdin.fileno()
        old_settings = termios.tcgetattr(fd)
        try:
            tty.setraw(sys.stdin.fileno())
            ch = sys.stdin.read(1)
        finally:
            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
        return ch


class _GetchWindows:
    def __init__(self):
        import msvcrt

    def __call__(self):
        import msvcrt
        return msvcrt.getch()


getch = _Getch()

( entnommen aus http://code.activestate.com/recipes/134892/ )

Yuval Adam
quelle
33
Ich finde es seltsam, dass sys.stdin.read (1) auf ein \ n wartet, lol. Vielen Dank für die Einreichung.
Evan Fosmark
3
Ein Zeichen oder ein Byte? Das ist nicht dasselbe
Chrysss
4
@Evan, das liegt daran, dass Python standardmäßig
John La Rooy
3
@EvanFosmark: Es ist nicht unbedingt so, dass sys.stdin.read (1) auf \ n wartet, sondern dass das Terminalprogramm, das entscheidet, wann andere Zeichen an Ihr Programm gesendet werden sollen, diese erst schreibt, wenn es '\ n' sieht - wie sonst Sie können die Rücktaste drücken und korrigieren, was Sie eingeben? (Die ernsthafte Antwort darauf lautet: Bringen Sie dem Python-Programm bei, die Zeilensteuerung zu implementieren, einen Puffer zu behalten und Backspaces zu verarbeiten, aber das ist eine andere Welt, in die Sie sich möglicherweise nicht einkaufen möchten, wenn Sie nur "ein Zeichen lesen" und Ihre Zeile erstellen könnten Umgang anders als alle anderen Programme auf Ihrem System.)
Tony Delroy
2
@ Seismoid EAFP
Vaultah
70

Das in zwei Antworten wörtlich zitierte ActiveState- Rezept ist überarbeitet. Es kann darauf reduziert werden:

def _find_getch():
    try:
        import termios
    except ImportError:
        # Non-POSIX. Return msvcrt's (Windows') getch.
        import msvcrt
        return msvcrt.getch

    # POSIX system. Create and return a getch that manipulates the tty.
    import sys, tty
    def _getch():
        fd = sys.stdin.fileno()
        old_settings = termios.tcgetattr(fd)
        try:
            tty.setraw(fd)
            ch = sys.stdin.read(1)
        finally:
            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
        return ch

    return _getch

getch = _find_getch()
Louis
quelle
Nett. Dies liest aber auch das erste Zeichen von KeyboardInterrupt (Strg + C), und Code hat die Möglichkeit, mit zu beenden 0.
user3342816
50

Ebenfalls einen Versuch wert ist die Readchar- Bibliothek, die teilweise auf dem in anderen Antworten erwähnten ActiveState-Rezept basiert.

Installation:

pip install readchar

Verwendungszweck:

import readchar
print("Reading a char:")
print(repr(readchar.readchar()))
print("Reading a key:")
print(repr(readchar.readkey()))

Getestet unter Windows und Linux mit Python 2.7.

Unter Windows nur die Tasten, die Buchstaben oder ASCII - Steuercodes Karte unterstützt ( Backspace, Enter, Esc, Tab, Ctrl+ Schreiben ). Auf GNU / Linux (auf genauen Terminal abhängig, vielleicht?) Erhalten Sie auch Insert, Delete, Pg Up, Pg Dn, Home, Endund Tasten ... aber dann gibt es Probleme , diese speziellen Schlüssel von einer Trennung .F nEsc

Caveat: Wie bei den meisten (? Alle) Antworten hier, Signaltasten wie Ctrl+ C, Ctrl+ Dund Ctrl+ Zgefangen und zurück (wie '\x03', '\x04'und '\x1a'jeweils); Es kann schwierig sein, Ihr Programm abzubrechen.

Søren Løvborg
quelle
3
Funktioniert auch mit Python 3 unter Linux. Viel besser als getch, da readchar das Drucken während des Wartens auf den Schlüssel (über Threads oder Asyncio) ermöglicht.
Wrobell
Getestet unter Win10 + Python 3.5: FEHLER: root: 'in <string>' erfordert einen String als linken Operanden, keine Bytes Traceback (letzter Aufruf zuletzt): Datei ".. \ main.py", Zeile 184, im Wrapper-Ergebnis = func (* args, ** kwargs) Datei "C: \ GitHub \ Python-Demo \ demo \ day_hello.py", Zeile 41, in readch_eg print (readchar.readchar ()) Datei "C: \ Users \ ipcjs \ AppData \ Local \ Programs \ Python \ Python35 \ lib \ site-packages \ readchar \ readchar_windows.py ", Zeile 14, in readchar, während ch in '\ x00 \ xe0': TypeError: 'in <string>' eine Zeichenfolge als linken Operanden erfordert , nicht Bytes
ipcjs
@ipcjs Bitte melden Sie diesen Fehler den Betreuern
Melih Yıldız '
1
Das ist die beste Antwort. Das Hinzufügen einer Abhängigkeit zur VS C ++ - Bibliothek nur für diese Funktionalität ist verrückt.
FistOfFury
17

Eine alternative Methode:

import os
import sys    
import termios
import fcntl

def getch():
  fd = sys.stdin.fileno()

  oldterm = termios.tcgetattr(fd)
  newattr = termios.tcgetattr(fd)
  newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO
  termios.tcsetattr(fd, termios.TCSANOW, newattr)

  oldflags = fcntl.fcntl(fd, fcntl.F_GETFL)
  fcntl.fcntl(fd, fcntl.F_SETFL, oldflags | os.O_NONBLOCK)

  try:        
    while 1:            
      try:
        c = sys.stdin.read(1)
        break
      except IOError: pass
  finally:
    termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm)
    fcntl.fcntl(fd, fcntl.F_SETFL, oldflags)
  return c

Aus diesem Blogbeitrag .

Tyler
quelle
Scheint bei mir nicht zu funktionieren - gibt sofort nach dem Aufruf eine leere Zeichenfolge zurück. Unter Linux mit Python 3.6.
Marein
1
@Marein Wenn Sie möchten, dass es blockiert (auf Eingabe warten), entfernen Sie das | os.O_NONBLOCK. Andernfalls können Sie es in eine Schleife einfügen (eine gute Idee, ein wenig in der Schleife zu schlafen, um ein Drehen zu verhindern).
Chris Gregg
In Python ist es besser , zu verwenden , while Truedann while 1.
Anonym
10

Dieser Code, der hier basiert , löst KeyboardInterrupt und EOFError korrekt aus, wenn Ctrl+ Coder Ctrl+ Dgedrückt werden.

Sollte unter Windows und Linux funktionieren. Eine OS X-Version ist von der Originalquelle verfügbar.

class _Getch:
    """Gets a single character from standard input.  Does not echo to the screen."""
    def __init__(self):
        try:
            self.impl = _GetchWindows()
        except ImportError:
            self.impl = _GetchUnix()

    def __call__(self): 
        char = self.impl()
        if char == '\x03':
            raise KeyboardInterrupt
        elif char == '\x04':
            raise EOFError
        return char

class _GetchUnix:
    def __init__(self):
        import tty
        import sys

    def __call__(self):
        import sys
        import tty
        import termios
        fd = sys.stdin.fileno()
        old_settings = termios.tcgetattr(fd)
        try:
            tty.setraw(sys.stdin.fileno())
            ch = sys.stdin.read(1)
        finally:
            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
        return ch


class _GetchWindows:
    def __init__(self):
        import msvcrt

    def __call__(self):
        import msvcrt
        return msvcrt.getch()


getch = _Getch()
kiri
quelle
7

Die (derzeit) am besten bewertete Antwort (mit dem ActiveState-Code) ist zu kompliziert. Ich sehe keinen Grund, Klassen zu verwenden, wenn eine bloße Funktion ausreichen sollte. Im Folgenden finden Sie zwei Implementierungen, die dasselbe erreichen, jedoch mit besser lesbarem Code.

Beide Implementierungen:

  1. funktionieren gut in Python 2 oder Python 3
  2. arbeiten unter Windows, OSX und Linux
  3. Lesen Sie nur ein Byte (dh sie warten nicht auf eine neue Zeile)
  4. hängen Sie nicht von externen Bibliotheken ab
  5. sind in sich geschlossen (kein Code außerhalb der Funktionsdefinition)

Version 1: lesbar und einfach

def getChar():
    try:
        # for Windows-based systems
        import msvcrt # If successful, we are on Windows
        return msvcrt.getch()

    except ImportError:
        # for POSIX-based systems (with termios & tty support)
        import tty, sys, termios  # raises ImportError if unsupported

        fd = sys.stdin.fileno()
        oldSettings = termios.tcgetattr(fd)

        try:
            tty.setcbreak(fd)
            answer = sys.stdin.read(1)
        finally:
            termios.tcsetattr(fd, termios.TCSADRAIN, oldSettings)

        return answer

Version 2: Wiederholte Importe und Ausnahmebehandlung vermeiden:

[BEARBEITEN] Ich habe einen Vorteil des ActiveState-Codes verpasst. Wenn Sie vorhaben, Zeichen mehrmals zu lesen, werden durch diesen Code die (vernachlässigbaren) Kosten für die Wiederholung des Windows-Imports und die Behandlung von ImportError-Ausnahmen auf Unix-ähnlichen Systemen vermieden. Während Sie sich wahrscheinlich mehr Gedanken über die Lesbarkeit von Code machen sollten als über diese vernachlässigbare Optimierung, gibt es hier eine Alternative (sie ähnelt Louis 'Antwort, aber getChar () ist in sich geschlossen), die genauso funktioniert wie der ActiveState-Code und besser lesbar ist:

def getChar():
    # figure out which function to use once, and store it in _func
    if "_func" not in getChar.__dict__:
        try:
            # for Windows-based systems
            import msvcrt # If successful, we are on Windows
            getChar._func=msvcrt.getch

        except ImportError:
            # for POSIX-based systems (with termios & tty support)
            import tty, sys, termios # raises ImportError if unsupported

            def _ttyRead():
                fd = sys.stdin.fileno()
                oldSettings = termios.tcgetattr(fd)

                try:
                    tty.setcbreak(fd)
                    answer = sys.stdin.read(1)
                finally:
                    termios.tcsetattr(fd, termios.TCSADRAIN, oldSettings)

                return answer

            getChar._func=_ttyRead

    return getChar._func()

Beispielcode, der eine der oben genannten Versionen von getChar () ausführt:

from __future__ import print_function # put at top of file if using Python 2

# Example of a prompt for one character of input
promptStr   = "Please give me a character:"
responseStr = "Thank you for giving me a '{}'."
print(promptStr, end="\n> ")
answer = getChar()
print("\n")
print(responseStr.format(answer))
Matthew Strax-Haber
quelle
2
Beim Drucken von Nachrichten beim gleichzeitigen Warten auf einen Schlüssel (Multithread) trat ein Problem mit tty.setraw () auf. Kurz gesagt, ich habe festgestellt, dass Sie mit tty.setcbreak () einen einzelnen Charakter erhalten können, ohne alle anderen normalen Dinge zu beschädigen. Lange Geschichte in dieser Antwort
TheDavidFactor
4

Dies kann ein Anwendungsfall für einen Kontextmanager sein. Abgesehen von den Zulassungen für das Windows-Betriebssystem ist hier mein Vorschlag:

#!/usr/bin/env python3
# file: 'readchar.py'
"""
Implementation of a way to get a single character of input
without waiting for the user to hit <Enter>.
(OS is Linux, Ubuntu 14.04)
"""

import tty, sys, termios

class ReadChar():
    def __enter__(self):
        self.fd = sys.stdin.fileno()
        self.old_settings = termios.tcgetattr(self.fd)
        tty.setraw(sys.stdin.fileno())
        return sys.stdin.read(1)
    def __exit__(self, type, value, traceback):
        termios.tcsetattr(self.fd, termios.TCSADRAIN, self.old_settings)

def test():
    while True:
        with ReadChar() as rc:
            char = rc
        if ord(char) <= 32:
            print("You entered character with ordinal {}."\
                        .format(ord(char)))
        else:
            print("You entered character '{}'."\
                        .format(char))
        if char in "^C^D":
            sys.exit()

if __name__ == "__main__":
    test()
Alex Kleider
quelle
Sie könnten auch zurückkehren self in __enter__und haben readMethode , dass die Renditen sys.stdin.read(1), dann könnte man mehrere Charaktere in einem Kontext lesen.
L3viathan
4

Versuchen Sie Folgendes : http://home.wlu.edu/~levys/software/kbhit.py Es ist nicht blockierend (das heißt, Sie können eine while-Schleife haben und einen Tastendruck erkennen, ohne ihn anzuhalten) und plattformübergreifend.

import os

# Windows
if os.name == 'nt':
    import msvcrt

# Posix (Linux, OS X)
else:
    import sys
    import termios
    import atexit
    from select import select


class KBHit:

    def __init__(self):
        '''Creates a KBHit object that you can call to do various keyboard things.'''

        if os.name == 'nt':
            pass

        else:

            # Save the terminal settings
            self.fd = sys.stdin.fileno()
            self.new_term = termios.tcgetattr(self.fd)
            self.old_term = termios.tcgetattr(self.fd)

            # New terminal setting unbuffered
            self.new_term[3] = (self.new_term[3] & ~termios.ICANON & ~termios.ECHO)
            termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.new_term)

            # Support normal-terminal reset at exit
            atexit.register(self.set_normal_term)


    def set_normal_term(self):
        ''' Resets to normal terminal.  On Windows this is a no-op.
        '''

        if os.name == 'nt':
            pass

        else:
            termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.old_term)


    def getch(self):
        ''' Returns a keyboard character after kbhit() has been called.
            Should not be called in the same program as getarrow().
        '''

        s = ''

        if os.name == 'nt':
            return msvcrt.getch().decode('utf-8')

        else:
            return sys.stdin.read(1)


    def getarrow(self):
        ''' Returns an arrow-key code after kbhit() has been called. Codes are
        0 : up
        1 : right
        2 : down
        3 : left
        Should not be called in the same program as getch().
        '''

        if os.name == 'nt':
            msvcrt.getch() # skip 0xE0
            c = msvcrt.getch()
            vals = [72, 77, 80, 75]

        else:
            c = sys.stdin.read(3)[2]
            vals = [65, 67, 66, 68]

        return vals.index(ord(c.decode('utf-8')))


    def kbhit(self):
        ''' Returns True if keyboard character was hit, False otherwise.
        '''
        if os.name == 'nt':
            return msvcrt.kbhit()

        else:
            dr,dw,de = select([sys.stdin], [], [], 0)
            return dr != []

Ein Beispiel dafür:

import kbhit

kb = kbhit.KBHit()

while(True): 
    print("Key not pressed") #Do something
    if kb.kbhit(): #If a key is pressed:
        k_in = kb.getch() #Detect what key was pressed
        print("You pressed ", k_in, "!") #Do something
kb.set_normal_term()

Oder Sie können das getch-Modul von PyPi verwenden . Dies würde jedoch die while-Schleife blockieren

jdev6
quelle
3

Dies ist NICHT BLOCKIEREND, liest eine Taste und speichert sie in keypress.key.

import Tkinter as tk


class Keypress:
    def __init__(self):
        self.root = tk.Tk()
        self.root.geometry('300x200')
        self.root.bind('<KeyPress>', self.onKeyPress)

    def onKeyPress(self, event):
        self.key = event.char

    def __eq__(self, other):
        return self.key == other

    def __str__(self):
        return self.key

in Ihrem Programm

keypress = Keypress()

while something:
   do something
   if keypress == 'c':
        break
   elif keypress == 'i': 
       print('info')
   else:
       print("i dont understand %s" % keypress)
Davoud Taghawi-Nejad
quelle
1
@ThorSummoner: Dieser Code weist eine Reihe von Problemen auf. Nein , er funktioniert nicht für Befehlszeilenanwendungen.
Martineau
Es wird für eine Befehlszeilenanwendung ausgeführt, sofern der Windows-Manager ausgeführt wird.
Davoud Taghawi-Nejad
Nein, es läuft nicht unter kopflosem Betriebssystem. Es wird jedoch in einem Befehlszeilenfenster ausgeführt.
Davoud Taghawi-Nejad
3

Die Antworten hier waren informativ, aber ich wollte auch eine Möglichkeit, Tastendrücke asynchron zu erhalten und Tastendrücke in separaten Ereignissen abzufeuern, alles auf threadsichere, plattformübergreifende Weise. PyGame war mir auch zu aufgebläht. Also habe ich Folgendes gemacht (in Python 2.7, aber ich vermute, es ist leicht portierbar), das ich hier teilen würde, falls es für andere nützlich wäre. Ich habe dies in einer Datei namens keyPress.py gespeichert.

class _Getch:
    """Gets a single character from standard input.  Does not echo to the
screen. From http://code.activestate.com/recipes/134892/"""
    def __init__(self):
        try:
            self.impl = _GetchWindows()
        except ImportError:
            try:
                self.impl = _GetchMacCarbon()
            except(AttributeError, ImportError):
                self.impl = _GetchUnix()

    def __call__(self): return self.impl()


class _GetchUnix:
    def __init__(self):
        import tty, sys, termios # import termios now or else you'll get the Unix version on the Mac

    def __call__(self):
        import sys, tty, termios
        fd = sys.stdin.fileno()
        old_settings = termios.tcgetattr(fd)
        try:
            tty.setraw(sys.stdin.fileno())
            ch = sys.stdin.read(1)
        finally:
            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
        return ch

class _GetchWindows:
    def __init__(self):
        import msvcrt

    def __call__(self):
        import msvcrt
        return msvcrt.getch()

class _GetchMacCarbon:
    """
    A function which returns the current ASCII key that is down;
    if no ASCII key is down, the null string is returned.  The
    page http://www.mactech.com/macintosh-c/chap02-1.html was
    very helpful in figuring out how to do this.
    """
    def __init__(self):
        import Carbon
        Carbon.Evt #see if it has this (in Unix, it doesn't)

    def __call__(self):
        import Carbon
        if Carbon.Evt.EventAvail(0x0008)[0]==0: # 0x0008 is the keyDownMask
            return ''
        else:
            #
            # The event contains the following info:
            # (what,msg,when,where,mod)=Carbon.Evt.GetNextEvent(0x0008)[1]
            #
            # The message (msg) contains the ASCII char which is
            # extracted with the 0x000000FF charCodeMask; this
            # number is converted to an ASCII character with chr() and
            # returned
            #
            (what,msg,when,where,mod)=Carbon.Evt.GetNextEvent(0x0008)[1]
            return chr(msg & 0x000000FF)

import threading


# From  https://stackoverflow.com/a/2022629/2924421
class Event(list):
    def __call__(self, *args, **kwargs):
        for f in self:
            f(*args, **kwargs)

    def __repr__(self):
        return "Event(%s)" % list.__repr__(self)            


def getKey():
    inkey = _Getch()
    import sys
    for i in xrange(sys.maxint):
        k=inkey()
        if k<>'':break
    return k

class KeyCallbackFunction():
    callbackParam = None
    actualFunction = None

    def __init__(self, actualFunction, callbackParam):
        self.actualFunction = actualFunction
        self.callbackParam = callbackParam

    def doCallback(self, inputKey):
        if not self.actualFunction is None:
            if self.callbackParam is None:
                callbackFunctionThread = threading.Thread(target=self.actualFunction, args=(inputKey,))
            else:
                callbackFunctionThread = threading.Thread(target=self.actualFunction, args=(inputKey,self.callbackParam))

            callbackFunctionThread.daemon = True
            callbackFunctionThread.start()



class KeyCapture():


    gotKeyLock = threading.Lock()
    gotKeys = []
    gotKeyEvent = threading.Event()

    keyBlockingSetKeyLock = threading.Lock()

    addingEventsLock = threading.Lock()
    keyReceiveEvents = Event()


    keysGotLock = threading.Lock()
    keysGot = []

    keyBlockingKeyLockLossy = threading.Lock()
    keyBlockingKeyLossy = None
    keyBlockingEventLossy = threading.Event()

    keysBlockingGotLock = threading.Lock()
    keysBlockingGot = []
    keyBlockingGotEvent = threading.Event()



    wantToStopLock = threading.Lock()
    wantToStop = False

    stoppedLock = threading.Lock()
    stopped = True

    isRunningEvent = False

    getKeyThread = None

    keyFunction = None
    keyArgs = None

    # Begin capturing keys. A seperate thread is launched that
    # captures key presses, and then these can be received via get,
    # getAsync, and adding an event via addEvent. Note that this
    # will prevent the system to accept keys as normal (say, if
    # you are in a python shell) because it overrides that key
    # capturing behavior.

    # If you start capture when it's already been started, a
    # InterruptedError("Keys are still being captured")
    # will be thrown

    # Note that get(), getAsync() and events are independent, so if a key is pressed:
    #
    # 1: Any calls to get() that are waiting, with lossy on, will return
    #    that key
    # 2: It will be stored in the queue of get keys, so that get() with lossy
    #    off will return the oldest key pressed not returned by get() yet.
    # 3: All events will be fired with that key as their input
    # 4: It will be stored in the list of getAsync() keys, where that list
    #    will be returned and set to empty list on the next call to getAsync().
    # get() call with it, aand add it to the getAsync() list.
    def startCapture(self, keyFunction=None, args=None):
        # Make sure we aren't already capturing keys
        self.stoppedLock.acquire()
        if not self.stopped:
            self.stoppedLock.release()
            raise InterruptedError("Keys are still being captured")
            return
        self.stopped = False
        self.stoppedLock.release()

        # If we have captured before, we need to allow the get() calls to actually
        # wait for key presses now by clearing the event
        if self.keyBlockingEventLossy.is_set():
            self.keyBlockingEventLossy.clear()

        # Have one function that we call every time a key is captured, intended for stopping capture
        # as desired
        self.keyFunction = keyFunction
        self.keyArgs = args

        # Begin capturing keys (in a seperate thread)
        self.getKeyThread = threading.Thread(target=self._threadProcessKeyPresses)
        self.getKeyThread.daemon = True
        self.getKeyThread.start()

        # Process key captures (in a seperate thread)
        self.getKeyThread = threading.Thread(target=self._threadStoreKeyPresses)
        self.getKeyThread.daemon = True
        self.getKeyThread.start()


    def capturing(self):
        self.stoppedLock.acquire()
        isCapturing = not self.stopped
        self.stoppedLock.release()
        return isCapturing
    # Stops the thread that is capturing keys on the first opporunity
    # has to do so. It usually can't stop immediately because getting a key
    # is a blocking process, so this will probably stop capturing after the
    # next key is pressed.
    #
    # However, Sometimes if you call stopCapture it will stop before starting capturing the
    # next key, due to multithreading race conditions. So if you want to stop capturing
    # reliably, call stopCapture in a function added via addEvent. Then you are
    # guaranteed that capturing will stop immediately after the rest of the callback
    # functions are called (before starting to capture the next key).
    def stopCapture(self):
        self.wantToStopLock.acquire()
        self.wantToStop = True 
        self.wantToStopLock.release()

    # Takes in a function that will be called every time a key is pressed (with that
    # key passed in as the first paramater in that function)
    def addEvent(self, keyPressEventFunction, args=None):   
        self.addingEventsLock.acquire()
        callbackHolder = KeyCallbackFunction(keyPressEventFunction, args)
        self.keyReceiveEvents.append(callbackHolder.doCallback)
        self.addingEventsLock.release()
    def clearEvents(self):
        self.addingEventsLock.acquire()
        self.keyReceiveEvents = Event()
        self.addingEventsLock.release()
    # Gets a key captured by this KeyCapture, blocking until a key is pressed.
    # There is an optional lossy paramater:
    # If True all keys before this call are ignored, and the next pressed key
    #   will be returned.
    # If False this will return the oldest key captured that hasn't
    #   been returned by get yet. False is the default.
    def get(self, lossy=False):
        if lossy:
            # Wait for the next key to be pressed
            self.keyBlockingEventLossy.wait()
            self.keyBlockingKeyLockLossy.acquire()
            keyReceived = self.keyBlockingKeyLossy
            self.keyBlockingKeyLockLossy.release()
            return keyReceived
        else:
            while True:
                # Wait until a key is pressed
                self.keyBlockingGotEvent.wait()

                # Get the key pressed
                readKey = None
                self.keysBlockingGotLock.acquire()
                # Get a key if it exists
                if len(self.keysBlockingGot) != 0:
                    readKey = self.keysBlockingGot.pop(0)
                # If we got the last one, tell us to wait
                if len(self.keysBlockingGot) == 0:
                    self.keyBlockingGotEvent.clear()
                self.keysBlockingGotLock.release()

                # Process the key (if it actually exists)
                if not readKey is None:
                    return readKey

                # Exit if we are stopping
                self.wantToStopLock.acquire()
                if self.wantToStop:
                    self.wantToStopLock.release()
                    return None
                self.wantToStopLock.release()




    def clearGetList(self):
        self.keysBlockingGotLock.acquire()
        self.keysBlockingGot = []
        self.keysBlockingGotLock.release()

    # Gets a list of all keys pressed since the last call to getAsync, in order
    # from first pressed, second pressed, .., most recent pressed
    def getAsync(self):
        self.keysGotLock.acquire();
        keysPressedList = list(self.keysGot)
        self.keysGot = []
        self.keysGotLock.release()
        return keysPressedList

    def clearAsyncList(self):
        self.keysGotLock.acquire();
        self.keysGot = []
        self.keysGotLock.release();

    def _processKey(self, readKey):
        # Append to list for GetKeyAsync
        self.keysGotLock.acquire()
        self.keysGot.append(readKey)
        self.keysGotLock.release()

        # Call lossy blocking key events
        self.keyBlockingKeyLockLossy.acquire()
        self.keyBlockingKeyLossy = readKey
        self.keyBlockingEventLossy.set()
        self.keyBlockingEventLossy.clear()
        self.keyBlockingKeyLockLossy.release()

        # Call non-lossy blocking key events
        self.keysBlockingGotLock.acquire()
        self.keysBlockingGot.append(readKey)
        if len(self.keysBlockingGot) == 1:
            self.keyBlockingGotEvent.set()
        self.keysBlockingGotLock.release()

        # Call events added by AddEvent
        self.addingEventsLock.acquire()
        self.keyReceiveEvents(readKey)
        self.addingEventsLock.release()

    def _threadProcessKeyPresses(self):
        while True:
            # Wait until a key is pressed
            self.gotKeyEvent.wait()

            # Get the key pressed
            readKey = None
            self.gotKeyLock.acquire()
            # Get a key if it exists
            if len(self.gotKeys) != 0:
                readKey = self.gotKeys.pop(0)
            # If we got the last one, tell us to wait
            if len(self.gotKeys) == 0:
                self.gotKeyEvent.clear()
            self.gotKeyLock.release()

            # Process the key (if it actually exists)
            if not readKey is None:
                self._processKey(readKey)

            # Exit if we are stopping
            self.wantToStopLock.acquire()
            if self.wantToStop:
                self.wantToStopLock.release()
                break
            self.wantToStopLock.release()

    def _threadStoreKeyPresses(self):
        while True:
            # Get a key
            readKey = getKey()

            # Run the potential shut down function
            if not self.keyFunction is None:
                self.keyFunction(readKey, self.keyArgs)

            # Add the key to the list of pressed keys
            self.gotKeyLock.acquire()
            self.gotKeys.append(readKey)
            if len(self.gotKeys) == 1:
                self.gotKeyEvent.set()
            self.gotKeyLock.release()

            # Exit if we are stopping
            self.wantToStopLock.acquire()
            if self.wantToStop:
                self.wantToStopLock.release()
                self.gotKeyEvent.set()
                break
            self.wantToStopLock.release()


        # If we have reached here we stopped capturing

        # All we need to do to clean up is ensure that
        # all the calls to .get() now return None.
        # To ensure no calls are stuck never returning,
        # we will leave the event set so any tasks waiting
        # for it immediately exit. This will be unset upon
        # starting key capturing again.

        self.stoppedLock.acquire()

        # We also need to set this to True so we can start up
        # capturing again.
        self.stopped = True
        self.stopped = True

        self.keyBlockingKeyLockLossy.acquire()
        self.keyBlockingKeyLossy = None
        self.keyBlockingEventLossy.set()
        self.keyBlockingKeyLockLossy.release()

        self.keysBlockingGotLock.acquire()
        self.keyBlockingGotEvent.set()
        self.keysBlockingGotLock.release()

        self.stoppedLock.release()

Die Idee ist, dass Sie entweder einfach anrufen können keyPress.getKey(), um eine Taste von der Tastatur zu lesen, und sie dann zurückgeben können.

Wenn Sie etwas mehr als das wollen, habe ich ein KeyCaptureObjekt gemacht. Sie können eine über so etwas wie erstellen keys = keyPress.KeyCapture().

Dann gibt es drei Dinge, die Sie tun können:

addEvent(functionName)übernimmt jede Funktion, die einen Parameter akzeptiert. Jedes Mal, wenn eine Taste gedrückt wird, wird diese Funktion mit der Zeichenfolge dieser Taste als Eingabe aufgerufen. Diese werden in einem separaten Thread ausgeführt, sodass Sie alles blockieren können, was Sie möchten, und die Funktionalität des KeyCapturer nicht beeinträchtigt oder die anderen Ereignisse verzögert werden.

get()Gibt einen Schlüssel auf dieselbe blockierende Weise wie zuvor zurück. Es wird jetzt hier benötigt, da die Schlüssel jetzt über das KeyCaptureObjekt erfasst werden. Dies keyPress.getKey()würde zu einem Konflikt mit diesem Verhalten führen und beide würden einige Schlüssel übersehen, da jeweils nur ein Schlüssel erfasst werden kann. Angenommen, der Benutzer drückt 'a', dann 'b', Sie rufen an get(), der Benutzer drückt 'c'. Dieser get()Aufruf gibt sofort 'a' zurück. Wenn Sie ihn erneut aufrufen, wird 'b' und dann 'c' zurückgegeben. Wenn Sie es erneut aufrufen, wird es blockiert, bis eine andere Taste gedrückt wird. Dies stellt sicher, dass Sie keine Schlüssel verpassen, auf Wunsch blockierend. Auf diese Weise ist es ein bisschen anders als keyPress.getKey()zuvor

Wenn Sie das Verhalten von getKey()zurück wollen, get(lossy=True)ist wie get(), außer dass es nur Tasten zurückgibt, die nach dem Anruf an gedrückt wurden get(). Im obigen Beispiel get()würde blockiert, bis der Benutzer 'c' drückt, und wenn Sie es erneut aufrufen, wird es blockiert, bis eine andere Taste gedrückt wird.

getAsync()ist ein bisschen anders. Es wurde für etwas entwickelt, das viel verarbeitet, dann gelegentlich zurückkommt und überprüft, welche Tasten gedrückt wurden. Somit wird getAsync()eine Liste aller seit dem letzten Aufruf gedrückten Tasten getAsync()in der Reihenfolge von der ältesten gedrückten bis zur zuletzt gedrückten Taste zurückgegeben. Es wird auch nicht blockiert, was bedeutet, dass getAsync()ein Leerzeichen zurückgegeben []wird , wenn seit dem letzten Aufruf von keine Tasten gedrückt wurden .

Um tatsächlich mit der Erfassung von Schlüsseln zu beginnen, müssen Sie keys.startCapture()mit Ihrem oben erstellten keysObjekt anrufen . startCaptureist nicht blockierend und startet einfach einen Thread, der nur die Tastendrücke aufzeichnet, und einen anderen Thread, um diese Tastendrücke zu verarbeiten. Es gibt zwei Threads, um sicherzustellen, dass der Thread, der Tastendrücke aufzeichnet, keine Tasten übersieht.

Wenn Sie die Erfassung von Schlüsseln beenden möchten, können Sie anrufen keys.stopCapture()und die Erfassung von Schlüsseln wird beendet. Da das Erfassen eines Schlüssels jedoch eine Blockierungsoperation ist, erfassen die Thread-Erfassungsschlüssel nach dem Aufruf möglicherweise einen weiteren Schlüssel stopCapture().

Um dies zu verhindern, können Sie einen oder mehrere optionale Parameter startCapture(functionName, args)an eine Funktion übergeben, die nur prüft, ob eine Taste gleich 'c' ist, und dann beendet wird. Es ist wichtig, dass diese Funktion nur sehr wenig bewirkt, bevor beispielsweise ein Schlaf hier dazu führt, dass wir Schlüssel verpassen.

Wenn stopCapture()diese Funktion jedoch aufgerufen wird, werden die Tastenerfassungen sofort gestoppt, ohne dass versucht wird, weitere zu erfassen, und alle get()Anrufe werden sofort mit "Keine" zurückgegeben, wenn noch keine Tasten gedrückt wurden.

Auch da get()und getAsync()speichern alle vorherigen Tasten gedrückt (bis Sie sie abrufen), können Sie anrufen clearGetList()und clearAsyncList()die Schlüssel vorher gedrückt zu vergessen.

Beachten Sie, dass get(), getAsync()und Ereignisse sind unabhängig, so dass , wenn eine Taste gedrückt wird: 1. Ein Anruf , get()dass wartet, mit verlustbehafteten auf, wird diese Taste zurück. Die anderen wartenden Anrufe (falls vorhanden) warten weiter. 2. Diese Taste wird in der Warteschlange der Get-Schlüssel gespeichert, sodass get()bei Verlust die älteste Taste zurückgegeben wird, die get()noch nicht zurückgegeben wurde . 3. Alle Ereignisse werden mit dieser Taste als Eingabe ausgelöst. 4. Diese Taste wird in der Liste der getAsync()Schlüssel gespeichert, in der diese Liste zurückgegeben und beim nächsten Aufruf an auf eine leere Liste gesetzt wirdgetAsync()

Wenn dies alles zu viel ist, ist hier ein Beispiel für einen Anwendungsfall:

import keyPress
import time
import threading

def KeyPressed(k, printLock):
    printLock.acquire()
    print "Event: " + k
    printLock.release()
    time.sleep(4)
    printLock.acquire()
    print "Event after delay: " + k
    printLock.release()

def GetKeyBlocking(keys, printLock):    
    while keys.capturing():
        keyReceived = keys.get()
        time.sleep(1)
        printLock.acquire()
        if not keyReceived is None:
            print "Block " + keyReceived
        else:
            print "Block None"
        printLock.release()

def GetKeyBlockingLossy(keys, printLock):   
    while keys.capturing():
        keyReceived = keys.get(lossy=True)
        time.sleep(1)
        printLock.acquire()
        if not keyReceived is None:
            print "Lossy: " + keyReceived
        else:
            print "Lossy: None"
        printLock.release()

def CheckToClose(k, (keys, printLock)):
    printLock.acquire()
    print "Close: " + k
    printLock.release()
    if k == "c":
        keys.stopCapture()

printLock = threading.Lock()

print "Press a key:"
print "You pressed: " + keyPress.getKey()
print ""

keys = keyPress.KeyCapture()

keys.addEvent(KeyPressed, printLock)



print "Starting capture"

keys.startCapture(CheckToClose, (keys, printLock))

getKeyBlockingThread = threading.Thread(target=GetKeyBlocking, args=(keys, printLock))
getKeyBlockingThread.daemon = True
getKeyBlockingThread.start()


getKeyBlockingThreadLossy = threading.Thread(target=GetKeyBlockingLossy, args=(keys, printLock))
getKeyBlockingThreadLossy.daemon = True
getKeyBlockingThreadLossy.start()

while keys.capturing():
    keysPressed = keys.getAsync()
    printLock.acquire()
    if keysPressed != []:
        print "Async: " + str(keysPressed)
    printLock.release()
    time.sleep(1)

print "done capturing"

Nach dem einfachen Test, den ich gemacht habe, funktioniert es gut für mich, aber ich nehme auch gerne andere Rückmeldungen entgegen, wenn ich etwas verpasst habe.

Ich habe das auch hier gepostet .

Phylliida
quelle
3

Ein Kommentar in einer der anderen Antworten erwähnte den cbreak-Modus, der für Unix-Implementierungen wichtig ist, da Sie im Allgemeinen nicht möchten, dass ^ C ( KeyboardError) von getchar verbraucht wird (wie es der Fall ist, wenn Sie das Terminal auf den Raw-Modus setzen, wie von die meisten anderen Antworten).

Ein weiteres wichtiges Detail ist, dass Sie, wenn Sie ein Zeichen und nicht ein Byte lesen möchten , 4 Bytes aus dem Eingabestream lesen sollten, da dies die maximale Anzahl von Bytes ist, aus denen ein einzelnes Zeichen in UTF-8 (Python 3+) besteht ). Das Lesen nur eines einzelnen Bytes führt zu unerwarteten Ergebnissen für Mehrbytezeichen wie z. B. Tastaturpfeile.

Hier ist meine geänderte Implementierung für Unix:

import contextlib
import os
import sys
import termios
import tty


_MAX_CHARACTER_BYTE_LENGTH = 4


@contextlib.contextmanager
def _tty_reset(file_descriptor):
    """
    A context manager that saves the tty flags of a file descriptor upon
    entering and restores them upon exiting.
    """
    old_settings = termios.tcgetattr(file_descriptor)
    try:
        yield
    finally:
        termios.tcsetattr(file_descriptor, termios.TCSADRAIN, old_settings)


def get_character(file=sys.stdin):
    """
    Read a single character from the given input stream (defaults to sys.stdin).
    """
    file_descriptor = file.fileno()
    with _tty_reset(file_descriptor):
        tty.setcbreak(file_descriptor)
        return os.read(file_descriptor, _MAX_CHARACTER_BYTE_LENGTH)
Noah
quelle
2

Versuchen Sie dies mit Pygame:

import pygame
pygame.init()             // eliminate error, pygame.error: video system not initialized
keys = pygame.key.get_pressed()

if keys[pygame.K_SPACE]:
    d = "space key"

print "You pressed the", d, "."
PyGuy
quelle
Das ist eine nette Idee, aber es funktioniert nicht in der Kommandozeile: pygame.error: video system not initialized
Dirkjot
2

Das Rezept des ActiveState scheint einen kleinen Fehler für "Posix" -Systeme zu enthalten, der eine Ctrl-CUnterbrechung verhindert (ich verwende einen Mac). Wenn ich den folgenden Code in mein Skript einfüge:

while(True):
    print(getch())

Ich werde niemals in der Lage sein, das Skript mit zu beenden Ctrl-C, und ich muss mein Terminal töten, um zu entkommen.

Ich glaube, die folgende Zeile ist die Ursache und auch zu brutal:

tty.setraw(sys.stdin.fileno())

Abgesehen davon wird das Paket ttynicht wirklich benötigt, termioses reicht aus, um damit umzugehen.

Unten ist der verbesserte Code, der für mich funktioniert ( Ctrl-Cunterbricht), mit der zusätzlichen getcheFunktion, die das Zeichen während der Eingabe wiedergibt:

if sys.platform == 'win32':
    import msvcrt
    getch = msvcrt.getch
    getche = msvcrt.getche
else:
    import sys
    import termios
    def __gen_ch_getter(echo):
        def __fun():
            fd = sys.stdin.fileno()
            oldattr = termios.tcgetattr(fd)
            newattr = oldattr[:]
            try:
                if echo:
                    # disable ctrl character printing, otherwise, backspace will be printed as "^?"
                    lflag = ~(termios.ICANON | termios.ECHOCTL)
                else:
                    lflag = ~(termios.ICANON | termios.ECHO)
                newattr[3] &= lflag
                termios.tcsetattr(fd, termios.TCSADRAIN, newattr)
                ch = sys.stdin.read(1)
                if echo and ord(ch) == 127: # backspace
                    # emulate backspace erasing
                    # https://stackoverflow.com/a/47962872/404271
                    sys.stdout.write('\b \b')
            finally:
                termios.tcsetattr(fd, termios.TCSADRAIN, oldattr)
            return ch
        return __fun
    getch = __gen_ch_getter(False)
    getche = __gen_ch_getter(True)

Verweise:

ibic
quelle
1

Das cursesPaket in Python kann verwendet werden, um mit nur wenigen Anweisungen in den "Raw" -Modus für die Zeicheneingabe vom Terminal zu wechseln. Die Hauptverwendung von Curses besteht darin, den Bildschirm für die Ausgabe zu übernehmen, was möglicherweise nicht das ist, was Sie wollen. Dieses Code-Snippet verwendet print()stattdessen Anweisungen, die verwendet werden können. Sie müssen jedoch wissen, wie Flüche die an die Ausgabe angehängten Zeilenenden ändern.

#!/usr/bin/python3
# Demo of single char terminal input in raw mode with the curses package.
import sys, curses

def run_one_char(dummy):
    'Run until a carriage return is entered'
    char = ' '
    print('Welcome to curses', flush=True)
    while ord(char) != 13:
        char = one_char()

def one_char():
    'Read one character from the keyboard'
    print('\r? ', flush= True, end = '')

    ## A blocking single char read in raw mode. 
    char = sys.stdin.read(1)
    print('You entered %s\r' % char)
    return char

## Must init curses before calling any functions
curses.initscr()
## To make sure the terminal returns to its initial settings,
## and to set raw mode and guarantee cleanup on exit. 
curses.wrapper(run_one_char)
print('Curses be gone!')
John Mark
quelle
1

Wenn ich etwas Kompliziertes mache, benutze ich Flüche, um Schlüssel zu lesen. Aber oft möchte ich nur ein einfaches Python 3-Skript, das die Standardbibliothek verwendet und Pfeiltasten lesen kann. Deshalb mache ich Folgendes:

import sys, termios, tty

key_Enter = 13
key_Esc = 27
key_Up = '\033[A'
key_Dn = '\033[B'
key_Rt = '\033[C'
key_Lt = '\033[D'

fdInput = sys.stdin.fileno()
termAttr = termios.tcgetattr(0)

def getch():
    tty.setraw(fdInput)
    ch = sys.stdin.buffer.raw.read(4).decode(sys.stdin.encoding)
    if len(ch) == 1:
        if ord(ch) < 32 or ord(ch) > 126:
            ch = ord(ch)
    elif ord(ch[0]) == 27:
        ch = '\033' + ch[1:]
    termios.tcsetattr(fdInput, termios.TCSADRAIN, termAttr)
    return ch
qel
quelle
0

Meine Lösung für Python3, unabhängig von Pip-Paketen.

# precondition: import tty, sys
def query_yes_no(question, default=True):
    """
    Ask the user a yes/no question.
    Returns immediately upon reading one-char answer.
    Accepts multiple language characters for yes/no.
    """
    if not sys.stdin.isatty():
        return default
    if default:
        prompt = "[Y/n]?"
        other_answers = "n"
    else:
        prompt = "[y/N]?"
        other_answers = "yjosiá"

    print(question,prompt,flush= True,end=" ")
    oldttysettings = tty.tcgetattr(sys.stdin.fileno())
    try:
        tty.setraw(sys.stdin.fileno())
        return not sys.stdin.read(1).lower() in other_answers
    except:
        return default
    finally:
        tty.tcsetattr(sys.stdin.fileno(), tty.TCSADRAIN , oldttysettings)
        sys.stdout.write("\r\n")
        tty.tcdrain(sys.stdin.fileno())
xro
quelle
0

Ich glaube, dass dies eine der elegantesten Lösungen ist.

import os

if os.name == 'nt':
    import msvcrt
    def getch():
        return msvcrt.getch().decode()
else:
    import sys, tty, termios
    fd = sys.stdin.fileno()
    old_settings = termios.tcgetattr(fd)
    def getch():
        try:
            tty.setraw(sys.stdin.fileno())
            ch = sys.stdin.read(1)
        finally:
            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
        return ch

und dann im Code verwenden:

if getch() == chr(ESC_ASCII_VALUE):
    print("ESC!")
theAlse
quelle
0

Die akzeptierte Antwort lief für mich nicht so gut (ich würde eine Taste halten, nichts würde passieren, dann würde ich eine andere Taste drücken und es würde funktionieren).

Nachdem Sie das Modul Flüche kennengelernt haben, scheint es wirklich der richtige Weg zu sein. Und es ist jetzt für Windows über Windows -Cursor (über Pip verfügbar) verfügbar, sodass Sie plattformunabhängig programmieren können. Hier ist ein Beispiel, das von diesem netten Tutorial auf YouTube inspiriert wurde :

import curses                                                                                                                                       
def getkey(stdscr):
    curses.curs_set(0)
    while True:
        key = stdscr.getch()
        if key != -1:
            break
    return key

if __name__ == "__main__":
    print(curses.wrapper(getkey))

Speichern Sie es mit einer .pyErweiterung oder führen Sie es curses.wrapper(getkey)im interaktiven Modus aus.

Ben Ogorek
quelle
0

Hier beantwortet: raw_input in Python ohne Enter

Verwenden Sie diesen Code-

from tkinter import Tk, Frame


def __set_key(e, root):
    """
    e - event with attribute 'char', the released key
    """
    global key_pressed
    if e.char:
        key_pressed = e.char
        root.destroy()


def get_key(msg="Press any key ...", time_to_sleep=3):
    """
    msg - set to empty string if you don't want to print anything
    time_to_sleep - default 3 seconds
    """
    global key_pressed
    if msg:
        print(msg)
    key_pressed = None
    root = Tk()
    root.overrideredirect(True)
    frame = Frame(root, width=0, height=0)
    frame.bind("<KeyRelease>", lambda f: __set_key(f, root))
    frame.pack()
    root.focus_set()
    frame.focus_set()
    frame.focus_force()  # doesn't work in a while loop without it
    root.after(time_to_sleep * 1000, func=root.destroy)
    root.mainloop()
    root = None  # just in case
    return key_pressed


def __main():
        c = None
        while not c:
                c = get_key("Choose your weapon ... ", 2)
        print(c)

if __name__ == "__main__":
    __main()

Referenz: https://github.com/unfor19/mg-tools/blob/master/mgtools/get_key_pressed.py

Meir Gabay
quelle
0

Wenn Sie nur einen einzigen Tastendruck registrieren möchten, auch wenn der Benutzer ihn mehrmals gedrückt hat oder die Taste länger gedrückt hat. Um zu vermeiden, dass mehrere Eingaben gedrückt werden, verwenden Sie die while-Schleife und übergeben Sie sie.

import keyboard

while(True):
  if(keyboard.is_pressed('w')):
      s+=1
      while(keyboard.is_pressed('w')):
        pass
  if(keyboard.is_pressed('s')):
      s-=1
      while(keyboard.is_pressed('s')):
        pass
  print(s)
Vinay Verma
quelle
0

Wenn Sie nur den Bildschirm halten möchten, damit Sie das Ergebnis auf dem Terminal sehen können, schreiben Sie einfach

input()

am Ende des Codes und es wird den Bildschirm halten

Khan Saad
quelle
-1

Der eingebaute raw_input sollte helfen.

for i in range(3):
    print ("So much work to do!")
k = raw_input("Press any key to continue...")
print ("Ok, back to work.")
Mabooka
quelle
6
raw_input wartet auf Eingabetaste
vac