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(); +});