我可以同时从 Node 的标准输入中读取行和字符吗?

Posted

技术标签:

【中文标题】我可以同时从 Node 的标准输入中读取行和字符吗?【英文标题】:Can I read both lines and characters from Node's stdin *at the same time*? 【发布时间】:2021-06-05 23:46:58 【问题描述】:

我有一段简单的代码用于读取基于终端的构建脚本的输入。

async function readLine(): Promise<string> 
  return new Promise<string>(resolve => 
    const callback = (data: any) => 
      process.stdin.off('data', callback);
      resolve(data.toString().trim());
    ;

    process.stdin.on('data', callback);
  );

这很好用,但我希望能够检测是否按下了向上箭头,以便用户可以返回到上一个提示。

到目前为止,我看到的每一个允许我检测向上箭头键的示例都需要完全放弃基于行的输入,而是一次处理所有输入一个字符。我不想那样做。

我想要一个仅由向上箭头键触发的回调(稍后可能还有其他特殊键),所有其他键都通过通常的 'data' 回调,一个完整的 Enter 终止一次一行。

有没有办法做到这一点?

【问题讨论】:

【参考方案1】:

没有找到更好的答案,我决定一次处理一个字符,并编写自己的终端行输入例程。

import * as readline from 'readline';
import  Key  from 'readline';

readline.emitKeypressEvents(process.stdin);
process.stdin.setRawMode(true);

function write(s: string): void 
  process.stdout.write(s);


async function readUserInput(): Promise<string> 
  return new Promise<string>(resolve => 
    let buffer = '';
    let length = 0;
    const clearLine = () => write('\x08 \x08'.repeat(length));

    const callback = (ch: string, key: Key) => 
      if (ch === '\x03')  // ctrl-C
        write('^C\n');
        process.exit(130);
      
      else if (ch === '\x15')  // ctrl-U
        clearLine();
        length = 0;
      
      else if (key.name === 'enter' || key.name === 'return') 
        write('\n');
        process.stdin.off('keypress', callback);
        resolve(buffer.substr(0, length).trim());
      
      else if (key.name === 'backspace' || key.name === 'left') 
        if (length > 0) 
          write('\x08 \x08');
          --length;
        
      
      else if (key.name === 'delete') 
        if (length > 0) 
          write('\x08 \x08');
          buffer = buffer.substr(0, --length) + buffer.substr(length + 1);
        
      
      else if (key.name === 'up') 
        clearLine();
        write('\n');
        process.stdin.off('keypress', callback);
        resolve('\x18');
      
      else if (key.name === 'right') 
        if (length < buffer.length) 
          write(buffer.charAt(length++));
        
      
      else if (ch != null && ch >= ' ' && !key.ctrl && !key.meta) 
        write(ch);
        buffer = buffer.substr(0, length) + ch + buffer.substr(length++);
      
    ;

    process.stdin.on('keypress', callback);
  );

【讨论】:

以上是关于我可以同时从 Node 的标准输入中读取行和字符吗?的主要内容,如果未能解决你的问题,请参考以下文章

从标准输入读取密码

shell命令行和在DOS窗口中输入命令有啥区别吗

为 emscripten HTML 程序提供标准输入?

从C中的文件中读取行和列

从标准输入读取而不阻塞

为啥从标准输入读取用户输入时我的字符串不匹配?