How the Ego-Lite Keyboard Helper Works: fillInput, typeText, pressKey, and dispatchKey Explained

The Ego-Lite keyboard helper is a thin CDP wrapper that converts high-level typing commands into Chrome DevTools Protocol Input.dispatchKeyEvent calls.

The keyboard helper lives in the citrolabs/ego-lite repository and provides agents with a robust interface for simulating user input. Located at package/ego-browser/src/driver/keyboard.ts, it abstracts the complexity of Chrome DevTools Protocol (CDP) into four intuitive methods that handle everything from filling form fields to dispatching raw key events.

Architecture Overview

The helper operates as a driver-layer abstraction over the CDP Input domain. Rather than requiring agents to manually construct CDP payloads, the helper exposes fillInput, typeText, pressKey, and dispatchKey methods that internally translate requests into Input.dispatchKeyEvent commands sent via the runtime's ego.sendCDPMessage transport.

All keyboard operations follow a three-phase pipeline:

  1. Element Resolution – The src/element-resolver.ts module converts user-friendly locators (CSS selectors, XPath, or role-based queries) into concrete CDP object IDs.
  2. Focus Management – The target element receives a focus command to ensure subsequent key events target the correct input field.
  3. Event Dispatch – The helper generates keyDown and keyUp events (or uses Input.insertText shortcuts when supported) through the low-level dispatchKeyEvent implementation found at lines 530-532 of the keyboard driver.

The Four Core Methods

fillInput

The fillInput method combines element resolution, clearing, and typing into a single operation. It accepts a locator string and a text value, resolves the target element, clears any existing value, and then streams the new text character by character.

Under the hood, it leverages dispatchKeyEvent for each character or falls back to Input.insertText when the browser runtime supports the optimization.

// Fill a search box using a CSS selector
await fillInput('css:#search-field', 'Ego Lite automation');

typeText

The typeText method provides a lighter alternative when you already have focus on the correct element. It skips the clearing phase and immediately begins dispatching keystrokes.

This helper is ideal for appending content to existing inputs or typing into elements already focused by previous actions. Like fillInput, it calls dispatchKeyEvent for every character in the provided string.

// Type into the currently focused element
await typeText('Hello, World!');

pressKey

The pressKey method simulates a single physical key press by dispatching paired keyDown and keyUp events for a specific virtual-key code. Use this for non-printable keys like Enter, Tab, ArrowLeft, or Escape that don't produce text characters but trigger application behavior.

// Submit a form by pressing Enter
await pressKey('Enter');

// Navigate with arrow keys
await pressKey('ArrowDown');

dispatchKey

The dispatchKey method exposes the raw CDP interface for advanced use cases. It accepts a complete CDP payload object and forwards it directly to Input.dispatchKeyEvent, bypassing the high-level abstractions.

This is the foundation upon which all other helpers are built, located at lines 530-532 of keyboard.ts.

// Send a raw CDP key event with specific modifiers
await dispatchKey({
  type: 'keyDown',
  windowsVirtualKeyCode: 0x41, // 'A' key
  code: 'KeyA',
  key: 'a',
  modifiers: 2 // Shift key
});

Error Handling and Retry Logic

When CDP calls fail due to session interruption or network latency, the keyboard helper detects timeout errors by matching the message pattern "CDP request timed out: Input.dispatchKeyEvent" (line 672). The driver automatically retries the operation according to the library's retry policy before surfacing the error to the calling agent.

This ensures that transient browser disconnections don't fail entire automation sequences, providing resilience for long-running tasks.

Practical Implementation Examples

Here is a complete workflow demonstrating the keyboard helper methods in context:

// Navigate and fill a login form
await fillInput('css:#username', 'admin');
await fillInput('css:#password', 'secret123');

// Submit with Enter key
await pressKey('Enter');

// Wait for navigation, then type a search query
await typeText('keyboard automation');
await pressKey('Enter');

// Send a custom keyboard shortcut (Ctrl+A)
await dispatchKey({
  type: 'keyDown',
  code: 'ControlLeft',
  key: 'Control',
  windowsVirtualKeyCode: 17
});
await dispatchKey({
  type: 'keyDown',
  code: 'KeyA',
  key: 'a',
  windowsVirtualKeyCode: 65
});
await dispatchKey({ type: 'keyUp', code: 'KeyA', key: 'a', windowsVirtualKeyCode: 65 });
await dispatchKey({ type: 'keyUp', code: 'ControlLeft', key: 'Control', windowsVirtualKeyCode: 17 });

Key Implementation Files

Understanding the keyboard helper requires familiarity with these specific files in the repository:

  • package/ego-browser/src/driver/keyboard.ts – Contains the implementations of fillInput, typeText, pressKey, and the low-level dispatchKeyEvent dispatcher.
  • package/ego-browser/src/element-resolver.ts – Handles the translation of user-friendly locators into CDP element references required by the keyboard methods.
  • skills/ego-browser/SKILL.md – Documents the public API surface for agent developers, listing available keyboard helpers and their signatures.
  • package/ego-browser/src/driver/keyboard.test.mjs – Validates that CDP calls are correctly formatted and that retry logic handles timeout scenarios properly.

Summary

  • The keyboard helper acts as a high-level interface to Chrome DevTools Protocol input commands, residing in package/ego-browser/src/driver/keyboard.ts.
  • fillInput resolves elements by selector, clears existing values, and types new text using dispatchKeyEvent.
  • typeText streams characters to the currently focused element without clearing existing content.
  • pressKey sends discrete down/up events for single virtual keys like Enter or Arrow keys.
  • dispatchKey provides raw access to CDP payloads, serving as the foundation for all other methods at lines 530-532.
  • The system implements automatic retry logic when detecting "CDP request timed out: Input.dispatchKeyEvent" errors (line 672).
  • Element resolution and focus management are decoupled into src/element-resolver.ts, ensuring consistent behavior across all input methods.

Frequently Asked Questions

What is the difference between fillInput and typeText?

fillInput combines three operations: it resolves an element using a selector, clears any existing value in that element, and then types the provided text. typeText only performs the typing action on the currently focused element without clearing content or resolving selectors. Use fillInput when targeting specific form fields by ID or CSS selector, and use typeText when the cursor is already positioned in the correct input field.

How does the keyboard helper handle CDP timeouts?

The helper monitors CDP responses for the specific error message "CDP request timed out: Input.dispatchKeyEvent" (as implemented at line 672 of keyboard.ts). When detected, the driver automatically retries the request according to the library's retry policy before re-attaching the session if necessary. This ensures that transient network issues or brief browser disconnections don't terminate automation workflows.

Can I use dispatchKey to simulate complex keyboard shortcuts?

Yes. While pressKey handles single keys, dispatchKey accepts complete CDP payload objects allowing you to construct complex chord sequences. You must manually dispatch individual keyDown and keyUp events for each key in the combination (such as Control, Alt, or Shift) in the correct order, providing full control over modifier states and timing that higher-level helpers abstract away.

Where does the keyboard helper resolve element selectors?

Element resolution occurs in src/element-resolver.ts, which converts user-friendly locators like css:#input or XPath expressions into CDP object IDs that the browser runtime understands. This resolver is shared across the keyboard helper methods, ensuring that fillInput and other locator-dependent functions consistently interpret selectors before focusing elements and dispatching key events.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →