10

I am using node.js v4.5

I wrote the function below to send repeated messages with a delay.

function send_messages() {
    Promise.resolve()
        .then(() => send_msg() )
        .then(() => Delay(1000) )
        .then(() => send_msg() )
        .then(() => Delay(1000))
        .then(() => send_msg() )        
    ;
}

function Delay(duration) {
    return new Promise((resolve) => {
        setTimeout(() => resolve(), duration);
    });
}

Instead of delay, I would like to activate the sending of messages using a keypress. Something like the function below.

function send_messages_keystroke() {
    Promise.resolve()
        .then(() => send_msg() )
        .then(() => keyPress('ctrl-b') ) //Run subsequent line of code send_msg() if keystroke ctrl-b is pressed
        .then(() => send_msg() )
        .then(() => keyPress('ctrl-b') )
        .then(() => send_msg() )        
    ;
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375

2 Answers2

6

You can put process.stdin in raw mode to access individual keystrokes.

Here's a standalone example:

function send_msg(msg) {
  console.log('Message:', msg);
}

// To map the `value` parameter to the required keystroke, see:
// http://academic.evergreen.edu/projects/biophysics/technotes/program/ascii_ctrl.htm
function keyPress(value) {
  return new Promise((resolve, reject) => {
    process.stdin.setRawMode(true);
    process.stdin.once('data', keystroke => {
      process.stdin.setRawMode(false);
      if (keystroke[0] === value) return resolve();
      return reject(Error('invalid keystroke'));
    });
  })
}

Promise.resolve()
  .then(() => send_msg('1'))
  .then(() => keyPress(2))
  .then(() => send_msg('2'))
  .then(() => keyPress(2))
  .then(() => send_msg('done'))
  .catch(e => console.error('Error', e))

It will reject any keystroke that isn't Ctrl-B, but the code is easily modifiable if you don't want that behaviour (and just want to wait for the first Ctrl-B, for instance).

The value passed to keyPress is the decimal ASCII value of the key: Ctrl-A is 1, Ctrl-B is 2, a is 97, etc.

EDIT: as suggested by @mh-cbon in the comments, a better solution might be to use the keypress module.

robertklep
  • 198,204
  • 35
  • 394
  • 381
  • Thanks for the answer. Upvoted. How do you get the value that 1 is Ctrl-A, 2 -> Ctrl-B and a -> 97? –  Sep 12 '16 at 11:08
  • 1
    @user91579631 see [this webpage](http://academic.evergreen.edu/projects/biophysics/technotes/program/ascii_ctrl.htm). The _"Dec"_ code is the number you pass to `keyPress`. For regular characters, see [this page](http://academic.evergreen.edu/projects/biophysics/technotes/program/ascii_std.htm). – robertklep Sep 12 '16 at 11:11
  • 1
    you should use tootallnate keypress module https://github.com/TooTallNate/keypress –  Sep 16 '16 at 20:20
  • @mh-cbon I searched for something like that before posting my answer but wasn't able to find anything. It does look spot-on for this task! – robertklep Sep 16 '16 at 20:30
  • I edited your answer, although, i don t quiet understand why the promise hangs if i type in the wrong key, makes this unusable. I definitely don t master promise. –  Sep 16 '16 at 22:17
1

Give this one a try. As mentioned above, using keypress makes it really simple. The key object in the code here tells you if ctrl or shift are pressed, as well as the character pressed. Unfortunately though, keypress doesn't seem to handle numbers or special characters.

var keypress = require('keypress');

keypress(process.stdin);

process.stdin.on('keypress', function (ch, key) {
  console.log("here's the key object", key);

  shouldExit(key);
  if (key) {
    sendMessage(key);
  }
});

function shouldExit(key) {
  if (key && key.ctrl && key.name == 'c') {
    process.stdin.pause();
  }
}

function sendMessage(key) {
  switch(key.name) {
    case 'a';
        console.log('you typed a'); break;
    case 'b';
        console.log('you typed b'); break;
    default:
        console.log('bob is cool');
  }
}

And of course, in the sendMessage() function here, you could easily replace the log statements with something else more complex, make some async calls, call some other function, whatever. The process.stdin.pause() here causes the program to exit on ctrl-c, otherwise, the program would just keep running, blocking your interrupt signal, and you'd have to kill the process manually via command line.

Hayden Braxton
  • 1,151
  • 9
  • 14