From 7fda7c30f15925bc91ef7f3ff66d4a7b0e10ee8c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=B6=85=E8=B6=85=E8=B6=85=E8=B6=85=E8=B6=85=E7=BA=A7?=
=?UTF-8?q?=E5=96=9C=E6=AC=A2=E4=BD=A0=E7=9A=84=E8=BE=BE=E5=A6=AE=E5=A8=85?=
<176143450+My-Denia@users.noreply.github.com>
Date: Sat, 31 Oct 2026 14:53:28 +0800
Subject: [PATCH 1/3] fix(hud): accept the system language prompt on Enter
---
src/components/launch/HudControls.tsx | 14 +++++
src/components/launch/LaunchWindow.test.tsx | 63 +++++++++++++++++++++
src/components/launch/LaunchWindow.tsx | 1 +
3 files changed, 78 insertions(+)
diff --git a/src/components/launch/HudControls.tsx b/src/components/launch/HudControls.tsx
index 78ef09a763..c417b754c2 100644
--- a/src/components/launch/HudControls.tsx
+++ b/src/components/launch/HudControls.tsx
@@ -746,6 +746,7 @@ export const HudNotice = memo(function HudNotice({
confirmLabel,
onDismiss,
onConfirm,
+ confirmOnEnter = false,
}: {
title: string;
description: string;
@@ -753,7 +754,20 @@ export const HudNotice = memo(function HudNotice({
confirmLabel: string;
onDismiss: () => void;
onConfirm: () => void;
+ /** Enter confirms while no control has focus; a focused control keeps its own Enter. */
+ confirmOnEnter?: boolean;
}) {
+ useEffect(() => {
+ if (!confirmOnEnter) return;
+ const handleKeyDown = (event: KeyboardEvent) => {
+ if (event.key !== "Enter" || event.repeat || event.target !== document.body) return;
+ if (event.ctrlKey || event.altKey || event.shiftKey || event.metaKey) return;
+ onConfirm();
+ };
+ window.addEventListener("keydown", handleKeyDown);
+ return () => window.removeEventListener("keydown", handleKeyDown);
+ }, [confirmOnEnter, onConfirm]);
+
return (
{
expect(recorderState.value.dismissSoftwareEncoderFallbackNotice).toHaveBeenCalledTimes(1);
expect(recorderState.value.dismissSoftwareEncoderFallbackNotice).toHaveBeenCalledWith(true);
});
+
+ it("leaves Enter alone", async () => {
+ recorderState.value.softwareEncoderFallbackNoticeVisible = true;
+
+ renderLaunchWindow();
+ await screen.findByRole("button", { name: "Got it" });
+ fireEvent.keyDown(document.body, { key: "Enter" });
+
+ expect(recorderState.value.dismissSoftwareEncoderFallbackNotice).not.toHaveBeenCalled();
+ });
+});
+
+// #1428: the prompt's buttons need the mouse, and a window with nothing focused took Enter nowhere.
+describe("LaunchWindow system language prompt", () => {
+ beforeEach(() => {
+ platformState.value = "win32";
+ resetLaunchMocks();
+ i18nState.value.systemLocaleSuggestion = "zh-CN";
+ });
+
+ afterEach(() => {
+ cleanup();
+ vi.unstubAllGlobals();
+ });
+
+ it("accepts the suggestion on Enter while no control has focus", async () => {
+ renderLaunchWindow();
+ await screen.findByRole("button", { name: "Switch to English" });
+
+ fireEvent.keyDown(document.body, { key: "Enter" });
+
+ expect(i18nState.value.acceptSystemLocaleSuggestion).toHaveBeenCalledTimes(1);
+ expect(i18nState.value.dismissSystemLocaleSuggestion).not.toHaveBeenCalled();
+ });
+
+ it("leaves Enter to a control that has focus", async () => {
+ renderLaunchWindow();
+ const keep = await screen.findByRole("button", { name: "Keep current language" });
+
+ fireEvent.keyDown(keep, { key: "Enter" });
+
+ expect(i18nState.value.acceptSystemLocaleSuggestion).not.toHaveBeenCalled();
+ });
+
+ it("ignores a held Enter, and other keys", async () => {
+ renderLaunchWindow();
+ await screen.findByRole("button", { name: "Switch to English" });
+
+ fireEvent.keyDown(document.body, { key: "Enter", repeat: true });
+ fireEvent.keyDown(document.body, { key: " " });
+ fireEvent.keyDown(document.body, { key: "Enter", ctrlKey: true });
+
+ expect(i18nState.value.acceptSystemLocaleSuggestion).not.toHaveBeenCalled();
+ });
+
+ it("leaves Enter alone while a popover is open", async () => {
+ renderLaunchWindow();
+ fireEvent.click(await screen.findByRole("button", { name: "Language: English" }));
+
+ fireEvent.keyDown(document.body, { key: "Enter" });
+
+ expect(i18nState.value.acceptSystemLocaleSuggestion).not.toHaveBeenCalled();
+ });
});
// #1149: sonner's default corner of the HUD window is where the bar is, so a toast covered
diff --git a/src/components/launch/LaunchWindow.tsx b/src/components/launch/LaunchWindow.tsx
index 0bad565d75..50df3e6450 100644
--- a/src/components/launch/LaunchWindow.tsx
+++ b/src/components/launch/LaunchWindow.tsx
@@ -1450,6 +1450,7 @@ export function LaunchWindow() {
})}
onDismiss={dismissSystemLocaleSuggestion}
onConfirm={acceptSystemLocaleSuggestion}
+ confirmOnEnter={!isPopoverOpen}
/>
)}
From 3af33042df75739bc073fe3a594d798a3f0b6aaf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=B6=85=E8=B6=85=E8=B6=85=E8=B6=85=E8=B6=85=E7=BA=A7?=
=?UTF-8?q?=E5=96=9C=E6=AC=A2=E4=BD=A0=E7=9A=84=E8=BE=BE=E5=A6=AE=E5=A8=85?=
<176143450+My-Denia@users.noreply.github.com>
Date: Sat, 31 Oct 2026 15:53:41 +0800
Subject: [PATCH 2/3] test(hud): press Enter on the focused Keep button
---
src/components/launch/LaunchWindow.test.tsx | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/components/launch/LaunchWindow.test.tsx b/src/components/launch/LaunchWindow.test.tsx
index 231b94f273..ff8cb47935 100644
--- a/src/components/launch/LaunchWindow.test.tsx
+++ b/src/components/launch/LaunchWindow.test.tsx
@@ -2277,9 +2277,12 @@ describe("LaunchWindow system language prompt", () => {
it("leaves Enter to a control that has focus", async () => {
renderLaunchWindow();
const keep = await screen.findByRole("button", { name: "Keep current language" });
+ const user = userEvent.setup();
- fireEvent.keyDown(keep, { key: "Enter" });
+ keep.focus();
+ await user.keyboard("{Enter}");
+ expect(i18nState.value.dismissSystemLocaleSuggestion).toHaveBeenCalledTimes(1);
expect(i18nState.value.acceptSystemLocaleSuggestion).not.toHaveBeenCalled();
});
From 4cc2d878ed7768656285bcf478fd4fce5740547d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=B6=85=E8=B6=85=E8=B6=85=E8=B6=85=E8=B6=85=E7=BA=A7?=
=?UTF-8?q?=E5=96=9C=E6=AC=A2=E4=BD=A0=E7=9A=84=E8=BE=BE=E5=A6=AE=E5=A8=85?=
<176143450+My-Denia@users.noreply.github.com>
Date: Sat, 31 Oct 2026 18:42:33 +0800
Subject: [PATCH 3/3] test(hud): cover Alt, Shift and Meta on the language
prompt's Enter
---
src/components/launch/LaunchWindow.test.tsx | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/components/launch/LaunchWindow.test.tsx b/src/components/launch/LaunchWindow.test.tsx
index ff8cb47935..fffc58d538 100644
--- a/src/components/launch/LaunchWindow.test.tsx
+++ b/src/components/launch/LaunchWindow.test.tsx
@@ -2293,6 +2293,9 @@ describe("LaunchWindow system language prompt", () => {
fireEvent.keyDown(document.body, { key: "Enter", repeat: true });
fireEvent.keyDown(document.body, { key: " " });
fireEvent.keyDown(document.body, { key: "Enter", ctrlKey: true });
+ fireEvent.keyDown(document.body, { key: "Enter", altKey: true });
+ fireEvent.keyDown(document.body, { key: "Enter", shiftKey: true });
+ fireEvent.keyDown(document.body, { key: "Enter", metaKey: true });
expect(i18nState.value.acceptSystemLocaleSuggestion).not.toHaveBeenCalled();
});