如何等待按下的键?

如何让我的python脚本等待直到用户按下任意键?

1262134 次浏览

在Python 3中,使用input()

input("Press Enter to continue...")

在Python 2中,使用raw_input()

raw_input("Press Enter to continue...")

python3中,使用input()

input("Press Enter to continue...")

python2中,使用raw_input()

raw_input("Press Enter to continue...")

这只等待用户按回车键。


在Windows/DOS上,可能需要使用msvcrtmsvcrt模块允许您访问Microsoft Visual C/C++运行时库(MSVCRT)中的许多函数:

import msvcrt as m
def wait():
m.getch()

这应该等待按键。


备注:

在Python 3中,raw_input()不存在。
在Python 2中,input(prompt)等价于eval(raw_input(prompt))

python手册提供以下内容:

import termios, fcntl, sys, os
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)
print "Got character", repr(c)
except IOError: pass
finally:
termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm)
fcntl.fcntl(fd, fcntl.F_SETFL, oldflags)

它可以滚动到您的用例中。

我不知道独立于平台的方法,但是在Windows下,如果你使用msvcrt模块,你可以使用它的getch函数:

import msvcrt
c = msvcrt.getch()
print 'you entered', c

mscvcrt还包含非阻塞kbshot()函数,用于查看是否在不等待的情况下按下了键(不确定是否有相应的curses函数)。在UNIX下,有curses包,但不确定是否可以在不将其用于所有屏幕输出的情况下使用它。这段代码在UNIX下工作:

import curses
stdscr = curses.initscr()
c = stdscr.getch()
print 'you entered', chr(c)
curses.endwin()

请注意,curses.getch()返回按下的键的序数,以便使其具有与我必须转换它相同的输出。

在我的linux机器上,我使用以下代码。这类似于我在其他地方看到的代码(例如在旧的python常见问题解答中),但该代码在一个紧密循环中旋转,而该代码没有,并且有很多奇怪的角落情况代码没有考虑到该代码。

def read_single_keypress():
"""Waits for a single keypress on stdin.


This is a silly function to call if you need to do it a lot because it has
to store stdin's current setup, setup stdin for reading single keystrokes
then read the single keystroke then revert stdin back after reading the
keystroke.


Returns a tuple of characters of the key that was pressed - on Linux,
pressing keys like up arrow results in a sequence of characters. Returns
('\x03',) on KeyboardInterrupt which can happen when a signal gets
handled.


"""
import termios, fcntl, sys, os
fd = sys.stdin.fileno()
# save old state
flags_save = fcntl.fcntl(fd, fcntl.F_GETFL)
attrs_save = termios.tcgetattr(fd)
# make raw - the way to do this comes from the termios(3) man page.
attrs = list(attrs_save) # copy the stored version to update
# iflag
attrs[0] &= ~(termios.IGNBRK | termios.BRKINT | termios.PARMRK
| termios.ISTRIP | termios.INLCR | termios. IGNCR
| termios.ICRNL | termios.IXON )
# oflag
attrs[1] &= ~termios.OPOST
# cflag
attrs[2] &= ~(termios.CSIZE | termios. PARENB)
attrs[2] |= termios.CS8
# lflag
attrs[3] &= ~(termios.ECHONL | termios.ECHO | termios.ICANON
| termios.ISIG | termios.IEXTEN)
termios.tcsetattr(fd, termios.TCSANOW, attrs)
# turn off non-blocking
fcntl.fcntl(fd, fcntl.F_SETFL, flags_save & ~os.O_NONBLOCK)
# read a single keystroke
ret = []
try:
ret.append(sys.stdin.read(1)) # returns a single character
fcntl.fcntl(fd, fcntl.F_SETFL, flags_save | os.O_NONBLOCK)
c = sys.stdin.read(1) # returns a single character
while len(c) > 0:
ret.append(c)
c = sys.stdin.read(1)
except KeyboardInterrupt:
ret.append('\x03')
finally:
# restore old state
termios.tcsetattr(fd, termios.TCSAFLUSH, attrs_save)
fcntl.fcntl(fd, fcntl.F_SETFL, flags_save)
return tuple(ret)

如果你想看看他们是否按了一个确切的键(比如说'b'),这样做:

while True:
choice = raw_input("> ")


if choice == 'b' :
print "You win"
input("yay")
break

如果您可以使用系统命令,则可以使用:

from __future__ import print_function
import os
import platform


if platform.system() == "Windows":
os.system("pause")
else:
os.system("/bin/bash -c 'read -s -n 1 -p \"Press any key to continue...\"'")
print()

它已被验证可以在Windows,Linux和Mac OS X上使用Python 2和3。

os.system似乎总是调用sh,它不识别读取的s和n选项。然而,read命令可以传递给bash:

 os.system("""bash -c 'read -s -n 1 -p "Press any key to continue..."'""")

简单地使用

input("Press Enter to continue...")

使用Python 2时会导致以下错误:

语法错误:解析时预期EOF。

在Python 2和Python 3上工作的代码的简单修复是使用:

try:
input("Press enter to continue")
except SyntaxError:
pass

跨平台,Python 2/3代码:

# import sys, os


def wait_key():
''' Wait for a key press on the console and return it. '''
result = None
if os.name == 'nt':
import msvcrt
result = msvcrt.getwch()
else:
import termios
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)


try:
result = sys.stdin.read(1)
except IOError:
pass
finally:
termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm)


return result

我删除了fctl/非阻塞的东西,因为它给出了#EYZ,我不需要它。我专门使用这段代码是因为我想让它阻塞。;)

增编:

我在PyPI上的一个包中实现了这一点,其中包含许多其他名为控制台的好东西:

>>> from console.utils import wait_key


>>> wait_key()
'h'

我是Python新手,我已经在想我太愚蠢了,无法复制这里提出的最简单的建议。 有一个陷阱,你应该知道:

当从IDLE执行python脚本时,一些IO命令的行为似乎完全不同(因为实际上没有终端窗口)。

例如msvcrt.getch是非阻塞的,并且总是返回$ff。 这在很久以前就已经被报道过了(例如https://bugs.python.org/issue9290)-它被标记为固定的,不知何故,这个问题似乎在当前版本的python/IDLE中仍然存在。

因此,如果上面发布的任何代码不适合您,请尝试手动运行脚本,然后不是IDLE的

如果您想等待回车(因此用户敲击键盘不会导致意外发生),请使用

sys.stdin.readline()

可以使用“键盘”库…

https://github.com/boppreh/keyboard#api

import keyboard
keyboard.wait('space')
print('space was pressed, continuing...')