You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

pywinauto send_keystrokes无法完全生效 如何扩展实现后台按键功能

实现方法

你需要的PressKey和ReleaseKey方法可以通过给pywinauto的win32窗口类做猴子补丁实现,不需要修改pywinauto源码。注意常规keybd_event接口只能给前台窗口发按键,要后台生效需要直接向目标窗口句柄投递键盘消息,不需要激活窗口。

首先在你的脚本开头加入以下补丁代码,整合ctypes调用Win32接口的逻辑:

import ctypes
from ctypes import wintypes
from pywinauto.controls.hwndwrapper import HwndWrapper

# Win32常量定义
WM_KEYDOWN = 0x0100
WM_KEYUP = 0x0101
KEYEVENTF_KEYUP = 0x0002
MAPVK_VK_TO_VSC = 0

# 加载系统API
user32 = ctypes.WinDLL('user32', use_last_error=True)
# 显式定义API参数类型,避免64位环境调用异常
user32.PostMessageW.argtypes = (wintypes.HWND, wintypes.UINT, wintypes.WPARAM, wintypes.LPARAM)
user32.PostMessageW.restype = wintypes.BOOL
user32.MapVirtualKeyW.argtypes = (wintypes.UINT, wintypes.UINT)
user32.MapVirtualKeyW.restype = wintypes.UINT
user32.keybd_event.argtypes = (wintypes.BYTE, wintypes.BYTE, wintypes.DWORD, ctypes.c_void_p)

def _build_key_lparam(vk_code, is_keyup=False):
    """构造键盘消息要求的lparam参数,和系统原生键盘事件参数格式对齐"""
    scan_code = user32.MapVirtualKeyW(vk_code, MAPVK_VK_TO_VSC)
    flag_bits = 0
    if is_keyup:
        flag_bits |= 1 << 30
        flag_bits |= 1 << 31
    return (scan_code << 16) | flag_bits

def press_key(self, vk_code, background=True):
    """
    按下指定虚拟键
    :param vk_code: 按键虚拟键码,例如0x31对应主键盘数字1
    :param background: 为True时后台向窗口投递消息,无需窗口前置;为False时用全局键盘事件,需要窗口在前台
    """
    if background:
        lparam = _build_key_lparam(vk_code, is_keyup=False)
        user32.PostMessageW(self.handle, WM_KEYDOWN, vk_code, lparam)
    else:
        scan_code = user32.MapVirtualKeyW(vk_code, MAPVK_VK_TO_VSC)
        user32.keybd_event(vk_code, scan_code, 0, 0)

def release_key(self, vk_code, background=True):
    """
    抬起指定虚拟键
    :param vk_code: 按键虚拟键码
    :param background: 为True时后台向窗口投递消息,无需窗口前置;为False时用全局键盘事件,需要窗口在前台
    """
    if background:
        lparam = _build_key_lparam(vk_code, is_keyup=True)
        user32.PostMessageW(self.handle, WM_KEYUP, vk_code, lparam)
    else:
        scan_code = user32.MapVirtualKeyW(vk_code, MAPVK_VK_TO_VSC)
        user32.keybd_event(vk_code, scan_code, KEYEVENTF_KEYUP, 0)

# 给pywinauto win32后端的窗口基类绑定方法
HwndWrapper.PressKey = press_key
HwndWrapper.ReleaseKey = release_key

使用说明

  • 补丁加载完成后,就可以按照你预期的方式直接调用方法,默认开启后台模式,不需要激活目标窗口:
from pywinauto import Application

appWavie = Application(backend='win32').connect(handle=790164)
Wavie = appWavie['Wavie']

VK_1 = 0x31
# 后台发送按键1的按下+抬起事件
Wavie.PressKey(VK_1)
Wavie.ReleaseKey(VK_1)
  • 针对你提到的无子窗口后台程序,PostMessage直接向顶层窗口发消息的模式兼容性远高于原生send_keystrokes——后者默认会尝试查找焦点子控件,无控件的程序上会出现部分区域失效的问题。
  • 如果遇到程序拦截窗口消息导致后台模式失效,可以切到前台模式,逻辑和ctypes实现的全局键盘事件完全一致:
Wavie.set_focus()
Wavie.PressKey(VK_1, background=False)
Wavie.ReleaseKey(VK_1, background=False)

注意:部分使用DirectInput读取输入的游戏、带反作弊的程序会拦截上述两种Win32层的按键模拟,这类场景需要驱动级输入方案,常规桌面程序都可以正常响应。

内容的提问来源于stack exchange,提问作者Wavilson Ferreira

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 05:06:20