fix: make capsule click-through outside recording

This commit is contained in:
Cooper-X-Oak committed 2026-05-02 00:54:37 +08:00
1 parent 08e48cc852
commit 27dbeadcfd
2 files changed
+52 -7

No files matched your search

@@ -6,12 +6,48 @@ function assertEqual(actual, expected, name) {
}
}
const raw = await readFile(new URL('../src-tauri/tauri.conf.json', import.meta.url), 'utf-8');
const config = JSON.parse(raw);
const mainWindow = config.app.windows.find((window) => window.label === 'main');
if (!mainWindow) {
throw new Error('main window config missing');
function assertMatch(source, pattern, name) {
if (!pattern.test(source)) {
throw new Error(`${name}: pattern ${pattern} not found`);
}
}
assertEqual(mainWindow.decorations, false, 'windows main window should use only custom titlebar');
const raw = await readFile(new URL('../src-tauri/tauri.conf.json', import.meta.url), 'utf-8');
const config = JSON.parse(raw);
const capsuleWindow = config.app.windows.find((window) => window.label === 'capsule');
const libRs = await readFile(new URL('../src-tauri/src/lib.rs', import.meta.url), 'utf-8');
const coordinatorRs = await readFile(new URL('../src-tauri/src/coordinator.rs', import.meta.url), 'utf-8');
if (!capsuleWindow) {
throw new Error('capsule window config missing');
}
assertEqual(capsuleWindow.width, 220, 'windows capsule config keeps translation-capable width baseline');
assertEqual(capsuleWindow.height, 110, 'windows capsule config keeps translation-capable height baseline');
assertEqual(capsuleWindow.transparent, true, 'capsule window should keep transparent visuals');
assertEqual(capsuleWindow.alwaysOnTop, true, 'capsule window should stay above the focused app while recording');
assertMatch(
libRs,
/#\[cfg\(target_os = "windows"\)\][\s\S]*?\(196\.0, height\)/,
'windows runtime capsule width should collapse to the visible pill',
);
assertMatch(
libRs,
/let height = if translation_active \{ 110\.0 \} else \{ 52\.0 \};/,
'windows runtime capsule height should shrink outside translation mode',
);
assertMatch(
libRs,
/window\.set_size\(LogicalSize::new\(cap_w, cap_h\)\)\?/,
'capsule positioning should resync runtime size with the computed layout',
);
assertMatch(
coordinatorRs,
/let accepts_cursor_events = matches!\(state, CapsuleState::Recording\);/,
'windows capsule should only accept clicks while actively recording',
);
assertMatch(
coordinatorRs,
/window\.set_ignore_cursor_events\(!accepts_cursor_events\)/,
'windows capsule should pass clicks through in non-recording states',
);
@@ -2456,6 +2456,15 @@ fn emit_capsule(
if let Some(window) = app.get_webview_window("capsule") {
let visible = !matches!(state, CapsuleState::Idle);
maybe_position_capsule_bottom_center(inner, &window, payload.translation);
#[cfg(target_os = "windows")]
{
// The capsule is always-on-top on Windows. Once recording stops, it must
// stop intercepting clicks meant for the app underneath.
let accepts_cursor_events = matches!(state, CapsuleState::Recording);
if let Err(e) = window.set_ignore_cursor_events(!accepts_cursor_events) {
log::warn!("[capsule] set_ignore_cursor_events failed: {e}");
}
}
if show_capsule && visible {
if cfg!(target_os = "windows") {
if !show_capsule_window_no_activate() {