nodejs comment lire les frappes depuis stdin

118

Est-il possible d'écouter les frappes entrantes dans un script nodejs en cours d'exécution? Si j'utilise process.openStdin()et écoute son 'data'événement, l'entrée est mise en mémoire tampon jusqu'à la prochaine nouvelle ligne, comme ceci:

// stdin_test.js
var stdin = process.openStdin();
stdin.on('data', function(chunk) { console.log("Got chunk: " + chunk); });

En exécutant ceci, j'obtiens:

$ node stdin_test.js
                <-- type '1'
                <-- type '2'
                <-- hit enter
Got chunk: 12

Ce que j'aimerais, c'est voir:

$ node stdin_test.js
                <-- type '1' (without hitting enter yet)
 Got chunk: 1

Je recherche un nodejs équivalent, par exemple, getcen ruby

Est-ce possible?

bantique
la source
(Ajout de ce commentaire pour que cette question soit plus facile à trouver; il m'a fallu quelques jours pour trouver les bons mots): Voici comment lire stdin caractère par caractère avant que le caractère de nouvelle ligne (nouvelle ligne) ne soit envoyé en entrée.
vertige

Réponses:

63

Vous pouvez y parvenir de cette façon, si vous passez en mode brut:

var stdin = process.openStdin(); 
require('tty').setRawMode(true);    

stdin.on('keypress', function (chunk, key) {
  process.stdout.write('Get Chunk: ' + chunk + '\n');
  if (key && key.ctrl && key.name == 'c') process.exit();
});
DanS
la source
6
Ne vous inquiétez pas, j'ai découvert moi-même,process.stdin.resume(); process.stdin.on('data', function (chunk) { process.stdout.write('data: ' + chunk); });
JamesM-SiteGen
3
Déplacez le setRawModepour qu'il se trouve sous le openStdin(), car vous ne pouvez définir le mode que si le stdinest initialisé.
Tour du
4
Il semble que stdin n'émette plus d'événement de pression de touche, mais émet à la place un événement de données, avec des paramètres de différence.
skeggse
2
Hey est openStdin()une API obsolète et ancienne? (J'ai appris le nœud bien après 2011 ...)
Steven Lu
3
Euh, ouais. En fait, il stdin.on('keypress',function(chunk,key))a été supprimé dans les versions récentes. Et je suis presque sûr qu'il openStdin()a été supprimé ou est obsolète. Maintenant, vous pouvez accéder à stdin asprocess.stdin
Élektra
132

Pour ceux qui trouvent cette réponse puisque cette capacité a été supprimée tty, voici comment obtenir un flux de caractères bruts à partir de stdin:

var stdin = process.stdin;

// without this, we would only get streams once enter is pressed
stdin.setRawMode( true );

// resume stdin in the parent process (node app won't quit all by itself
// unless an error or process.exit() happens)
stdin.resume();

// i don't want binary, do you?
stdin.setEncoding( 'utf8' );

// on any data into stdin
stdin.on( 'data', function( key ){
  // ctrl-c ( end of text )
  if ( key === '\u0003' ) {
    process.exit();
  }
  // write the key to stdout all normal like
  process.stdout.write( key );
});

assez simple - essentiellement comme la documentation de process.stdin mais en utilisant setRawMode( true )pour obtenir un flux brut, ce qui est plus difficile à identifier dans la documentation.

Dan Heberden
la source
2
Merci .. c'était simple et facile à mettre en œuvre tout de suite .. :) exactement ce que je voulais.
Kushal Likhi
2
Ne fonctionne pas avec Node.js 0.8+. Vous devez importer «keypress». Voir la réponse de Peter Lyons.
G-Wiz
2
cela a fonctionné avec 0.8, mais c'est amusant de voir comment c'est une API en constante évolution.
Dan Heberden
devrait utiliser la clé == '\ u0003' (double au lieu de triple signe égal) pour le faire fonctionner
WHITECOLOR
1
Y a-t-il un moyen de faire en sorte que ces touches d'écriture haut, bas, gauche, droite aussi?
Tom R
47

Dans node> = v6.1.0:

const readline = require('readline');

readline.emitKeypressEvents(process.stdin);
process.stdin.setRawMode(true);

process.stdin.on('keypress', (str, key) => {
  console.log(str)
  console.log(key)
})

Voir https://github.com/nodejs/node/issues/6626

arve0
la source
3
Essayer ceci sur 7 et j'obtiens process.stdin.setRawMode is not a function. J'essaierai de plonger un peu plus loin plus tard.
Matt Molnar
3
@MattMolnar La fonction n'est présente que s'il s'agit d'un TTY, alors vérifiez pour cela en premier
curiousdannii
@MattMolnar, vous devez exécuter votre application en tant que terminal externe, voir stackoverflow.com/questions/17309749/…
Maksim Shamihulau
29

Cette version utilise le module keypress et prend en charge les versions 0.10, 0.8 et 0.6 de node.js ainsi que iojs 2.3. Assurez-vous de courir npm install --save keypress.

var keypress = require('keypress')
  , tty = require('tty');

// make `process.stdin` begin emitting "keypress" events
keypress(process.stdin);

// listen for the "keypress" event
process.stdin.on('keypress', function (ch, key) {
  console.log('got "keypress"', key);
  if (key && key.ctrl && key.name == 'c') {
    process.stdin.pause();
  }
});

if (typeof process.stdin.setRawMode == 'function') {
  process.stdin.setRawMode(true);
} else {
  tty.setRawMode(true);
}
process.stdin.resume();
Peter Lyons
la source
Cela ne fonctionne pas sur le nœud v0.10.25, il dit utiliser à la process.stdin.setRawMode()place mais que des erreurs et ne dit aucune méthode setRawMode, très ennuyeux
Plentybinary
@Plentybinary Je suppose que vous n'exécutez pas réellement le nœud v0.10.25. J'ai testé cela avec la v0.10.25 et cela fonctionne correctement. et process.stdin.setRawModeexiste, est une fonction et fonctionne correctement. J'ai également testé sur iojs-2.3.1 et cela fonctionne toujours là aussi.
Peter Lyons
FWIW, cela continue à bien fonctionner au moins jusqu'à la v0.10.40
John Rix
8

Avec nodejs 0.6.4 testé ( échec du test dans la version 0.8.14 ):

rint = require('readline').createInterface( process.stdin, {} ); 
rint.input.on('keypress',function( char, key) {
    //console.log(key);
    if( key == undefined ) {
        process.stdout.write('{'+char+'}')
    } else {
        if( key.name == 'escape' ) {
            process.exit();
        }
        process.stdout.write('['+key.name+']');
    }

}); 
require('tty').setRawMode(true);
setTimeout(process.exit, 10000);

si vous l'exécutez et:

  <--type '1'
{1}
  <--type 'a'
{1}[a]

Code important n ° 1:

require('tty').setRawMode( true );

Code important n ° 2:

.createInterface( process.stdin, {} );
befzz
la source
2
if(Boolean(process.stdout.isTTY)){
  process.stdin.on("readable",function(){
    var chunk = process.stdin.read();
    if(chunk != null)
      doSomethingWithInput(chunk);
  });
  process.stdin.setRawMode(true);
} else {
  console.log("You are not using a tty device...);
}
Élektra
la source