45

我是 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':
        ...

等等......有什么帮助吗?

4

7 回答 7

63

通过我自己测试所有的东西弄清楚了。找不到任何关于它的主题,所以我将把解决方案留在这里。这可能不是唯一甚至最好的解决方案,但它适用于我的目的(在 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()))
于 2012-08-29T14:01:26.187 回答
10

请参阅 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 之前。

于 2012-08-29T12:45:42.417 回答
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)
于 2019-08-17T08:12:29.443 回答
1
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()
于 2017-05-15T19:32:20.983 回答
1

我也试图实现这一目标。从上面的代码中,我了解到您可以多次调用 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 CODE)如果需要,您可以在 if 内部自定义特定键

于 2020-05-02T13:23:38.330 回答
1

现在真的很晚了,但我制作了一个适用于 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 ......)。

于 2021-01-27T10:30:03.727 回答
0
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()
于 2021-12-08T10:39:44.013 回答