nodejs como ler pressionamentos de tecla de stdin

118

É possível ouvir as teclas digitadas em um script nodejs em execução? Se eu usar process.openStdin()e ouvir seu 'data'evento, a entrada será armazenada em buffer até a próxima nova linha, assim:

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

Executando isso, eu obtenho:

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

O que eu gostaria é de ver:

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

Estou procurando um nodejs equivalente a, por exemplo, getcem ruby

Isso é possível?

bantic
fonte
(Adicionando este comentário para que esta questão seja mais fácil de encontrar; demorei alguns dias para encontrar as palavras certas): Isto é como ler stdin caractere por caractere antes que o caractere de nova linha (nova linha) seja enviado na entrada.
tonto

Respostas:

62

Você pode conseguir desta forma, se alternar para o modo bruto:

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
fonte
6
Não se preocupe, descobri por mim mesmo,process.stdin.resume(); process.stdin.on('data', function (chunk) { process.stdout.write('data: ' + chunk); });
JamesM-SiteGen
3
Mova o setRawModepara abaixo de openStdin(), porque você só pode definir o modo se stdinfor inicializado.
Torre
4
Parece que stdin não emite mais um evento de pressionamento de tecla, mas sim um evento de dados, com parâmetros de diferença.
skeggse
2
Ei, é openStdin()uma API obsoleta e antiga? (Aprendi a maneira de nó depois de 2011 ...)
Steven Lu
3
Uh, sim. Na verdade stdin.on('keypress',function(chunk,key)), foi removido em versões recentes. E eu tenho certeza openStdin()que foi removido ou está obsoleto. Agora, você pode acessar stdin asprocess.stdin
Élektra
132

Para aqueles que encontraram essa resposta, uma vez que esse recurso foi removido tty, veja como obter um fluxo de caractere bruto 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 );
});

muito simples - basicamente como a documentação do process.stdin, mas usando setRawMode( true )para obter um fluxo bruto, que é mais difícil de identificar na documentação.

Dan Heberden
fonte
2
Obrigado .. foi simples e fácil de implementar imediatamente .. :) exatamente o que eu queria.
Kushal Likhi
2
Não funciona com Node.js 0.8+. Você deve importar 'keypress'. Veja a resposta de Peter Lyons.
G-Wiz
2
este fez o trabalho com 0,8, mas divertido como é essa api sempre em mudança.
Dan Heberden
deve usar a chave == '\ u0003' (duplo em vez de triplicar o sinal de igual) para fazê-lo funcionar
WHITECOLOR
1
Existe uma maneira de escrever as teclas para cima, para baixo, para a esquerda e para a direita também?
Tom R
46

No nó> = 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)
})

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

arve0
fonte
3
Tentando no 7 e eu entendo process.stdin.setRawMode is not a function. Tentarei mergulhar um pouco mais fundo depois.
Matt Molnar
3
@MattMolnar A função só está presente se for um TTY, então verifique primeiro
curiousdannii
@MattMolnar, você precisa executar seu aplicativo como um terminal externo, consulte stackoverflow.com/questions/17309749/…
Maksim Shamihulau
29

Esta versão usa o módulo keypress e oferece suporte a node.js versão 0.10, 0.8 e 0.6, bem como iojs 2.3. Certifique-se de correr 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
fonte
Isso não funciona no nó v0.10.25, ele diz use em process.stdin.setRawMode()vez disso, mas que erros e não diz nenhum método setRawMode, muito chato
Plentybinary
@Plentybinary Eu suspeito que você não está realmente executando o nó v0.10.25. Eu testei isso contra v0.10.25 e funciona corretamente. e process.stdin.setRawModeexiste, é uma função e funciona corretamente. Eu também testei no iojs-2.3.1 e ele ainda funciona lá.
Peter Lyons
FWIW, isso continua a funcionar bem pelo menos até v0.10.40
John Rix
8

Com nodejs 0.6.4 testado ( teste falhou na versão 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);

se você executá-lo e:

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

Código importante # 1:

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

Código importante 2:

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