首页 > 解决方案 > 理解线程与阻塞键盘监听器的结合

问题描述

我尝试实现的是一个超时倒计时,它可以被一个pynput关键事件打断。

在我的第一个实现中存在一个错误:我看不到告诉 pynput 线程超时结束的可能性。

根据 Python线程文档,我是否需要创建更复杂的Condition对象或同步线程?还是我想扩展原来的 pynput 类?

对我来说,在这种情况下很难理解哪个线程是生产者或者消费者

编码..

模块代码

import threading
import time
from pynput import keyboard
import subprocess

class CountdownWithInterrupt:
    """A countdown feature which user can interrupt by pressing Enter key"""
    def __init__(self, interval, message="Press enter to continue..."):
        """Constructor"""
        self.window_id = self.obtain_window_id()
        self.interrupt_key = keyboard.Key.enter
        self.message = message
        self.user_pressed_key = False
        self.timeout_over = False
        self.timer_thread = threading.Thread(name='timer',
                                             target=self.timer,
                                             kwargs={"interval":interval})
        self.kblistener_thread = threading.Thread(name='keyboard_listener',
                                                  target=self.keyboard_listener)

    def obtain_window_id(self):
    """Ignore keyboard events if they come from other windows"""
        try:
            result = subprocess.run(['xdotool', 'getactivewindow'], stdout=subprocess.PIPE)
            window_id = result.stdout
        except DisplayNameError:
            window_id = print (random.randint(1,21)*5)

        return window_id

    def lock(self):
        return self.user_pressed_key or self.timeout_over

    def start(self):
        """starts countdown"""
        print(self.message)
        self.timer_thread.start()
        self.kblistener_thread.start()


    def on_release(self, key):
        """listener action"""
        if (self.window_id != self.obtain_window_id()):
            return True
        if key == self.interrupt_key:
            # Stop listener
            self.user_pressed_key = True
            return False

        return True

    def keyboard_listener(self):
        """listen for interrupt"""
        with keyboard.Listener(on_release=self.on_release) as listener:
            listener.join()

    def timer(self, interval):
        """set up the resource to be used by the consumer"""
        time_left = interval
        while time_left > 0:
            if self.user_pressed_key:
                break
            print(time_left, end='\r', flush=True)
            time.sleep(1)
            time_left = time_left - 1
        self.timeout_over = True

实际程序

from modules.helpers import CountdownWithInterrupt

msg =  ("Press enter..")
interruptableCountdown = CountdownWithInterrupt(5, msg)
interruptableCountdown.start()
while(interruptableCountdown.lock() == False):
    pass
print("tuut!")

标签: pythonmultithreading

解决方案


为我工作listener.stop()


推荐阅读