如何实现暂停(和更多)功能?

Bru*_*oij 13 python windows multithreading

我事先就问题的长度道歉,我不想遗漏任何东西.

一些背景资料

我正在尝试通过编写使用Windows API来模拟击键,鼠标移动和窗口/控制操作的Python应用程序来自动化数据输入过程.我不得不求助于这种方法,因为我没有(还)有直接访问数据存储/数据库所需的安全许可(例如,使用SQL)或间接通过更适合的API.官僚主义,这是一种痛苦;-)

数据输入过程涉及由于物品可用性的变化而更正销售订单.不可用的文章要么从订单中删除,要么被其他合适的文章替换.

最初我希望人类能够监控自动数据输入过程,以确保一切正常.为了实现这一点,我一方面减慢了操作的速度,另一方面也通过固定窗口告知用户当前正在进行的操作.

实际的问题

为了允许用户暂停自动化过程,我将Pause/Break键注册为热键,在处理程序中我想暂停自动化功能.但是,我目前正在努力找到一种方法来正确暂停自动化功能的执行.当调用pause函数时,无论它在做什么,我都希望自动化过程停止在其轨道上.我不希望它甚至执行另一次击键.

更新[23/01]:我实际上想要做的不仅仅是暂停,我希望能够在自动化过程运行时与自动化流程进行通信并请求它暂停,跳过当前的销售订单,完全放弃甚至可能更多.

任何人都可以告诉我The Right Way(TM)来实现我想要的吗?

更多信息

以下是自动化工作原理的示例(我正在使用pywinauto库):

from pywinauto import application
app = application.Application()
app.start_("notepad")
app.Notepad.TypeKeys("abcdef")
Run Code Online (Sandbox Code Playgroud)

更新[25/01]:在我的应用程序工作几天后,我注意到我并没有真正使用pywinauto那么多,现在我只是用它来查找窗口然后我直接SendKeysCtypes.SendKeys用来模拟键盘输入和win32api模拟鼠标输入的功能.

到目前为止我发现了什么

以下是我在寻找答案时遇到的一些方法:

  1. 我可以在两个单独的进程中分离自动化功能和接口+热键监听器.我们将前者称为"automator",将后者称为"manager".然后,管理器可以通过向进程发送SIGSTOP信号并使用SIGCONT信号(或Windows等效的SuspendThread/ResumeThread)取消暂停来暂停执行automator .

    为了能够更新用户界面,自动机将需要通过某种IPC机制通知管理器其进展.

    缺点:

    • 使用SIGSTOP会不会有点苛刻?它甚至可以正常工作吗?很多人似乎都在反对它,甚至称之为"危险".

    • 我担心实施IPC机制会有点复杂.另一方面,我与DBus合作过,实施起来并不难.

  2. 第二种方法和许多人似乎建议的方法涉及使用线程,并且基本归结为以下(简化):

    while True:
        if self.pause: # pause
        # Do the work...
    
    Run Code Online (Sandbox Code Playgroud)

    但是,这样做似乎只会在没有更多工作要做之后暂停.我认为这种方法可行的唯一方法是将工作(整个自动化过程)划分为较小的工作段(即任务).在开始新任务之前,工作线程将检查它是否应该暂停并等待.

    缺点:

    • 似乎是将工作划分为较小部分的实现,例如上面的部分,将是非常丑陋的代码(美学上).

      我想象的方式,所有语句都将转换为类似于:( queue.put((function, args))例如queue.put((app.Notepad.TypeKeys, "abcdef")))并且您将使自动化过程线程贯穿任务并在开始任务之前不断检查暂停状态.那不可能是正确的......

    • 该程序实际上不会停止在其轨道上,但在实际暂停之前首先完成一项任务(无论多么小).

取得了进展

更新[23/01]:我已经通过提到的SuspendThread/ResumeThread功能使用第一种方法实现了我的应用程序的一个版本.到目前为止,这似乎工作非常好,也允许我编写自动化的东西,就像你写任何其他脚本一样.我遇到的唯一怪癖是键盘修饰符(CTRL,ALT,SHIFT)在暂停时"卡住".我可以轻松解决的问题.

我还使用第二种方法(线程和信号/消息传递)编写了测试并实现了暂停功能.然而,它看起来真的很丑陋(检查暂停标志和与"做工作"相关的一切).所以如果有人能给我一个类似于第二种方法的正确例子,我会很感激.

相关问题

Win*_*ert 2

我不知道 pywinauto。但我假设您有一个类似 Application 类的东西,您可以获取该类,并具有 SendKeys/SendMouseEvent/etc 之类的方法来执行操作。

创建您自己的 MyApplication 类,其中包含对 pywinauto 的应用程序类的引用。提供相同的方法,但在每个方法之前检查是否发生了暂停事件。如果有,您可以跳转到处理暂停事件的代码。这样,您每次引发事件时都会检查是否有暂停,但这一切都由一个类处理,而无需在整个代码中暂停。

一旦检测到暂停,您就可以按照自己喜欢的方式处理它。例如,您可以抛出异常来强制放弃当前任务。