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

如何在应用未聚焦时通过winit接收DeviceEvent?

Windows平台下让Rust winit后台接收DeviceEvent的方法

winit默认仅在窗口聚焦时接收设备事件,要实现后台接收,需要结合Windows原生API修改输入监听逻辑,步骤如下:

1. 获取窗口的HWND句柄

先从winit窗口中提取Windows平台的窗口句柄(HWND),后续API调用依赖该句柄:

use winit::window::Window;
use raw_window_handle::RawWindowHandle;

fn get_hwnd(window: &Window) -> Option<isize> {
    match window.raw_window_handle() {
        RawWindowHandle::Win32(win32_handle) => Some(win32_handle.hwnd as isize),
        _ => None,
    }
}

2. 注册原始输入设备

通过Windows的RegisterRawInputDevicesAPI注册鼠标输入,指定RIDEV_INPUTSINK标记,允许窗口在未聚焦时接收输入:

use winapi::{
    shared::minwindef::{BOOL, DWORD, UINT},
    um::winuser::{
        RegisterRawInputDevices, RAWINPUTDEVICE, RIDEV_INPUTSINK, RIM_TYPEMOUSE,
    },
};
use std::ptr;

fn register_raw_input(hwnd: isize) -> bool {
    let rid = RAWINPUTDEVICE {
        usUsagePage: 0x01, // 通用桌面控件页面
        usUsage: 0x02,     // 鼠标设备
        dwFlags: RIDEV_INPUTSINK, // 允许后台接收输入
        hwndTarget: hwnd as _,
    };

    unsafe {
        RegisterRawInputDevices(
            &rid,
            1,
            std::mem::size_of::<RAWINPUTDEVICE>() as UINT,
        ) != 0
    }
}

3. 在事件循环中处理原始输入

winit的DeviceEvent不会自动包含后台输入,需通过WindowEvent::RawWindowEvent拦截Windows原生消息,处理WM_INPUT事件:

use winit::event::{Event, WindowEvent};
use winapi::um::winuser::WM_INPUT;

// 事件循环示例
for event in event_loop.run() {
    match event {
        Event::WindowEvent { event, .. } => match event {
            WindowEvent::RawWindowEvent { raw_window_event, .. } => {
                if let raw_window_handle::RawWindowEvent::Win32(msg) = raw_window_event {
                    if msg.message == WM_INPUT {
                        // 此处添加原始鼠标输入的解析逻辑
                        // 可参考Windows API文档处理RAWINPUT结构体
                        println!("后台收到鼠标输入");
                    }
                }
            }
            _ => {}
        },
        _ => {}
    }
}

依赖与注意事项

  • 在Cargo.toml中添加必要依赖:
    [dependencies]
    winit = "0.29"
    raw-window-handle = "0.5"
    winapi = { version = "0.3", features = ["winuser", "minwindef"] }
    
  • 相比全局钩子,原始输入注册的方式性能更优,且无需额外DLL
  • 若使用全局钩子(SetWindowsHookExW),需注意钩子函数的线程安全与资源释放

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 05:52:41