npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@limbusfoundation/winput

v2.0.0

Published

Native Windows input capture and injection for Node.js.

Readme

Winput

Native Windows input capture and injection for Node.js.

@limbusfoundation/winput provides a simple TypeScript API for listening to and controlling keyboard and mouse input through native Win32 APIs.

The native implementation is written in Rust and communicates with Windows through Win32 and N-API.

Windows only


Installation

npm install @limbusfoundation/winput

Basic Usage

import { Winput } from "@limbusfoundation/winput";

const input = new Winput();

input.onAnyKeydown(event => {
    console.log(event.key);
});

input.onClick(event => {
    console.log(event.button, event.x, event.y);
});

Keyboard

Listening

onAnyKeydown

Listen for every key press.

input.onAnyKeydown(event => {
    console.log(event.key);
});

onAnyKeyup

Listen for every key release.

input.onAnyKeyup(event => {
    console.log(event.key);
});

onKeydown

Listen for a specific key.

input.onKeydown("A", event => {
    console.log(event.key);
});

onKeyup

Listen for a specific key release.

input.onKeyup("A", event => {
    console.log(event.key);
});

Keyboard Event

interface WinputKeyEvent {
    key: string;
    state: "Pressed" | "Released";
    modifiers: string;
}

modifiers contains the currently active modifier keys.

Example:

ctrl
shift
alt
none

Keyboard Injection

keyDown(key)

Press and hold a key.

input.keyDown("A");

Important: keyDown() does not release the key.

The key remains pressed until keyUp() is called.

input.keyDown("A");

// A is still pressed here.

input.keyUp("A");

Always release keys that were manually pressed.


keyUp(key)

Release a previously pressed key.

input.keyUp("A");

keyTap(key)

Press and release a key immediately.

input.keyTap("A");

For normal single-key input, prefer keyTap() when you do not need to keep the key pressed.


Mouse

Listening

onMouseMove

Listen for mouse movement.

input.onMouseMove(event => {
    console.log(event.x, event.y);
});

onClick

Listen for mouse button presses.

input.onClick(event => {
    console.log(event.button, event.x, event.y);
});

onDoubleClick

Listen for double clicks.

input.onDoubleClick(event => {
    console.log(event.button, event.x, event.y);
});

onMouseScroll

Listen for mouse wheel events.

input.onMouseScroll(event => {
    console.log(event.delta, event.x, event.y);
});

Mouse Events

interface WinputClickEvent {
    button: string;
    x: number;
    y: number;
}
interface WinputMouseMoveEvent {
    x: number;
    y: number;
}
interface WinputMouseScrollEvent {
    delta: number;
    x: number;
    y: number;
}

Mouse Injection

mouseMove(x, y, absolute)

Move the mouse.

Absolute position

When absolute is true, the coordinates represent a position on the screen.

input.mouseMove(500, 300, true);

Relative movement

When absolute is false, the coordinates represent movement relative to the current cursor position.

input.mouseMove(100, 50, false);

Mouse Buttons

The following buttons are supported:

left
right
middle
x1
x2

mouseDown(button)

Press and hold a mouse button.

input.mouseDown("left");

Important: mouseDown() does not release the button.

The button remains pressed until mouseUp() is called.

input.mouseDown("left");

// Left button is still pressed here.

input.mouseUp("left");

Always pair a manual mouseDown() with a corresponding mouseUp().


mouseUp(button)

Release a mouse button.

input.mouseUp("left");

click(button)

Perform a complete click.

input.click("left");

Conceptually, this performs:

input.mouseDown("left");
input.mouseUp("left");

Use click() when you want a normal click.

Use mouseDown() and mouseUp() separately when you need to control how long the button remains pressed.


scroll(delta)

Inject a mouse wheel event.

input.scroll(120);

Positive and negative values represent opposite scroll directions.


Safe Usage

Winput can control real system input. Be careful when using manual press/release operations.

Always release manually pressed keys

Avoid:

input.keyDown("A");

without a corresponding release.

Prefer:

input.keyDown("A");

try {
    // Work while A is pressed.
} finally {
    input.keyUp("A");
}

This guarantees that the key is released even if an error occurs.


Always release manually pressed mouse buttons

Avoid:

input.mouseDown("middle");

without a corresponding mouseUp().

Prefer:

input.mouseDown("middle");

try {
    // Work while the button is pressed.
} finally {
    input.mouseUp("middle");
}

A forgotten mouseUp() can leave the button logically pressed by Windows.

This can make the mouse behave as if it is stuck or unresponsive.


Prefer click() for normal clicks

If you simply want to click a button, use:

input.click("left");

instead of manually doing:

input.mouseDown("left");
input.mouseUp("left");

Manual mouseDown() / mouseUp() should be used when the pressed state itself is important.


Complete Example

import { Winput } from "@limbusfoundation/winput";

const input = new Winput();

input.onAnyKeydown(event => {
    console.log("[KEY DOWN]", event.key, event.modifiers);
});

input.onAnyKeyup(event => {
    console.log("[KEY UP]", event.key, event.modifiers);
});

input.onClick(event => {
    console.log("[CLICK]", event.button, event.x, event.y);
});

input.onDoubleClick(event => {
    console.log("[DOUBLE CLICK]", event.button, event.x, event.y);
});

input.onMouseMove(event => {
    console.log("[MOVE]", event.x, event.y);
});

input.onMouseScroll(event => {
    console.log("[SCROLL]", event.delta, event.x, event.y);
});

input.keyTap("A");

input.click("left");

input.mouseMove(500, 300, true);

input.scroll(120);

API

| Method | Description | | --------------------------- | --------------------------------- | | onAnyKeydown(callback) | Listen for all key presses | | onAnyKeyup(callback) | Listen for all key releases | | onKeydown(key, callback) | Listen for a specific key press | | onKeyup(key, callback) | Listen for a specific key release | | onMouseMove(callback) | Listen for mouse movement | | onClick(callback) | Listen for mouse button presses | | onDoubleClick(callback) | Listen for double clicks | | onMouseScroll(callback) | Listen for mouse wheel events | | onMouseDown(callback) | Listen for mouse button is pressed| | onMouseUp(callback) | Listen for mouse button is release| | keyDown(key) | Press and hold a key | | keyUp(key) | Release a key | | keyTap(key) | Press and release a key | | mouseMove(x, y, absolute) | Move the cursor | | mouseDown(button) | Press and hold a mouse button | | mouseUp(button) | Release a mouse button | | click(button) | Press and release a mouse button | | scroll(delta) | Inject mouse wheel input |


Native Implementation

Winput uses:

TypeScript
    ↓
N-API
    ↓
Rust
    ↓
Win32
    ↓
Windows

Keyboard and mouse events are captured using native Windows low-level hooks, while input injection uses the Windows SendInput API.

No third-party input automation framework is required for the native input layer.