nodejs как читать нажатия клавиш из stdin

118

Можно ли прослушивать входящие нажатия клавиш в запущенном скрипте nodejs? Если я использую process.openStdin()и слушаю его 'data'событие, то ввод буферизируется до следующей новой строки, например:

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

Запустив это, я получаю:

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

Я бы хотел увидеть:

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

Я ищу nodejs, эквивалентный, например, getcв ruby

Это возможно?

bantic
источник
(Добавление этого комментария, чтобы этот вопрос было легче найти; мне потребовалось несколько дней, чтобы найти для него правильные слова): Вот как читать символ stdin за символом до того, как символ новой строки (новой строки) будет отправлен на ввод.
dizzy

Ответы:

63

Вы можете добиться этого, если переключитесь в необработанный режим:

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
источник
6
Не волнуйтесь, я сам это узнал,process.stdin.resume(); process.stdin.on('data', function (chunk) { process.stdout.write('data: ' + chunk); });
JamesM-SiteGen
3
Переместите так, setRawModeчтобы он был ниже openStdin(), потому что вы можете установить режим только в том случае, если stdinинициализирован.
Башня
4
Похоже, что stdin больше не генерирует событие нажатия клавиши, а вместо этого генерирует событие данных с параметрами различия.
скеггсе
2
Эй, openStdin()это устаревший и старый API? (Я выучил узел после 2011 года ...)
Стивен Лу
3
Ага. Фактически stdin.on('keypress',function(chunk,key))был удален в последних версиях. И я почти уверен, что openStdin()он либо был удален, либо устарел. Теперь вы можете получить доступ к stdin asprocess.stdin
Élektra
132

Для тех, кто нашел этот ответ, поскольку эта возможность была лишена tty, вот как получить необработанный поток символов из 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 );
});

довольно просто - в основном как документация process.stdin, но с использованием setRawMode( true )для получения необработанного потока, который труднее идентифицировать в документации.

Дэн Хеберден
источник
2
Спасибо .. это было просто и легко реализовать сразу .. :) именно то, что я хотел.
Кушал Лихи
2
Не работает с Node.js 0.8+. Вы должны импортировать "нажатие клавиши". См. Ответ Питера Лайонса.
G-Wiz
2
это сделало работу с 0,8, но весело , как это такой постоянно меняющейся апи.
Дэн Хеберден
следует использовать ключ == '\ u0003' (двойное вместо тройного знака равенства), чтобы заставить его работать
WHITECOLOR
1
Есть ли способ сделать так, чтобы клавиши записи вверх, вниз, влево и вправо тоже были?
Tom R
47

В узле> = 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)
})

См. Https://github.com/nodejs/node/issues/6626

arve0
источник
3
Примеряю это на 7 и получаю process.stdin.setRawMode is not a function. Попробую нырнуть чуть глубже позже.
Мэтт Молнар
3
@MattMolnar Функция присутствует, только если это TTY, поэтому сначала проверьте это
curiousdannii
@MattMolnar вам нужно запустить приложение в качестве внешнего терминала см stackoverflow.com/questions/17309749/...
Максим Shamihulau
29

Эта версия использует модуль нажатия клавиш и поддерживает node.js версии 0.10, 0.8 и 0.6, а также iojs 2.3. Обязательно беги 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();
Питер Лайонс
источник
Это не работает на узле v0.10.25, process.stdin.setRawMode()вместо этого он говорит об использовании, но об ошибках и говорит, что нет метода setRawMode, очень раздражает
Plentybinary
@Plentybinary Я подозреваю, что вы на самом деле не используете node v0.10.25. Я тестировал это против v0.10.25, и он работает правильно. и process.stdin.setRawModeсуществует, является функцией и работает правильно. Я также тестировал iojs-2.3.1, и он все еще работает.
Питер Лайонс
FWIW, это продолжает работать хорошо, по крайней мере, до версии 0.10.40
Джон Рикс,
8

При тестировании nodejs 0.6.4 ( тест не прошел в версии 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);

если вы запустите его и:

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

Важный код №1:

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

Важный код № 2:

.createInterface( process.stdin, {} );
befzz
источник
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...);
}
Электра
источник