Python设计指定延时内无鼠标/键盘操作后执行设定的任务

开发环境

  • Windows
  • Python 3
  • 依赖库:pynput

需求背景

就像电脑无操作几分钟后会进入屏保/锁定屏幕一样,我希望在电脑一段时间无操作后执行某些命令(比如自动保存、最小化、隐藏窗口)。

设计方法

Python内建threading库的Timer类可以发起后台计时器,不过我希望在最后一个计时器结束计时的时候才执行任务,所以我设计了一个自己的计时器类:

添加计时器

这个计时器类可以根据接收的延时时间,发起很多计时器后台线程,并且增加一个线程就标记有一个线程正在运行(线程计数器加1)。

在每个线程运行结束后,判断当前是否还有未运行完毕的线程,如果没有,则执行预先设定的回调函数。

下面做了一个简单的例子,用tkinter绘制窗口,输入框输入数字(或小数)设置延时时间,(多次)点击按钮启动后台线程计时器。

注意每一次可以设置不同的延时时间。当最后一个计时器结束运行时,会执行回调函数:

在这里插入图片描述

示例代码

import tkinter
from threading import Timer
from threading import Thread


class MyTimer:
    def __init__(self, func):
        self.func = func
        self.count = 0

    def wait(self, seconds):
        self.count += 1
        Timer(seconds, self.timeout).start()

    def timeout(self):
        self.count -= 1
        if self.count == 0:
            self.func()


def callback():
    timer.wait(float(txt.get()))


timer = MyTimer(lambda: print("It's time to work!"))

top = tkinter.Tk()
txt = tkinter.Entry(top)
txt.insert(0, '5')
txt.pack(side='left')
tkinter.Button(top, text='延时执行', command=callback).pack(side='left')
top.mainloop()

此方法不容易将后台线程全部安全退出。不过在主线程停止后,不会再发起新的线程,所以最后一个线程完成计时后后台线程就会停止

但是为了解决立刻退出的问题,我又写了另一种计时器:只让最后一次设定的计时器有效。

唯一的区别是当每次延时如果设置了不同的时间参数,可能得到不同的执行顺序。不过这种需求或许并不经常出现:

class MyLastTimer:
    def __init__(self, func):
        self.func = func
        self.th = Timer(0, int)

    def wait(self, seconds): # only last timer work.
        self.th.cancel()
        self.th = Timer(seconds, self.timeout)
        self.th.start()

    def timeout(self):
        self.func()

添加键盘监控

结合我最近写的另一篇文章:《Python开发基于pynput的后台鼠标键盘监控程序示例》

实现键盘监控器后,获得任何有关键盘/鼠标的操作,刷新延时计时器的线程。计时器截止后会运行传入的函数,即可实现指定时间内无操作后触发的任务操作。

监控器可以用monitor.stop()、计时器可以用timer.th.cancel()方法安全退出,防止主线程关闭后仍然会有线程执行任务

完整代码

from threading import Timer
from threading import Thread

import pynput


class Monitor:
    def __init__(self, func):
        self.func = func
        Thread(target=self.mouser).start()
        Thread(target=self.keyboarder).start()

    def hook(self, *typ_names):
        for name in typ_names:
            yield (lambda typ: (lambda *args: self.func(typ, *args)))(name)

    def mouser(self):
        with pynput.mouse.Listener(*self.hook('move', 'click', 'scroll')) as self.ml:
            self.ml.join()

    def keyboarder(self):
        with pynput.keyboard.Listener(*self.hook('press', 'release')) as self.kl:
            self.kl.join()

    def close(self):
        pynput.keyboard.Listener.stop(self.kl)
        pynput.mouse.Listener.stop(self.ml)


class MyLastTimer:
    def __init__(self, func):
        self.func = func
        self.th = Timer(0, int)

    def wait(self, seconds): # only last timer work.
        self.th.cancel()
        self.th = Timer(seconds, self.timeout)
        self.th.start()

    def timeout(self):
        self.func()


timer = MyLastTimer(lambda: print('No actions in 5 seconds!'))
Monitor(lambda *_: timer.wait(5))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值