nodejs, wie man Tastenanschläge von stdin liest

118

Ist es möglich, in einem laufenden NodeJS-Skript auf eingehende Tastenanschläge zu warten? Wenn ich process.openStdin()sein 'data'Ereignis verwende und abhöre, wird die Eingabe bis zur nächsten neuen Zeile gepuffert, wie folgt:

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

Wenn ich das laufen lasse, bekomme ich:

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

Was ich sehen möchte ist:

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

Ich suche nach einem Knoten, der z. B. getcin Ruby entspricht

Ist das möglich?

bantic
quelle
(Hinzufügen dieses Kommentars, damit diese Frage leichter zu finden ist; ich habe einige Tage gebraucht, um die richtigen Wörter dafür zu finden): So lesen Sie stdin zeichenweise, bevor das neue Zeilenzeichen (neue Zeile) in die Eingabe gesendet wird.
schwindlig

Antworten:

62

Sie können dies auf diese Weise erreichen, wenn Sie in den Rohmodus wechseln:

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
quelle
6
Keine Sorge, ich habe es selbst herausgefundenprocess.stdin.resume(); process.stdin.on('data', function (chunk) { process.stdout.write('data: ' + chunk); });
JamesM-SiteGen
3
Bewegen Sie das setRawMode, um unter das zu sein openStdin(), da Sie den Modus nur einstellen können, wenn das stdininitialisiert ist.
Turm
4
Es scheint, dass stdin kein Tastendruckereignis mehr ausgibt, sondern stattdessen ein Datenereignis mit Differenzparametern.
skeggse
2
Hey ist openStdin()eine veraltete und alte API? (Ich habe Node Way nach 2011 gelernt ...)
Steven Lu
3
Oh ja. In der Tat stdin.on('keypress',function(chunk,key))wurde in neueren Versionen entfernt. Und ich bin mir ziemlich sicher, dass openStdin()entweder entfernt wurde oder veraltet ist. Jetzt können Sie auf stdin asprocess.stdin
Élektra
132

Für diejenigen, die diese Antwort finden, da diese Funktion entfernt wurde tty, ist hier, wie man einen rohen Zeichenstrom von stdin erhält:

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 );
});

ziemlich einfach - im Grunde genau wie die Dokumentation von process.stdin, aber verwendet setRawMode( true ), um einen Rohdatenstrom zu erhalten, der in der Dokumentation schwerer zu identifizieren ist.

Dan Heberden
quelle
2
Danke .. es war einfach und leicht sofort zu implementieren .. :) genau das, was ich wollte.
Kushal Likhi
2
Funktioniert nicht mit Node.js 0.8+. Sie müssen 'Tastendruck' importieren. Siehe die Antwort von Peter Lyons.
G-Wiz
2
Das hat mit 0.8 funktioniert, aber es macht Spaß, wie sich die API ständig ändert.
Dan Heberden
sollte key == '\ u0003' (doppeltes statt dreifaches Gleichheitszeichen) verwenden, damit es funktioniert
WHITECOLOR
1
Gibt es eine Möglichkeit, diese Tasten auch nach oben, unten, links und rechts zu schreiben?
Tom R
46

In Knoten> = 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)
})

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

arve0
quelle
3
Wenn ich das auf 7 versuche, bekomme ich process.stdin.setRawMode is not a function. Ich werde später versuchen, etwas tiefer zu tauchen.
Matt Molnar
3
@MattMolnar Die Funktion ist nur vorhanden, wenn es ein TTY ist, überprüfen Sie so für die erste
curiousdannii
@MattMolnar Sie müssen Ihre App als externes Terminal ausführen
Maksim Shamihulau
29

Diese Version verwendet das Tastendruckmodul und unterstützt node.js Version 0.10, 0.8 und 0.6 sowie iojs 2.3. Stellen Sie sicher, dass Sie rennen 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
quelle
Dies funktioniert nicht auf Knoten v0.10.25, es heißt process.stdin.setRawMode()stattdessen verwenden, aber diese Fehler und sagt keine Methode setRawMode, sehr ärgerlich
Plentybinary
@Plentybinary Ich vermute, Sie führen den Knoten v0.10.25 nicht aus. Ich habe dies gegen v0.10.25 getestet und es funktioniert ordnungsgemäß. und process.stdin.setRawModeexistiert, ist eine Funktion und funktioniert richtig. Ich habe auch auf iojs-2.3.1 getestet und es funktioniert auch dort noch.
Peter Lyons
FWIW, dies funktioniert weiterhin gut, zumindest bis v0.10.40
John Rix
8

Mit NodeJS 0.6.4 getestet ( Test in Version 0.8.14 fehlgeschlagen ):

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);

wenn Sie es ausführen und:

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

Wichtiger Code Nr. 1:

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

Wichtiger Code # 2:

.createInterface( process.stdin, {} );
befzz
quelle
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
quelle