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

Я шукаю вузли, еквівалентні, наприклад, getcу рубіні

Чи можливо це?


(Додавши цей коментар, щоб це питання було легше знайти; мені знадобилося кілька днів, щоб знайти потрібні слова для нього): Ось як читати символ stdin за символом, перш ніж символ нового рядка (нового рядка) буде надісланий у введення.
запаморочення

Відповіді:


62

Ви можете досягти цього таким чином, якщо перейти в неочищений режим:

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
Не хвилюйтеся, я дізнався про себе,process.stdin.resume(); process.stdin.on('data', function (chunk) { process.stdout.write('data: ' + chunk); });
JamesM-SiteGen

3
Перемістіть на, setRawModeщоб бути нижче openStdin(), тому що ви можете встановити режим лише у випадку stdinініціалізації.
Вежа

4
Здається, stdin більше не випромінює подію натискання клавіші, а натомість випробовує подію даних з різними параметрами.
skeggse

2
Гей, openStdin()це застарілий і старий API? (Я дізнався шлях до вузла після 2011 року ...)
Стівен Лу

3
Ага, так. Фактично stdin.on('keypress',function(chunk,key))було видалено в останніх версіях. І я впевнений, що openStdin()його або видалено, або застаріло. Тепер ви можете отримати доступ до stdin якprocess.stdin
Електра

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
Чи є спосіб зробити це також записати вгору, вниз, вліво, вправо?
Том Р

46

У вузлі> = 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/isissue/6626


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 Я підозрюю, що ви насправді не працює вузол v0.10.25. Я перевірив це на v0.10.25, і він працює належним чином. і process.stdin.setRawModeіснує, є функцією та працює належним чином. Я також тестував на iojs-2.3.1, і він все ще працює там.
Пітер Ліонс

FWIW, це продовжує працювати принаймні до v0.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, {} );

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...);
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.