Get a Keypress in NodeJS

This turned out to be surprisingly difficult to find an answer for; I wanted to, in a node terminal program, wait for and return a single keypress.

The solution worked out to be to set process.stdin into raw mode and listen for a data event:

function getKeyPress() {
return new Promise((resolve, _reject) => {
  process.stdin.setRawMode(true);
  process.stdin.resume(); // needed if previously paused
  process.stdin.once('data', (key) => {
    process.stdin.pause(); // needed so that app doesn't hang
    process.stdin.setRawMode(false);
    resolve(key.toString('utf-8'));
  });
});
}

One caveat is that this eats control codes: if you press ^C, the Promise resolves with '\u03' .

Another worry is that if stdin is a pipe, this will fail because there is no setRawMode method, but getting a keypress from a pipe is silly so you’ll want to check for that before using this technique; process.stdin.isTTY is your friend, or just check for the existence of process.stdin.setRawMode.

A cool bonus though: at least on a mobile device, entering an emoji is read as a single keypress. Your terminal font might not display the emoji (I got a bunch of missing glyph markers in testing), but it’ll try, and it will be there in the string.

Edit 2024-09-30: With thanks to https://fosstodon.org/@rauschma, updated the function to be callable more than once. Thanks!

Author: Eddie Roosenmaallen

By day I'm a senior backend engineer at Deel. In my off time I explore Linux, JavaScript and the web, and I try to share some of my knowledge and some of my humour online.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.