pynput 键盘侦听器自动重复

pynput keyboard Listener autorepeat

我正在尝试使用 pynput 获取实时键盘输入,但 on_press 函数在自动重复时被调用。

示例代码:

#!/usr/bin/env python3

import sys

import numpy as np
import sounddevice as sd

from pynput import keyboard

frequency = []

def on_press(key):
    global frequency
    try:
        print(key.vk)
        if key.char == "q":
            frequency.append(440)
        elif key.char == "w":
            frequency.append(880)
    except AttributeError:
        pass

def on_release(key):
    global frequency
    if key == keyboard.Key.esc:
        # Stop listener
        print("Press Enter")
        return False
    elif key.char == "q":
        frequency.remove(440)
    elif key.char == "w":
        frequency.remove(880)

listener = keyboard.Listener(
    on_press=on_press,
    on_release=on_release,
    suppress = True)
listener.start()

start_idx = 0

def callback(outdata, frames, time, status):
    if status:
        print(status, file=sys.stderr)
    print(frames)
    global start_idx
    t = (start_idx + np.arange(frames)) / 48000
    t = t.reshape(-1, 1)
    outdata[:] = 0 * t
    if len(frequency) > 0:
        print("Playing")
    for freq in frequency:
        outdata[:] = outdata[:] + 0.2 * np.sin(2 * np.pi * freq * t)

    start_idx += frames

try:
    with sd.OutputStream(channels=1, callback=callback,
            samplerate=48000):
        input()
        listener.stop()
except Exception as e:
    print("Exception")
    listener.stop()
    exit()

如果你 运行 代码并按住 Q 键,键盘自动重复开始并破坏整个听众。是否有 python 输入模块可以正确处理原始键盘输入?

第二件事是代码经常使我的 Xorg 崩溃。我只是 运行 脚本几次,Xorg 就崩溃了。我不知道为什么。 Linux 5.5.2-zen1-1-zen x86_64 GNU/Linux, X.Org 1.20.7.

第三件事是声音合成似乎有点滞后。回调函数的帧数好像在400左右徘徊,在每秒48000个样本的速率下不到10毫秒,但实际的音频反馈感觉有几百毫秒的延迟。

pygame 有一个很好的 keylistener 并且很容易构建一个显示输出的 GUI window。它也适用于 Linux:

import pygame

def main_loop():
    #code
    loopExit = False
    while not loopExit:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                loopExit = True
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_q:
                    #code

            if event.type == pygame.KEYUP:
                if event.key == pygame.K_q:
                    #code

https://www.pygame.org/docs/ref/key.html