nodejs, jak czytać naciśnięcia klawiszy ze standardowego wejścia

118

Czy można nasłuchiwać nadchodzących naciśnięć klawiszy w działającym skrypcie nodejs? Jeśli używam process.openStdin()i słucham jego 'data'zdarzenia, dane wejściowe są buforowane do następnej nowej linii, na przykład:

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

Uruchamiając to, otrzymuję:

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

Chciałbym zobaczyć:

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

Szukam odpowiednika nodejs np. getcW rubinie

czy to możliwe?

bantic
źródło
(Dodanie tego komentarza, aby było łatwiej znaleźć to pytanie; znalezienie odpowiednich słów zajęło mi kilka dni): Oto jak czytać standardowe wejście znak po znaku przed wysłaniem znaku nowej linii (nowej linii) na wejściu.
zawrotny

Odpowiedzi:

62

Możesz to osiągnąć w ten sposób, jeśli przełączysz się na tryb surowy:

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
źródło
6
Nie martw się, dowiedziałem się o sobieprocess.stdin.resume(); process.stdin.on('data', function (chunk) { process.stdout.write('data: ' + chunk); });
JamesM-SiteGen,
3
Przesuń, setRawModeaby znajdował się poniżej openStdin(), ponieważ możesz ustawić tryb tylko wtedy, gdy stdinjest zainicjowany.
Wieża
4
Wygląda na to, że stdin nie emituje już zdarzenia naciśnięcia klawisza, ale zamiast tego emituje zdarzenie danych z różnymi parametrami.
skeggse
2
Hej, openStdin()czy interfejs API jest przestarzały i stary? (Nauczyłem się węzła dużo po 2011 ...)
Steven Lu
3
O Tak. W rzeczywistości stdin.on('keypress',function(chunk,key))został usunięty w ostatnich wersjach. I jestem prawie pewien, openStdin()że został usunięty lub jest przestarzały. Teraz możesz uzyskać dostęp do stdin asprocess.stdin
Élektra
132

Dla tych, którzy znaleźli tę odpowiedź, ponieważ ta możliwość została pozbawiona tty, oto jak uzyskać surowy strumień znaków ze standardowego wejścia:

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

całkiem proste - w zasadzie tak jak w dokumentacji procesu.stdin, ale używa się go setRawMode( true )do uzyskania surowego strumienia, który jest trudniejszy do zidentyfikowania w dokumentacji.

Dan Heberden
źródło
2
Dzięki… to było proste i łatwe do wykonania od razu… :) dokładnie to czego chciałem.
Kushal Likhi
2
Nie działa z Node.js 0.8+. Musisz zaimportować „keypress”. Zobacz odpowiedź Petera Lyonsa.
G-Wiz
2
to zrobił pracę z 0,8, ale zabawa jak to takie ciągle zmieniających api.
Dan Heberden
należy użyć klucza == '\ u0003' (podwójny zamiast potrójnego znaku równości), aby to zadziałało
WHITECOLOR
1
Czy istnieje sposób, aby to zapisać klawisze w górę, w dół, w lewo, w prawo?
Tom R
46

W węźle> = 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)
})

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

arve0
źródło
3
Próbuję tego na 7 i otrzymuję process.stdin.setRawMode is not a function. Spróbuje później zanurkować nieco głębiej.
Matt Molnar
3
@MattMolnar Funkcja jest obecna tylko wtedy, gdy jest to TTY, więc najpierw sprawdź to
curiousdannii
@MattMolnar musisz uruchomić swoją aplikację jako terminal zewnętrzny, patrz stackoverflow.com/questions/17309749/…
Maksim Shamihulau
29

Ta wersja wykorzystuje przyciśnięcie modułu i podpory node.js wersja 0.10, 0.8 i 0.6 jak również iojs 2.3. Pamiętaj, aby biegać 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
źródło
To nie działa na węźle v0.10.25, process.stdin.setRawMode()zamiast tego mówi użyj, ale to błędy i mówi, że nie ma metody setRawMode, bardzo denerwujące
Plentybinary
@Plentybinary Podejrzewam, że w rzeczywistości nie używasz Node v0.10.25. Przetestowałem to z wersją0.10.25 i działa poprawnie. i process.stdin.setRawModeistnieje, jest funkcją i działa prawidłowo. Testowałem również na iojs-2.3.1 i nadal tam działa.
Peter Lyons
FWIW, to nadal działa dobrze, przynajmniej do wersji 0.40.40
John Rix
8

Po przetestowaniu nodejs 0.6.4 ( test nie powiódł się w wersji 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);

jeśli go uruchomisz i:

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

Ważny kod nr 1:

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

Ważny kod nr 2:

.createInterface( process.stdin, {} );
befzz
źródło
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
źródło