本文介绍了实时捕获和处理按键(例如按键事件)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意:我希望在不使用任何外部包(如PyGame等)的情况下完成此操作。

我正在尝试在单个按键到达时捕获它们,并针对特定字符执行操作,无论我只是想"重新回显"该字符,还是根本不显示它并执行其他操作。

我找到了一个跨平台(尽管不确定OS X)的Getch()实现,因为我不想像Input()那样读取整行:

# http://code.activestate.com/recipes/134892/
def getch():
    try:
        import termios
    except ImportError:
        # Non-POSIX. Return msvcrt's (Windows') getch.
        import msvcrt
        return msvcrt.getch

    # POSIX system. Create and return a getch that manipulates the tty.
    fd = sys.stdin.fileno()
    old_settings = termios.tcgetattr(fd)
    try:
        tty.setraw(fd)
        ch = sys.stdin.read(1)
    finally:
        termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
    return ch

[尝试1]我首先尝试了一个简单的WHILE-TRUE循环来轮询Getch,但是如果我打字太快,字符就会丢失。减少睡眠时间会让情况变得更糟。调试语句仅在按Enter键时打印,并且在时间和位置上不一致。(看起来可能正在进行一些行缓冲?)去掉循环并休眠会让它完美地工作一次。

#!/usr/bin/env python3

import sys
import tty
import time


def main():
    while True:
        time.sleep(1)
        sys.stdout.write(" DEBUG:Before ")
        sys.stdout.write(getch())
        sys.stdout.write(" DEBUG:After ")


if __name__ == "__main__":
    main()

[尝试2]我得到了一个使用线程化方法(https://stackoverflow.com/a/14043979/2752206)的示例,但它"锁定"并且不接受任何输入(包括Ctrl-C等)。

#!/usr/bin/env python3

import sys
import tty
import time
import threading

key = 'Z'


def main():
    threading.Thread(target=getchThread).start()

    while True:
        time.sleep(1)
        sys.stdout.write(" DEBUG:Before ")
        sys.stdout.write(key)
        sys.stdout.write(" DEBUG:After ")


def getchThread():
    global key
    lock = threading.Lock()
    while True:
        with lock:
            key = getch()


if __name__ == "__main__":
    main()

有没有人有什么建议或指导?或者更重要的是,谁能解释一下为什么这两次尝试都不起作用?谢谢。

推荐答案

首先,我并不认为您需要多线程。例如,如果您想要执行一些任务,如在屏幕上绘图或执行其他操作,并在执行此操作时捕获按键,则需要此功能。

让我们考虑这样一种情况:您只想捕获按键,并且在每次按键后执行一些操作:如果按下了x,则退出,否则只打印字符。在这种情况下,只需使用简单的WHILE循环

def process(key):
    if key == 'x':
        exit('exitting')
    else:
        print(key, end="", flush=True)

if __name__ == "__main__":
    while True:
        key = getch()
        process(key)

注意睡眠不足()。我假设您认为Getch()不会等待用户输入,所以您设置了1秒的睡眠时间。然而,您的Getch()等待一个条目,然后返回它。在这种情况下,全局变量并不真正有用,因此您最好在循环内调用process(Getch())。

print(key, end="", flush=True)=>额外的参数将确保按下的键保持在一行中,而不是每次打印内容时都追加换行符。

在另一种情况下,您希望同时执行不同的程序,则应使用线程。

考虑以下代码:

n = 0
quit = False

def process(key):
    if key == 'x':
        global quit
        quit = True
        exit('exitting')
    elif key == 'n':
        global n
        print(n)
    else:
        print(key, end="", flush=True)

def key_capturing():
    while True:
        process(getch())

if __name__ == "__main__":
    threading.Thread(target=key_capturing).start()
    while not quit:
        n += 1
        time.sleep(0.1)

这将创建全局变量n,并在主线程中每秒递增10次。同时,key_capturing方法侦听按下的键,并执行与上一个示例中相同的操作+当您按键盘上的n时,将打印全局变量n的当前值。

结束语:正如@Zondo所指出的,您确实遗漏了Getch()定义中的大括号。return msvcrt.getch最有可能是return msvcrt.getch()

这篇关于实时捕获和处理按键(例如按键事件)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-27 10:27