【问题标题】:raw_input without pressing enterraw_input 不按回车
【发布时间】:2011-04-01 04:36:35
【问题描述】:

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

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

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

【问题讨论】:

标签: python user-input


【解决方案1】:

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

读取按键并返回 结果字符。没有回声 到控制台。此调用将阻塞 如果按键还没有 可用,但不会等待 Enter 被按下。

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

【讨论】:

  • 它按预期工作,并且拥有跨平台解决方案非常棒。感谢您的回答!
  • 直接转到pypi.python.org/pypi/readchar,似乎可以完成大部分工作,尽管我无法正确读取 OSX 上的箭头键。
  • Linux 和 Mac 用户呢?有什么选择吗?
【解决方案2】:

Python 不提供开箱即用的多平台解决方案。
如果你在 Windows 上,你可以试试msvcrt

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

【讨论】:

  • 我遇到过这个模块,但我需要它在 *nixes 上工作。还是谢谢!
【解决方案3】:

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

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

【讨论】:

    【解决方案4】:

    附带说明,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
    

    【讨论】:

      【解决方案5】:

      为了获取单个字符,我使用了getch,但我不知道它是否适用于Windows。

      【讨论】:

        【解决方案6】:

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

        【讨论】:

          【解决方案7】:

          我知道这是旧的,但解决方案对我来说还不够好。 我需要支持跨平台无需安装任何外部 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()
          

          【讨论】:

            【解决方案8】:

            实际上在此期间(从这个线程开始将近 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")
            

            【讨论】:

              【解决方案9】:

              如果您可以使用外部库,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 块内时,终端的行编辑功能将被禁用。

              cbreakinkey 和带有inkeyexample 的文档。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2018-10-26
                • 1970-01-01
                • 2012-03-31
                • 2023-03-09
                • 2018-12-04
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多