Skip to content

[fix]: report key/code on keydown for printable keyPress keys - #3110

Open
antonvishal wants to merge 5 commits into
browserbase:mainfrom
antonvishal:fix/keypress-key-identity
Open

antonvishal wants to merge 5 commits into
browserbase:mainfrom
antonvishal:fix/keypress-key-identity

Conversation

@antonvishal

@antonvishal antonvishal commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

why

I was navigating across https://teleoperator.mindblown.ai/?mb=game (a browser game driven with WASD-style keys) and found that Stagehand's key presses didn't move anything. This PR fixes that.

The real bug: page.keyPress("w") (and locator.press, which uses it) sent printable keys as a text-only keyDown, with no key, code, or virtual key code. Text still landed in inputs, but keydown listeners saw an empty key. Measured in Chrome on main:

event key code keyCode
keydown "" "" 0
keyup "w" "KeyW" 87

Games, shortcut handlers, and anything else reading event.key / event.code on keydown ignored the press.

what changed

  • Printable keys now send key, code, and windowsVirtualKeyCode on keyDown, alongside the text, the same way Playwright does.
  • Key codes for punctuation come from a US-layout table (. is Period/190, ( is Digit9/57). The old helper derived them from ASCII, which is wrong and harmful once sent on keyDown: Chromium runs editing commands from the key code, so . (46) acted as Delete and ( % & ' $ # acted as the arrow keys, Home, and End. I hit this regression while writing the first version of the fix, and the integration test below guards against it.
  • Characters outside the US layout (e.g. é) send no code or key code, so they can't trigger editing commands.
  • event.key matches the character typed ("W" for keyPress("W")). Shortcuts still report the unshifted letter (Control+A gives "a"), as a physical keyboard does.

test plan

  • packages/extension/tests/page-keyboard.test.ts (new): exact CDP events for letters, digits, space, punctuation, non-US characters, and shortcuts.
  • keyboard.test.ts integration: keydown reports key/code, and . ( % $ # ' insert at the caret instead of moving it or deleting. Fails on main, passes here.
  • facade-frames.test.ts: locator.press("w", {delay}) and "w+a" report KeyW/KeyA with the delay honored, in same-origin and out-of-process iframes.
  • Existing keyboard and clipboard integration tests (Cmd+A, Delete, Tab, Enter, +, etc.) still pass.

Summary by cubic

Fixes page.keyPress and locator.press so keydown listeners see the pressed key and code instead of an empty string, leaving keyboard-driven games and shortcut handlers unresponsive.

Bug Fixes

  • Printable keys now send key, code, and windowsVirtualKeyCode on keyDown, matching Playwright behavior.
  • Key codes come from a US-layout table; the old ASCII-derived codes made . trigger Delete and ( % & ' $ # trigger arrow/Home/End editing commands in Chromium.
  • Characters outside the US layout (like é) send no code or VK so they can't trigger editing commands.
  • Adds unit and integration tests covering letters, punctuation, shortcuts, key delay, and iframes.

Written for commit 6ffe393. Summary will update on new commits.

View guided diff

keyPress sent printable keys as text-only keyDown events, so keydown listeners saw an
empty key and code. Send the physical key with US-layout VKs; ASCII-derived VKs would
make punctuation run editing commands such as Delete and the arrow keys.

Co-authored-by: Cursor <cursoragent@cursor.com>
@changeset-bot

changeset-bot Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 6ffe393

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 24 packages
Name Type
@browserbasehq/stagehand-extension Patch
@browserbasehq/stagehand Patch
@browserbasehq/stagehand-python Patch
@browserbasehq/stagehand-go Patch
browse Patch
@browserbasehq/stagehand-examples Patch
@browserbasehq/stagehand-integrations-claude-cua-sdk Patch
@browserbasehq/stagehand-integrations Patch
@browserbasehq/eve Patch
@browserbasehq/stagehand-integrations-gemini-cua-sdk Patch
@browserbasehq/stagehand-integrations-example-pi-facade Patch
@browserbasehq/stagehand-integrations-claude-agent-sdk Patch
@browserbasehq/stagehand-integrations-example-claude-code-facade Patch
@browserbasehq/stagehand-integrations-codex-sdk Patch
@browserbasehq/stagehand-integrations-example-codex-facade Patch
@browserbasehq/stagehand-integrations-cursor-sdk Patch
@browserbasehq/stagehand-integrations-example-cursor-facade Patch
@browserbasehq/stagehand-integrations-deepagents-sdk Patch
@browserbasehq/stagehand-integrations-eve-sdk Patch
@browserbasehq/stagehand-integrations-fx-sdk Patch
@browserbasehq/stagehand-integrations-mastra-sdk Patch
@browserbasehq/stagehand-integrations-example-mastra-facade Patch
@browserbasehq/stagehand-integrations-pi-sdk Patch
@browserbasehq/stagehand-integrations-example-vercel-ai-facade Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions

github-actions Bot commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

This PR is from an external contributor and must be approved by a stagehand team member with write access before CI can run.
Approving the latest commit mirrors it into an internal PR owned by the approver.
If new commits are pushed later, the internal PR stays open but is marked stale until someone approves the latest external commit and refreshes it.

@github-actions github-actions Bot added external-contributor Tracks PRs mirrored from external contributor forks. external-contributor:awaiting-approval Waiting for a stagehand team member to approve the latest external commit. labels Oct 5, 2026
@antonvishal
antonvishal marked this pull request as ready for review October 5, 2026 18:59
# Conflicts:
#	packages/sdk-go/internal/extensionassets/stagehand-extension.zip
# Conflicts:
#	packages/sdk-go/internal/extensionassets/stagehand-extension.zip
# Conflicts:
#	packages/sdk-go/internal/extensionassets/stagehand-extension.zip
# Conflicts:
#	packages/sdk-go/internal/extensionassets/stagehand-extension.zip

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

external-contributor:awaiting-approval Waiting for a stagehand team member to approve the latest external commit. external-contributor Tracks PRs mirrored from external contributor forks.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant