feat: 添加模拟器管理器

This commit is contained in:
MoeSnowyFox
2025-09-27 03:32:43 +08:00
parent 632ad33562
commit 7b0307070e
6 changed files with 1285 additions and 0 deletions

View File

@@ -0,0 +1,156 @@
import ctypes
import asyncio
# 加载 user32.dll
user32 = ctypes.windll.user32
# Windows 消息常量
WM_KEYDOWN = 0x0100
WM_KEYUP = 0x0101
async def post_key_to_hwnd(hwnd: int, vk_code: int) -> bool:
"""
使用 PostMessage 向指定窗口句柄发送一个完整的按键(按下 + 释放)。
!由于 PostMessage 是异步的,并不能保证按键一定被处理。
参数:
hwnd (int): 目标窗口句柄
vk_code (int): 虚拟键码
注意:
- 此函数不检查 hwnd 是否有效,也不等待消息处理(异步)。
- 如果 hwnd 无效PostMessage 会静默失败。
"""
if hwnd <= 0:
raise ValueError("hwnd 必须是正整数")
if not (0 <= vk_code <= 0xFFFF):
raise ValueError("vk_code 必须是有效的虚拟键码0~65535")
user32.PostMessageW(hwnd, WM_KEYDOWN, vk_code, 0)
user32.PostMessageW(hwnd, WM_KEYUP, vk_code, 0)
return True
async def send_key_to_hwnd_sync(hwnd: int, vk_code: int) -> bool:
"""
使用 SendMessage 向指定窗口句柄同步发送一个完整的按键(按下 + 释放)。
参数:
hwnd (int): 目标窗口句柄
vk_code (int): 虚拟键码
返回:
bool:
- 对于 SendMessage返回值是目标窗口过程WindowProc对消息的返回值。
- 通常非零表示成功,但具体含义由目标窗口定义。
- 如果 hwnd 无效,会返回 0。
注意:
- 此调用是**同步阻塞**的:当前线程会等待目标窗口处理完消息才返回。
- 如果目标窗口无响应hung当前程序也会卡住
"""
if hwnd <= 0:
raise ValueError("hwnd 必须是正整数")
if not (0 <= vk_code <= 0xFFFF):
raise ValueError("vk_code 必须是有效的虚拟键码0~65535")
# 发送 WM_KEYDOWN
result_down = user32.SendMessageW(hwnd, WM_KEYDOWN, vk_code, 0)
# 发送 WM_KEYUP
result_up = user32.SendMessageW(hwnd, WM_KEYUP, vk_code, 0)
return bool(result_down and result_up)
async def post_keys_to_hwnd(
hwnd: int, vk_codes: list[int], hold_time: float = 0.05
) -> bool:
"""
使用 PostMessage 向指定窗口句柄同时发送多个按键
!由于 PostMessage 是异步的,并不能保证按键一定被处理。
参数:
hwnd (int): 目标窗口句柄
vk_codes (List[int]): 虚拟键码列表
hold_time (float): 按键保持时间(秒),默认 0.05 秒
返回:
bool: 总是返回 TruePostMessage 不提供错误反馈)
注意:
- 此函数不检查 hwnd 是否有效,也不等待消息处理(异步)。
- 如果 hwnd 无效PostMessage 会静默失败。
- 按键顺序:先按下所有键,等待,然后按相反顺序释放所有键。
"""
if hwnd <= 0:
raise ValueError("hwnd 必须是正整数")
if not vk_codes:
raise ValueError("vk_codes 不能为空")
# 验证所有虚拟键码
for vk_code in vk_codes:
if not (0 <= vk_code <= 0xFFFF):
raise ValueError(f"vk_code {vk_code} 必须是有效的虚拟键码0~65535")
# 按下所有按键
for vk_code in vk_codes:
user32.PostMessageW(hwnd, WM_KEYDOWN, vk_code, 0)
# 保持按键状态
await asyncio.sleep(hold_time)
# 按相反顺序释放所有按键(模拟真实按键行为)
for vk_code in reversed(vk_codes):
user32.PostMessageW(hwnd, WM_KEYUP, vk_code, 0)
return True
async def post_keys_to_hwnd_sync(
hwnd: int, vk_codes: list[int], hold_time: float = 0.05
) -> bool:
"""
使用 SendMessage 向指定窗口句柄同步发送多个按键
先按下所有按键,等待指定时间,然后释放所有按键。
参数:
hwnd (int): 目标窗口句柄
vk_codes (List[int]): 虚拟键码列表
hold_time (float): 按键保持时间(秒),默认 0.05 秒
返回:
bool: 如果所有消息都成功发送则返回 True
注意:
- 此调用是**同步阻塞**的:当前线程会等待目标窗口处理完每个消息才继续。
- 如果目标窗口无响应hung当前程序也会卡住
- 按键顺序:先按下所有键,等待,然后按相反顺序释放所有键。
"""
if hwnd <= 0:
raise ValueError("hwnd 必须是正整数")
if not vk_codes:
raise ValueError("vk_codes 不能为空")
# 验证所有虚拟键码
for vk_code in vk_codes:
if not (0 <= vk_code <= 0xFFFF):
raise ValueError(f"vk_code {vk_code} 必须是有效的虚拟键码0~65535")
# 按下所有按键
down_results = []
for vk_code in vk_codes:
result = user32.SendMessageW(hwnd, WM_KEYDOWN, vk_code, 0)
down_results.append(result)
# 保持按键状态
await asyncio.sleep(hold_time)
# 按相反顺序释放所有按键(模拟真实按键行为)
up_results = []
for vk_code in reversed(vk_codes):
result = user32.SendMessageW(hwnd, WM_KEYUP, vk_code, 0)
up_results.append(result)
# 如果所有按键操作都成功,则返回 True
return all(down_results) and all(up_results)