Python đọc một ký tự từ người dùng


261

Có cách nào để đọc một ký tự từ đầu vào của người dùng không? Chẳng hạn, họ nhấn một phím ở thiết bị đầu cuối và nó được trả về (đại loại như thế getch()). Tôi biết có một chức năng trong Windows cho nó, nhưng tôi muốn một cái gì đó là đa nền tảng.


1
Trên cửa sổ tôi gặp vấn đề tương tự như trong câu hỏi này . Giải pháp là thay thế msvcrt.getchbằng msvcrt.getwch, như đề xuất ở đó.
A. Roy

Giải pháp là cài đặt mô-đun getch "pip install getch". Đối với Python2, hãy sử dụng lệnh "pip2 install files.pythonhosted.org/packages/56/f7/ mẹo ". Giải pháp này cũng hoạt động trong Termux (Android).
Petr Mach

Câu trả lời:


189

Đây là một liên kết đến một trang web cho biết cách bạn có thể đọc một ký tự trong Windows, Linux và OSX: 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()

18
mã có vẻ đủ ngắn để bạn có thể đưa nó vào, nhưng +1 để tìm câu trả lời tốt (đa nền tảng) rất nhanh.
John Mulder

4
Liệu nó có xử lý tốt các chữ cái không phải là tiếng Latin (ví dụ, cyrillic) không? Tôi đang gặp vấn đề với điều đó và không thể hiểu được, đó có phải là lỗi của tôi hay không.
Phlya

7
Tôi không thích cách ImportErrorngoại lệ được sử dụng như một loại câu lệnh if; tại sao không gọi platform.system () để kiểm tra HĐH?
Seismoid

10
@Seismoid: Yêu cầu sự tha thứ thường được coi là tốt hơn, xem stackoverflow.com/questions/12265451/ chất
dirkjot

4
Không hoạt động trên OS X: "old_sinstall = termios.tcgetattr (fd)" "termios.error: (25, 'ioctl không phù hợp cho thiết bị')"
Tên hiển thị

79
sys.stdin.read(1)

về cơ bản sẽ đọc 1 byte từ STDIN.

Nếu bạn phải sử dụng phương pháp không chờ đợi, \nbạn có thể sử dụng mã này như được đề xuất trong câu trả lời trước:

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

( lấy từ http://code.activestate.com/recipes/134892/ )


33
Tôi thấy thật kỳ lạ khi sys.stdin.read (1) chờ đợi một \ n, lol. Cảm ơn đã gửi, mặc dù.
Evan Fosmark

3
Một ký tự hay một byte? Điều đó không giống nhau.
chryss

4
@Evan, đó là vì python ở chế độ đệm theo mặc định
John La Rooy

3
@EvanFosmark: không nhất thiết là sys.stdin.read (1) chờ đợi \ n, đó là chương trình đầu cuối quyết định khi nào gửi các ký tự khác đến chương trình của bạn không viết chúng cho đến khi thấy '\ n' - làm thế nào khác bạn có thể nhấn backspace và sửa những gì bạn đang gõ không? (câu trả lời nghiêm túc cho điều đó là - dạy chương trình python thực hiện điều khiển dòng, giữ bộ đệm, xử lý các khoảng trống, nhưng đó là một thế giới khác mà bạn có thể không muốn mua khi chỉ "đọc một ký tự" và có thể tạo dòng của bạn xử lý khác với tất cả các chương trình khác trên hệ thống của bạn.)
Tony Delroy

2
@Seismoid EAFP
vaultah

70

Công thức ActiveState trích dẫn nguyên văn trong hai câu trả lời là quá kỹ thuật. Nó có thể được đun sôi để này:

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

Đẹp. Nhưng điều này cũng sẽ đọc char đầu tiên của KeyboardInterrupt (Ctrl + C) và mã có khả năng thoát với 0.
dùng3342816

51

Cũng đáng thử là thư viện readchar , một phần dựa trên công thức ActiveState được đề cập trong các câu trả lời khác.

Cài đặt:

pip install readchar

Sử dụng:

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

Đã thử nghiệm trên Windows và Linux với Python 2.7.

Trên Windows, chỉ có phím mà bản đồ để chữ, mã điều khiển ASCII được hỗ trợ ( Backspace, Enter, Esc, Tab, Ctrl+ thư ). Trên GNU / Linux (tùy thuộc vào thiết bị đầu cuối chính xác, có lẽ?), Bạn cũng có được Insert, Delete, Pg Up, Pg Dn, Home, Endvà phím ... nhưng sau đó, có vấn đề tách các phím đặc biệt từ một .F nEsc

Hãy cẩn thận: Giống như với hầu hết các câu trả lời (tất cả?) Ở đây, các phím tín hiệu như Ctrl+ C, Ctrl+ DCtrl+ Zđược bắt và trả lại (như '\x03', '\x04''\x1a'tương ứng); chương trình của bạn có thể trở nên khó bỏ.


3
Hoạt động với Python 3 trên Linux là tốt. Tốt hơn nhiều so với getch, bởi vì readchar cho phép in ra thiết bị xuất chuẩn trong khi chờ khóa (thông qua các luồng hoặc asyncio).
wrobell

Đã thử nghiệm trên Win10 + Python 3.5, ERROR: root: 'in <string>' yêu cầu chuỗi là toán hạng bên trái, không phải byte TracBack (cuộc gọi gần đây nhất cuối cùng): Tệp ".. \ main.py", dòng 184, trong kết quả trình bao bọc = func (* args, ** kwargs) Tệp "C: \ GitHub \ Python-Demo \ demo \ day_hello.py", dòng 41, in readch_eg (readchar.readchar ()) Tệp "C: \ Users \ ipcjs \ AppData \ Local \ Programs \ Python \ Python35 \ lib \ site-gói \ readchar \ readchar_windows.py ", dòng 14, trong readchar trong khi ch trong '\ x00 \ xe0': TypeError: 'in <string>' yêu cầu chuỗi là toán hạng trái , không phải byte
ipcjs

@ipcjs vui lòng báo cáo lỗi đó cho những người bảo trì
Melih Yıldız '

1
đây là câu trả lời tốt nhất thêm một phụ thuộc vào thư viện VS C ++ chỉ cho chức năng này là điên rồ.
FistOfFury

18

Một phương pháp khác:

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

Từ bài viết trên blog này .


Dường như không hoạt động đối với tôi - trả về chuỗi trống ngay khi gọi. Trên Linux với Python 3.6.
Marein

1
@Marein Nếu bạn muốn nó chặn (chờ đầu vào), hãy xóa | os.O_NONBLOCK. Nếu không, bạn có thể đặt nó trong một vòng lặp (ý tưởng tốt để ngủ một chút trong vòng lặp để tránh quay).
Chris Gregg

Trong Python, tốt hơn là sử dụng while Truesau đó while 1.
Ẩn danh

10

Mã này, dựa trên đây , sẽ nâng chính xác KeyboardInterrupt và EOFError nếu nhấn Ctrl+ Choặc Ctrl+ D.

Nên hoạt động trên Windows và Linux. Phiên bản OS X có sẵn từ nguồn ban đầu.

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

7

Câu trả lời được xếp hạng hàng đầu (hiện tại) (với mã ActiveState) quá phức tạp. Tôi không thấy một lý do để sử dụng các lớp khi một chức năng đơn thuần là đủ. Dưới đây là hai triển khai thực hiện cùng một điều nhưng với mã dễ đọc hơn.

Cả hai cách thực hiện này:

  1. chỉ hoạt động tốt trong Python 2 hoặc Python 3
  2. hoạt động trên Windows, OSX và Linux
  3. chỉ đọc một byte (nghĩa là họ không chờ đợi một dòng mới)
  4. không phụ thuộc vào bất kỳ thư viện bên ngoài
  5. là khép kín (không có mã ngoài định nghĩa hàm)

Phiên bản 1: dễ đọc và đơn giản

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

Phiên bản 2: tránh nhập lặp lại và xử lý ngoại lệ:

[EDIT] Tôi đã bỏ lỡ một lợi thế của mã ActiveState. Nếu bạn có kế hoạch đọc các ký tự nhiều lần, mã đó sẽ tránh được chi phí (không đáng kể) khi lặp lại quá trình nhập Windows và xử lý ngoại lệ ImportError trên các hệ thống giống Unix. Mặc dù có lẽ bạn nên quan tâm đến khả năng đọc mã hơn là tối ưu hóa không đáng kể, nhưng đây là một cách thay thế (tương tự như câu trả lời của Louis, nhưng getChar () khép kín) có chức năng giống như mã ActiveState và dễ đọc hơn:

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

Mã ví dụ thực hiện một trong các phiên bản getChar () ở trên:

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))

2
Tôi gặp vấn đề với tty.setraw () khi in tin nhắn trong khi chờ đợi một khóa (đa luồng). Tóm lại, tôi thấy rằng việc sử dụng tty.setcbreak () cho phép bạn có được một nhân vật duy nhất mà không phá vỡ tất cả những thứ bình thường khác. Câu chuyện dài trong câu trả lời
TheDavidFactor

4

Đây có thể là một trường hợp sử dụng cho một trình quản lý bối cảnh. Bỏ các khoản phụ cấp cho HĐH Windows, đây là gợi ý của tôi:

#!/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()

Bạn cũng có thể trở lại self trong __enter__và có một readphương pháp mà lợi nhuận sys.stdin.read(1), sau đó bạn có thể đọc nhiều nhân vật trong một ngữ cảnh.
L3viathan

4

Hãy thử sử dụng cái này: http://home.wlu.edu/~levys/software/kbhit.py Nó không chặn (điều đó có nghĩa là bạn có thể có một vòng lặp while và phát hiện một phím bấm mà không dừng nó) và đa nền tảng.

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

Một ví dụ để sử dụng điều này:

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

Hoặc bạn có thể sử dụng mô-đun getch từ PyPi . Nhưng điều này sẽ chặn vòng lặp while


3

Đây là NON-BLOCKING, đọc một khóa và lưu nó trong 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

trong chương trình của bạn

keypress = Keypress()

while something:
   do something
   if keypress == 'c':
        break
   elif keypress == 'i': 
       print('info')
   else:
       print("i dont understand %s" % keypress)

1
@ThorSummoner: Mã này có một số vấn đề - vì vậy không , nó sẽ không hoạt động cho các ứng dụng dòng lệnh.
martineau

Nó chạy cho một ứng dụng dòng lệnh, với điều kiện là trình quản lý windows đang chạy.
Davoud Taghawi-Nejad

Không, nó không chạy trong hệ điều hành không đầu. Nhưng nó chạy trong một cửa sổ dòng lệnh.
Davoud Taghawi-Nejad

3

Các câu trả lời ở đây có nhiều thông tin, tuy nhiên tôi cũng muốn có một cách để bấm phím không đồng bộ và tắt các lần nhấn phím trong các sự kiện riêng biệt, tất cả đều theo cách đa nền tảng, an toàn cho luồng. PyGame cũng quá bồng bột đối với tôi. Vì vậy, tôi đã thực hiện như sau (trong Python 2.7 nhưng tôi nghi ngờ nó dễ dàng mang theo), mà tôi nghĩ rằng tôi sẽ chia sẻ ở đây trong trường hợp nó hữu ích cho bất kỳ ai khác. Tôi đã lưu trữ tệp này trong một tệp có tên keyPress.py.

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

Ý tưởng là bạn có thể chỉ cần gọi keyPress.getKey(), sẽ đọc một phím từ bàn phím, sau đó trả lại.

Nếu bạn muốn một cái gì đó nhiều hơn thế, tôi đã tạo ra một KeyCaptuređối tượng. Bạn có thể tạo một cái thông qua một cái gì đó như keys = keyPress.KeyCapture().

Sau đó, có ba điều bạn có thể làm:

addEvent(functionName)có bất kỳ chức năng nào trong một tham số. Sau đó, mỗi lần nhấn phím, hàm này sẽ được gọi với chuỗi của khóa đó làm đầu vào. Chúng được chạy trong một luồng riêng biệt, vì vậy bạn có thể chặn tất cả những gì bạn muốn trong chúng và nó sẽ không làm rối loạn chức năng của KeyCapturer cũng như không làm trì hoãn các sự kiện khác.

get()trả về một khóa theo cách chặn giống như trước đây. Bây giờ nó cần thiết ở đây vì các khóa hiện đang bị bắt qua KeyCaptuređối tượng, do đó keyPress.getKey()sẽ xung đột với hành vi đó và cả hai sẽ bỏ lỡ một số khóa vì mỗi lần chỉ có thể bắt được một khóa. Ngoài ra, giả sử người dùng nhấn 'a', sau đó 'b', bạn gọi get(), người dùng nhấn 'c'. Cuộc get()gọi đó sẽ ngay lập tức trả về 'a', sau đó nếu bạn gọi lại, nó sẽ trả về 'b', sau đó 'c'. Nếu bạn gọi lại, nó sẽ chặn cho đến khi nhấn phím khác. Điều này đảm bảo rằng bạn không bỏ lỡ bất kỳ phím nào, theo cách chặn nếu muốn. Vì vậy, theo cách này, nó hơi khác so keyPress.getKey()với trước đây

Nếu bạn muốn hành vi getKey()quay lại, get(lossy=True)giống như get(), ngoại trừ việc nó chỉ trả về các phím được nhấn sau khi gọi đến get(). Vì vậy, trong ví dụ trên, get()sẽ chặn cho đến khi người dùng nhấn 'c', và sau đó nếu bạn gọi lại, nó sẽ chặn cho đến khi nhấn phím khác.

getAsync()là một chút khác nhau. Nó được thiết kế cho một cái gì đó xử lý nhiều, sau đó thỉnh thoảng quay lại và kiểm tra xem phím nào được nhấn. Do đó, getAsync()trả về một danh sách tất cả các phím được nhấn kể từ lần gọi cuối cùng getAsync(), theo thứ tự từ phím cũ nhất được nhấn đến phím được nhấn gần đây nhất. Nó cũng không chặn, có nghĩa là nếu không có phím nào được nhấn kể từ lần gọi cuối cùng getAsync(), một khoảng trống []sẽ được trả về.

Để thực sự bắt đầu chụp các phím, bạn cần gọi keys.startCapture()với keysđối tượng được thực hiện ở trên. startCapturekhông chặn và chỉ cần bắt đầu một luồng chỉ ghi lại các lần nhấn phím và một luồng khác để xử lý các lần nhấn phím đó. Có hai luồng để đảm bảo rằng luồng ghi phím bấm không bỏ sót phím nào.

Nếu bạn muốn dừng chụp phím, bạn có thể gọi keys.stopCapture()và nó sẽ dừng bắt phím. Tuy nhiên, vì bắt một khóa là một hoạt động chặn, các phím chụp luồng có thể bắt thêm một phím sau khi gọi stopCapture().

Để ngăn chặn điều này, bạn có thể chuyển (các) tham số tùy chọn vào startCapture(functionName, args)một hàm chỉ thực hiện một thao tác nào đó như kiểm tra nếu một khóa bằng 'c' và sau đó thoát. Điều quan trọng là chức năng này thực hiện rất ít trước đây, ví dụ, một giấc ngủ ở đây sẽ khiến chúng ta bỏ lỡ các phím.

Tuy nhiên, nếu stopCapture()được gọi trong chức năng này, các thao tác bắt phím sẽ bị dừng ngay lập tức, mà không cố gắng bắt giữ nữa và tất cả các get()cuộc gọi sẽ được trả lại ngay lập tức, với Không nếu chưa có phím nào được nhấn.

Ngoài ra, vì get()getAsync()lưu trữ tất cả các phím trước đó được nhấn (cho đến khi bạn truy xuất chúng), bạn có thể gọi clearGetList()clearAsyncList()quên các phím đã nhấn trước đó.

Lưu ý rằng get(), getAsync()và các sự kiện độc lập, vì vậy nếu một phím được nhấn: 1. Một lời kêu gọi get()đó là chờ đợi, với tổn hao trên, sẽ trở lại khóa đó. Các cuộc gọi chờ khác (nếu có) sẽ tiếp tục chờ. 2. Khóa đó sẽ được lưu trong hàng đợi các phím get, do đó, get()khi mất dữ liệu sẽ trả về khóa cũ nhất được nhấn chưa được trả về get(). 3. Tất cả các sự kiện sẽ được kích hoạt bằng phím đó làm đầu vào của chúng 4. Phím đó sẽ được lưu trong danh sách các getAsync()khóa, trong đó khóa đó sẽ được trả về và được đặt thành danh sách trống trong cuộc gọi tiếp theogetAsync()

Nếu tất cả điều này là quá nhiều, đây là một trường hợp sử dụng ví dụ:

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"

Nó hoạt động tốt với tôi từ bài kiểm tra đơn giản mà tôi đã thực hiện, nhưng tôi sẽ vui vẻ nhận phản hồi của người khác nếu có điều gì đó tôi bỏ lỡ.

Tôi đăng bài này ở đây là tốt.


3

Một nhận xét trong một trong những câu trả lời khác đã đề cập đến chế độ bẻ khóa, điều này rất quan trọng đối với việc triển khai Unix bởi vì bạn thường không muốn ^ C ( KeyboardError) được sử dụng bởi getchar (như khi bạn đặt thiết bị đầu cuối ở chế độ thô, như được thực hiện bởi hầu hết các câu trả lời khác).

Một chi tiết quan trọng khác là nếu bạn đang muốn đọc một ký tự chứ không phải một byte , bạn nên đọc 4 byte từ luồng đầu vào, vì đó là số byte tối đa mà một ký tự sẽ bao gồm trong UTF-8 (Python 3+ ). Chỉ đọc một byte đơn sẽ tạo ra kết quả bất ngờ cho các ký tự nhiều byte như mũi tên bàn phím.

Đây là triển khai thay đổi của tôi cho 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)

2

Hãy thử điều này với 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, "."

Đó là một ý tưởng gọn gàng, nhưng nó không hoạt động trên dòng lệnh: pygame.error: video system not initialized
dirkjot

2

Công thức của ActiveState dường như có một lỗi nhỏ đối với các hệ thống "posix" ngăn chặn sự Ctrl-Cgián đoạn (Tôi đang sử dụng Mac). Nếu tôi đặt đoạn mã sau vào tập lệnh của mình:

while(True):
    print(getch())

Tôi sẽ không bao giờ có thể chấm dứt kịch bản với Ctrl-C, và tôi phải giết thiết bị đầu cuối của mình để trốn thoát.

Tôi tin rằng dòng sau đây là nguyên nhân, và nó cũng quá tàn bạo:

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

Bên cạnh đó, gói ttykhông thực sự cần thiết, termioslà đủ để xử lý nó.

Dưới đây là mã được cải tiến phù hợp với tôi ( Ctrl-Csẽ làm gián đoạn), với getchechức năng bổ sung lặp lại char khi bạn nhập:

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)

Người giới thiệu:


1

Các cursesgói trong python có thể được sử dụng để vào chế độ "thô" cho đầu vào nhân vật từ nhà ga chỉ với một vài báo cáo. Công dụng chính của Curses là chiếm lấy màn hình để xuất ra, đây có thể không phải là điều bạn muốn. Đoạn mã này sử dụng các print()câu lệnh thay thế, có thể sử dụng được, nhưng bạn phải nhận thức được cách nguyền rủa thay đổi kết thúc dòng được gắn vào đầu ra.

#!/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!')

1

Nếu tôi đang làm gì đó phức tạp, tôi sẽ sử dụng những lời nguyền để đọc các phím. Nhưng nhiều lần tôi chỉ muốn một tập lệnh Python 3 đơn giản sử dụng thư viện chuẩn và có thể đọc các phím mũi tên, vì vậy tôi làm điều này:

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

0

Giải pháp của tôi cho python3, không phụ thuộc vào bất kỳ gói pip nào.

# 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())

0

Tôi tin rằng đây là một giải pháp tao nhã nhất.

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

và sau đó sử dụng nó trong mã:

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

0

Câu trả lời được chấp nhận đã không thực hiện tốt cho tôi (Tôi giữ một phím, sẽ không có gì xảy ra, sau đó tôi nhấn một phím khác và nó sẽ hoạt động).

Sau khi tìm hiểu về mô-đun lời nguyền , nó thực sự có vẻ là cách đúng đắn để đi. Và hiện đã có sẵn cho Windows thông qua các con trỏ windows (có sẵn thông qua pip), vì vậy bạn có thể lập trình theo cách thức bất khả tri của nền tảng. Dưới đây là một ví dụ lấy cảm hứng từ hướng dẫn hay này trên YouTube:

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))

Lưu nó với một .pyphần mở rộng, hoặc chạy curses.wrapper(getkey)trong chế độ tương tác.


0

Đã trả lời ở đây: raw_input trong python mà không cần nhấn enter

Sử dụng mã này-

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

Tham khảo: https://github.com/unfor19/mg-tools/blob/master/mgtools/get_key_pressed.py


0

Nếu bạn muốn đăng ký chỉ một phím bấm ngay cả khi người dùng nhấn nó nhiều lần hoặc nhấn phím lâu hơn. Để tránh nhận được nhiều đầu vào ép, sử dụng vòng lặp while và vượt qua nó.

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)

0

Nếu bạn chỉ muốn giữ màn hình để bạn có thể thấy kết quả trên thiết bị đầu cuối, chỉ cần viết

input()

ở cuối mã và nó sẽ giữ màn hình


-1

Raw_input tích hợp sẽ giúp.

for i in range(3):
    print ("So much work to do!")
k = raw_input("Press any key to continue...")
print ("Ok, back to work.")

6
raw_input đang chờ nhập khóa
vac
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.