/** * Holding the keyboard without wrecking the terminal on the way out. * * Leaving the terminal in raw mode when a process exits is not a cosmetic * problem: the shell that gets it back is left with an input mode it did not set, * and on Windows it typically dies on the spot, taking the window with it. That * was measured: a process that exits with raw mode still on killed the shell in * every trial, while setting and restoring it was harmless in every trial. * * A `finally` block is not enough on its own, because the ways out of a terminal * program include the ones that skip it: an exception thrown from a keypress * handler (which runs on its own stack, not inside the loop), a signal, or a * direct exit. So the restore is registered with the process itself, and running * twice is harmless. */ export interface RawTerminal { /** Put the terminal back. Safe to call more than once. */ restore: () => void; } export interface RawTerminalOptions { /** * Called instead of ending the process when a signal arrives, so an owner with * its own loop can wind down cleanly rather than being cut off mid-frame. */ onEnd?: (signal: NodeJS.Signals) => void; /** Written once on the way out, for cursor and screen restore sequences. */ epilogue?: string; stdin?: NodeJS.ReadStream & { setRawMode?: (v: boolean) => void; }; stdout?: { write: (s: string) => unknown; }; /** Injected in tests instead of the real process. */ proc?: Pick & { exit?: (code?: number) => never; kill?: (pid: number, signal?: NodeJS.Signals) => void; }; } /** * Take the keyboard, and guarantee it is handed back. * * Returns the restore function for the normal path; the same function is wired to * process exit and to signals, so an unexpected end restores the terminal too. */ export declare function claimRawTerminal(options?: RawTerminalOptions): RawTerminal;