Constructs a new Mouse instance.
Optionaloptions: MouseOptions
Optional configuration options for mouse behavior and dependencies.
Configuration options for the Mouse class. All properties are optional and provide sensible defaults.
OptionalclickDistanceThreshold?: numberMaximum allowed distance (in cells) between press and release to qualify as a click. Defaults to 1, meaning the press and release must be within 1 cell in both X and Y directions. Set to 0 to require exact same position, or higher values to allow more movement.
OptionaldegradedDedupDistance?: numberIn degraded mode, presses within this many cells of the last synthesized click are treated as the same click (one terminal click can be reported as several button presses at the same spot). Defaults to 1.
OptionaldegradedDedupWindowMs?: numberIn degraded mode, how long (ms) a synthesized click's position is deduplicated for. A press at the same spot after this window is a NEW click, not a duplicate report. Defaults to 300. Set to 0 to dedupe only same-millisecond bursts (practically disables position dedup).
Optionalemitter?: EventEmitterThe event emitter to use for emitting mouse events. Defaults to a new EventEmitter instance.
OptionalinputStream?: ReadableStreamWithEncodingThe readable stream to listen for mouse events on.
Defaults to process.stdin.
OptionaloutputStream?: NodeJS.WriteStreamThe writable stream to send control sequences to.
Defaults to process.stdout.
OptionalpressStormThreshold?: numberConsecutive press events with no release in between that trigger
degraded "press-is-click" mode. Some terminals (e.g. VS Code's built-in
terminal) stop reporting releases after multiple buttons are pressed
simultaneously; without this fallback clicks would never be synthesized
there. Defaults to 3. Set to Infinity to disable degraded mode.
OptionalpressStormWindowMs?: numberHow long (ms) presses are allowed to span while still counting toward
pressStormThreshold. A press arriving after this window restarts the
count. Defaults to 500. This prevents a slow multi-button press on a
well-behaved terminal from spuriously entering degraded mode. Set to
Infinity to count presses without any time limit.
OptionalsetRawMode?: (mode: boolean) => voidCustom function to set raw mode on the input stream.
If not provided, defaults to inputStream.setRawMode.
This is useful for testing or for custom terminal behavior.
// Default configuration
const mouse = new Mouse();
// Custom streams
const mouse2 = new Mouse({
inputStream: customStdin,
outputStream: customStdout,
});
// Custom emitter
const mouse3 = new Mouse({
emitter: myEventEmitter,
});
// Testing with mock setRawMode
const mockSetRawMode = vi.fn();
const mouse4 = new Mouse({ setRawMode: mockSetRawMode });
// Custom click threshold
const mouse5 = new Mouse({ clickDistanceThreshold: 0 });
// All options combined
const mouse6 = new Mouse({
emitter: myEventEmitter,
inputStream: customStdin,
outputStream: customStdout,
setRawMode: mockSetRawMode,
clickDistanceThreshold: 5,
});
Static ReadonlySupportResult type for terminal capability checks.
ReadonlyNotTTY: "not_tty"Input stream is not a TTY
ReadonlyOutputNotTTY: "output_not_tty"Output stream is not a TTY
ReadonlySupported: "supported"Mouse events are supported
Returns an async generator that yields move events at most once per specified interval.
This method provides debounced move events, reducing event frequency for smooth animations
and performance optimization. Unlike eventsOf('move') which yields every move event,
this method waits for a quiet period before emitting, ensuring you only get events at
a controlled rate.
Debouncing Behavior:
Cancellation with AbortSignal: The async generator supports cancellation through
the signal option. When the provided AbortSignal is aborted, the generator will stop
immediately and clean up all listeners.
Cleanup: The generator automatically cleans up event listeners and timers when:
Optionaloptions: { interval?: number; signal?: AbortSignal }
Configuration for the debounced event stream.
Optionalinterval?: numberMinimum time in milliseconds between yielded events. Defaults to 16 (~60fps).
Optionalsignal?: AbortSignalAn AbortSignal to cancel the async generator and clean up resources.
const mouse = new Mouse();
mouse.enable();
// Track mouse position at ~60fps for smooth cursor following
for await (const event of mouse.debouncedMoveEvents()) {
console.log(`Mouse at ${event.x}, ${event.y}`);
}
// Slower update rate (30fps) for less frequent UI updates
for await (const event of mouse.debouncedMoveEvents({ interval: 33 })) {
updateCursorPosition(event.x, event.y);
}
// Debounced move events with cancellation
const controller = new AbortController();
setTimeout(() => controller.abort(), 10000); // Stop after 10 seconds
try {
for await (const event of mouse.debouncedMoveEvents({ signal: controller.signal })) {
// Smooth animation update at 60fps
renderFrame(event.x, event.y);
}
} catch (err) {
if (err instanceof MouseError && err.message.includes('aborted')) {
console.log('Animation stopped');
}
}
// Comparing debounced vs raw move events
const mouse = new Mouse();
mouse.enable();
// Raw: Can fire hundreds of times per second
for await (const event of mouse.eventsOf('move')) {
console.log('Raw move'); // May print too fast to read
if (event.x > 50) break;
}
// Debounced: Controlled rate, easier to process
for await (const event of mouse.debouncedMoveEvents({ interval: 100 })) {
console.log('Debounced move'); // Prints at most 10 times per second
if (event.x > 50) break;
}
Disables mouse tracking and removes all event listeners.
Recommended for Immediate Cleanup:
This method is the recommended way to clean up a Mouse instance when you're done with it.
While automatic cleanup via FinalizationRegistry prevents memory leaks on garbage collection,
calling destroy() explicitly ensures immediate and predictable resource release with
no dependency on GC timing.
Idempotent: Calling this method multiple times is safe and has no additional effect.
Side Effects:
disable() to stop mouse tracking and restore stream stateDisables mouse event tracking. This method restores the input stream to its previous state and stops listening for data.
enable to enable tracking and capture mouse events
Enables mouse event tracking.
This method activates mouse event capture by putting the input stream into raw mode and sending the appropriate ANSI escape sequences to enable mouse tracking in the terminal.
TTY Requirement: This method requires the input stream to be a TTY (terminal).
Mouse events cannot be captured when the input is piped, redirected, or running in a
non-interactive environment. Check process.stdin.isTTY before calling this method.
Error Handling: This method throws a MouseError if:
Automatic Cleanup:
When enable() is called, the Mouse instance registers with a FinalizationRegistry.
If the instance is garbage collected without explicit cleanup via disable() or destroy(),
the registry will automatically remove the stdin listener and restore stream state to prevent
memory leaks. This is a safety net - explicit cleanup via destroy() is still recommended
for immediate and predictable resource release.
Side Effects:
disable()Returns an async generator that yields mouse events of a specific type.
This method provides a convenient way to iterate over mouse events using async/await syntax. The async generator will yield events as they occur, allowing for clean and readable event handling code.
Cancellation with AbortSignal: The async generator supports cancellation through the signal option.
When the provided AbortSignal is aborted, the generator will throw a MouseError and clean up all listeners.
This is particularly useful for implementing timeout functionality or user-initiated cancellation.
Queue Management:
maxQueue (default: 100, max: 1000)latestOnly is true, only the most recent event is buffered, dropping intermediate eventsError Handling: Errors from the mouse event stream will be thrown from the generator, allowing for try/catch error handling in the iteration loop.
Cleanup: The generator automatically cleans up event listeners when:
The type of mouse event to listen for (e.g., 'press', 'drag', 'wheel').
Optionaloptions: { latestOnly?: boolean; maxQueue?: number; signal?: AbortSignal }
Configuration for the event stream.
OptionallatestOnly?: booleanIf true, only the latest event is buffered. Defaults to false.
OptionalmaxQueue?: numberThe maximum number of events to queue. Defaults to 100, with a maximum of 1000.
Optionalsignal?: AbortSignalAn AbortSignal to cancel the async generator and clean up resources.
const mouse = new Mouse();
mouse.enable();
// Collect 5 mouse clicks
const clicks: MouseEvent[] = [];
for await (const event of mouse.eventsOf('click')) {
clicks.push(event);
console.log(`Click at ${event.x}, ${event.y}`);
if (clicks.length >= 5) break;
}
mouse.disable();
// Track mouse movement with cancellation after 5 seconds
const controller = new AbortController();
setTimeout(() => controller.abort(), 5000);
try {
for await (const event of mouse.eventsOf('move', { signal: controller.signal })) {
console.log(`Mouse moved to ${event.x}, ${event.y}`);
}
} catch (err) {
if (err instanceof MouseError && err.message.includes('aborted')) {
console.log('Tracking stopped after timeout');
} else {
throw err;
}
}
// Track only the latest mouse position (for high-frequency events)
const mouse = new Mouse();
mouse.enable();
// Display cursor position updates
for await (const event of mouse.eventsOf('move', { latestOnly: true })) {
// Clear line and show position
process.stdout.write(`\r\x1b[KPosition: ${event.x}, ${event.y}`);
}
// Implement drag detection with user cancellation
const controller = new AbortController();
// Listen for Ctrl+C to cancel
process.stdin.setRawMode(true);
process.stdin.on('data', (key) => {
if (key[0] === 3) { // Ctrl+C
controller.abort();
}
});
try {
for await (const event of mouse.eventsOf('drag', { signal: controller.signal })) {
console.log(`Dragging at ${event.x}, ${event.y} with button ${event.button}`);
}
} catch (err) {
if (err instanceof MouseError && err.message.includes('aborted')) {
console.log('\nDrag tracking cancelled by user');
}
} finally {
mouse.disable();
}
Gets the last known mouse position synchronously.
This method immediately returns the last cached mouse position from move or drag events, without waiting for new events. Returns null if no mouse movement has occurred yet.
No Waiting: Unlike getMousePosition(), this method never waits - it returns
the cached position immediately or null if unavailable.
Use Cases:
The last known position as { x, y }, or null if no movement yet.
const mouse = new Mouse();
mouse.enable();
// Returns null if mouse hasn't moved yet
const pos = mouse.getLastPosition();
if (pos) {
console.log(`Mouse at ${pos.x}, ${pos.y}`);
} else {
console.log('No movement yet');
}
Gets the current mouse position, returning immediately if available.
This method returns the last known mouse position from move or drag events. If the mouse has moved since tracking was enabled, the position is returned immediately without waiting. Otherwise, it waits for the next move event.
Cached Position: The method maintains an internal cache of the last position from move or drag events. This allows for instant position retrieval without waiting for new events.
Timeout: The method will reject with a MouseError if the timeout is exceeded
while waiting for the first move event.
Cancellation: The method can be cancelled early using an AbortSignal.
Optionaloptions: { signal?: AbortSignal; timeout?: number }
Configuration options for the wait operation.
Optionalsignal?: AbortSignalAn AbortSignal to cancel the operation early.
Optionaltimeout?: numberMaximum time to wait in milliseconds. Defaults to 30000 (30 seconds).
A promise that resolves with the x, y coordinates.
const mouse = new Mouse();
mouse.enable();
try {
// If mouse has moved, returns immediately
// Otherwise waits for first move event
const { x, y } = await mouse.getMousePosition();
console.log(`Mouse is at ${x}, ${y}`);
} finally {
mouse.disable();
}
Checks if mouse event tracking is currently enabled.
True if enabled, false otherwise.
Checks if mouse event emission is currently paused.
This method returns the current pause state of mouse event emission. When paused, no mouse events will be emitted, but terminal mouse mode remains active.
Independent from enabled state: The paused state is independent from the enabled state. You can have:
Difference from isEnabled():
True if event emission is paused, false otherwise.
const mouse = new Mouse();
mouse.enable();
console.log(mouse.isPaused()); // false
mouse.pause();
console.log(mouse.isPaused()); // true
mouse.resume();
console.log(mouse.isPaused()); // false
// Comparing isPaused() vs isEnabled()
const mouse = new Mouse();
mouse.enable();
console.log(mouse.isEnabled()); // true (terminal mouse mode active)
console.log(mouse.isPaused()); // false (events are being emitted)
mouse.pause();
console.log(mouse.isEnabled()); // true (terminal mouse mode still active!)
console.log(mouse.isPaused()); // true (events are paused)
mouse.disable();
console.log(mouse.isEnabled()); // false (terminal mouse mode inactive)
console.log(mouse.isPaused()); // true (pause state is preserved)
// Practical use: Check state before performing operations
const mouse = new Mouse();
mouse.enable();
function performSensitiveOperation() {
// Save current state
const wasPaused = mouse.isPaused();
// Ensure we're paused during the operation
mouse.pause();
// ... perform operation ...
// Restore previous state
if (!wasPaused) {
mouse.resume();
}
}
Removes a listener for a specific mouse event.
Type Inference:
This method uses the same type inference as on() to ensure type safety when removing listeners.
The name of the event to stop listening for.
The callback function to remove.
The event emitter instance.
on to add a listener
Registers a listener for a specific mouse event.
Type Inference: This method uses TypeScript's type inference to provide accurate types for the event parameter based on the event name. For example:
event.button is typed as 'wheel-up' | 'wheel-down' | 'wheel-left' | 'wheel-right'event.button is typed as 'none'event.button excludes wheel buttonsThe name of the event to listen for.
The callback function to execute when the event is triggered.
The event emitter instance.
off to remove the listener
const mouse = new Mouse();
mouse.enable();
// TypeScript knows event.button is a wheel button type here
mouse.on('wheel', (event) => {
console.log(event.button); // 'wheel-up' | 'wheel-down' | 'wheel-left' | 'wheel-right'
});
// TypeScript knows event.button is 'none' here
mouse.on('move', (event) => {
console.log(event.button); // 'none'
});
Registers a one-time listener that automatically removes itself after the first event.
Type Inference:
This method uses the same type inference as on() to provide accurate types for the event parameter.
Automatic Cleanup: The listener is automatically removed after the first invocation, preventing memory leaks and eliminating the need for manual cleanup code.
The name of the event to listen for.
The callback function to execute once when the event is triggered.
The event emitter instance.
const mouse = new Mouse();
mouse.enable();
// Listen for a single click
mouse.once('click', (event) => {
console.log('Got one click!', event);
// Listener is automatically removed after this execution
});
// Wait for first wheel event
mouse.once('wheel', (event) => {
// TypeScript knows event.button is a wheel button type
console.log(`Scrolled: ${event.button}`);
});
// Simplified one-time event handling
// Before (manual cleanup required):
const handler = (event) => {
console.log('Got click', event);
mouse.off('click', handler);
// continue logic...
};
mouse.on('click', handler);
// After (automatic cleanup):
mouse.once('click', (event) => {
console.log('Got click', event);
// continue logic... listener already removed
});
Pauses mouse event emission without disabling terminal mouse mode.
This method temporarily stops the emission of mouse events while keeping the terminal mouse mode active. This is useful when you want to temporarily ignore mouse events without the overhead of disabling and re-enabling mouse tracking.
Idempotent: Calling this method when already paused has no effect.
No Terminal State Changes: Unlike disable, this method does not:
Difference from disable():
const mouse = new Mouse();
mouse.enable();
// Temporarily ignore mouse events during an operation
mouse.pause();
// ... perform operations that should not trigger mouse events
mouse.resume();
// Comparing pause() vs disable()
const mouse = new Mouse();
mouse.enable();
// Using pause(): Fast, no terminal overhead
mouse.pause();
performQuickOperation();
mouse.resume(); // Terminal mouse mode was never disabled
// VS using disable(): Slower, terminal overhead
mouse.disable();
performQuickOperation();
mouse.enable(); // Had to re-enable terminal mouse mode
Resumes mouse event emission without modifying terminal mouse mode.
This method resumes the emission of mouse events after they were paused using pause. The terminal mouse mode remains active throughout.
Idempotent: Calling this method when not paused has no effect.
No Terminal State Changes: Unlike enable, this method does not:
Difference from enable():
const mouse = new Mouse();
mouse.enable();
// Temporarily ignore mouse events during an operation
mouse.pause();
// ... perform operations that should not trigger mouse events
mouse.resume(); // Events will now be emitted again
// Comparing resume() vs enable()
const mouse = new Mouse();
mouse.enable();
// Pause and resume: Fast state change
mouse.pause();
performOperation();
mouse.resume(); // No terminal overhead
// VS disable and enable: Slower, re-enables terminal
mouse.disable();
performOperation();
mouse.enable(); // Re-enables terminal mouse mode (ANSI codes, raw mode)
Returns an async generator that yields all mouse events. Each yielded value is an object containing the event type and the event data.
Optionaloptions: { latestOnly?: boolean; maxQueue?: number; signal?: AbortSignal }
Configuration for the event stream.
OptionallatestOnly?: booleanIf true, only the latest event is buffered. Defaults to false.
OptionalmaxQueue?: numberThe maximum number of events to queue. Defaults to 1000.
Optionalsignal?: AbortSignalAn AbortSignal to cancel the async generator.
Waits for a single click event and returns it.
This is a convenience method that wraps the streaming API into a simple promise-based helper. It's useful for common interaction patterns like "wait for user to click anywhere".
Timeout: The method will reject with a MouseError if the timeout is exceeded.
Cancellation: The method can be cancelled early using an AbortSignal.
Optionaloptions: { signal?: AbortSignal; timeout?: number }
Configuration options for the wait operation.
Optionalsignal?: AbortSignalAn AbortSignal to cancel the operation early.
Optionaltimeout?: numberMaximum time to wait in milliseconds. Defaults to 30000 (30 seconds).
A promise that resolves with the click event.
const mouse = new Mouse();
mouse.enable();
try {
const click = await mouse.waitForClick();
console.log(`Clicked at ${click.x}, ${click.y} with ${click.button}`);
} catch (err) {
if (err instanceof MouseError) {
console.error('Timeout or error:', err.message);
}
} finally {
mouse.disable();
}
// Cancel with AbortController
const controller = new AbortController();
setTimeout(() => controller.abort(), 1000);
try {
const click = await mouse.waitForClick({ signal: controller.signal });
} catch (err) {
if (err instanceof MouseError && err.message.includes('aborted')) {
console.log('Wait cancelled');
}
}
Waits for any mouse input event and returns it.
This is a convenience method that waits for any mouse event (press, release, click, drag, wheel, or move). Useful for "wait for any user interaction" patterns.
Timeout: The method will reject with a MouseError if the timeout is exceeded.
Cancellation: The method can be cancelled early using an AbortSignal.
Optionaloptions: { signal?: AbortSignal; timeout?: number }
Configuration options for the wait operation.
Optionalsignal?: AbortSignalAn AbortSignal to cancel the operation early.
Optionaltimeout?: numberMaximum time to wait in milliseconds. Defaults to 30000 (30 seconds).
A promise that resolves with the first mouse event received.
StaticcheckPerforms a detailed check of terminal mouse event support.
This method provides more information than isSupported() by checking
specific streams and returning the reason if support is not available.
Use Cases:
Optionaloptions: Pick<MouseOptions, "inputStream" | "outputStream">
Optional configuration with custom streams to check
The input stream to check (defaults to process.stdin)
The output stream to check (defaults to process.stdout)
A result from SupportCheckResult indicating support status
import { Mouse } from 'xterm-mouse';
const result = Mouse.checkSupport();
if (result === Mouse.SupportCheckResult.Supported) {
console.log('Mouse events are supported!');
} else if (result === Mouse.SupportCheckResult.NotTTY) {
console.error('Not running in a terminal');
} else if (result === Mouse.SupportCheckResult.OutputNotTTY) {
console.error('Output is not a terminal');
}
StaticisChecks if the current terminal environment supports mouse events.
This is a convenience method that wraps checkSupport and returns
a simple boolean. It checks if the provided streams (or process.stdin/
process.stdout by default) are TTYs.
Use Cases:
Note: For detailed error information (e.g., to distinguish between input and output stream issues), use checkSupport instead.
OptionalinputStream: ReadableStreamWithEncoding
Optional input stream to check (defaults to process.stdin)
OptionaloutputStream: WriteStream
Optional output stream to check (defaults to process.stdout)
true if the terminal likely supports mouse events
Represents and manages mouse events in a TTY environment.
This class is a facade that composes smaller, focused components:
Automatic Cleanup: Mouse instances automatically register for cleanup when
enable()is called. If a Mouse instance is garbage collected without explicit cleanup viadisable()ordestroy(), the TTYController ensures that stdin event listeners are removed to prevent memory leaks.Recommended Cleanup: Despite automatic cleanup, it's still recommended to explicitly call
destroy()when done with a Mouse instance for immediate and predictable resource release.