How the Ego-Lite Keyboard Driver Handles `fill`, `press`, `pressSequentially`, and `selectOption`
The Ego-Lite keyboard driver in package/ego-browser/src/driver/keyboard.ts provides Playwright-style form interaction helpers that wrap Chrome DevTools Protocol (CDP) commands with synthetic DOM event fallbacks.
This article examines the implementation of four core keyboard methods in the ego-lite browser automation framework. The driver balances reliability (via CDP's Input.dispatchKeyEvent) with graceful degradation (via injected JavaScript probes), delivering a robust API for text entry, keystrokes, and dropdown selection.
Keyboard Driver Architecture
The keyboard driver follows a layered design with shared utilities at the base and high-level helpers built on top.
Key Definitions and Modifier Handling
Core constants are defined early in keyboard.ts:
KEYS(lines 22–40): Maps semantic names likeEnter,Backspace, andTabto their corresponding key valuesMODIFIER_BITS(lines 80–85): Assigns bit flags toAlt,Control,Meta, andShiftpressedModifiers(lines 98–99): A runtimeSettracking which modifiers are currently active
The parseKeyCombo() function (lines 100–130) splits strings like "Ctrl+Shift+A" into a base key and a numeric modifier mask. When dispatching events, activeModifierBits() combines this parsed mask with any currently-pressed modifiers.
Low-Level CDP Integration
Two mechanisms ensure keystrokes reach the browser:
dispatchKeyEvent()(lines 30–37): Sends rawInput.dispatchKeyEventCDP commands with configurable timeout- Key probe system (
installKeyProbe()at lines 39–66,finishKeyProbe()at lines 67–77): Injects a synthetickeydownlistener to detect when CDP events fail to register, triggering fallback DOM events
fill(selector, value, options): Rapid Form Population
The fill method provides the fastest way to replace an input's contents. In package/ego-browser/src/driver/keyboard.ts (lines 82–123), it executes five sequential operations:
- Element resolution: Optionally waits for
selectorviawaitForSelector - Focus: Calls
focus(selector)usingRuntime.callFunctionOn - Clear existing content (when
clearFirstis true): Detects content-editable or<input>elements, clears them, and firesinputwithdeleteContentBackward - Text insertion: Uses
Input.insertTextCDP command for immediate population - Event completion: Emits final
inputandchangeevents to trigger form validation
// Fill an input, clearing it first (default behavior)
await page.fill('#email', 'user@example.com');
The clearFirst option defaults to true, making fill behave like a complete replacement operation rather than an append.
press(keyCombo): Single Keystroke Dispatch
The press method handles individual keys and modifier combinations. Implementation spans lines 102–144 in keyboard.ts:
- Parse and build:
parseKeyCombo()extracts base key and modifiers; constructs key-definition object - Editing commands:
editingCommandsForKey()(lines 64–77) maps keys to browser editing actions (selectAll,deleteBackward,deleteForward) - Event sequence: Dispatches
keydown(with optionaltextandcommands), pauses forINPUT_EVENT_DELAY_MS, then dispatcheskeyup - Verification: Uses probe logic (lines 136–144); if the key goes unobserved, falls back to synthetic DOM events
// Press Ctrl+A to select all text
await page.keyboard.press('ControlOrMeta+a');
The ControlOrMeta alias automatically selects Control on Linux/Windows and Meta on macOS, ensuring cross-platform scripts work without modification.
pressSequentially(selectorOrText, textOrOptions?, options?): Character-by-Character Typing
The pressSequentially method simulates realistic user typing with configurable delays. Located at lines 42–56, it supports two calling conventions:
Pattern 1: Target element explicitly
await page.keyboard.pressSequentially('#search', 'hello world');
Pattern 2: Type into focused element
await page.keyboard.pressSequentially('hello world', { delay: 50 });
Implementation details:
focusWithTimeout()ensures the target element is active before typing begins- Iterates the string, calling
press(char)for each character - Optionally awaits
state.sleep(delay)between keystrokes whendelayoption is provided
The delay parameter mimics human typing patterns, useful for triggering JavaScript auto-complete or validation that responds to individual keystrokes.
selectOption(selector, values): Dropdown Manipulation
The selectOption method programmatically controls <select> elements. In keyboard.ts (lines 33–57), it:
- Resolves the
<select>element and executes a script viaRuntime.callFunctionOn - Normalizes the
valuesargument—accepts single strings, arrays, or objects withvalue,label, orindexproperties - Clears existing selections and marks matching
<option>elements as selected - Fires
inputandchangeevents to notify JavaScript listeners - Returns an array of selected option values
// Select multiple options using mixed value types
await page.selectOption('#countries', [
'us',
{ label: 'Canada' },
{ index: 3 }
]);
The flexible value format allows scripts to target options by their underlying value, visible label, or positional index.
Integration with User-Facing API
These driver methods are exposed to automation scripts through package/ego-browser/src/helpers.ts (lines 741–746), where they're mounted under the keyboard namespace:
// helpers.ts re-exports
keyboard: {
press: keyboard.press.bind(keyboard),
pressSequentially: keyboard.pressSequentially.bind(keyboard),
// ... plus page-level shortcuts
}
The page.fill() and page.selectOption() shortcuts delegate directly to the driver methods while handling additional element-waiting logic.
Summary
fillcombines CDP'sinsertTextwith element clearing and event emission for complete input replacementpressparses key combinations, dispatches CDP events with editing commands, and falls back to synthetic events via the probe systempressSequentiallytypes character-by-character with optional delays, supporting both targeted and focused-element modesselectOptionexecutes JavaScript in the browser to manipulate<select>elements and trigger change notifications
All four methods share the driver's core infrastructure: modifier tracking, CDP command dispatch, and the key-probe fallback mechanism implemented in package/ego-browser/src/driver/keyboard.ts.
Frequently Asked Questions
What is the difference between fill and pressSequentially in ego-lite?
fill replaces content immediately using CDP's insertText—no individual keystrokes are simulated, making it faster but less realistic. pressSequentially types character-by-character with optional delays, triggering JavaScript event handlers that respond to each keystroke. Use fill for speed; use pressSequentially when page behavior depends on key event sequences.
How does ego-lite handle keyboard shortcuts across operating systems?
The driver defines platform-agnostic aliases like ControlOrMeta in KEYS (lines 22–40). When press parses a key combination, it resolves these aliases to the appropriate modifier bit (Control on Windows/Linux, Meta on macOS) via MODIFIER_BITS (lines 80–85). Scripts using these aliases work cross-platform without modification.
What happens when CDP keyboard events fail to register?
The key probe system (installKeyProbe at lines 39–66) injects a temporary JavaScript keydown listener before dispatch. finishKeyProbe (lines 67–77) checks whether the listener observed the event; if not, the driver falls back to synthetic DOM events through dispatchKeyEvent. This dual-path approach ensures compatibility with iframe-heavy or event-intercepting pages.
Can selectOption handle multi-select elements?
Yes. The values parameter accepts arrays, and the implementation (lines 46–57 in keyboard.ts) clears then repopulates selected options for both single and multiple selection modes. The method returns all currently selected values, allowing verification of the final state.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →