nodejs cómo leer las pulsaciones de teclas desde stdin

118

¿Es posible escuchar las pulsaciones de teclas entrantes en un script de nodejs en ejecución? Si utilizo process.openStdin()y escucho su 'data'evento, la entrada se almacena en búfer hasta la siguiente nueva línea, así:

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

Al ejecutar esto, obtengo:

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

Lo que me gustaría es ver:

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

Estoy buscando un nodejs equivalente a, por ejemplo, getcen ruby

es posible?

bantic
fuente
(Agregar este comentario para que esta pregunta sea más fácil de encontrar; me tomó unos días encontrar las palabras correctas): así es como leer stdin carácter por carácter antes de que se envíe el carácter de nueva línea (nueva línea) en la entrada.
mareado

Respuestas:

62

Puede lograrlo de esta manera, si cambia al modo sin formato:

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
fuente
6
No se preocupe, lo descubrí yo mismo,process.stdin.resume(); process.stdin.on('data', function (chunk) { process.stdout.write('data: ' + chunk); });
JamesM-SiteGen
3
Mueva el setRawModepara estar debajo de openStdin(), porque solo puede establecer el modo si el stdinestá inicializado.
Torre
4
Parece que stdin ya no emite un evento de pulsación de tecla, sino que emite un evento de datos, con parámetros diferentes.
skeggse
2
Oye, ¿es openStdin()una API antigua y obsoleta? (Aprendí el modo de nodo después de 2011 ...)
Steven Lu
3
Oh, sí. De hecho stdin.on('keypress',function(chunk,key))se ha eliminado en versiones recientes. Y estoy bastante seguro de que openStdin()se ha eliminado o está obsoleto. Ahora, puede acceder a stdin comoprocess.stdin
Élektra
132

Para aquellos que encuentren esta respuesta ya que se eliminó esta capacidad tty, aquí se explica cómo obtener un flujo de caracteres sin procesar 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 );
});

bastante simple, básicamente como la documentación de process.stdin, pero se usa setRawMode( true )para obtener un flujo sin procesar, que es más difícil de identificar en la documentación.

Dan Heberden
fuente
2
Gracias ... fue simple y fácil de implementar de inmediato ... :) exactamente lo que quería.
Kushal Likhi
2
No funciona con Node.js 0.8+. Debe importar 'pulsación de tecla'. Vea la respuesta de Peter Lyons.
G-Wiz
2
esto hizo trabajo con 0.8, pero divertido cómo es una API siempre cambiante.
Dan Heberden
debe usar la clave == '\ u0003' (doble en lugar de triple signo igual) para que funcione
WHITECOLOR
1
¿Hay alguna manera de hacer que esto escriba las teclas arriba, abajo, izquierda, derecha también?
Tom R
46

En el nodo> = 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)
})

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

arve0
fuente
3
Probar esto en 7 y obtengo process.stdin.setRawMode is not a function. Intentaré sumergirme un poco más más tarde.
Matt Molnar
3
@MattMolnar La función solo está presente si es un TTY, así que
verifíquelo
@MattMolnar necesita ejecutar su aplicación como terminal externo, consulte stackoverflow.com/questions/17309749/…
Maksim Shamihulau
29

Esta versión utiliza el módulo de pulsación de teclas y es compatible con la versión 0.10, 0.8 y 0.6 de node.js, así como con iojs 2.3. Asegúrate 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
fuente
Esto no funciona en el nodo v0.10.25, dice use process.stdin.setRawMode()en su lugar pero que errores y dice que no hay método setRawMode, muy molesto
Plentybinary
@Plentybinary Sospecho que en realidad no está ejecutando el nodo v0.10.25. Probé esto contra v0.10.25 y funciona correctamente. y process.stdin.setRawModeexiste, es una función y funciona correctamente. También probé en iojs-2.3.1 y todavía funciona allí.
Peter Lyons
FWIW, esto continúa funcionando bien al menos hasta la v0.10.40
John Rix
8

Con nodejs 0.6.4 probado (la prueba falló en la versión 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 lo ejecuta y:

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

Código importante # 1:

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

Código importante # 2:

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