将击键发送到特定窗口(在后台),但同时做其他事情[重复]
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 FindWindow
和 FindWindowsEx
。首先通过FindWindow
获取应用程序的Top Level窗口句柄。然后使用FindWindowsEx
获取子窗口或控件的句柄接收键。
因为应用程序的顶部窗口并不总是接受Keystroke的窗口(如notepad.exe,实际接受Keystroke的窗口是Notepad主窗口下的Edit控件),所以可以通过ClassID或Caption找到。
假设目标窗口的句柄已经拿到(hwnd),则将key消息发送到PostMessage
的窗口。
对于普通字符键,直接使用WM_CHAR消息是最简单的,如下:
PostMessage(hwnd, WM_CHAR, 'a', 0);
对于非正常字符键,如功能键、方向键等,应使用WM_KEYDOWN
和WM_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>>16
、0x0001|VirtualKey>>16|C0>>24
、0x001E0001
、0xC01E0001
、0x003E0001 |0x20000000
或0xC03E0001 | 0x20000000
?我看了你链接的 MSDN 帖子,但还是有点神秘。
这些是虚拟键状态和标志。
0x0001
(0-15 bits)表示重复消息的数量,VirtualKey
,0xC01E0001
中的1E
(VirtualKey of 'a')和3E
(VirtualKey 0x003E0001
中的 "F4") 表示扫描仪代码(16-23 位),C0
是 0xC0
(1100,0000) 的写入错误,我已修复。它代表状态的 24-31 位。所以它需要“>>24”。保留 25-28 位,设置为零,第 29 位为零,因为Alt
键未关闭。第 30 位为 1,因为先前的键状态已关闭。由于密钥被释放,第 31 位为 1。 0x20000000
表示第 29 位设置为 1,因为按住 Alt
键。
不适用于我的特定用例,但很有趣!
那些是右移吗?除非我遗漏了某些东西,否则 0xc0>>24 最终会变成 0,因为所有位都已被清除,因此与它进行 ORing 似乎毫无意义。在我的解释器中运行它会给我 0x0,而运行左移 (0xC0
以上是关于将击键发送到特定窗口(在后台),但同时做其他事情[重复]的主要内容,如果未能解决你的问题,请参考以下文章