使用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消息处理输入。改用
SendInputAPI(通过pywin32或ctypes调用),模拟硬件级输入,兼容性更强。 - 确保控件获得焦点:找到输入控件句柄后,先发送
WM_SETFOCUS消息让控件激活,再发送输入消息。
内容的提问来源于stack exchange,提问作者Suchindra Chandrahas
相关产品推荐
相关产品推荐

