Слушатель клавиатуры pynput вызывает задержки

Я делаю программу, которая включается и выключается определенной клавишей на клавиатуре (используя pynput). Я поместил цикл прослушивания клавиатуры в первый поток, а цикл действия — во второй. Проблема в том, что после того, как я запускаю код, он не слушает клавиатуру сразу, только по прошествии 9-10 секунд. И иногда отказывается реагировать на кнопку Esc, а иногда работает. Как исправить отставание? Код в порядке?

from threading import Thread
from pynput import keyboard
import time

flag = False
kill = False

def on_press(key):
    global flag
    global kill

    if key == keyboard.KeyCode.from_char('a'):
        print('pressed A')
        flag = not flag
    if key == keyboard.Key.esc:
        kill = True
        return False

def thr2():
    print('joining...')
    with keyboard.Listener(on_press=on_press) as listen:
        listen.join()

def thr1():
    while True:
        if kill:
            break
        if flag:
            print('looping....')
            time.sleep(0.4)

if __name__ == "__main__":
    thread1 = Thread(target=thr1)
    thread2 = Thread(target=thr2)
    thread1.start()
    thread2.start()

person Mirrah    schedule 19.01.2020    source источник


Ответы (2)


Похоже, что фактическая задержка исходит от самого обработчика контекста pynput keyboard.Listener. Я не могу сказать вам, что происходит под капотом, но задержка не связана с тем, как вы управляете своими потоками.

# pynput library creating keyboard.Listener thread causes the delay
with keyboard.Listener(on_press=on_press) as listen:  
    print('listen thread created')  # This does not happen until after the delay
    listen.join()

Вы можете перефразировать вопрос так, чтобы он относился к клавиатуре pynput. Слушатель

person Jake Hill    schedule 19.01.2020
comment
вы пробовали запускать код? вы испытываете такое же отставание? Я заметил, что задержки не происходит, если я не помещаю ее в поток, НО когда вместо этого я использую многопроцессорность и меняю Thread(target=...) на Process(target=...), задержка исчезает. Но я не могу использовать многопроцессорность, потому что она по какой-то причине не распознает глобальные переменные, и это то, что я пытаюсь выяснить прямо сейчас. Вы случайно не знаете, как передавать переменные «флаг» и «убить» между процессами? - person Mirrah; 19.01.2020
comment
У меня была такая же задержка при запуске как внутри потока, так и вне потока. Тот факт, что он уже находится в потоке, не должен иметь значения, потому что обработчик keyboard.Listen все равно создает новый поток. Использование многопроцессорности вместо потоков усложняет задачу, поскольку процессы не имеют явного доступа к чему-либо, что существует вне их. - person Jake Hill; 21.01.2020

Вот решение, которое хорошо работает с многопроцессорностью:

import sys
from pynput import keyboard
from time import sleep
from multiprocessing import Process, Event
from functools import partial


def thr2(kill_event, flag_event):

    def on_press(kill_event, flag_event, key):
        if key == keyboard.KeyCode.from_char('a'):
            print('pressed A')
            if flag_event.is_set():
                flag_event.clear()
            else:
                flag_event.set()
        if key == keyboard.Key.esc:
            print('esc')
            kill_event.set()
            sys.exit(0)

    with keyboard.Listener(on_press=partial(on_press, kill_event, flag_event)) as listen:
        listen.join()


def thr1(kill_event, flag_event):
    while True:
        if kill_event.is_set():
            print('kill')
            sys.exit(0)
        if flag_event.is_set():
            print('looping....')
            sleep(0.4)


if __name__ == "__main__":
    kill_event = Event()
    flag_event = Event()

    thread1 = Process(target=thr1, args=(kill_event, flag_event))
    thread2 = Process(target=thr2, args=(kill_event, flag_event))

    thread1.start()
    thread2.start()

    thread1.join()  # Join processes here to avoid main process exit
    thread2.join()
person Jake Hill    schedule 21.01.2020