nodejs cara membaca penekanan tombol dari stdin

118

Apakah mungkin untuk mendengarkan penekanan tombol yang masuk dalam skrip nodejs yang sedang berjalan? Jika saya menggunakan process.openStdin()dan mendengarkan 'data'acaranya maka input akan di-buffer hingga baris baru berikutnya, seperti:

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

Menjalankan ini, saya mendapatkan:

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

Yang ingin saya lihat adalah:

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

Saya mencari nodejs yang setara dengan, misalnya, getcdi ruby

Apakah ini mungkin?

olok-olok
sumber
(Menambahkan komentar ini sehingga pertanyaan ini lebih mudah ditemukan; butuh beberapa hari untuk menemukan kata yang tepat untuk itu): Ini adalah cara membaca karakter stdin demi karakter sebelum karakter baris baru (baris baru) dikirim sebagai masukan.
pusing

Jawaban:

63

Anda dapat mencapainya dengan cara ini, jika Anda beralih ke mode mentah:

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
sumber
6
Jangan khawatir, saya menemukan diri saya,process.stdin.resume(); process.stdin.on('data', function (chunk) { process.stdout.write('data: ' + chunk); });
JamesM-SiteGen
3
Pindahkan setRawModeke bawah openStdin(), karena Anda hanya dapat mengatur mode jika stdindiinisialisasi.
Menara
4
Tampaknya stdin tidak lagi memancarkan peristiwa penekanan tombol, melainkan memancarkan peristiwa data, dengan parameter perbedaan.
skeggse
2
Hai, apakah openStdin()API lama dan usang? (Saya belajar cara node setelah 2011 ...)
Steven Lu
3
Uh, ya. Faktanya stdin.on('keypress',function(chunk,key))telah dihapus dalam versi terbaru. Dan saya cukup yakin openStdin()telah dihapus atau tidak digunakan lagi. Sekarang, Anda dapat mengakses stdin sebagaiprocess.stdin
Élektra
132

Bagi mereka yang menemukan jawaban ini karena kemampuan ini dilucuti tty, berikut ini cara mendapatkan aliran karakter mentah dari 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 );
});

cukup sederhana - pada dasarnya seperti dokumentasi process.stdin tetapi menggunakan setRawMode( true )untuk mendapatkan aliran mentah, yang lebih sulit untuk diidentifikasi dalam dokumentasi.

Dan Heberden
sumber
2
Terima kasih .. itu sederhana dan mudah diterapkan sekarang .. :) persis apa yang saya inginkan.
Kushal Likhi
2
Tidak bekerja dengan Node.js 0.8+. Anda harus mengimpor 'penekanan tombol'. Lihat jawaban Peter Lyons.
G-Wiz
2
ini melakukan pekerjaan dengan 0,8, tapi menyenangkan bagaimana hal itu seperti api yang terus berubah.
Dan Heberden
harus menggunakan kunci == '\ u0003' (dua kali lipat bukan tanda sama dengan tiga kali lipat) untuk membuatnya berfungsi
WHITECOLOR
1
Adakah cara untuk membuat tombol ini menulis ke atas, bawah, kiri, kanan juga?
Tom R
47

Dalam node> = 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)
})

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

arve0
sumber
3
Mencoba ini pada 7 dan saya mendapatkan process.stdin.setRawMode is not a function. Akan mencoba menyelam lebih dalam nanti.
Matt Molnar
3
@MattMolnar Fungsi ini hanya ada jika itu adalah TTY, jadi periksa dulu
penasarandannii
@MattMolnar Anda perlu menjalankan aplikasi Anda sebagai terminal eksternal, lihat stackoverflow.com/questions/17309749/…
Maksim Shamihulau
29

Versi ini menggunakan modul keypress dan mendukung node.js versi 0.10, 0.8 dan 0.6 serta iojs 2.3. Pastikan untuk lari 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
sumber
Ini tidak berfungsi pada node v0.10.25 ia mengatakan gunakan process.stdin.setRawMode()sebagai gantinya tetapi kesalahan itu dan mengatakan tidak ada metode setRawMode, sangat mengganggu
Plentybinary
@Plentybinary Saya curiga Anda tidak benar-benar menjalankan node v0.10.25. Saya menguji ini terhadap v0.10.25 dan berfungsi dengan baik. dan process.stdin.setRawModeada, merupakan fungsi, dan bekerja dengan baik. Saya juga menguji iojs-2.3.1 dan masih berfungsi di sana juga.
Peter Lyons
FWIW, ini terus bekerja dengan baik setidaknya hingga v0.10.40
John Rix
8

Dengan nodejs 0.6.4 diuji ( Pengujian gagal di versi 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);

jika Anda menjalankannya dan:

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

Kode penting # 1:

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

Kode penting # 2:

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