Version
v24.11.0
Platform
Microsoft Windows NT 10.0.26200.0 x64
Subsystem
node:tty or node:fs
What steps will reproduce the bug?
Run the following code in a CommonJS setting (or convert requires to imports):
constfs=require("node:fs");consttty=require("node:tty");constfd=fs.openSync("\\\\.\\CONIN$","r");constinput=newtty.ReadStream(fd);input.setRawMode(true);How often does it reproduce? Is there a required condition?
Windows
What is the expected behavior? Why is that the expected behavior?
Successful open of console/TTY in raw mode
What do you see instead?
\\.\CONIN$ opens and new tty.ReadStream(fd) reports isTTY: true, but setRawMode(true) throws EPERM.
Additional information
Motivation
A terminal TUI/pager such as hunk needs to read application data from stdin, while still interacting via keyboard/mouse input from the controlling console. For example:
In this process, fd 0 is the pipe containing the diff, not the keyboard. On Unix, this can be handled by opening /dev/tty and passing that fd to new tty.ReadStream(fd), then calling setRawMode(true). On Windows, I expected \\.\CONIN$ to be the equivalent, and Node can open it and reports the resulting tty.ReadStream as a TTY, but setRawMode(true) fails with EPERM.
I also tried a few other names for CONIN$:
constfs=require("node:fs");consttty=require("node:tty");for(constpathof["CON","CONIN$","\\\\.\\CONIN$","//./CONIN$"]){try{constfd=fs.openSync(path,"r");conststream=newtty.ReadStream(fd);letresult;try{stream.setRawMode(true);result="raw ok";stream.setRawMode(false);}catch(error){result=`raw failed: ${error.code}${error.message}`;}console.error(path,{
fd,isTTY: stream.isTTY,
result,});stream.destroy();}catch(error){console.error(path,"open failed:",error.code,error.message);}}Output:
CON open failed: ENOENT ENOENT: no such file or directory, open '...\CON'
CONIN$ open failed: ENOENT ENOENT: no such file or directory, open '...\CONIN$'
\\.\CONIN$ { fd: 3, isTTY: true, result: 'raw failed: EPERM setRawMode EPERM' }
//./CONIN$ { fd: 3, isTTY: true, result: 'raw failed: EPERM setRawMode EPERM' }
There should be a supported way for a Windows CLI/TUI application to reopen the controlling console input while stdin is a pipe, then enable raw mode on that input stream. Otherwise, tools that consume piped stdin but need interactive terminal input cannot work as full-screen TUIs on Windows without native addons or platform-specific external helpers.
Version
v24.11.0
Platform
Subsystem
node:tty or node:fs
What steps will reproduce the bug?
Run the following code in a CommonJS setting (or convert
requires toimports):How often does it reproduce? Is there a required condition?
Windows
What is the expected behavior? Why is that the expected behavior?
Successful open of console/TTY in raw mode
What do you see instead?
\\.\CONIN$opens andnew tty.ReadStream(fd)reportsisTTY: true, butsetRawMode(true)throwsEPERM.Additional information
Motivation
A terminal TUI/pager such as hunk needs to read application data from stdin, while still interacting via keyboard/mouse input from the controlling console. For example:
git diff | hunk pager -In this process, fd 0 is the pipe containing the diff, not the keyboard. On Unix, this can be handled by opening
/dev/ttyand passing that fd tonew tty.ReadStream(fd), then callingsetRawMode(true). On Windows, I expected\\.\CONIN$to be the equivalent, and Node can open it and reports the resultingtty.ReadStreamas a TTY, butsetRawMode(true)fails withEPERM.I also tried a few other names for
CONIN$:Output:
There should be a supported way for a Windows CLI/TUI application to reopen the controlling console input while stdin is a pipe, then enable raw mode on that input stream. Otherwise, tools that consume piped stdin but need interactive terminal input cannot work as full-screen TUIs on Windows without native addons or platform-specific external helpers.