【问题标题】:Python method for reading keypress?用于读取按键的 Python 方法?
【发布时间】:2012-08-23 22:43:44
【问题描述】:

我是 Python 新手,我刚刚用 Python 制作了一个游戏和一个菜单。 问题是,使用 (raw_)input() 需要我在每次按键后按回车键,我想这样做,以便按下向下箭头将立即选择下一个菜单项,或在游戏中向下移动。目前,它要求我喜欢输入“向下”,然后按 Enter。我也做了很多研究,但我不希望仅仅为了实现一个 keyDown() 方法而下载巨大的模块(例如 pygame)。那么有没有更简单的方法,我只是找不到?

编辑: 刚刚发现msvcrt.getch() 可以解决问题。这不是 keyDown(),但它有效。但是,我也不知道如何使用它,看起来很奇怪,这里有什么帮助吗?这是我目前得到的:

from msvcrt import getch
while True:
    key = getch()
    print(key)

但是,它总是给我所有这些无意义的字节,例如,向下箭头是这样的:

b'\xe0'
b'P'

而且我不知道如何使用它们,我尝试与 chr() 进行比较,甚至使用 ord() 但实际上无法进行任何比较。我要做的基本上是这样的:

from msvcrt import getch
while True:
    key = getch()
    if key == escape:
        break
    elif key == downarrow:
        movedown()
    elif key == 'a':
        ...

等等……有什么帮助吗?

【问题讨论】:

  • 不是那个副本。这是关于 keydown 事件,而不是单个字符输入。
  • 我可以跨平台解决方案?? msvcrt 在 Python 的 mac/linux 发行版上不可用

标签: python windows key keydown getch


【解决方案1】:

请参阅 MSDN getch 文档。具体来说:

_getch 和_getwch 函数从控制台读取单个字符而不回显该字符。这些函数都不能用于读取 CTRL+C。读取功能键或方向键时,每个功能必须调用两次;第一次调用返回 0 或 0xE0,第二次调用返回实际的键码。

Python 函数返回一个字符。您可以使用ord() 获取可以测试的整数值,例如keycode = ord(msvcrt.getch())

因此,如果您读取 0x00 或 0xE0,请再次读取以获取箭头或功能键的键码。根据实验,0x00 在 F1-F10 (0x3B-0x44) 之前,0xE0 在箭头键和 Ins/Del/Home/End/PageUp/PageDown 之前。

【讨论】:

  • 好吧,我现在想通了,但无法发布最终解决方案。但是这个 + ord() + char()
【解决方案2】:

通过我自己测试所有的东西来解决这个问题。 找不到任何关于它的主题,所以我将把解决方案留在这里。这可能不是唯一甚至不是最好的解决方案,但它适用于我的目的(在 getch 的限制内)并且总比没有好。

注意:正确的keyDown() 可以识别所有按键和实际按键,仍然很有价值。

解决方案: 使用ord()-function 先将getch() 转为整数(我猜是虚拟键码,但不太确定)可以正常工作,然后比较结果为代表所需密钥的实际数字。另外,如果需要,我可以在返回的数字周围添加一个额外的chr(),以便将其转换为字符。但是,我主要使用向下箭头、esc 等,因此将它们转换为字符将是愚蠢的。这是最终代码:

from msvcrt import getch
while True:
    key = ord(getch())
    if key == 27: #ESC
        break
    elif key == 13: #Enter
        select()
    elif key == 224: #Special keys (arrows, f keys, ins, del, etc.)
        key = ord(getch())
        if key == 80: #Down arrow
            moveDown()
        elif key == 72: #Up arrow
            moveUp()

另外,如果其他人需要,您可以轻松地从谷歌找到键码,或者使用 python 并按下键:

from msvcrt import getch
while True:
    print(ord(getch()))

【讨论】:

  • 我正在使用上面的代码,但我的代码只是在 getch() 处阻塞,然后什么也没有发生。有什么帮助吗?
  • @AnumSheraz 上述方法仅在您从命令提示符运行代码时有效。
  • 如果您首先将 char 转换为字节,您可以直接与 keypressed 比较 'keypressed == bytes('q', 'utf-8')' 检查 q 是否被按下。它适用于特殊键,例如 enter 或 esc,但您需要知道这些键的代码(例如,esc 是 '\x1b')
【解决方案3】:
from msvcrt import getch

pos = [0, 0]

def fright():
    global pos
    pos[0] += 1

def fleft():
    global pos 
    pos[0] -= 1

def fup():
    global pos
    pos[1] += 1

def fdown():
    global pos
    pos[1] -= 1

while True:
    print'Distance from zero: ', pos
    key = ord(getch())
    if key == 27: #ESC
        break
    elif key == 13: #Enter
        print('selected')
    elif key == 32: #Space
        print('jump')
    elif key == 224: #Special keys (arrows, f keys, ins, del, etc.)
        key = ord(getch())
        if key == 80: #Down arrow
            print('down')
            fdown
        elif key == 72: #Up arrow
            print('up')
            fup()
        elif key == 75: #Left arrow
            print('left')
            fleft()
        elif key == 77: #Right arrow
            print('right')
            fright()

【讨论】:

  • 请在您的答案中添加一些解释来解释您的代码。
  • 当你按箭头键时,为什么你必须做另一个 key = ord(getch())?在第一次,你得到一个 224,但它会立即得到该密钥的正确代码。怎么样?
  • @luturol- 因为某些键返回 2 个字节(箭头键、功能键等)。需要第二次获取才能查看按下了哪个箭头键或功能键.....
【解决方案4】:

我真的不想将此作为评论发布,因为我需要评论所有答案和原始问题。

所有答案似乎都依赖于 MSVCRT Microsoft Visual C Runtime。 如果你想避免这种依赖:

如果您需要跨平台支持,请在此处使用该库:

https://pypi.org/project/getkey/#files

https://github.com/kcsaff/getkey

可以提供更优雅的解决方案。

代码示例:

from getkey import getkey, keys
key = getkey()
if key == keys.UP:
  ...  # Handle the UP key
elif key == keys.DOWN:
  ...  # Handle the DOWN key
elif key == 'a':
  ...  # Handle the `a` key
elif key == 'Y':
  ...  # Handle `shift-y`
else:
  # Handle other text characters
  buffer += key
  print(buffer)

【讨论】:

  • 在内置模块 (msvcrt) 已经可以正常工作的情况下,安装特殊库 ('getkey') 是一种非常无效的解决方案!
  • @Apostolos 正如他在他的解决方案中所说,msvcrt 仅在 Windows 上可用,getkey 是跨平台的。
  • 我明白你的意思。但是想想:由于每个平台都有自己的内置“getkey”模块(在 Windows 中为“msvcrt”),安装额外的“getkey”模块总是没用! :)(简单的逻辑)
  • @Apostolos 试试 Ctrl + Keys 和 mscvrt,看看代码的可读性提高了多少,现在想想一个盒子的奇迹。我发布的代码可以在所有平台上安装和使用,而不依赖于其他任何东西 - 完全可移植,并且一站式可维护性 - 它可以正常工作,请尝试使用基于 Windows msvcrt 构建的代码。如果您依赖该平台,那么您将绑定到该平台,并且您的代码是特定于平台的,并且为每个平台维护唯一版本不是非常明智或高效 - 尽管它确实会导致繁忙的工作。
  • 没关系。本质是做好该做的工作。我个人已经建立了数百个 PY 文件,而且我的“mscvrt”总是完全覆盖我的。否则,我使用一些外部模块不会有任何问题,就像我经常使用其他主题一样。
【解决方案5】:

我也在努力实现这一目标。从上面的代码中,我了解到您可以多次调用 getch() 函数,以便从函数中获取两个字节。因此,如果您只是想与字节对象一起使用,则不需要 ord() 函数。

while True :
    if m.kbhit() :
        k = m.getch()
        if b'\r' == k :
            break
        elif k == b'\x08'or k == b'\x1b':
            # b'\x08' => BACKSPACE
            # b'\x1b' => ESC
            pass
        elif k == b'\xe0' or k == b'\x00':
            k = m.getch()
            if k in [b'H',b'M',b'K',b'P',b'S',b'\x08']:
                # b'H' => UP ARROW
                # b'M' => RIGHT ARROW
                # b'K' => LEFT ARROW
                # b'P' => DOWN ARROW
                # b'S' => DELETE
                pass
            else:
                print(k.decode(),end='')
        else:
            print(k.decode(),end='')

此代码将打印任何键,直到在 CMD 或 IDE 中按下回车键 (我使用的是 VS 代码) 如果需要,您可以在 if 中自定义特定键

【讨论】:

    【解决方案6】:

    现在已经很晚了,但我制作了一个适用于 Windows、Mac 和 Linux 的快速脚本,只需使用每个命令行:

    import os, platform
    
    def close():
        if platform.system() == "Windows":
            print("Press any key to exit . . .")
            os.system("pause>nul")
            exit()
        
        elif platform.system() == "Linux":
            os.system("read -n1 -r -p \"Press any key to exit . . .\" key")
            exit()
        
        elif platform.system() == "Darwin":
            print("Press any key to exit . . .")
            os.system("read -n 1 -s -p \"\"")
            exit()
        
        else:
            exit()
    

    它只使用内置函数,并且应该适用于所有三个函数(虽然我只测试过 Windows 和 Linux...)。

    【讨论】:

    • 这是一个糟糕的解决方案。这甚至没有使用内置函数。您正在打开一个 shell 子进程并运行 linux 命令只是为了检测按键
    【解决方案7】:
    import keyboard
    
    def mywait():
        keyboard.read_key()
    
    def my_function():
        print("going down")
    
    def my_exit():
        quit()
    
    keyboard.add_hotkey('down', my_function)
    keyboard.add_hotkey('esc', my_exit)
    
    while True:
        mywait()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-29
      • 1970-01-01
      • 2022-08-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多