From b76a9d6052df44ffe95116d7cddeec9e47b061e6 Mon Sep 17 00:00:00 2001
From: npub1jh9wn95s0472h86ahapupaf7m6kx4v9sx2n0atj2hltcfer8k06s5n3pyf
<95cae996907d7cab9f5dbf43c0f53edeac6ab0b032a6feae4abfd784e467b3f5@buzz.block.builderlab.xyz>
Date: Mon, 3 Aug 2026 09:33:55 -0400
Subject: [PATCH] fix(desktop): retain terminal focus on viewport click
Co-authored-by: npub1jh9wn95s0472h86ahapupaf7m6kx4v9sx2n0atj2hltcfer8k06s5n3pyf <95cae996907d7cab9f5dbf43c0f53edeac6ab0b032a6feae4abfd784e467b3f5@buzz.block.builderlab.xyz>
Signed-off-by: npub1jh9wn95s0472h86ahapupaf7m6kx4v9sx2n0atj2hltcfer8k06s5n3pyf <95cae996907d7cab9f5dbf43c0f53edeac6ab0b032a6feae4abfd784e467b3f5@buzz.block.builderlab.xyz>
---
.../features/terminal/TerminalSubstrate.tsx | 12 +++++-
desktop/tests/e2e/terminal-wheel.spec.ts | 43 +++++++++++++++++++
2 files changed, 54 insertions(+), 1 deletion(-)
diff --git a/desktop/src/features/terminal/TerminalSubstrate.tsx b/desktop/src/features/terminal/TerminalSubstrate.tsx
index 83dd1e04b3..081b121a8a 100644
--- a/desktop/src/features/terminal/TerminalSubstrate.tsx
+++ b/desktop/src/features/terminal/TerminalSubstrate.tsx
@@ -517,7 +517,17 @@ export function TerminalSubstrate({
{shortcutLabel} BUZZ
-
+ {/* biome-ignore lint/a11y/noStaticElementInteractions: the hidden textarea owns keyboard semantics; this only preserves its focus across canvas clicks. */}
+
{
+ if (owner !== "terminal") return;
+ // Preventing the canvas mousedown also suppresses selection. Revisit
+ // this when the terminal gains mouse selection support.
+ event.preventDefault();
+ textareaRef.current?.focus({ preventScroll: true });
+ }}
+ >
{welcomeVisible && banner ? (
diff --git a/desktop/tests/e2e/terminal-wheel.spec.ts b/desktop/tests/e2e/terminal-wheel.spec.ts
index bd3d742e1a..d90fb9da85 100644
--- a/desktop/tests/e2e/terminal-wheel.spec.ts
+++ b/desktop/tests/e2e/terminal-wheel.spec.ts
@@ -187,3 +187,46 @@ test("scrollback: wheel over Buzz Term reaches terminal_scroll", async ({
console.log("SCROLLS", JSON.stringify(scrolls));
expect(scrolls).toEqual([-5, 2]);
});
+
+test("terminal viewport click retains keyboard input ownership", async ({
+ page,
+}) => {
+ await reveal(page);
+ const input = page.getByLabel("Terminal input");
+ await expect(input).toBeFocused();
+
+ await page
+ .locator(".buzz-terminal-viewport")
+ .click({ position: { x: 40, y: 40 } });
+ await expect(input).toBeFocused();
+
+ await page.keyboard.type("FOCUS_KEYSTROKE");
+ await expect
+ .poll(async () =>
+ page.evaluate(() =>
+ (
+ window as typeof window & { __SAMI_TERM__: { inputs: string[] } }
+ ).__SAMI_TERM__.inputs.join(""),
+ ),
+ )
+ .toContain("FOCUS_KEYSTROKE");
+});
+
+test("concealed terminal viewport does not steal Buzz focus", async ({
+ page,
+}) => {
+ await reveal(page);
+ await page.keyboard.press("Meta+j");
+ await expect(page.locator(TERM)).toHaveAttribute(
+ "data-terminal-owner",
+ "buzz",
+ );
+
+ const input = page.getByLabel("Terminal input");
+ await expect(input).not.toBeFocused();
+ await page.locator(".buzz-terminal-viewport").click({
+ force: true,
+ position: { x: 40, y: 40 },
+ });
+ await expect(input).not.toBeFocused();
+});