From 812d296397ced8b5f1b2712a15178f80f0eaf4e0 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Fri, 26 Jun 2026 16:05:18 +1200 Subject: [PATCH 1/4] tty: add raw-vt and io raw modes Signed-off-by: Samuel Williams --- doc/api/tty.md | 30 ++++++++++++++--- lib/tty.js | 24 +++++++++++--- src/tty_wrap.cc | 10 ++++-- test/pseudo-tty/test-set-raw-mode-modes.js | 36 +++++++++++++++++++++ test/pseudo-tty/test-set-raw-mode-modes.out | 4 +++ 5 files changed, 92 insertions(+), 12 deletions(-) create mode 100644 test/pseudo-tty/test-set-raw-mode-modes.js create mode 100644 test/pseudo-tty/test-set-raw-mode-modes.out diff --git a/doc/api/tty.md b/doc/api/tty.md index 03f86cd66052fd..b626a9ed6218de 100644 --- a/doc/api/tty.md +++ b/doc/api/tty.md @@ -69,12 +69,18 @@ A `boolean` that is always `true` for `tty.ReadStream` instances. -* `mode` {boolean} If `true`, configures the `tty.ReadStream` to operate as a - raw device. If `false`, configures the `tty.ReadStream` to operate in its - default mode. The `readStream.isRaw` property will be set to the resulting - mode. +* `mode` {boolean|string} If `true` or `'raw-vt'`, configures the + `tty.ReadStream` to operate as a raw device. If `'io'`, configures the + `tty.ReadStream` to operate in binary-safe I/O mode. If `false`, configures + the `tty.ReadStream` to operate in its default mode. The `readStream.isRaw` + property will be set to whether the stream is in raw mode, and the + `readStream.rawMode` property will be set to the resulting mode. * Returns: {this} The read stream instance. Allows configuration of `tty.ReadStream` so that it operates as a raw device. @@ -86,6 +92,22 @@ characters. Ctrl+C will no longer cause a `SIGINT` when in this mode. This mode does not affect terminal output processing, such as newline translation on Unix terminals. +When in binary-safe I/O mode, terminal output processing is also disabled. +This corresponds to libuv's `UV_TTY_MODE_IO` mode and is not supported on +Windows. + +### `readStream.rawMode` + + + +* {boolean|string} + +The current raw mode for the `tty.ReadStream`. This is `false` when the stream +is in its default mode, `'raw-vt'` when raw input mode is enabled, and `'io'` +when binary-safe I/O mode is enabled. + ## Class: `tty.WriteStream` From 1c0e5d33fb45bf2b32f9874fc3f51c4f8a17151f Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Tue, 30 Jun 2026 11:38:39 +1200 Subject: [PATCH 3/4] tty: use raw as public raw mode name Signed-off-by: Samuel Williams --- doc/api/tty.md | 8 ++++---- lib/tty.js | 4 ++-- test/pseudo-tty/test-set-raw-mode-modes.js | 8 ++++---- test/pseudo-tty/test-set-raw-mode-modes.out | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/doc/api/tty.md b/doc/api/tty.md index b2cd3401ce0a41..3387c201e8797b 100644 --- a/doc/api/tty.md +++ b/doc/api/tty.md @@ -72,10 +72,10 @@ added: v0.7.7 changes: - version: REPLACEME pr-url: https://github.com/nodejs/node/pull/64140 - description: The `mode` argument supports `'raw-vt'` and `'io'`. + description: The `mode` argument supports `'raw'` and `'io'`. --> -* `mode` {boolean|string} If `true` or `'raw-vt'`, configures the +* `mode` {boolean|string} If `true` or `'raw'`, configures the `tty.ReadStream` to operate as a raw device. If `'io'`, configures the `tty.ReadStream` to operate in binary-safe I/O mode. If `false`, configures the `tty.ReadStream` to operate in its default mode. The `readStream.isRaw` @@ -105,8 +105,8 @@ added: REPLACEME * {boolean|string} The current raw mode for the `tty.ReadStream`. This is `false` when the stream -is in its default mode, `'raw-vt'` when raw input mode is enabled, and `'io'` -when binary-safe I/O mode is enabled. +is in its default mode, `'raw'` when raw input mode is enabled, and `'io'` when +binary-safe I/O mode is enabled. ## Class: `tty.WriteStream` diff --git a/lib/tty.js b/lib/tty.js index f37dc731d332cc..a577a7f0a3d3c9 100644 --- a/lib/tty.js +++ b/lib/tty.js @@ -82,11 +82,11 @@ ObjectSetPrototypeOf(ReadStream.prototype, net.Socket.prototype); ObjectSetPrototypeOf(ReadStream, net.Socket); ReadStream.prototype.setRawMode = function(mode) { - const rawMode = mode === 'io' ? 'io' : (mode ? 'raw-vt' : false); + const rawMode = mode === 'io' ? 'io' : (mode ? 'raw' : false); let ttyMode = UV_TTY_MODE_NORMAL; if (rawMode === 'io') { ttyMode = UV_TTY_MODE_IO; - } else if (rawMode === 'raw-vt') { + } else if (rawMode === 'raw') { ttyMode = UV_TTY_MODE_RAW_VT; } const err = this._handle?.setRawMode(ttyMode); diff --git a/test/pseudo-tty/test-set-raw-mode-modes.js b/test/pseudo-tty/test-set-raw-mode-modes.js index c2d32cc8540dee..28e0e41c0e8e13 100644 --- a/test/pseudo-tty/test-set-raw-mode-modes.js +++ b/test/pseudo-tty/test-set-raw-mode-modes.js @@ -16,16 +16,16 @@ function isOnlcrEnabled() { process.stdin.setRawMode(true); console.log(`raw=${isOnlcrEnabled()}`); assert.strictEqual(process.stdin.isRaw, true); -assert.strictEqual(process.stdin.rawMode, 'raw-vt'); +assert.strictEqual(process.stdin.rawMode, 'raw'); process.stdin.setRawMode(false); console.log(`normal=${process.stdin.isRaw}`); assert.strictEqual(process.stdin.rawMode, false); -process.stdin.setRawMode('raw-vt'); -console.log(`raw-vt=${isOnlcrEnabled()}`); +process.stdin.setRawMode('raw'); +console.log(`raw-string=${isOnlcrEnabled()}`); assert.strictEqual(process.stdin.isRaw, true); -assert.strictEqual(process.stdin.rawMode, 'raw-vt'); +assert.strictEqual(process.stdin.rawMode, 'raw'); process.stdin.setRawMode(false); process.stdin.setRawMode('io'); diff --git a/test/pseudo-tty/test-set-raw-mode-modes.out b/test/pseudo-tty/test-set-raw-mode-modes.out index f8eee605b9cb55..e449081d60cb3c 100644 --- a/test/pseudo-tty/test-set-raw-mode-modes.out +++ b/test/pseudo-tty/test-set-raw-mode-modes.out @@ -1,4 +1,4 @@ raw=true normal=false -raw-vt=true +raw-string=true io=false From 15fdba05352c0779b1a0764599bfc803b4f149d3 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Tue, 30 Jun 2026 11:39:07 +1200 Subject: [PATCH 4/4] tty: reject unknown raw mode strings Signed-off-by: Samuel Williams --- lib/tty.js | 11 ++++++++++- test/pseudo-tty/test-set-raw-mode-modes.js | 7 +++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/tty.js b/lib/tty.js index a577a7f0a3d3c9..309930f67c3531 100644 --- a/lib/tty.js +++ b/lib/tty.js @@ -37,6 +37,7 @@ const { const { ErrnoException, codes: { + ERR_INVALID_ARG_VALUE, ERR_INVALID_FD, ERR_TTY_INIT_FAILED, }, @@ -82,7 +83,15 @@ ObjectSetPrototypeOf(ReadStream.prototype, net.Socket.prototype); ObjectSetPrototypeOf(ReadStream, net.Socket); ReadStream.prototype.setRawMode = function(mode) { - const rawMode = mode === 'io' ? 'io' : (mode ? 'raw' : false); + let rawMode; + if (mode === 'io' || mode === 'raw') { + rawMode = mode; + } else if (typeof mode === 'string') { + throw new ERR_INVALID_ARG_VALUE( + 'mode', mode, "must be true, false, 'raw', or 'io'"); + } else { + rawMode = mode ? 'raw' : false; + } let ttyMode = UV_TTY_MODE_NORMAL; if (rawMode === 'io') { ttyMode = UV_TTY_MODE_IO; diff --git a/test/pseudo-tty/test-set-raw-mode-modes.js b/test/pseudo-tty/test-set-raw-mode-modes.js index 28e0e41c0e8e13..0c2c747a97c8a7 100644 --- a/test/pseudo-tty/test-set-raw-mode-modes.js +++ b/test/pseudo-tty/test-set-raw-mode-modes.js @@ -21,6 +21,13 @@ assert.strictEqual(process.stdin.rawMode, 'raw'); process.stdin.setRawMode(false); console.log(`normal=${process.stdin.isRaw}`); assert.strictEqual(process.stdin.rawMode, false); +assert.throws( + () => process.stdin.setRawMode('raw-vt'), + { + code: 'ERR_INVALID_ARG_VALUE', + name: 'TypeError', + }); +assert.strictEqual(process.stdin.rawMode, false); process.stdin.setRawMode('raw'); console.log(`raw-string=${isOnlcrEnabled()}`);