Rust中如何重置等待/睡眠时间?适配OSD弹窗按键场景
解决EWW OSD弹窗的延迟关闭与计时器重置问题
核心思路
绝对不能用阻塞式的sleep(),否则会卡死整个按键监听逻辑。必须依赖异步定时器结合程序的事件循环实现延迟关闭,同时通过维护定时器句柄,实现多次按键时的计时器重置。
问题1:实现非阻塞延迟关闭弹窗
使用程序框架提供的异步定时器API(比如GLib的timeout_add、Rust的事件循环定时器、Python的GLib定时器),将关闭弹窗的任务加入事件队列,等待N毫秒后执行,完全不会阻塞当前的按键监听流程。
问题2:弹窗关闭前多次按键重置计时器
需要保存当前活跃的定时器句柄(ID/引用),每次触发按键时:
- 若存在未触发的旧定时器,先取消它;
- 重新启动一个新的N毫秒定时器;
- 调用
osd_open确保弹窗处于打开状态(EWW的widget重复打开通常不会产生多窗口)。
代码示例(Rust + GLib)
假设程序基于GLib事件循环(Linux桌面应用常用):
// 在全局或结构体中维护定时器句柄 let mut vol_osd_timer: Option<glib::SourceId> = None; if event.event_type == KeyPress(VOL_DN) { // 打开音量OSD弹窗 osd_open("osd-vol"); // 取消之前未触发的定时器 if let Some(timer_id) = vol_osd_timer.take() { glib::source_remove(timer_id); } // 启动新的异步定时器,N毫秒后关闭弹窗 vol_osd_timer = Some(glib::timeout_add_local( std::time::Duration::from_millis(N), move || { osd_close("osd-vol"); // 返回Break表示定时器仅执行一次 glib::ControlFlow::Break }, )); }
代码示例(Python + PyGObject)
import gi gi.require_version('GLib', '2.0') from gi.repository import GLib # 全局变量保存定时器ID vol_osd_timer = None def handle_volume_down(event): global vol_osd_timer # 打开OSD弹窗 osd_open("osd-vol") # 取消旧定时器 if vol_osd_timer is not None: GLib.source_remove(vol_osd_timer) vol_osd_timer = None # 定义延迟关闭的回调函数 def close_osd(): osd_close("osd-vol") return False # 仅执行一次 # 启动新定时器(N为毫秒数) vol_osd_timer = GLib.timeout_add(N, close_osd)
关键注意事项
- 优先使用与主事件循环集成的异步定时器,避免手动创建线程(线程会增加复杂度,易引发竞态问题);
- 确认
osd_open重复调用不会产生多窗口(EWW默认支持单实例widget,重复执行eww open不会重复创建); - 若使用其他框架(比如Qt的
QTimer),核心逻辑一致:维护定时器实例,每次按键时停止旧定时器并启动新的。
内容的提问来源于stack exchange,提问作者candifloss__
相关产品推荐
相关产品推荐

