Node: Double keypress in readline / process.stdin

Created on 1 Feb 2019  路  5Comments  路  Source: nodejs/node

  • Version: 11.8.0, 11.9.0
  • Platform: Windows 10 (x64)
  • Subsystem: console

This code produces repeated output:

const readline = require('readline')
const process = require('process')

let rl = readline.createInterface({terminal: true, input: process.stdin, output: process.stdout})
rl.resume()
rl.input.on('data', (chunk) => {
  console.log(`Received ${chunk.length} bytes of data - content was: ${chunk}`)
})

Run this with Node 11.8.0 or above and press the down arrow; two messages are produced:

Received 3 bytes of data - content was:

Received 3 bytes of data - content was:

Revert to Node 11.7.0, a single message is produced.

Received 3 bytes of data - content was:

This breaks, among many things, scrolling through menus in Inquirer.js: https://github.com/SBoudrias/Inquirer.js/issues/778

This appears to be Windows specific (as far as I could tell, I was only able to test on a Linux VM via Docker right now).

Git bisect tells me this issue first appeared with c0859d71765b2f728256b8ac1cfc948311321b37, which upgraded libuv to 1.25.0.

I'll keep digging into libuv (I already have an idea of where the problem was introduced in 1.25.0) but since this impacts Node on Windows somehwat significantly I figured it would be useful to have a way to track this!

doc libuv readline

Most helpful comment

Word on the street is that https://github.com/libuv/libuv/pull/2160 will fix the issue.

All 5 comments

@nodejs/libuv @nodejs/repl

@Ezekiel-DA Can you try changing that logging line to use chunk.toString('hex') and comment with the output?

I get:

Received 3 bytes of data - content was: 1b5b42

The libuv change * tty,win: fix Alt+key under WSL (Bartosz Sosnowski) seems suspect to have changed that on your system.


However, I am quite sure this is not a bug.

The 'data' event you are listening to is from process.stdin itself and it's intention is to emit data events as the stdio connection passes them. This is not what you should be using, but I can't blame you - the documentation for what you should be using is actually missing completely.

Node.js internally uses this functionality to condense stdio connection events into what we would expect -- keypresses.

That isn't directly exposed but is used in readline.emitKeypressEvents(), which is automatically used on readline when attached to a Pipe or a Raw-mode TTY (terminal). The events are emitted off of the stream (rl.input), though, for some reason.

The resulting output from the 'keypress' and the down arrow key looks like this:

[Arguments] {
  '0': undefined,
  '1':
   { sequence: '\u001b[B',
     name: 'down',
     ctrl: false,
     meta: false,
     shift: false,
     code: '[B' } 
}

... I don't really know why this event is emitted where it is and why it is not documented, but this is what you should use, I think.

@Fishrock123 Thanks for looking into this! The only reason I listen to 'data' is to try and find a minimal reproduction for a change in behavior that impacts Inquirer (see https://github.com/SBoudrias/Inquirer.js/issues/778) and appeared when libuv was upgraded to 1.25.0.

I'm pretty sure I found the source of the problem in libuv, and I opened https://github.com/libuv/libuv/issues/2168. As you can see there, the specific scenario of Windows, special keys (e.g. down arrow here) hits a regression that produces an even for both key down and key up, which I'm pretty sure is not the desired behavior!

As a data point, I can also reproduce this issue and has been happening since last Node.js upgrade (Windows 10 x64 1809).

Word on the street is that https://github.com/libuv/libuv/pull/2160 will fix the issue.

Was this page helpful?
0 / 5 - 0 ratings