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

如何通过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,提问作者梦断难寻

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 14:17:02