raw_input 无需按 Enter 键

发布于 2024-09-15 15:12:40 字数 271 浏览 6 评论 0原文

我在 Python 中使用 raw_input 与 shell 中的用户交互。

c = raw_input('Press s or n to continue:')
if c.upper() == 'S':
    print 'YES'

它按预期工作,但用户必须在按“s”后在 shell 中按 Enter。有没有一种方法可以通过用户输入完成我需要的操作,而无需在 shell 中按 Enter 键?我正在使用 *nixes 机器。

I'm using raw_input in Python to interact with user in shell.

c = raw_input('Press s or n to continue:')
if c.upper() == 'S':
    print 'YES'

It works as intended, but the user has to press enter in the shell after pressing 's'. Is there a way to accomplish what I need from an user input without needing to press enter in the shell? I'm using *nixes machines.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

水波映月 2024-09-22 15:12:40

实际上,与此同时(距本线程开始近 10 年)有一个名为 pynput 的跨平台模块出现了。
在第一个剪切下方 - 即仅适用于小写的 's'。
我已经在 Windows 上测试过它,但我几乎 100% 肯定它应该可以在 Linux 上运行。

from pynput import keyboard

print('Press s or n to continue:')

with keyboard.Events() as events:
    # Block for as much as possible
    event = events.get(1e6)
    if event.key == keyboard.KeyCode.from_char('s'):
        print("YES")

Actually in the meantime (almost 10 years from the start of this thread) a cross-platform module named pynput appeared.
Below a first cut - i.e. that works with lowercase 's' only.
I have tested it on Windows but I am almost 100% positive that it should work on Linux.

from pynput import keyboard

print('Press s or n to continue:')

with keyboard.Events() as events:
    # Block for as much as possible
    event = events.get(1e6)
    if event.key == keyboard.KeyCode.from_char('s'):
        print("YES")
猫七 2024-09-22 15:12:40

在 Windows 下,您需要 msvcrt 模块,具体来说,从您描述问题的方式来看,函数 msvcrt.getch

读取按键并返回
由此产生的字符。没有任何回声
到控制台。此调用将被阻止
如果尚未按下按键
可用,但不会等待 Enter
被按下。

(等等——请参阅我刚刚指出的文档)。对于 Unix,请参阅此食谱 用于构建类似的 getch 函数的简单方法(另请参阅该配方的评论线程中的几个替代方案 &c)。

Under Windows, you need the msvcrt module, specifically, it seems from the way you describe your problem, the function msvcrt.getch:

Read a keypress and return the
resulting character. Nothing is echoed
to the console. This call will block
if a keypress is not already
available, but will not wait for Enter
to be pressed.

(etc -- see the docs I just pointed to). For Unix, see e.g. this recipe for a simple way to build a similar getch function (see also several alternatives &c in the comment thread of that recipe).

我不会写诗 2024-09-22 15:12:40

Python 不提供开箱即用的多平台解决方案。
如果您使用的是 Windows,您可以尝试 msvcrt

import msvcrt
print 'Press s or n to continue:\n'
input_char = msvcrt.getch()
if input_char.upper() == 'S': 
   print 'YES'

Python does not provide a multiplatform solution out of the box.
If you are on Windows you could try msvcrt with:

import msvcrt
print 'Press s or n to continue:\n'
input_char = msvcrt.getch()
if input_char.upper() == 'S': 
   print 'YES'
梦屿孤独相伴 2024-09-22 15:12:40

curses 也可以做到这一点:

import curses, time

def input_char(message):
    try:
        win = curses.initscr()
        win.addstr(0, 0, message)
        while True: 
            ch = win.getch()
            if ch in range(32, 127): 
                break
            time.sleep(0.05)
    finally:
        curses.endwin()
    return chr(ch)

c = input_char('Do you want to continue? y/[n]')
if c.lower() in ['y', 'yes']:
    print('yes')
else:
    print('no (got {})'.format(c))

curses can do that as well :

import curses, time

def input_char(message):
    try:
        win = curses.initscr()
        win.addstr(0, 0, message)
        while True: 
            ch = win.getch()
            if ch in range(32, 127): 
                break
            time.sleep(0.05)
    finally:
        curses.endwin()
    return chr(ch)

c = input_char('Do you want to continue? y/[n]')
if c.lower() in ['y', 'yes']:
    print('yes')
else:
    print('no (got {})'.format(c))
清君侧 2024-09-22 15:12:40

适用于类 Unix 操作系统(包括 Linux)的标准库解决方案:

def getch():
    import sys, termios

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

    new = termios.tcgetattr(fd)
    new[3] = new[3] & ~termios.ICANON
    new[6][termios.VMIN] = 1
    new[6][termios.VTIME] = 0

    try:
        termios.tcsetattr(fd, termios.TCSAFLUSH, new)
        return sys.stdin.read(1)
    finally:
        termios.tcsetattr(fd, termios.TCSAFLUSH, orig)

其工作原理是在从终端读取数据之前将终端置于非规范输入模式。

不回显用户输入的替代解决方案(例如,如果用户按 zz 将不会出现在屏幕上):

def getch():
    import sys, termios, tty

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

    try:
        tty.setcbreak(fd)  # or tty.setraw(fd) if you prefer raw mode's behavior.
        return sys.stdin.read(1)
    finally:
        termios.tcsetattr(fd, termios.TCSAFLUSH, orig)

使用示例:

print('Press s or n to continue: ', end='', flush=True)
c = getch()
print()
if c.upper() == 'S':
    print('YES')

Standard library solution for Unix-like operating systems (including Linux):

def getch():
    import sys, termios

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

    new = termios.tcgetattr(fd)
    new[3] = new[3] & ~termios.ICANON
    new[6][termios.VMIN] = 1
    new[6][termios.VTIME] = 0

    try:
        termios.tcsetattr(fd, termios.TCSAFLUSH, new)
        return sys.stdin.read(1)
    finally:
        termios.tcsetattr(fd, termios.TCSAFLUSH, orig)

This works by putting the terminal into non-canonical input mode before reading from the terminal.

Alternative solution that does not echo the user's input (e.g. if the user presses z, z will not appear on screen):

def getch():
    import sys, termios, tty

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

    try:
        tty.setcbreak(fd)  # or tty.setraw(fd) if you prefer raw mode's behavior.
        return sys.stdin.read(1)
    finally:
        termios.tcsetattr(fd, termios.TCSAFLUSH, orig)

Usage example:

print('Press s or n to continue: ', end='', flush=True)
c = getch()
print()
if c.upper() == 'S':
    print('YES')
路弥 2024-09-22 15:12:40

为了获得单个字符,我使用了 getch,但我不知道它是否适用视窗。

To get a single character, I have used getch, but I don't know if it works on Windows.

拥醉 2024-09-22 15:12:40

使用 readchar:

import readchar

key = readchar.readkey()

if key == "a":
  print("text")

https://pypi.org/project/readchar/ 到网页

use readchar:

import readchar

key = readchar.readkey()

if key == "a":
  print("text")

https://pypi.org/project/readchar/ to webpage

森林很绿却致人迷途 2024-09-22 15:12:40

除了 msvcrt 模块,您还可以使用 WConio

>>> import WConio
>>> ans = WConio.getkey()
>>> ans
'y'

Instead of the msvcrt module you could also use WConio:

>>> import WConio
>>> ans = WConio.getkey()
>>> ans
'y'
陌伤浅笑 2024-09-22 15:12:40

附带说明一下,msvcrt.kbhit() 返回一个布尔值,确定当前是否按下了键盘上的任何键。

因此,如果您正在制作游戏或其他内容,并且希望按键执行某些操作但又不想完全停止游戏,则可以在 if 语句中使用 kbhit() 以确保仅在用户确实想要执行某些操作时才检索密钥。

Python 3 中的示例:

# this would be in some kind of check_input function
if msvcrt.kbhit():
    key = msvcrt.getch().decode("utf-8").lower() # getch() returns bytes data that we need to decode in order to read properly. i also forced lowercase which is optional but recommended
    if key == "w": # here 'w' is used as an example
        # do stuff
    elif key == "a":
        # do other stuff
    elif key == "j":
        # you get the point

On a side note, msvcrt.kbhit() returns a boolean value determining if any key on the keyboard is currently being pressed.

So if you're making a game or something and want keypresses to do things but not halt the game entirely, you can use kbhit() inside an if statement to make sure that the key is only retrieved if the user actually wants to do something.

An example in Python 3:

# this would be in some kind of check_input function
if msvcrt.kbhit():
    key = msvcrt.getch().decode("utf-8").lower() # getch() returns bytes data that we need to decode in order to read properly. i also forced lowercase which is optional but recommended
    if key == "w": # here 'w' is used as an example
        # do stuff
    elif key == "a":
        # do other stuff
    elif key == "j":
        # you get the point
一城柳絮吹成雪 2024-09-22 15:12:40

我知道这已经很旧了,但解决方案对我来说还不够好。
我需要支持跨平台并且无需安装任何外部Python包的解决方案。

我的解决方案,以防其他人遇到这篇文章

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

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

I know this is old, but the solution wasn't good enough for me.
I need the solution to support cross-platform and without installing any external Python packages.

My solution for this, in case anyone else comes across this post

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

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()
云醉月微眠 2024-09-22 15:12:40

如果您可以使用外部库, blessed (跨平台)可以做到做到这一点很容易:

from blessed import Terminal

term = Terminal()

with term.cbreak(): # set keys to be read immediately 
    print("Press any key to continue")
    inp = term.inkey() # wait and read one character

请注意,在 with 块内时,终端的行编辑功能将被禁用。

cbreak 的文档, inkey< /code>,以及示例inkey

If you can use an external library, blessed (cross platform) can do do this quite easily:

from blessed import Terminal

term = Terminal()

with term.cbreak(): # set keys to be read immediately 
    print("Press any key to continue")
    inp = term.inkey() # wait and read one character

Note that while inside the with block, line editing capabilities of the terminal will be disabled.

Documentation for cbreak, inkey, and an example with inkey.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文