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+ENTER
,key.shift
永远不会是true
:
{
letter: '\r',
key: {sequence: '\r', name: 'return', ctrl: false, meta: false, shift: false}
}
为什么?如何在节点中使用readline
检测SHIFT+ENTER
。js?
我在做什么?我正在构建一个terminal prompt app,因此readline
模块非常方便,因为它带有自动完成器,历史记录,分页,提示前缀等。但是,我也希望能够输入多行提示符。
3条答案
按热度按时间xurqigkl1#
为什么:
无法从stdin中获取shift键状态的原因是因为shift键不是进入stdin的字节,stdin只是一个字节流,不直接与键盘交互。
实际输入内容:
例如,如果您要运行以下代码并按Shift+Enter(然后按Ctrl+C):
您会看到类似以下内容的回显:
如您所见,只有一个
0x0A
或\n
字符,没有按下Shift键的指示。您可以使用其他工具重复此过程,以确认它不仅仅是一个节点。
这里
cat
从stdin读取一个换行符并将其写入文件。为什么节点stdin按键事件可以有
shift
=true
:如果我们看看
lib/internal/readline/utils.js
中的emitKeys
,我们可以看到shift键是如何根据特定输入推断的。例如,您可以看到,对于字母数字字符,将根据字符是否为大写来推断移位状态。它并不知道shift键的状态,如果你粘贴大写A
,它会假设shift
是true
,而不是meta
或ctrl
。从本质上讲,它是伪造一个类似于你在浏览器中看到的事件。
你需要做的:
要知道shift键的实际状态,您必须从操作系统查询该信息。您可能需要一个本机代码库,其中包含您希望支持的每个操作系统的实现,使用每个操作系统中可用的任何系统API来查询此信息。我不知道任何现有的第三方模块,并没有找到一个在搜索。另外请记住,这不会在ssh上工作。
这就是为什么命令提示符中的多行输入通常需要转义换行符,或者有某种方法来检测表达式是否不完整。
据我所知,一些终端应用程序,如iTerm应用程序,也可以检测多行输入的粘贴,并在一次写入stdin时将其缓冲在一起,但这些应用程序可以访问的不仅仅是stdin来实现这一点。
qnakjoqk2#
不要依赖
readline
的keypress
事件,它似乎不完整,只能检测一个字符一次,导致在大写锁定模式下按下时将大写“F”识别为shift+f。你可以找到源代码:
emitKeys
。iecba09b3#
你有没有试过将Shift + EnterMap到其他序列,然后检查它是否有效。
我不认为你所提到的仅仅是
readline
npm包是可能的,它可能涉及到对特定终端的一些修补,但对于通用解决方案来说并不真正有用。默认情况下,Enter和
Shift+Enter
(以及Ctrl+v
和Ctrl+Shift+m
)都生成相同的键序列^M(至少在大多数常见的终端模拟器中)。zsh
(以及其它 shell )不作用于密钥绑定,而是作用于从终端接收的密钥序列。将按键和组合转换成按键序列是终端的责任。一些终端模拟器允许配置发送的密钥序列。例如,iTerm2允许您设置自定义的键绑定来发送转义序列(在Profile〉Keys中),您应该能够在那里为
Shift+Enter
定义一个序列,例如。然后可以在zsh: bindkey '^[[[SE' 'accept-and-hold'
中进行适当的设置。