/** Terminal focus detection via DECSET ?1004. Shared via globalThis. */ const FOCUS_ENABLE = "\x1b[?1004h"; const FOCUS_DISABLE = "\x1b[?1004l"; const FOCUS_IN_SEQ = "\x1b[I"; const FOCUS_OUT_SEQ = "\x1b[O"; export type FocusListener = (focused: boolean) => void; interface FocusState { refs: number; focused: boolean; listener?: (chunk: Buffer) => void; listeners: Set; buf: string; } const G = globalThis as unknown as { __bugabinga_pi_focus?: FocusState }; G.__bugabinga_pi_focus ??= { refs: 0, focused: true, listeners: new Set(), buf: "", }; const state = G.__bugabinga_pi_focus; function notify(next: boolean): void { if (next === state.focused) return; state.focused = next; for (const fn of state.listeners) { try { fn(state.focused); } catch { /* best-effort */ } } } export function isFocused(): boolean { return state.focused; } export function onFocus(fn: FocusListener): void { state.listeners.add(fn); } export function offFocus(fn: FocusListener): void { state.listeners.delete(fn); } export function attach(): void { if (!process.stdout.isTTY || !process.stdin.isTTY) return; state.refs++; if (state.refs > 1) return; try { process.stdout.write(FOCUS_ENABLE); } catch { state.refs--; return; } const maxSeq = Math.max(FOCUS_IN_SEQ.length, FOCUS_OUT_SEQ.length); const handler = (chunk: Buffer) => { try { state.buf += chunk.toString("binary"); let i = 0; while (i + maxSeq <= state.buf.length) { if (state.buf.startsWith(FOCUS_IN_SEQ, i)) { notify(true); i += FOCUS_IN_SEQ.length; } else if (state.buf.startsWith(FOCUS_OUT_SEQ, i)) { notify(false); i += FOCUS_OUT_SEQ.length; } else { i++; } } state.buf = state.buf.slice(i); if (state.buf.length > 64) state.buf = state.buf.slice(-(maxSeq - 1)); } catch { /* best-effort */ } }; process.stdin.on("data", handler); state.listener = handler; } export function detach(): void { if (state.refs <= 0) return; state.refs--; if (state.refs > 0) return; if (state.listener) { try { process.stdin.off("data", state.listener); } catch { /* noop */ } state.listener = undefined; } try { process.stdout.write(FOCUS_DISABLE); } catch { /* noop */ } }