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 🙏

© 2025 – Pkg Stats / Ryan Hefner

custom-keyboard

v0.0.0

Published

custom-keyboard =========================

Downloads

5

Readme

custom-keyboard

English | 中文

Demo Game -- Hold on for 60 seconds

  • Support for any number of key combinations. (First your keyboard has to support N-key rollover).
  • Support for any number of key sequences.。
  • Support binding to 'key' | 'keyCode' | 'code' three different types of keyboard events。
  • Support binding to keydown event and keyup event (sequence keys without keyup events)。
  • Support for switching event responses between contexts.
  • It's lightweight. 4kb after compression (gzip).

Install

npm install --save custom-keyboard

Usage

custom-keyboard makes an intuitive preset name (click for details) for most of the keys, thus enabling a set of rules binding to three different keyboard event types ('key' | 'keyCode' | 'code'). You need to mount() once before you start using custom-keyboard, and unmount() to unload the event listener when you don't need it anymore. The symbol '+' represents Combination, '->' represents Sequence, and the symbols are legal with or without spaces between the keys.

import Keyboard from 'custom-keyboard';

Keyboard.mount();

// Combination
Keyboard.bind('a + b', () => {
    console.log('press a + b')
}, () => {
    console.log('release a + b')
});
Keyboard.bind(['q + w+e', 'a+s+d'], () => {
    console.log('q + w + e | a + s + d')
});

// Sequence
Keyboard.bind('enter -> 1', () => {
    console.log('enter -> 1')
});
Keyboard.bind('q -> q -> q', () => {
    console.log('q -> q -> q')
});
// Keyboard.unmount();

bind

type EventType = 'key' | 'keyCode' | 'code';

interface BindOption {
    bindKeys: string | Array<string>;
    eventType?: EventType;
    context?: string | null;
    preventRepeat?: boolean;
    strictOrder?: boolean | 'equal';
    caseSensitive?: boolean;
}

function bind(bindOption: BindOption['bindKeys'] | BindOption, pressDownExecutor?: (() => void) | null, pressUpExecutor?: () => void): Listener[];

bindKeys :string | Array<string> If the bindKeys does not match the rules, such as invalid key names; The '+' and '->' symbols appear at the same time; etc., the bind does not take effect and return false. A successful bind return an array of Listeners that can be used to unbind(Listeners) events; The pressUpExecutor of Sequence type bindKey will be ignored.

eventType :'key' | 'keyCode' | 'code' = 'key' Optionally bind to three different standard keyboard events, you can refer here for the differences.

preventRepeat (Valid only for combination type) :boolean = true If keep pressed and not released, is the response repeated.

strictOrder (Valid only for combination type) :boolean | 'equal' = false

Keyboard.bind({
    bindKeys: '2 + 3 + 4',
    strictOrder: false,
}, () => {
    console.log('press 2 + 3 + 4');
});

strictOrder defaults to false. in the above example, press 2, 3, and 4 in whatever order they are pressed, they will all take effect.

When strictOrder is true, it only takes effect when pressed in order of 2, 3 and 4.

When strictOrder is 'equal', if you pressed in order of 1, 2, 3 and 4, it will not work, but when strictOrder is true, it will work.

caseSensitive (Only eventType === 'key' is valid) :boolean = false event.key is case-sensitive. For 26 letters, if the user unintentionally presses the capslock, the bound listener will not be effective. This is not expected to happen in most cases, so case desensitization is done by default. If this behavior is not desired, explicitly setting this option to true is sufficient.

context :string = undefined You can bind to different contexts, and if undefined or null, it will take effect in all contexts.

unbind

function unbind(listener: Listener | Array<Listener>): boolean;

const listeners1 = Keyboard.bind('s + d');
Keyboard.unbind(listeners1);
const listeners2 = Keyboard.bind(['a + b', 'b + c']);
Keyboard.unbind(listeners2);
const listeners3 = Keyboard.bind(['q + w', 'e + r']);
Keyboard.unbind(listeners3[0]); // Only the 'e + r' event is released, and 'q + w' continues to run.

setSequenceInterval

Set the detection interval (ms) for Sequence type, the default is 666.

function setSequenceInterval(iInterval: number): void;

Keyboard.setSequenceInterval(600);

setSequenceMustReleaseLastPress

Set whether the next key press needs to release the last pressed key to take effect, the default is false.

function setSequenceMustReleaseLastPress(bool: boolean): void;

Keyboard.setSequenceMustReleaseLastPress(true);

About the context

function setContext(context: string): void;
function getCurrentContext(): string | null;
function getAllContext(): Array<string>;

Keyboard.setContext('some context');

When you bind an event, you can set the context in which it will take effect; if you leave it blank, it will take effect in any context. getAllContext gets the set of all the contexts bound by the events whose bind is in effect.

reset && getAllListener

function reset(): void;
function getAllListener(): Array<Listener>;

// The following two are equivalent
Keyboard.unbind(Keyboard.getAllListener());
Keyboard.reset();

getAllListener gets all the event listeners for which bind is in effect. reset clears all bound event listeners. custom-keyboard use Event Delegate, unmount() function will unbind root listener.

Cautions

There is a system-level problem with command-based key Combination under MacOS.

When you press and hold command and then press any other key to trigger the key Combination, then press and hold command and release other keys, the keyup event of the released key will not be triggered by the browser.

So the keyup event of the key Combination will be triggered only after the command is released.

Run Demo game

Run the demos:

npm install
npm run start

Build Lib

npm install
npm run build:lib

License

MIT