diff --git a/README.md b/README.md
index 8ffff2d..7c3790b 100644
--- a/README.md
+++ b/README.md
@@ -93,7 +93,7 @@ npm run dist:win -- --config.win.signAndEditExecutable=false
| `R` | 回到顶部 |
| `↑` / `↓` | 快速滚动页面 |
| `←` / `→` | 调节滚动速度 |
-| `Esc` | 关闭第二屏输出窗口(仅桌面版) |
+| `Esc` | 关闭第二屏输出(仅桌面版,主窗口或第二屏中均可);未开第二屏时停止播放 |
## 开发检查
diff --git "a/docs/\346\233\264\346\226\260\346\227\245\345\277\227-6.6.md" "b/docs/\346\233\264\346\226\260\346\227\245\345\277\227-6.6.md"
index 36d8a8f..17e3951 100644
--- "a/docs/\346\233\264\346\226\260\346\227\245\345\277\227-6.6.md"
+++ "b/docs/\346\233\264\346\226\260\346\227\245\345\277\227-6.6.md"
@@ -2,6 +2,10 @@
6.6 版本起 Tauri 版成为主力维护的全平台版本,支持 Windows、macOS 和 Linux;Electron 版保留为 Windows 备用版本。
+## 6.6.1
+
+- 修复开启第二屏后按 `Esc` 退出不稳定的问题。之前只有键盘焦点在第二屏窗口时 `Esc` 才会关闭第二屏,而打开第二屏后焦点通常交回主窗口(macOS 上落在哪个窗口不确定)。现在开启第二屏时,在主窗口或第二屏中按 `Esc` 都能关闭第二屏,编辑稿件时同样生效,且不改变播放状态;未开第二屏时 `Esc` 仍为暂停播放。
+
## 6.6.0
### 全平台支持
diff --git a/tauri/web/index.html b/tauri/web/index.html
index 15d3cc8..293268e 100644
--- a/tauri/web/index.html
+++ b/tauri/web/index.html
@@ -2168,6 +2168,19 @@
准备一段稿件
}
}
+ async function closeOutputWindowFromMain() {
+ if (!window.teleprompterBridge?.closeOutputWindow || outputTogglePending) {
+ return;
+ }
+ outputTogglePending = true;
+ try {
+ applyOutputStatus(await window.teleprompterBridge.closeOutputWindow());
+ elements.stage.focus({ preventScroll: true });
+ } finally {
+ outputTogglePending = false;
+ }
+ }
+
function startResize(event) {
event.preventDefault();
resizing = true;
@@ -2551,6 +2564,13 @@ 准备一段稿件
}
return;
}
+ // 打开第二屏后键盘焦点通常留在主窗口(macOS 上焦点落在哪个窗口还不确定),
+ // 所以主窗口里按 Esc 也要能关闭第二屏;编辑稿件时同样生效
+ if (event.key === "Escape" && outputActive) {
+ event.preventDefault();
+ closeOutputWindowFromMain();
+ return;
+ }
// 只有正在输入文字的控件(文本框、下拉框)才把按键留给控件本身;
// 按钮和滑块获得焦点时不拦截,让空格/R/F/方向键等全局快捷键始终可用
const shortcutTarget = event.target;
diff --git "a/tauri/\345\212\237\350\203\275\344\273\213\347\273\215.md" "b/tauri/\345\212\237\350\203\275\344\273\213\347\273\215.md"
index 612fdf3..c5ce22b 100644
--- "a/tauri/\345\212\237\350\203\275\344\273\213\347\273\215.md"
+++ "b/tauri/\345\212\237\350\203\275\344\273\213\347\273\215.md"
@@ -21,7 +21,7 @@
- `R`:回到顶部
- `↑ / ↓`:快速滚动页面
- `← / →`:调节滚动速度
- - `Esc`:在第二屏窗口中退出第二屏输出
+ - `Esc`:关闭第二屏输出(主窗口或第二屏窗口中均可);未开第二屏时停止播放
## 显示调节
@@ -46,7 +46,7 @@
- 第二屏只显示提词内容,不显示底部控制栏。
- 第二屏顶部显示更醒目的剩余字数。
- 中间指示线包含进度点,便于判断当前阅读位置。
-- 按钮再次点击可以关闭第二屏输出,第二屏窗口按 `Esc` 也可以退出。
+- 按钮再次点击可以关闭第二屏输出,在主窗口或第二屏窗口按 `Esc` 也可以退出。
- 关闭程序时会同步结束相关窗口和进程。
## 主屏预览
diff --git a/tests/teleprompter.spec.js b/tests/teleprompter.spec.js
index 16812bc..0462d79 100644
--- a/tests/teleprompter.spec.js
+++ b/tests/teleprompter.spec.js
@@ -537,3 +537,45 @@ test("output mode ignores playback keys and only handles Escape", async ({ page
await page.keyboard.press("Escape");
await expect.poll(() => page.evaluate(() => window.__closeCalls)).toBe(1);
});
+
+test("Escape in the main window closes an open output window", async ({ page }) => {
+ await page.addInitScript(() => {
+ window.__closeCalls = 0;
+ window.teleprompterBridge = {
+ toggleOutputWindow: async () => ({ opened: true, displayCount: 2, outputWidth: 1280, outputHeight: 720 }),
+ closeOutputWindow: async () => {
+ window.__closeCalls += 1;
+ return { opened: false, displayCount: 2 };
+ },
+ sendState: () => {},
+ onState: () => {},
+ onOutputStatus: () => {},
+ };
+ });
+
+ await page.goto(appUrl);
+ await page.locator("#outputButton").click();
+ await expect(page.locator("#outputButton")).toHaveAttribute("aria-pressed", "true");
+
+ // 播放中按 Esc 只关第二屏,不改变播放状态
+ await page.keyboard.press("Space");
+ await expect(page.locator("#playButton")).not.toHaveClass(/primary/);
+ await page.keyboard.press("Escape");
+ await expect(page.locator("#outputButton")).toHaveAttribute("aria-pressed", "false");
+ await expect.poll(() => page.evaluate(() => window.__closeCalls)).toBe(1);
+ await expect(page.locator("#playButton")).not.toHaveClass(/primary/);
+
+ // 第二屏关闭后,Esc 恢复为暂停播放,不再调用关闭
+ await page.keyboard.press("Escape");
+ await expect(page.locator("#playButton")).toHaveClass(/primary/);
+ expect(await page.evaluate(() => window.__closeCalls)).toBe(1);
+
+ // 编辑稿件时按 Esc 也能关闭第二屏
+ await page.locator("#outputButton").click();
+ await expect(page.locator("#outputButton")).toHaveAttribute("aria-pressed", "true");
+ await page.locator("#toggleEditorButton").click();
+ await page.locator("#scriptInput").focus();
+ await page.keyboard.press("Escape");
+ await expect(page.locator("#outputButton")).toHaveAttribute("aria-pressed", "false");
+ await expect.poll(() => page.evaluate(() => window.__closeCalls)).toBe(2);
+});
diff --git a/windows-electron/index.html b/windows-electron/index.html
index 15d3cc8..293268e 100644
--- a/windows-electron/index.html
+++ b/windows-electron/index.html
@@ -2168,6 +2168,19 @@ 准备一段稿件
}
}
+ async function closeOutputWindowFromMain() {
+ if (!window.teleprompterBridge?.closeOutputWindow || outputTogglePending) {
+ return;
+ }
+ outputTogglePending = true;
+ try {
+ applyOutputStatus(await window.teleprompterBridge.closeOutputWindow());
+ elements.stage.focus({ preventScroll: true });
+ } finally {
+ outputTogglePending = false;
+ }
+ }
+
function startResize(event) {
event.preventDefault();
resizing = true;
@@ -2551,6 +2564,13 @@ 准备一段稿件
}
return;
}
+ // 打开第二屏后键盘焦点通常留在主窗口(macOS 上焦点落在哪个窗口还不确定),
+ // 所以主窗口里按 Esc 也要能关闭第二屏;编辑稿件时同样生效
+ if (event.key === "Escape" && outputActive) {
+ event.preventDefault();
+ closeOutputWindowFromMain();
+ return;
+ }
// 只有正在输入文字的控件(文本框、下拉框)才把按键留给控件本身;
// 按钮和滑块获得焦点时不拦截,让空格/R/F/方向键等全局快捷键始终可用
const shortcutTarget = event.target;
diff --git "a/windows-electron/\345\212\237\350\203\275\344\273\213\347\273\215.md" "b/windows-electron/\345\212\237\350\203\275\344\273\213\347\273\215.md"
index 99af31d..9aba707 100644
--- "a/windows-electron/\345\212\237\350\203\275\344\273\213\347\273\215.md"
+++ "b/windows-electron/\345\212\237\350\203\275\344\273\213\347\273\215.md"
@@ -23,7 +23,7 @@
- `R`:回到顶部
- `↑ / ↓`:快速滚动页面
- `← / →`:调节滚动速度
- - `Esc`:在第二屏窗口中退出第二屏输出
+ - `Esc`:关闭第二屏输出(主窗口或第二屏窗口中均可);未开第二屏时停止播放
## 显示调节
@@ -48,7 +48,7 @@
- 第二屏只显示提词内容,不显示底部控制栏。
- 第二屏顶部显示更醒目的剩余字数。
- 中间指示线包含进度点,便于判断当前阅读位置。
-- 按钮再次点击可以关闭第二屏输出,第二屏窗口按 `Esc` 也可以退出。
+- 按钮再次点击可以关闭第二屏输出,在主窗口或第二屏窗口按 `Esc` 也可以退出。
- 关闭程序时会同步结束相关窗口和进程。
## 主屏预览
diff --git "a/\344\275\277\347\224\250\346\214\207\345\215\227.md" "b/\344\275\277\347\224\250\346\214\207\345\215\227.md"
index a3ffa7d..c81a795 100644
--- "a/\344\275\277\347\224\250\346\214\207\345\215\227.md"
+++ "b/\344\275\277\347\224\250\346\214\207\345\215\227.md"
@@ -45,7 +45,7 @@
- 支持水平镜像和垂直镜像
- 顶部显示剩余字数
- 指示线上显示进度圆点
-- 按 `Esc` 可以退出第二屏
+- 在主窗口或第二屏中按 `Esc` 都可以退出第二屏
6.1 版本中,主窗口采用固定比例预览画布,主屏看到的换行、字号、指示线位置会尽量和第二屏一致。
@@ -106,7 +106,7 @@
- `←`:降低滚动速度
- `→`:提高滚动速度
- `Shift + ← / →`:更大幅度调节速度
-- `Esc`:第二屏窗口中退出第二屏;播放时停止播放
+- `Esc`:开启第二屏时关闭第二屏(在主窗口或第二屏中按都可以,不影响播放状态);未开第二屏时停止播放
编辑稿件时,方向键会优先用于文本编辑,不会触发提词器快捷操作。