Enigo 多屏幕下鼠标移动问题

March 25, 2025 / 栗何生 / 31阅读 / 0评论 / 分类: 代码段
enigo = "0.3.0"

该版本下,windows在多屏幕,分辨率不同,含有缩放的情况时,在鼠标移动到其他屏幕再通过程序进行鼠标位移,会导致鼠标移动到角落,无法实现正常的平移功能。

在move_mouse实现中使用的是

// 通过 main_display 获取 w 和 h
let w = unsafe { GetSystemMetrics(SM_CXSCREEN) };
let h = unsafe { GetSystemMetrics(SM_CYSCREEN) };

let w = w as i64 - 1;
let h = h as i64 - 1;
let x = x as i64;
let y = y as i64;
let x = (x * 65535 + w / 2 * x.signum()) / w;
let y = (y * 65535 + h / 2 * y.signum()) / h;
// TODO: Check if we should use MOUSEEVENTF_VIRTUALDESK too
(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE, x as i32, y as i32)

// 这里可以看到作者有考虑使用MOUSEEVENTF_VIRTUALDESK这个类型进行鼠标移动

重写move_mouse实现

// 同参考网站中可以看到使用这个类型,可以修复这个问题
fn virtual_screen() -> InputResult<(i32, i32, i32, i32)> {
    let x = unsafe { GetSystemMetrics(SM_XVIRTUALSCREEN) };  // 最左边的屏幕X坐标
    let y = unsafe { GetSystemMetrics(SM_YVIRTUALSCREEN) };  // 最上边的屏幕Y坐标
    let w = unsafe { GetSystemMetrics(SM_CXVIRTUALSCREEN) };  // 虚拟桌面总宽度
    let h = unsafe { GetSystemMetrics(SM_CYVIRTUALSCREEN) };  // 虚拟桌面总高度
    Ok((x, y, w, h))
}
let (virtual_x, virtual_y, virtual_w, virtual_h) = virtual_screen()?;
let x = x as i64;
let y = y as i64;
let w = virtual_w as i64 - 1;
let h = virtual_h as i64 - 1;

// 修正归一化计算,基于整个虚拟桌面
let x = ((x - virtual_x as i64) * 65535 + w / 2 * x.signum()) / w;
let y = ((y - virtual_y as i64) * 65535 + h / 2 * y.signum()) / h;
// 使用 MOUSEEVENTF_VIRTUALDESK,确保鼠标在整个虚拟屏幕内移动
(MOUSEEVENTF_MOVE  | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK, x as i32, y as i32)

对move_mouse添加一个新的实现或者通过上面的方式进行重写,测试后windows可以正常在多屏幕,缩放和分辨率不同的情况下,正常移动鼠标位置。

参考

How to move the mouse cursor through WinAPI in a multi-monitor setup

文章作者:栗何生

文章链接:https://ronan.ink/archives/enigo-duo-ping-mu-xia-shu-biao-yi-dong-wen-ti

版权声明:本博客所有文章除特别声明外,均采用CC BY-NC-SA 4.0 许可协议,转载请注明出处!


评论