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

使用win32api.PostMessage无法向非活动窗口发送字符键的问题

问题描述

在Windows系统上使用Python编写了如下代码,通过win32api.PostMessage向非活动窗口发送按键:

import win32gui
import win32con
import win32api
import time
import win32com.client

def send_key(hwnd, key):
    win32api.PostMessage(hwnd, win32con.WM_KEYDOWN, key, 0)
    time.sleep(1)
    win32api.PostMessage(hwnd, win32con.WM_KEYUP, key, 0)
   
def send_key_comb(hwnd, key1, key2):
     win32api.PostMessage(hwnd, win32con.WM_KEYDOWN, key1, 0)
     time.sleep(1)
     win32api.PostMessage(hwnd, win32con.WM_KEYDOWN, key2, 0)
     time.sleep(1)
     win32api.PostMessage(hwnd, win32con.WM_KEYUP, key1, 0)
     time.sleep(1)
     win32api.PostMessage(hwnd, win32con.WM_KEYUP, key2, 0)
     time.sleep(1)
     

def get_window_handle():
    hwndMain = win32gui.FindWindow(None, "MyApp - V2.2")
    #
    # Notepad example - working
    #
    # hwndMain = win32gui.FindWindow(None, "*Untitled - Notepad")
    #
    return hwndMain
     
def send_str(hwnd, strng):
    for c in strng:
        send_key(hwnd, ord(c))
       
def send_tabs(hwnd, n):
    for i in range(n):
        send_key(hwnd, win32con.VK_TAB)
        
if __name__ == "__main__":
    hwnd = get_window_handle()
    send_str(hwnd, "abcd")
    #
    # Tried the below also, but not working
    #
    # child =  win32gui.GetWindow(hwnd, win32con.GW_CHILD)
    # send_str(child, "abcd")

该脚本可向记事本发送字符,但无法向目标应用“MyApp - V2.2”发送字符;不过能向目标应用发送Tab键,尝试获取子窗口发送字符也无效,寻求解决思路。


解决思路
  • 定位正确的输入控件句柄:GW_CHILD仅返回第一个子窗口,目标应用的输入控件可能是更深层级的子控件。用*Spy++*工具精准定位到实际接收输入的文本框或控件句柄,而非仅使用主窗口或第一个子窗口。
  • 改用WM_CHAR消息发送字符:WM_KEYDOWN传递的是虚拟键码,而字符输入应使用WM_CHAR消息(传递字符的ASCII/Unicode值),且SendMessage同步消息的兼容性优于PostMessage。修改字符发送逻辑:
    def send_char(hwnd, char):
        win32api.SendMessage(hwnd, win32con.WM_CHAR, ord(char), 0)
    
    然后更新send_str函数调用send_char而非send_key。
  • 完善WM_KEYDOWN/WM_KEYUP的参数:当前传递的lParam为0,部分应用会忽略参数不全的按键消息。用MapVirtualKey获取扫描码构造合法的lParam:
    def send_key(hwnd, key):
        scan_code = win32api.MapVirtualKey(key, 0)
        # 构造按下时的lParam:扫描码左移16位 + 按下标志
        lparam_down = (scan_code << 16) | 1
        win32api.PostMessage(hwnd, win32con.WM_KEYDOWN, key, lparam_down)
        time.sleep(0.1)
        # 构造抬起时的lParam:扫描码左移16位 + 抬起标志
        lparam_up = (scan_code << 16) | 0xC0000001
        win32api.PostMessage(hwnd, win32con.WM_KEYUP, key, lparam_up)
    
  • 尝试硬件级输入模拟:若目标应用基于Qt、WPF等框架,可能不依赖传统Windows消息处理输入。改用SendInput API(通过pywin32或ctypes调用),模拟硬件级输入,兼容性更强。
  • 确保控件获得焦点:找到输入控件句柄后,先发送WM_SETFOCUS消息让控件激活,再发送输入消息。

内容的提问来源于stack exchange,提问作者Suchindra Chandrahas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 10:01:58