* On Windows, add ENABLE_VIRTUAL_TERMINAL_INPUT (0x0200) to the stdin * console handle so the terminal sends VT sequences for modified keys * (e.g. \x1b[Z for Shift+Tab). Without this, libuv's ReadConsoleInputW * discards modifier state and Shift+Tab arrives as plain \t.
()
| 336 | * discards modifier state and Shift+Tab arrives as plain \t. |
| 337 | */ |
| 338 | private enableWindowsVTInput(): void { |
| 339 | if (process.platform !== "win32") return; |
| 340 | try { |
| 341 | const arch = process.arch; |
| 342 | if (arch !== "x64" && arch !== "arm64") return; |
| 343 | |
| 344 | // Dynamic require so non-Windows and bundled/browser paths never load the |
| 345 | // native helper. In the npm package native/ is next to dist/; in compiled |
| 346 | // binary archives native/ is copied next to the executable. |
| 347 | const moduleDir = path.dirname(fileURLToPath(import.meta.url)); |
| 348 | const nativePath = path.join("native", "win32", "prebuilds", `win32-${arch}`, "win32-console-mode.node"); |
| 349 | const candidates = [ |
| 350 | path.join(moduleDir, "..", nativePath), |
| 351 | path.join(moduleDir, nativePath), |
| 352 | path.join(path.dirname(process.execPath), nativePath), |
| 353 | ]; |
| 354 | for (const modulePath of candidates) { |
| 355 | try { |
| 356 | const helper = cjsRequire(modulePath) as { enableVirtualTerminalInput?: () => boolean }; |
| 357 | helper.enableVirtualTerminalInput?.(); |
| 358 | return; |
| 359 | } catch { |
| 360 | // Try the next possible packaging location. |
| 361 | } |
| 362 | } |
| 363 | } catch { |
| 364 | // Native helper not available — Shift+Tab won't be distinguishable from Tab. |
| 365 | } |
| 366 | } |
| 367 | |
| 368 | async drainInput(maxMs = 1000, idleMs = 50): Promise<void> { |
| 369 | const shouldDisableKittyProtocol = this.keyboardProtocolPushed || this._kittyProtocolActive; |