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

我正在寻找一个等效于例如ruby的nodejsgetc

这可能吗?


(添加此注释以使此问题更容易找到;花了我几天时间找到适合的单词):这是在输入中输入换行符(换行符)之前,如何逐字符读取stdin的方法。
头晕

Answers:


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不再发出keypress事件,而是发出带有差异参数的data事件。
skeggse

2
openStdin(),旧的API已弃用吗?(我在2011年之后才知道节点方式...)
史蒂文·卢

3
嗯是的 实际上stdin.on('keypress',function(chunk,key))已在最新版本中删除。而且我很确定openStdin()已经删除或已弃用。现在,您可以访问作为标准输入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
谢谢..这很容易立即实现.. :)正是我想要的。
Kushal Likhi 2013年

2
不适用于Node.js 0.8+。您必须导入“ keypress”。参见彼得·里昂斯的答案。
G-Wiz 2013年

2
确实适用于0.8,但有趣的是它是如何不断变化的api。
Dan Heberden 2013年

应该使用键=='\ u0003'(而不是三重等号)来使其正常工作
WHITECOLOR

1
有没有办法使此键向上,向下,向左,向右键写入?
Tom R

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/issues/6626


3
在7上尝试这个,我得到了process.stdin.setRawMode is not a function。稍后将尝试进一步深入。
马特·莫纳

3
@MattMolnar该函数仅在是TTY时才存在,因此请先检查该内容
curiousdannii

@MattMolnar你需要运行你的应用程序作为外部端子,见stackoverflow.com/questions/17309749/...
马克西姆Shamihulau

29

此版本使用 keypress模块,并支持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 2015年

@Plentybinary我怀疑您实际上不是在运行节点v0.10.25。我针对v0.10.25进行了测试,它可以正常工作。并且process.stdin.setRawMode存在,是一个功能,并且可以正常工作。我也在iojs-2.3.1上进行了测试,它仍然可以正常运行。
Peter Lyons 2015年

FWIW,至少在v0.10.40以下,它仍然可以正常运行
John Rix

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...);
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.