将击键发送到特定窗口(在后台),但同时做其他事情[重复]

Posted

技术标签:

【中文标题】将击键发送到特定窗口(在后台),但同时做其他事情[重复]【英文标题】:Send keystrokes to a specific window (in background), but do something else in the meantime [duplicate] 【发布时间】:2019-07-19 20:00:38 【问题描述】:

这段代码(灵感来自 Which is the easiest way to simulate keyboard and mouse on Python?)打开记事本并每秒发送 A、B、C、D、...、Z 键:

import win32com.client, time
shell = win32com.client.Dispatch("WScript.Shell")
shell.Run('Notepad')
time.sleep(1)
shell.AppActivate("Notepad")
for i in range(65,91):
    shell.SendKeys(chr(i))
    time.sleep(1)

我想让此操作在后台继续,继续我在计算机上的工作,并将击键发送到记事本(在后台)

问题:如果我同时打开另一个应用程序(例如:浏览器),击键被发送到当前活动窗口,我不想要!

问题:如何让 Python 将击键发送到 notepad.exe,即使此应用程序不在前台?

上下文:我正在自动化一些长时间的任务,要求我的 Python 脚本在大约 15 分钟内将击键发送到 app.exe(在后台),但我想在此期间用计算机做一些其他事情。

注意:更一般地说,我感兴趣的用例是进程 app.exe 可能打开对话框、关闭对话框、打开其他窗口的情况,因此解决方案应该能够将击键发送到 进程的活动窗口。因此,像here 这样具有固定 hWnd 的解决方案不能直接工作。

【问题讨论】:

使用 UI 自动化自动化其他程序 谢谢@DavidHeffernan。您能否在几行中提供一个简单的示例(在记事本案例中),以展示如何从 Python 脚本中使用它? 不,我不会有,但我确信可以找到。也就是说,您可以更轻松地使用不同的语言进行实验。至少要说服自己这甚至是可能的。毫无疑问,记事本不是最终产品的预期目标。 记事本没有这样的功能。 Word 有一个用于自动化的 IDispatch 接口,但使用 C++ 可能更可行。其实不费吹灰之力,还是自己编辑文字比较好(如果是记事本的话)。 @Michael 许多应用程序可以自动化,而无需它们以办公方式提供定制的自动化界面。您的 cmets 非常具有误导性。 【参考方案1】:

为了将 Keystroke 发送到任何应用程序窗口,而不激活应用程序以获得输入焦点。我们必须首先获取 windows 处理程序。这需要 Windows API FindWindowFindWindowsEx。首先通过FindWindow获取应用程序的Top Level窗口句柄。然后使用FindWindowsEx获取子窗口或控件的句柄接收键。 因为应用程序的顶部窗口并不总是接受Keystroke的窗口(如notepad.exe,实际接受Keystroke的窗口是Notepad主窗口下的Edit控件),所以可以通过ClassID或Caption找到。

假设目标窗口的句柄已经拿到(hwnd),则将key消息发送到PostMessage的窗口。

对于普通字符键,直接使用WM_CHAR消息是最简单的,如下:

PostMessage(hwnd, WM_CHAR, 'a', 0);

对于非正常字符键,如功能键、方向键等,应使用WM_KEYDOWNWM_KEYUP消息如下:

VirtualKey = MapVirtualKeyA(VK_RIGHT, 0);
PostMessage(hwnd, WM_KEYDOWN, VK_RIGHT, 0x0001|VirtualKey<<16);
PostMessage(hwnd, WM_KEYUP, VK_RIGHT, 0x0001|VirtualKey<<16|0xC0<<24);

最后一个参数(lParam)的详细信息可以参考msdn。

对于“Shift/Ctrl”键,示例:

keybd_event(VK_SHIFT, 0, 0, 0);
PostMessage(hwnd, WM_KEYDOWN, 0x41, 0x001E0001);
PostMessage(hwnd, WM_KEYUP, 0x41, 0xC01E0001);
keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);

对于“Alt”键,属于系统按钮,使用WM_SYSKEYDOWN/WM_SYSKEYUP消息。示例:

PostMessage(hwnd, WM_SYSKEYDOWN, VK_F4, 0x003E0001 |0x20000000);
PostMessage(hwnd, WM_SYSKEYUP, VK_F4, 0xC03E0001 | 0x20000000);

0x20000000 表示上下文代码,如果“Alt”键按下,则值为 1。

【讨论】:

谢谢你的回答,我试试这个。您能否详细说明为什么在您的示例中使用0x0001|VirtualKey&gt;&gt;160x0001|VirtualKey&gt;&gt;16|C0&gt;&gt;240x001E00010xC01E00010x003E0001 |0x200000000xC03E0001 | 0x20000000?我看了你链接的 MSDN 帖子,但还是有点神秘。 这些是虚拟键状态和标志。 0x0001(0-15 bits)表示重复消息的数量,VirtualKey0xC01E0001中的1E(VirtualKey of 'a')和3E(VirtualKey 0x003E0001 中的 "F4") 表示扫描仪代码(16-23 位),C00xC0(1100,0000) 的写入错误,我已修复。它代表状态的 24-31 位。所以它需要“>>24”。保留 25-28 位,设置为零,第 29 位为零,因为Alt 键未关闭。第 30 位为 1,因为先前的键状态已关闭。由于密钥被释放,第 31 位为 1。 0x20000000 表示第 29 位设置为 1,因为按住 Alt 键。 不适用于我的特定用例,但很有趣! 那些是右移吗?除非我遗漏了某些东西,否则 0xc0>>24 最终会变成 0,因为所有位都已被清除,因此与它进行 ORing 似乎毫无意义。在我的解释器中运行它会给我 0x0,而运行左移 (0xC0

以上是关于将击键发送到特定窗口(在后台),但同时做其他事情[重复]的主要内容,如果未能解决你的问题,请参考以下文章

将击键发送到 PowerPoint 窗口

通过 JNA 向隐藏窗口发送击键

Vbscript从批处理文件运行而不将击键发送到批处理文件

将快速文本输入发送到另一个进程(窗口)

关于Windows更新窗口内容的问题(作为一个实验,效果很明显)

从 Winforms 应用程序发送全局击键/伪造全局热键