CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-puppeteer-core

A high-level API to control headless Chrome and Firefox browsers over the DevTools Protocol and WebDriver BiDi

94

1.02x
Overview
Eval results
Files

input-simulation.mddocs/

Input Simulation

Realistic keyboard, mouse, and touchscreen input simulation with timing controls and platform-specific key mappings.

Capabilities

Keyboard Interface

Provides keyboard input simulation with support for key combinations, text typing, and special keys.

interface Keyboard {
  /** Press key down (without releasing) */
  down(key: string, options?: KeyDownOptions): Promise<void>;
  /** Release key */
  up(key: string): Promise<void>;
  /** Press and release key */
  press(key: string, options?: PressOptions): Promise<void>;
  /** Type text character by character */
  type(text: string, options?: TypeOptions): Promise<void>;
  /** Send single character */
  sendCharacter(char: string): Promise<void>;
}

interface KeyDownOptions {
  /** Text to insert */
  text?: string;
  /** Commands to send (Mac only) */
  commands?: string[];
}

interface PressOptions {
  /** Delay between key down and up */
  delay?: number;
  /** Text to insert */
  text?: string;
  /** Commands to send (Mac only) */
  commands?: string[];
}

interface TypeOptions {
  /** Delay between key presses */
  delay?: number;
}

Usage Examples:

import puppeteer from "puppeteer-core";

const browser = await puppeteer.launch({ executablePath: "/path/to/chrome" });
const page = await browser.newPage();
await page.goto("https://example.com");

const keyboard = page.keyboard;

// Basic typing
await page.focus("#text-input");
await keyboard.type("Hello World!", { delay: 100 });

// Key combinations
await keyboard.down("Control");
await keyboard.press("a"); // Select all
await keyboard.up("Control");

await keyboard.down("Control");
await keyboard.press("c"); // Copy
await keyboard.up("Control");

// Special keys
await keyboard.press("Tab");
await keyboard.press("Enter");
await keyboard.press("Escape");
await keyboard.press("Backspace");

// Arrow keys and navigation
await keyboard.press("ArrowUp");
await keyboard.press("ArrowDown");
await keyboard.press("ArrowLeft");
await keyboard.press("ArrowRight");

await keyboard.press("Home");
await keyboard.press("End");
await keyboard.press("PageUp");
await keyboard.press("PageDown");

// Function keys
await keyboard.press("F1");
await keyboard.press("F12");

// Modifier combinations
await keyboard.down("Shift");
await keyboard.press("ArrowRight"); // Select text
await keyboard.up("Shift");

await keyboard.down("Alt");
await keyboard.press("Tab"); // Alt+Tab
await keyboard.up("Alt");

await browser.close();

Mouse Interface

Provides mouse input simulation including movement, clicking, dragging, and scrolling.

interface Mouse {
  /** Move mouse to coordinates */
  move(x: number, y: number, options?: MouseMoveOptions): Promise<void>;
  /** Click at coordinates */
  click(x: number, y: number, options?: ClickOptions): Promise<void>;
  /** Press mouse button down */
  down(options?: MouseDownOptions): Promise<void>;
  /** Release mouse button */
  up(options?: MouseUpOptions): Promise<void>;
  /** Scroll mouse wheel */
  wheel(options?: MouseWheelOptions): Promise<void>;
  /** Drag from current position to target */
  drag(start: { x: number; y: number }, target: { x: number; y: number }): Promise<void>;
  /** Drag and drop operation */
  dragAndDrop(start: { x: number; y: number }, target: { x: number; y: number }, options?: DragAndDropOptions): Promise<void>;
}

interface MouseMoveOptions {
  /** Number of intermediate steps */
  steps?: number;
}

interface ClickOptions {
  /** Mouse button to click */
  button?: "left" | "right" | "middle";
  /** Number of clicks */
  clickCount?: number;
  /** Delay between mousedown and mouseup */
  delay?: number;
}

interface MouseDownOptions {
  /** Mouse button to press */
  button?: "left" | "right" | "middle";
  /** Number of clicks */
  clickCount?: number;
}

interface MouseUpOptions {
  /** Mouse button to release */
  button?: "left" | "right" | "middle";
  /** Number of clicks */
  clickCount?: number;
}

interface MouseWheelOptions {
  /** Horizontal scroll delta */
  deltaX?: number;
  /** Vertical scroll delta */
  deltaY?: number;
}

interface DragAndDropOptions {
  /** Delay during drag operation */
  delay?: number;
}

Usage Examples:

const mouse = page.mouse;

// Basic mouse operations
await mouse.move(100, 200);
await mouse.click(100, 200);

// Different click types
await mouse.click(300, 400, { button: "right" }); // Right-click
await mouse.click(500, 600, { button: "middle" }); // Middle-click
await mouse.click(700, 800, { clickCount: 2 }); // Double-click

// Mouse down/up for custom timing
await mouse.move(150, 250);
await mouse.down();
await page.waitForTimeout(1000); // Hold for 1 second
await mouse.up();

// Drag operations
await mouse.move(100, 100);
await mouse.down();
await mouse.move(200, 200, { steps: 10 }); // Smooth movement
await mouse.up();

// Drag and drop
await mouse.dragAndDrop(
  { x: 100, y: 100 },
  { x: 300, y: 300 },
  { delay: 100 }
);

// Scrolling
await mouse.move(500, 500);
await mouse.wheel({ deltaY: -100 }); // Scroll up
await mouse.wheel({ deltaY: 100 });  // Scroll down
await mouse.wheel({ deltaX: -50 });  // Scroll left
await mouse.wheel({ deltaX: 50 });   // Scroll right

// Complex mouse interactions
const element = await page.$("#draggable");
if (element) {
  const box = await element.boundingBox();
  if (box) {
    // Click and drag element
    await mouse.move(box.x + box.width / 2, box.y + box.height / 2);
    await mouse.down();
    await mouse.move(box.x + 100, box.y + 100, { steps: 5 });
    await mouse.up();
  }
}

Touchscreen Interface

Provides touch input simulation for mobile and touch-enabled devices.

interface Touchscreen {
  /** Tap at coordinates */
  tap(x: number, y: number): Promise<void>;
  /** Start touch at coordinates */
  touchStart(touches: TouchPoint[]): Promise<void>;
  /** Move touch points */
  touchMove(touches: TouchPoint[]): Promise<void>;
  /** End touch */
  touchEnd(): Promise<void>;
}

interface TouchPoint {
  x: number;
  y: number;
  /** Touch identifier for multi-touch */
  id?: number;
  /** Touch radius */
  radiusX?: number;
  radiusY?: number;
  /** Touch rotation angle */
  rotationAngle?: number;
  /** Touch pressure */
  force?: number;
}

Usage Examples:

const touchscreen = page.touchscreen;

// Basic tap
await touchscreen.tap(200, 300);

// Multi-touch gestures
await touchscreen.touchStart([
  { x: 100, y: 100, id: 0 },
  { x: 200, y: 200, id: 1 }
]);

// Pinch gesture (zoom out)
await touchscreen.touchMove([
  { x: 110, y: 110, id: 0 },
  { x: 190, y: 190, id: 1 }
]);

await touchscreen.touchEnd();

// Swipe gesture
await touchscreen.touchStart([{ x: 300, y: 400 }]);
await touchscreen.touchMove([{ x: 100, y: 400 }]); // Swipe left
await touchscreen.touchEnd();

// Complex touch interaction
const button = await page.$("#touch-button");
if (button) {
  const box = await button.boundingBox();
  if (box) {
    await touchscreen.tap(
      box.x + box.width / 2,
      box.y + box.height / 2
    );
  }
}

Key Constants and Mappings

Common key constants and platform-specific mappings:

type Key = 
  | "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
  | "Power" | "Eject" | "Abort" | "Help" | "Backspace" | "Tab" 
  | "Numlock" | "Scrolllock" | "Delete" | "Escape" | "F1" | "F2" 
  | "F3" | "F4" | "F5" | "F6" | "F7" | "F8" | "F9" | "F10" 
  | "F11" | "F12" | "F13" | "F14" | "F15" | "F16" | "F17" | "F18" 
  | "F19" | "F20" | "F21" | "F22" | "F23" | "F24" | "Digit0" 
  | "Digit1" | "Digit2" | "Digit3" | "Digit4" | "Digit5" | "Digit6" 
  | "Digit7" | "Digit8" | "Digit9" | "KeyA" | "KeyB" | "KeyC" 
  | "KeyD" | "KeyE" | "KeyF" | "KeyG" | "KeyH" | "KeyI" | "KeyJ" 
  | "KeyK" | "KeyL" | "KeyM" | "KeyN" | "KeyO" | "KeyP" | "KeyQ" 
  | "KeyR" | "KeyS" | "KeyT" | "KeyU" | "KeyV" | "KeyW" | "KeyX" 
  | "KeyY" | "KeyZ" | "Semicolon" | "Equal" | "Comma" | "Minus" 
  | "Period" | "Slash" | "Backquote" | "BracketLeft" | "Backslash" 
  | "BracketRight" | "Quote" | "Altleft" | "Altright" | "CapsLock" 
  | "ControlLeft" | "MetaLeft" | "ShiftLeft" | "ControlRight" 
  | "MetaRight" | "ShiftRight" | "ContextMenu" | "Enter" | "Space" 
  | "ArrowDown" | "ArrowLeft" | "ArrowRight" | "ArrowUp" | "End" 
  | "Home" | "Insert" | "PageDown" | "PageUp" | "PrintScreen" 
  | "NumpadDivide" | "NumpadMultiply" | "NumpadSubtract" 
  | "NumpadAdd" | "NumpadEnter" | "NumpadDecimal" | "Numpad0" 
  | "Numpad1" | "Numpad2" | "Numpad3" | "Numpad4" | "Numpad5" 
  | "Numpad6" | "Numpad7" | "Numpad8" | "Numpad9" | "Copy" 
  | "Cut" | "Paste" | "AudioVolumeMute" | "AudioVolumeDown" 
  | "AudioVolumeUp" | "MediaTrackNext" | "MediaTrackPrevious" 
  | "MediaStop" | "MediaPlayPause" | "BrowserSearch" | "BrowserHome" 
  | "BrowserBack" | "BrowserForward" | "BrowserRefresh" 
  | "BrowserStop" | "BrowserFavorites" | "LaunchApplication1" 
  | "LaunchApplication2" | "LaunchMail" | "LaunchMediaPlayer";

interface USKeyboardLayout {
  [key: string]: {
    keyCode: number;
    shiftKeyCode?: number;
    key: string;
    shiftKey?: string;
    code: string;
    text?: string;
    shiftText?: string;
    location?: number;
  };
}

Usage Examples:

// Using key constants
await keyboard.press("Enter");
await keyboard.press("ArrowDown");
await keyboard.press("F1");
await keyboard.press("ControlLeft");

// Key combinations with proper timing
await keyboard.down("ShiftLeft");
await keyboard.press("KeyA"); // Capital A
await keyboard.up("ShiftLeft");

// Platform-specific shortcuts
const isMac = process.platform === "darwin";
const cmdOrCtrl = isMac ? "MetaLeft" : "ControlLeft";

await keyboard.down(cmdOrCtrl);
await keyboard.press("KeyC"); // Copy
await keyboard.up(cmdOrCtrl);

await keyboard.down(cmdOrCtrl);
await keyboard.press("KeyV"); // Paste
await keyboard.up(cmdOrCtrl);

Advanced Input Scenarios

Complex input scenarios and best practices:

interface AdvancedInputScenarios {
  /** Simulate realistic typing with human-like delays */
  humanType(text: string, options?: HumanTypeOptions): Promise<void>;
  /** Simulate form filling with tab navigation */
  fillForm(fields: FormField[]): Promise<void>;
  /** Simulate file drag and drop */
  dragDropFile(filePath: string, target: ElementHandle): Promise<void>;
  /** Simulate drawing/signature input */
  drawPath(points: Point[], options?: DrawOptions): Promise<void>;
}

interface HumanTypeOptions {
  /** Base delay between keystrokes */
  baseDelay?: number;
  /** Random delay variation */
  variation?: number;
  /** Typing mistakes probability */
  mistakeRate?: number;
}

interface FormField {
  selector: string;
  value: string;
  type?: "text" | "email" | "password" | "number";
}

interface Point {
  x: number;
  y: number;
}

interface DrawOptions {
  pressure?: number;
  smooth?: boolean;
  delay?: number;
}

Usage Examples:

// Realistic human typing
async function humanType(page: Page, selector: string, text: string) {
  await page.focus(selector);
  
  for (let i = 0; i < text.length; i++) {
    const char = text[i];
    const delay = Math.random() * 100 + 50; // 50-150ms random delay
    
    await page.keyboard.type(char);
    await page.waitForTimeout(delay);
    
    // Occasionally make a mistake and correct it
    if (Math.random() < 0.05) { // 5% mistake rate
      await page.keyboard.press("Backspace");
      await page.waitForTimeout(200);
      await page.keyboard.type(char);
    }
  }
}

// Form automation with tab navigation
async function fillFormWithTabs(page: Page) {
  const fields = [
    { selector: "#firstName", value: "John" },
    { selector: "#lastName", value: "Doe" },
    { selector: "#email", value: "john.doe@example.com" },
    { selector: "#phone", value: "555-0123" }
  ];
  
  await page.focus(fields[0].selector);
  
  for (const field of fields) {
    await page.keyboard.type(field.value);
    await page.keyboard.press("Tab");
    await page.waitForTimeout(200);
  }
}

// Signature/drawing simulation
async function drawSignature(page: Page, canvasSelector: string) {
  const canvas = await page.$(canvasSelector);
  if (!canvas) return;
  
  const box = await canvas.boundingBox();
  if (!box) return;
  
  const startX = box.x + 50;
  const startY = box.y + box.height / 2;
  
  // Draw a simple signature curve
  await page.mouse.move(startX, startY);
  await page.mouse.down();
  
  for (let i = 0; i <= 100; i++) {
    const x = startX + i * 2;
    const y = startY + Math.sin(i * 0.1) * 20;
    await page.mouse.move(x, y);
    await page.waitForTimeout(10);
  }
  
  await page.mouse.up();
}

// File drag and drop simulation
async function simulateFileDrop(page: Page, filePath: string, dropSelector: string) {
  const dropZone = await page.$(dropSelector);
  if (!dropZone) return;
  
  const box = await dropZone.boundingBox();
  if (!box) return;
  
  // Simulate drag and drop events
  const fileInput = await page.evaluateHandle(() => {
    const input = document.createElement('input');
    input.type = 'file';
    input.style.display = 'none';
    document.body.appendChild(input);
    return input;
  });
  
  await fileInput.uploadFile(filePath);
  
  await page.evaluate((input, dropZone) => {
    const file = input.files[0];
    const dt = new DataTransfer();
    dt.items.add(file);
    
    const dragEvent = new DragEvent('drop', {
      dataTransfer: dt,
      bubbles: true,
      cancelable: true
    });
    
    dropZone.dispatchEvent(dragEvent);
  }, await fileInput.asElement(), await dropZone.asElement());
}

Error Handling

Common input-related errors and handling strategies:

class InputError extends Error {
  constructor(message: string);
}

class KeyboardError extends InputError {
  constructor(message: string);
}

class MouseError extends InputError {
  constructor(message: string);
}

Usage Examples:

// Safe input operations
async function safeType(page: Page, selector: string, text: string) {
  try {
    await page.waitForSelector(selector, { timeout: 5000 });
    await page.focus(selector);
    await page.keyboard.type(text);
    return true;
  } catch (error) {
    console.log(`Failed to type in ${selector}:`, error.message);
    return false;
  }
}

// Retry mechanism for flaky inputs
async function retryClick(page: Page, x: number, y: number, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      await page.mouse.click(x, y);
      return true;
    } catch (error) {
      console.log(`Click attempt ${i + 1} failed:`, error.message);
      if (i === maxRetries - 1) throw error;
      await page.waitForTimeout(1000);
    }
  }
  return false;
}

Install with Tessl CLI

npx tessl i tessl/npm-puppeteer-core

docs

browser-contexts.md

browser-management.md

element-handling.md

index.md

input-simulation.md

locators-selectors.md

network-management.md

page-interaction.md

tile.json