fix(hotkey): 250ms debounce on pressed-edge dispatch
避免微动开关回弹 / 用户手抖双击造成的空转写报错和 ASR session 抢资源: 相邻 < 250ms 的 press 边沿直接丢弃,记 log。 - coordinator.rs: Inner 新增 last_hotkey_dispatch_at: Mutex<Option<Instant>> - coordinator/dictation.rs: HOTKEY_DEBOUNCE 常量 + handle_pressed_edge 入口检查 与 hotkey_trigger_held 互补:held 防 press-without-release,本检查防 press-release-press 三连过快。每个有效边沿都会更新时间戳;用户正常使用 (不会快于 4 次/秒)不会触发。
This commit is contained in:
1 parent
e3a6c44d4d
commit
60ab2418bd
2 files changed
+31
No files matched your search
@@ -119,6 +119,11 @@ struct Inner {
|
||||
hotkey: Mutex<Option<HotkeyMonitor>>,
|
||||
hotkey_status: Mutex<HotkeyStatus>,
|
||||
hotkey_trigger_held: AtomicBool,
|
||||
/// 防抖时间戳:handle_pressed_edge 入口检查与本字段的距离,< 250ms 的边沿直接
|
||||
/// 丢弃(误触双击 / 微动开关回弹 / 用户连点过快造成的空转写报错)。
|
||||
/// 与 `hotkey_trigger_held` 互补 —— held 防 press-without-release,本字段防
|
||||
/// press-release-press 三连过快。
|
||||
last_hotkey_dispatch_at: Mutex<Option<std::time::Instant>>,
|
||||
shortcut_recording_active: AtomicBool,
|
||||
/// 自定义组合键监听器(global-hotkey crate)。当 `prefs.hotkey.trigger == Custom` 时
|
||||
/// 代替 modifier-only 的 hotkey monitor。`None` 表示不使用自定义组合键或还没成功安装。
|
||||
@@ -199,6 +204,7 @@ impl Coordinator {
|
||||
hotkey: Mutex::new(None),
|
||||
hotkey_status: Mutex::new(HotkeyStatus::default()),
|
||||
hotkey_trigger_held: AtomicBool::new(false),
|
||||
last_hotkey_dispatch_at: Mutex::new(None),
|
||||
shortcut_recording_active: AtomicBool::new(false),
|
||||
combo_hotkey: Mutex::new(None),
|
||||
translation_hotkey: Mutex::new(None),
|
||||
@@ -245,6 +251,7 @@ impl Coordinator {
|
||||
hotkey: Mutex::new(None),
|
||||
hotkey_status: Mutex::new(HotkeyStatus::default()),
|
||||
hotkey_trigger_held: AtomicBool::new(false),
|
||||
last_hotkey_dispatch_at: Mutex::new(None),
|
||||
shortcut_recording_active: AtomicBool::new(false),
|
||||
combo_hotkey: Mutex::new(None),
|
||||
translation_hotkey: Mutex::new(None),
|
||||
|
||||
@@ -9,9 +9,33 @@ use super::qa::handle_qa_option_edge;
|
||||
use super::resources::*;
|
||||
use super::*;
|
||||
|
||||
/// 同一个 hotkey 边沿之间的最小间隔。低于此阈值的连按整体作为误触丢弃 ——
|
||||
/// 避免微动开关回弹 / 用户手抖双击造成的空转写报错和 ASR session 抢资源。
|
||||
const HOTKEY_DEBOUNCE: std::time::Duration = std::time::Duration::from_millis(250);
|
||||
|
||||
pub(super) async fn handle_pressed_edge(inner: &Arc<Inner>) {
|
||||
let was_held = inner.hotkey_trigger_held.swap(true, Ordering::SeqCst);
|
||||
if !was_held {
|
||||
// 防抖:相邻 < HOTKEY_DEBOUNCE 的边沿直接丢弃,记到 log 方便排查。
|
||||
// 与 `hotkey_trigger_held` 互补:held 防 press-without-release,本检查防
|
||||
// press-release-press 三连过快。每个有效边沿都会更新时间戳。
|
||||
let now = std::time::Instant::now();
|
||||
let too_soon = {
|
||||
let mut last = inner.last_hotkey_dispatch_at.lock();
|
||||
let drop = matches!(*last, Some(t) if now.duration_since(t) < HOTKEY_DEBOUNCE);
|
||||
if !drop {
|
||||
*last = Some(now);
|
||||
}
|
||||
drop
|
||||
};
|
||||
if too_soon {
|
||||
log::info!(
|
||||
"[coord] hotkey pressed edge debounced (< {} ms since last dispatch)",
|
||||
HOTKEY_DEBOUNCE.as_millis()
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// 路由:QA 浮窗可见时,rightOption 边沿走 QA;否则走主听写。详见 issue #118 v2。
|
||||
// 例外:dictation session 已经在跑(Starting / Listening / Processing / Inserting),
|
||||
// 即使 QA 浮窗被打开了,这条边沿也必须先走 dictation。否则 begin_qa_session 会
|
||||
|
||||
Reference in new issue
Block a user