如何在nodejs终端中检测shift + enter?

k4emjkb1  于 2023-04-29  发布在  Node.js
关注(0)|答案(3)|浏览(148)

bounty还有5天到期。回答此问题可获得+250声望奖励。pathikrit正在寻找典型答案

我有以下nodejs程序

import readline from 'readline'

readline.createInterface({input: process.stdin, output: process.stdout}).prompt()

process.stdin.on('keypress', (letter, key) => console.log({letter: letter, key: key}))

大多数情况下,E。例如,如果我按下SHIFT+X,它会正确输出key.shift === True

{
  letter: 'X',
  key: { sequence: 'X', name: 'x', ctrl: false, meta: false, shift: true }
}

但是,如果我按SHIFT+ENTERkey.shift永远不会是true

{
  letter: '\r',
  key: {sequence: '\r', name: 'return', ctrl: false, meta: false, shift: false}
}

为什么?如何在节点中使用readline检测SHIFT+ENTER。js?
我在做什么?我正在构建一个terminal prompt app,因此readline模块非常方便,因为它带有自动完成器,历史记录,分页,提示前缀等。但是,我也希望能够输入多行提示符。

xurqigkl

xurqigkl1#

为什么:

无法从stdin中获取shift键状态的原因是因为shift键不是进入stdin的字节,stdin只是一个字节流,不直接与键盘交互。

实际输入内容:

例如,如果您要运行以下代码并按Shift+Enter(然后按Ctrl+C):

process.stdin.on('data', d => {
    console.log([d]);
});

您会看到类似以下内容的回显:

$ node main.mjs

[ <Buffer 0a> ]
^C

如您所见,只有一个0x0A\n字符,没有按下Shift键的指示。
您可以使用其他工具重复此过程,以确认它不仅仅是一个节点。

$ cat > stdin.txt

^C
$ xxd stdin.txt
00000000: 0a                                       .

这里cat从stdin读取一个换行符并将其写入文件。

为什么节点stdin按键事件可以有shift = true

如果我们看看lib/internal/readline/utils.js中的emitKeys,我们可以看到shift键是如何根据特定输入推断的。例如,您可以看到,对于字母数字字符,将根据字符是否为大写来推断移位状态。它并不知道shift键的状态,如果你粘贴大写A,它会假设shifttrue,而不是metactrl

} else if (RegExpPrototypeExec(/^[0-9A-Za-z]$/, ch) !== null) {
      // Letter, number, shift+letter
      key.name = StringPrototypeToLowerCase(ch);
      key.shift = RegExpPrototypeExec(/^[A-Z]$/, ch) !== null;
      key.meta = escaped;

从本质上讲,它是伪造一个类似于你在浏览器中看到的事件。

你需要做的:

要知道shift键的实际状态,您必须从操作系统查询该信息。您可能需要一个本机代码库,其中包含您希望支持的每个操作系统的实现,使用每个操作系统中可用的任何系统API来查询此信息。我不知道任何现有的第三方模块,并没有找到一个在搜索。另外请记住,这不会在ssh上工作。
这就是为什么命令提示符中的多行输入通常需要转义换行符,或者有某种方法来检测表达式是否不完整。
据我所知,一些终端应用程序,如iTerm应用程序,也可以检测多行输入的粘贴,并在一次写入stdin时将其缓冲在一起,但这些应用程序可以访问的不仅仅是stdin来实现这一点。

qnakjoqk

qnakjoqk2#

不要依赖readlinekeypress事件,它似乎不完整,只能检测一个字符一次,导致在大写锁定模式下按下时将大写“F”识别为shift+f。
你可以找到源代码:emitKeys

iecba09b

iecba09b3#

你有没有试过将Shift + EnterMap到其他序列,然后检查它是否有效。
我不认为你所提到的仅仅是readline npm包是可能的,它可能涉及到对特定终端的一些修补,但对于通用解决方案来说并不真正有用。
默认情况下,Enter和Shift+Enter(以及Ctrl+vCtrl+Shift+m)都生成相同的键序列^M(至少在大多数常见的终端模拟器中)。zsh(以及其它 shell )不作用于密钥绑定,而是作用于从终端接收的密钥序列。将按键和组合转换成按键序列是终端的责任。
一些终端模拟器允许配置发送的密钥序列。例如,iTerm2允许您设置自定义的键绑定来发送转义序列(在Profile〉Keys中),您应该能够在那里为Shift+Enter定义一个序列,例如。然后可以在zsh: bindkey '^[[[SE' 'accept-and-hold'中进行适当的设置。

相关问题