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?


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

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.


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


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

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

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...);
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.