如何通过PostMessageW向Tauri发送点击消息?问题求助
问题分析与解决
1. 窗口句柄定位错误
你当前用GetWindow(hwnd, GW_CHILD)直接取主窗口的第一个子窗口,这不一定是WebView2的实际渲染窗口。Tauri的窗口结构里,主窗口下可能包含多个子控件(比如标题栏、边框容器),WebView2的渲染窗口通常是更深层的子窗口,且可通过类名WebView2Host识别。
修正查找逻辑,改用EnumWindows枚举顶层窗口,找到目标窗口后再用EnumChildWindows枚举其子窗口,精准定位WebView2:
use windows::Win32::UI::WindowsAndMessaging::{EnumChildWindows, EnumWindows, GetClassNameW, GetWindowTextW}; unsafe fn get_webview_hwnd() -> Foundation::HWND { let mut target_hwnd = Foundation::HWND(0); EnumWindows(Some(enum_windows_callback), &mut target_hwnd as *mut _ as _); target_hwnd } unsafe extern "system" fn enum_windows_callback(hwnd: Foundation::HWND, lparam: Foundation::LPARAM) -> Foundation::BOOL { let target_hwnd = lparam as *mut Foundation::HWND; let mut title_buf = [0u16; 256]; GetWindowTextW(hwnd, &mut title_buf); let title = String::from_utf16_lossy(&title_buf).trim().to_string(); if title == "mhxyh5" { EnumChildWindows(hwnd, Some(enum_child_callback), target_hwnd as _); return Foundation::BOOL(0); // 找到顶层窗口后停止枚举 } Foundation::BOOL(1) } unsafe extern "system" fn enum_child_callback(hwnd: Foundation::HWND, lparam: Foundation::LPARAM) -> Foundation::BOOL { let target_hwnd = lparam as *mut Foundation::HWND; let mut class_buf = [0u16; 256]; GetClassNameW(hwnd, &mut class_buf); let class_name = String::from_utf16_lossy(&class_buf).trim().to_string(); if class_name == "WebView2Host" { *target_hwnd = hwnd; return Foundation::BOOL(0); // 找到WebView窗口后停止枚举 } Foundation::BOOL(1) }
2. 坐标未处理DPI缩放
Tauri默认启用DPI感知,窗口客户区坐标会受DPI缩放影响。你直接计算的坐标是物理像素,而WebView2使用逻辑像素,需要先转换:
use windows::Win32::Graphics::Gdi::GetDpiForWindow; // 在发送消息前处理坐标 let dpi = GetDpiForWindow(hwnd); let scale_factor = dpi as f64 / 96.0; // 96为系统默认DPI let logical_x = (100 as f64 / scale_factor) as u32; let logical_y = (10 as f64 / scale_factor) as u32; let position = (logical_x << 16) | logical_y; let lparam = Foundation::LPARAM(position as isize);
3. WebView2不响应WM_LBUTTONDOWN/UP消息
WebView2内部有独立的输入处理机制,直接发送窗口消息无法触发网页点击事件。更可靠的方式是用SendInput模拟真实鼠标输入:
use windows::Win32::UI::Input::KeyboardAndMouse::{SendInput, INPUT, INPUT_0, MOUSEINPUT, MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MOVE}; use windows::Win32::UI::WindowsAndMessaging::ClientToScreen; use windows::Win32::System::LibraryLoader::GetSystemMetrics; unsafe fn simulate_mouse_click(hwnd: Foundation::HWND, client_x: i32, client_y: i32) { // 将客户区坐标转换为屏幕坐标 let mut point = Foundation::POINT { x: client_x, y: client_y }; ClientToScreen(hwnd, &mut point); // 移动鼠标到目标位置 let move_input = INPUT { r#type: 0, // INPUT_MOUSE Anonymous: INPUT_0 { mi: MOUSEINPUT { dx: point.x * 65535 / GetSystemMetrics(0), dy: point.y * 65535 / GetSystemMetrics(1), mouseData: 0, dwFlags: MOUSEEVENTF_MOVE, time: 0, dwExtraInfo: 0, }, }, }; // 鼠标按下 let down_input = INPUT { r#type: 0, Anonymous: INPUT_0 { mi: MOUSEINPUT { dx: 0, dy: 0, mouseData: 0, dwFlags: MOUSEEVENTF_LEFTDOWN, time: 0, dwExtraInfo: 0, }, }, }; // 鼠标抬起 let up_input = INPUT { r#type: 0, Anonymous: INPUT_0 { mi: MOUSEINPUT { dx: 0, dy: 0, mouseData: 0, dwFlags: MOUSEEVENTF_LEFTUP, time: 0, dwExtraInfo: 0, }, }, }; let inputs = [move_input, down_input, up_input]; SendInput(&inputs); }
4. 初始化顺序问题
你在main里先启动自动化线程,此时Tauri窗口还未创建,第一次循环可能找不到窗口。调整为窗口创建完成后再启动线程:
fn main() { tauri::Builder::default() .setup(|app| { let window = app.get_window("main").unwrap(); // 对应tauri.conf.json里的窗口label std::thread::spawn(move || { std::thread::sleep(Duration::from_secs(10)); unsafe { let hwnd = get_webview_hwnd(); simulate_mouse_click(hwnd, 100, 10); } }); Ok(()) }) .run(tauri::generate_context!()) .expect("error while running tauri application"); }
替代方案:直接调用WebView2 API触发点击
如果上述方法仍无效,可直接通过Tauri的WebView API执行JavaScript触发点击,这是最可靠的方式:
// 在setup的窗口回调中执行 window.eval(r#"document.elementFromPoint(100,10).click();"#).unwrap();
内容的提问来源于stack exchange,提问作者梦断难寻
相关产品推荐
相关产品推荐

