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 🙏

© 2024 – Pkg Stats / Ryan Hefner

sirrobert-keypress

v1.1.6

Published

Handle keyboard keypresses in realtime.

Downloads

10

Readme

Installation

Install locally

npm install --save sirrobert-keypress

Install globally

npm install --global sirrobert-keypress

Overview

This module provides keystroke-based input listeners. It allows terminal-based software to listen to stdin and react on a keystroke-by-keystroke basis.

The Basics

The module provides an object-oriented interface for listening (and responding) to keyboard input.

If you start listening with no hooks enabled, the process is effectively completely mute. It will not even be able to respond to interrupt codes like CTRL-C and CTRL-D.

Built-In Listeners

That's completely fine if you want to roll your own, but it can be discombobulating if you're not expecting it. The module provides some small built-in bundles of listeners for getting started.

.addListener(name)

.addListeners([name1, name2, ...])

The .addListener() functions simply take the names of the provided preset functionality. .addListeners() is just a small wrapper that loops through the values provided and sets them using .addListener().

var Keypress = require("sirrobert-keypress");

var keypress = new Keypress();
keypress.listen(true);
keypress.addListeners(["interrupts", "echo"]);

This example provides a very simple echo server. You type in characters and they are displayed on the screen. Pressing Enter provides a newline. CTRL-C and CTRL-D quit the process.

Echo

The echo listener adds listeners for most characters (excluding escape, arrow right, arrow left, arrow up, arrow down, backspace, tab, CTRL-C, and CTRL-D). Pressing any of the excluded keys will have no effect. Other characters will be echoed to stdout.

Interrupts

The interrupts listener listens for CTRL-C and CTRL-D. Either of these will cause the process to exit immediately (using process.exit()).

Adding Custom Listeners

In addition to the (very simple) built-in listeners, you can also define your own. These are managed according to the following methods.

.listen(doListen, transform)

The .listen() method is responsible for monitoring or not monitoring stdin. You can control this manually, but this method provides a convenient way to do it on your own.

doListen [Boolean]

Setting doListen to true causes the process to start listening to stdin in raw mode.

process.stdin.setRawMode(true);
process.stdin.on("data", keypressHandler);

Setting it to false turns off raw mode and stops listening.

process.stdin.setRawMode(false);
process.stdin.removeListener('data', keypressHandler);

transform [Function]

The transform() function allows you to do something with the "chunk" of data that comes in from a keypress. Here's an example, followed by an explanation.

// You have some object that does stuff in your program.
myThing = new Thing();

// Now start listening to the input stream.  Each time a chunk of data
// comes in, set `myThing.chunk` to be equal to that chunk of data.
keypress.listen(true, chunk => {
  myThing.chunk = chunk;
  return myThing;
});

// Now set a listener
keypress.on("arrow up", thing => { console.log(thing.chunk) });

In this example, each time the user presses the up arrow, it is sent as a "chunk" of data. When the event is fired, the transform() function transforms that chunk however you tell it to. The return value of transform() is passed into your event handler as its sole argument. That allows you to do things like inspection of the keystrokes as they come in, or basically smuggling any other data into your keypress event handler. without needing that data to have originated in an enclosure.

.on(character, handler)

Sets a new listener, listening for a specific character (or list of characters). The second argument, handler, is a function to be called when the event fires.

function do_quit () { process.exit() }
keypress.on("q", do_quit); 

With this listener, whenever the character "q" is pressed, the process will exit. The same could also be set at the same time on more than one key press:

function do_quit () { process.exit() }
keypress.on(["q", "x", "c"], do_quit);

In this case, pressing "q" for "quit", "x" for "exit", or "c" for "close" causes the process to exit.

In these simple example, the event handler did not take any arguments. In fact, information is passed to the function by the .fire() method. See that for more information.

Multiple handlers can be set for the same character. The order in which they are set is the order in which they will fire.

.onNot(character, handler)

This is a negation of the .on() method. An .onNot() listener fires on any keypress that is not the specified character or characters.

Multiple handlers can be set at once in the same manner as the .on() method.

function do_continue() { console.log("continuing..." }
keypress.onNot("escape", do_continue);
keypress.onNot(["CTRL-C", "CTRL-D"], do_continue);

keypress.on(["escape", "CTRL-C", "CTRL-D"], () => { process.exit() });

Now when a user presses anything except escape, CTRL-C, or CTRL-D, the program prints

continuing...

If one of those three keys (or in the case of the CTRL characters, key combinations), the process quits.

Multiple .onNot() handlers can be set for the same character. The order in which they are set is the order in which they will fire.

.fire(charname, data)

When a character with a listener is pressed, the corresponding event handler is fired using the .fire() method. This method takes two arguments, charname and data.

data [Any]

The data argument can be anything you want to pass into the event handler function.

charname [String]

The charname argument is a simple string representing a keypress chunk. The tables below list all the available characters. To use them, simply pass them in as strings (such as "a" or "@" or "space").

Alpha

| | | | | | | | | | | | |:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:| | a | b | c | d | e | f | g | h | i | j | k | | l | m | n | o | p | q | r | s | t | u | v | | w | x | y | z | A | B | C | D | E | F | G | | H | I | J | K | L | M | N | O | P | Q | R | | S | T | U | V | W | X | Y | Z |

Numeric

| | | | | | | | | | | | |:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:| | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 |

Punctuation

| | | | | | | | | | | | |:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:| | ` | ~ | ! | @ | # | $ | % | ^ | & | * | ( | | ) | _ | + | ; | : | ' | " | , | . | / | < | | > | ? | { | } | [ | ] | \ | | |

Whitespace

| | | | | :-: | :-: | :-: | | space | tab | enter |

Movement

| | | | | |:-:|:-:|:-:|:-:| | arrow up | arrow down | arrow left | arrow right |

Screen Control

| | | | | | | | | :-: | :-: | :-: | :-: | :-: | :-: | :-: | | insert | delete | home | end | page up | page down | escape |

Function Keys

| | | | | | | | | | | | | |:-: |:-: |:-: |:-: |:-: |:-: |:-: |:-: |:-: | :-: | :-: | :-: | | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F8 | F10 | F11 | F12 |

Control Sequences

| | | | :-: | :-: | | CTRL-C | CTRL-D |

Miscellaneous

The maps also contain an extra code. It's not actually a keypress, it's a special character that can be written to stdout to clear the screen:

| | | :-: | | clear screen |

You can use it like this:

process.stdout.write(Keypress.charmap["clear screen"]);
Inspection & Extensibility

You can inspect the map of codes yourself by looking at Keypress.charmap and Keypress.codemap. These two lists contain the same data, but indexed by either the name of the code (such as "a" or "escape") or the code represented by the name (such as "61" or "1b", respectively). This is possible because the keys and values are both unique lists.

console.log(JSON.stringify(Keypress.charmap, null, 2));
// [
//   "A" : "41",
//   "B" : "42",
//   "C" : "43",
//   ...
// ]

console.log(JSON.stringify(Keypress.codemap, null, 2));
// [
//   "41" : "A",
//   "42" : "B",
//   "43" : "C",
//   ...
// ]

You can also add your own sequences by simply adding to the maps. As soon as an entry is added, listeners can be attached to it. Note that adding a listener before a character has been added to the maps will throw an error that looks like this:

Cannot listen for undefined character name: deux

Here's an example of adding codes to the maps.

// Rename "entree" to "enter" (almost french for "enter")
Keypress.addChar("entree", "0d");

Note that this deletes any entry already existing for either "deux" or "32" and replaces them with the values provided. This does not allow for synonyms, only replacements.

As in the example above, this can be useful for things like localization to different languages.

Rationale

I needed a module to handle keypress inputs of various kinds. This originally came out of my sirrobert-shell module, in which I implemented a node-based shell for linux. But other uses emerged, such as non-text keystroke controls for things like games.