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

kimetra

v2.0.1

Published

A low level and light weight cross-platform keyboard automation library using native OS APIs

Readme

Kimetra

npm version License: MIT Node.js Version Platform Support

Banner

Kimetra is a cross-platform keyboard automation library for Node.js. It is a performance first library focused on speed and precision with no external dependencies at all. It suits gaming macros just as well as any automation tool or script.

Features

  • Native performance: direct OS API calls through precompiled binaries.
  • Cross-platform: Windows, macOS and Linux, with the same key names everywhere.
  • Batched execution: a whole action sequence runs inside one native call, so JavaScript adds no latency between key events.
  • Microsecond timing: waits target an absolute deadline instead of drifting.
  • Small: three exports, no dependencies, one small binary per platform.
  • Low level access: the raw addon is always reachable through ki.core.

How it works

Kimetra ships a small C++ addon per platform and architecture, built on SendInput on Windows, CGEvent on macOS and uinput on Linux. Nothing is compiled at install time. It deletes the binaries and key maps which your machine cannot use post install, leaving one binary of well under 150 KB behind.

The npm download itself contains all six binaries, so the download is larger than the installed footprint.

Install

npm install kimetra

Platform setup

Windows needs nothing. macOS and Linux each need a one-time permission grant else, Kimetra throws with instructions if the grant is missing.

Windows

No config but one caveat: Windows blocks input from a normal process to a window running as administrator. If the target app is elevated, run your script elevated too.

macOS

Open System Settings > Privacy & Security > Accessibility and enable the application running your script: Terminal, iTerm, VS Code, or your packaged app. If it is already listed, remove it, add it again, then restart the process.

macOS invalidates the grant whenever the binary's signature changes. Terminal's "Secure Keyboard Entry" and focused password fields block synthetic input entirely.

Linux

Kimetra writes to /dev/uinput, which works on both X11 and Wayland but needs permission:

echo 'KERNEL=="uinput", GROUP="input", MODE="0660"' | sudo tee /etc/udev/rules.d/99-kimetra.rules
sudo usermod -aG input $USER

Reboot afterwards, or run the process as root.

Quick start

import { Kimetra } from 'kimetra';
// or in CommonJS
const { Kimetra } = require('kimetra');

const options = {
  unit: 'microsecond', // 'microsecond' (default) or 'millisecond'
  delay: 0,            // delay before an action starts
  interval: 700,       // gap between repeated actions
  duration: 700,       // how long a single key is held
  hotkeyDelay: 1500    // how long a combination is held before release
}

const ki = Kimetra(options); // whole options object is optional (more on it below)

await ki.pressKey('enter');
await ki.pressHotkey(['ctrl', 'c']);
await ki.pressKeys(['a', 'b', 'c']);
await ki.typeText('Kimetra focuses on speed, precision and staying small');

ki.cleanup();

Key names

Keys are plain strings. Names are lower case, with no spaces or punctuation.

await ki.pressKey('a');
await ki.pressKey('f11');
await ki.pressHotkey(['ctrl', 'shift', 'escape']);

| Group | Names | | --- | --- | | Letters and digits | a to z, 0 to 9 | | Function keys | f1 to f20 | | Modifiers | ctrl, shift, alt, meta & lctrl, rshift, lalt, lmeta | | Control | enter, escape, space, tab, backspace, delete, capslock | | Navigation | up, down, left, right, home, end, pageup, pagedown | | Numpad | numpad0 to numpad9, numpadadd, numpadsubtract, numpadmultiply, numpaddivide, numpaddecimal | | Symbols | semicolon, equal, comma, hyphen, dot, fslash, bslash, grave, quote, squarebracketstart, squarebracketend | | Volume | volumemute, volumedown, volumeup |

ctrl, shift, alt and meta resolve to the left-hand key. Use lctrl or rctrl when the side matters. meta is the Windows key, the Command key on macOS and the Super key on Linux, and also answers to cmd, win and super.

Everything above works on all three platforms. Keys that only some platforms have, such as insert, printscreen, numlock, the media transport keys and the browser keys, throw a clear error where the OS has no such key. Your editor will flag them through the TypeScript definitions.

API

The package exports exactly three things.

const { Kimetra, Kimacro, Key } = require('kimetra');

Kimetra(options)

const ki = Kimetra({
  unit: 'microsecond', // 'microsecond' (default) or 'millisecond'
  delay: 0,            // delay before an action starts
  interval: 700,       // gap between repeated actions
  duration: 700,       // how long a single key is held
  hotkeyDelay: 1500    // how long a combination is held before release
});

unit decides how Kimetra reads the numbers you pass, both in the options above and in every method argument. In millisecond mode ki.pressKey('a', 5) holds the key for 5 milliseconds. In microsecond mode the same call holds it for 5 microseconds.

It does not change the built-in defaults. Those are fixed real durations, so a key you never gave a duration for is held for 700 microseconds either way. Switching units never silently retimes anything you did not write yourself.

| Call | microsecond mode | millisecond mode | | --- | --- | --- | | pressKey('a') | 700 µs hold | 700 µs hold | | pressKey('a', 5) | 5 µs hold | 5 ms hold | | sleep(500) | 500 µs | 500 ms |

Pick a unit once and stay with it. The same snippet means different things under different units.

Methods

| Method | Description | | --- | --- | | pressKey(key, duration?, delay?) | Press and release a key, holding it for duration. | | pressKeys(keys[], interval?, delay?) | Press several keys one after another. | | pressHotkey(keys[], duration?, delay?) | Press keys together, releasing in reverse order. | | repeatKey(key, times, interval?, delay?) | Press the same key times times. | | typeText(text, delay?) | Type text. | | keyDown(key, delay?) | Press a key down and leave it held. | | keyUp(key, delay?) | Release a held key. | | sleep(duration) | Block for duration. | | executeSequence(actions[]) | Run a list of actions as one batch. | | cleanup() | Release native resources. Safe to call more than once. |

All of these return a promise. To hold a key for two seconds, pass a duration:

await ki.pressKey('shift', 2000000); // two seconds in microseconds

Editing shortcuts

These resolve to the chord each platform actually uses, so the same call works everywhere. Cmd on macOS, Ctrl elsewhere.

await ki.copy();
await ki.paste();
await ki.cut();
await ki.selectAll();
await ki.undo();
await ki.redo();    // Ctrl+Y on Windows, Cmd+Shift+Z on macOS, Ctrl+Shift+Z on Linux
await ki.save();
await ki.find();
await ki.replace(); // Ctrl+H, or Cmd+Option+F on macOS

Anything else is a hotkey. There is no separate cmd family and no aliases for single keys:

await ki.pressHotkey(['alt', 'f4']);
await ki.pressKey('meta');
await ki.repeatKey('tab', 3);
await ki.repeatKey('up', 5, 100);

Sequences

A sequence compiles into one native call, which makes it the fastest way to run several actions.

await ki.executeSequence([
  { type: 'hotkey', keys: ['alt', 'tab'] },
  { type: 'wait', duration: 500000 },
  { type: 'text', text: 'Sequence text' },
  { type: 'key', key: 'enter' },
  { type: 'repeat', key: 'down', times: 3, interval: 1000 },
  { type: 'keys', keys: ['a', 'b'], interval: 2000 }
]);

| Action | Fields | | --- | --- | | key | key, duration?, delay? | | keys | keys[], interval?, delay? | | hotkey | keys[], duration?, delay? | | repeat | key, times, interval?, delay? | | text | text, delay? | | wait | duration |

Kimacro(options)

A chainable builder over the same sequences, with JSON serialisation. A macro can be replayed as often as you like.

const { Kimacro } = require('kimetra');

const macro = Kimacro()
  .pressKey('enter')
  .typeText('hello')
  .pressHotkey(['ctrl', 's'])
  .wait(1000000);

await macro.exec();
await macro.exec(); // runs again, the sequence is kept

Saving and loading:

const fs = require('fs');

fs.writeFileSync('login.json', JSON.stringify(macro.toJSON()));

const loaded = Kimacro().fromJSON(JSON.parse(fs.readFileSync('login.json')));
await loaded.exec();

Kimacro takes the same options as Kimetra, and also has add(action), clear() and cleanup().

Low level access

ki.core is the raw addon. Everything there works in key codes and microseconds regardless of the instance options, which is what Key is for.

const { Kimetra, Key } = require('kimetra');

const ki = Kimetra();
const core = ki.core;

core.KeyDown(Key.enter);
core.Sleep(500);
core.KeyUp(Key.enter);

core.SendString('Kimetra is Key plus Simulation plus Spectra');

console.log(ki.os, ki.arch);
ki.cleanup();

core exposes KeyDown, KeyUp, SendString, Sleep, Run and Cleanup. Sleep is more accurate than setTimeout and avoids the scheduling overhead of returning to the event loop.

Notes

Execution is synchronous. The methods return promises so that await reads naturally and so real concurrency can be added later, but the work happens in a blocking native call. A one second wait blocks the event loop for one second. Use short waits inside sequences, and keep long pauses in JavaScript.

Linux text is US ASCII. uinput sends scan codes, so typeText on Linux can only produce what a US QWERTY layout produces. Anything else throws and names the character. Windows and macOS inject unicode directly and handle any text. Use the clipboard for unicode on Linux.

Layouts matter. Key names describe physical keys. On a non-US layout, quote is whatever your layout puts on that key.

Newline and tab are sent as real Enter and Tab key presses on every platform, so typeText('a\nb') behaves the same everywhere.

Supported targets

win32-x64, win32-ia32, darwin-x64, darwin-arm64, linux-x64, linux-ia32. Node 16 or newer.

Anything else, including linux-arm64 and Alpine, fails at require time with a message naming your platform.

Building from source

The addon binaries are not committed to this repository. They are compiled from src/cpp by the GitHub Actions workflow and injected into the package at publish time, so nothing ships that was not built from this source in a public, auditable run. Every release is published with npm provenance, which cryptographically ties the tarball to the exact commit and workflow that produced it. You can verify it with npm audit signatures.

To build them yourself you need Python 3 and a C++ toolchain (MSVC on Windows, Xcode command line tools on macOS, build-essential on Linux):

npm install node-addon-api && npx node-gyp configure build

That produces build/Release/keyboard.node. Copy it into src/bin under the name for your platform and architecture, for example src/bin/win32x64.node or src/bin/linuxx64.node, then run npm test.

License

MIT © Saad