fix(extension): preserve key identity and prevent VK collisions on printable keydown
why
Closes #3236
Calling page.keyPress("w") inserts text into focused inputs, but the dispatched DOM keydown event lacks key identity (event.key === "" and event.code === "" and event.keyCode === 0). Handlers inspecting event.key or event.code (e.g. shortcut managers and games) ignore the press, even though the subsequent keyup event identifies the key.
Furthermore, punctuation characters in describePrintableKey fell back to vk: ch.toUpperCase().charCodeAt(0). In ASCII, . is charCode 46, which collides with Windows Virtual Key VK_DELETE (46). In Chromium, passing windowsVirtualKeyCode: 46 for . causes the browser's editing command handler to trigger Delete instead of inserting the period.
what changed
- Defined a complete standard US keyboard
PRINTABLE_PUNCTUATIONlookup covering printable punctuation and shifted symbol keys (e.g..maps tocode: "Period", vk: 190rather than VK 46 /VK_DELETE). - Updated
Page.describePrintableKey():- Resolves punctuation through
PRINTABLE_PUNCTUATION. - Preserves uppercase key identity when an uppercase character is passed directly (
ch === upper). - Avoids assigning synthetic charCode virtual key codes in the fallback to prevent command collisions.
- Resolves punctuation through
- Updated
Page.keyDown()for single printable characters (length 1) in the typing path to includekey: desc.key,code: desc.code, andwindowsVirtualKeyCode: desc.vk. - Refactored
Page.type()to sharedescribePrintableKey()for consistent keyboard event metadata acrosstype()andkeyPress(). - Added unit tests in
packages/extension/tests/page-key-press.test.ts. - Added a patch changeset for
@browserbasehq/stagehand-extension,@browserbasehq/stagehand,@browserbasehq/stagehand-go, and@browserbasehq/stagehand-python.
test plan
- Run format check:
pnpm run fmt:check(passes) - Run linter:
pnpm run lint(passes) - Run typecheck:
pnpm --filter @browserbasehq/stagehand-extension run typecheck(passes) - Run unit tests:
pnpm vitest run packages/extension/tests/page-key-press.test.ts(passes, 4/4 tests) - Run full extension test suite:
pnpm --filter @browserbasehq/stagehand-extension run test:unit(passes, 67/67 files, 1007 tests)
Summary by cubic
Fixes page.keyPress() and page.type() dispatching keydown events without key identity (event.key, event.code, and event.keyCode were empty), which caused handlers checking those fields (shortcut managers, games) to ignore the press. Also fixes punctuation collisions where . fell back to VK 46 (VK_DELETE) and triggered Delete in Chromium instead of inserting a period.
- Added a full US keyboard
PRINTABLE_PUNCTUATIONmapping so characters like.dispatchcode: "Period",vk: 190rather than VK 46. - Unified
describePrintableKey()acrosskeyPress(),keyDown(), andtype()so all typing paths share consistent metadata; uppercase characters passed directly keep their uppercase identity. - The fallback for unknown characters no longer synthesizes a VK code from charCode, preventing command collisions.
- Added unit tests and a patch changeset for all
@browserbasehq/stagehand-*packages.