@maciejwojs/input-bridge
v0.3.1
Published
Native input bridge addon for Node.js
Downloads
108
Maintainers
Readme
@maciejwojs/input-bridge
Native Node.js addon for simulating hardware input events on Windows and Linux. The package exposes a single JavaScript API for mouse movement, clicks, keyboard events, scrolling, and typed text, with batched execution and optimization support.
Features
- Windows backend using the native
SendInputAPI - Linux backend using the Freedesktop
RemoteDesktopportal on Wayland - Optional Linux X11 backend for environments where Wayland is unavailable
- Batched event queue with explicit
flush()execution - Relative and absolute mouse movement
- Mouse button clicks and wheel scrolling
- Raw keyboard events and typed Unicode text
- DOM
KeyboardEvent.codemapping viakeyPressDOM() - Clipboard reading and writing text and files support for Wayland (
wl-copy/wl-paste) and X11 (xclip) - Movement optimization via
optimizeMouseMovesRelative()andoptimizeMouseMovesAbsolute() - Optional native logger callback from the addon
Install
bun installQuick start
import { InputBridge } from '@maciejwojs/input-bridge';
const bridge = new InputBridge({ autoFlush: false });
await bridge.init();
bridge.moveMouseRelative(10, 0);
bridge.mouseClick(0, true);
bridge.mouseClick(0, false);
bridge.flush();API overview
init()- initializes the native bridge; on Wayland runs the full portal flow throughRemoteDesktop.Startso monitor list is ready for screen-capture pairingmoveMouseRelative(x, y)- queue a relative mouse movementmoveMouseAbsolute(x, y)- queue an absolute mouse movementmouseClick(button, down)- queue a mouse button press/releasekeyPress(keyCode, down)- queue a raw keyboard press/releasekeyPressDOM(domCode, down)- queue a scan-code based key event from DOMKeyboardEvent.codescrollMouse(delta)- queue a mouse wheel scroll eventtypeString(text)- queue typed Unicode textsetClipboardText(text)- copy text to the clipboardgetClipboardText()- read text from the clipboardsetClipboardFiles(paths)- copy a list of files to the clipboardgetClipboardFiles()- read a list of files from the clipboardoptimizeMouseMovesRelative(distanceThreshold)- reduce buffered relative move eventsoptimizeMouseMovesAbsolute(distanceThreshold)- reduce buffered absolute move eventstoggleOptimization()- enable/disable internal mouse move optimizationflush()- execute all queued input eventssetLogger(callback)- receive native backend log messages
In addition to the InputBridge class, the package exports a standalone
getCursorType() function that returns the current system pointer cursor as
a CSS-compatible name.
import { getCursorType } from '@maciejwojs/input-bridge';
console.log(getCursorType()); // "default", "pointer", "text", ...Behavior per platform:
- Windows uses
GetCursorInfoand maps the standard system cursors to CSS values such asdefault,pointer,text,crosshair,move,wait,progress,help,not-allowed, and the*-resizefamily. - Linux X11 (built with
use_x11_backend=1) reads the active cursor name via the Xfixes extension and maps known X cursor themes to CSS. - Linux Wayland and the default portal-only build return
default. Wayland intentionally hides the global pointer cursor from background processes, so inspecting the cursor of another surface is not possible without integrating with a PipeWire screencast metadata stream. - Application-defined or unknown cursors fall back to
default.
Build and development
bun run build
bun run rebuildTo verify the native addon loads successfully:
bun run test:loadPrebuilt binaries
Create a prebuilt binary for the current platform:
bun run prebuildifyCreate prebuilt binaries for Windows, Linux, and macOS targets:
bun run prebuildify:allBuilt artifacts are placed in prebuilds/ and loaded automatically by lib/index.ts.
Supported platforms
win32- fully implemented with WindowsSendInputlinux- supported on Wayland via the RemoteDesktop portal and optionally on X11 when built with the X11 backend- other OSes use the stub fallback if compiled, but native injection is only available on supported backends
Project layout
lib/- JavaScript API surface and wrapper exportssrc/addon.cpp- N-API bridge implementationsrc/win/platform_input_win.cpp- Windows backendsrc/linux/platform_input_linux.cpp- Linux backendsrc/platform_input_stub.cpp- fallback implementationsrc/platform_input.hpp- shared backend interface and event queuesrc/cursor/- standalone module exposinggetCursorType()(Win32 / X11 + Xfixes / Wayland stub)binding.gyp- native addon build configuration
Notes
The repository is designed to keep the public JS API stable while allowing per-platform native backend extensions. The InputBridge wrapper always exposes the same methods regardless of the active backend.
Wayland addon sharing with screen-capture
For single portal permission flow across addons:
await inputBridge.init();
// IMPORTANT: Call openPipeWireRemoteFd() before getMonitors() so Start has run and
// stream IDs in getMonitors() match the portal PipeWire nodes.
const portalSessionHandle = inputBridge.getPortalSessionHandle();
const pipewireRemoteFd = inputBridge.openPipeWireRemoteFd();
const portalMonitors = inputBridge.getMonitors().map((m) => ({
id: m.id,
name: m.name,
index: m.index,
x: m.x,
y: m.y,
width: m.width,
height: m.height,
pipewireStream: Number(m.id),
}));
const capture = new ScreenCapture({
portalSessionHandle: portalSessionHandle ?? undefined,
pipewireRemoteFd: pipewireRemoteFd ?? undefined,
portalMonitors,
});Expected order: one shared session, one RemoteDesktop.Start, then ScreenCast.OpenPipeWireRemote.
