Merge 6e942c5933 into ae614d919f
commit
2f7b938b78
|
|
@ -16,7 +16,7 @@ import {
|
|||
on,
|
||||
onCleanup,
|
||||
} from "solid-js"
|
||||
import { win32DisableProcessedInput, win32InstallCtrlCGuard } from "./win32"
|
||||
import { win32DisableProcessedInput, win32Init, win32InstallCtrlCGuard } from "./win32"
|
||||
import { Flag } from "@/flag/flag"
|
||||
import semver from "semver"
|
||||
import { DialogProvider, useDialog } from "@tui/ui/dialog"
|
||||
|
|
@ -176,6 +176,7 @@ export function tui(input: {
|
|||
}) {
|
||||
// promise to prevent immediate exit
|
||||
return new Promise<void>(async (resolve) => {
|
||||
await win32Init()
|
||||
const unguard = win32InstallCtrlCGuard()
|
||||
win32DisableProcessedInput()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,24 +1,34 @@
|
|||
import { dlopen, ptr } from "bun:ffi"
|
||||
|
||||
const STD_INPUT_HANDLE = -10
|
||||
const ENABLE_PROCESSED_INPUT = 0x0001
|
||||
|
||||
const kernel = () =>
|
||||
dlopen("kernel32.dll", {
|
||||
GetStdHandle: { args: ["i32"], returns: "ptr" },
|
||||
GetConsoleMode: { args: ["ptr", "ptr"], returns: "i32" },
|
||||
SetConsoleMode: { args: ["ptr", "u32"], returns: "i32" },
|
||||
FlushConsoleInputBuffer: { args: ["ptr"], returns: "i32" },
|
||||
})
|
||||
let mod: typeof import("bun:ffi") | undefined
|
||||
type K32 = {
|
||||
GetStdHandle: (n: number) => bigint | number
|
||||
GetConsoleMode: (h: bigint | number, mode: unknown) => number
|
||||
SetConsoleMode: (h: bigint | number, mode: number) => number
|
||||
FlushConsoleInputBuffer: (h: bigint | number) => number
|
||||
}
|
||||
|
||||
let k32: ReturnType<typeof kernel> | undefined
|
||||
let k32: K32 | undefined
|
||||
let ready: boolean | undefined
|
||||
|
||||
function load() {
|
||||
type Ptr = typeof import("bun:ffi").ptr
|
||||
|
||||
export async function win32Init() {
|
||||
if (process.platform !== "win32") return false
|
||||
if (ready !== undefined) return ready
|
||||
try {
|
||||
k32 ??= kernel()
|
||||
mod = await import("bun:ffi")
|
||||
k32 = (mod.dlopen("kernel32.dll", {
|
||||
GetStdHandle: { args: ["i32"], returns: "ptr" },
|
||||
GetConsoleMode: { args: ["ptr", "ptr"], returns: "i32" },
|
||||
SetConsoleMode: { args: ["ptr", "u32"], returns: "i32" },
|
||||
FlushConsoleInputBuffer: { args: ["ptr"], returns: "i32" },
|
||||
}).symbols as unknown as K32)
|
||||
ready = true
|
||||
return true
|
||||
} catch {
|
||||
ready = false
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
@ -29,15 +39,17 @@ function load() {
|
|||
export function win32DisableProcessedInput() {
|
||||
if (process.platform !== "win32") return
|
||||
if (!process.stdin.isTTY) return
|
||||
if (!load()) return
|
||||
if (!k32 || !mod) return
|
||||
const ptr = mod.ptr as Ptr
|
||||
|
||||
const handle = k32!.symbols.GetStdHandle(STD_INPUT_HANDLE)
|
||||
const lib = k32
|
||||
const handle = lib.GetStdHandle(STD_INPUT_HANDLE)
|
||||
const buf = new Uint32Array(1)
|
||||
if (k32!.symbols.GetConsoleMode(handle, ptr(buf)) === 0) return
|
||||
if (lib.GetConsoleMode(handle, ptr(buf)) === 0) return
|
||||
|
||||
const mode = buf[0]!
|
||||
if ((mode & ENABLE_PROCESSED_INPUT) === 0) return
|
||||
k32!.symbols.SetConsoleMode(handle, mode & ~ENABLE_PROCESSED_INPUT)
|
||||
lib.SetConsoleMode(handle, mode & ~ENABLE_PROCESSED_INPUT)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -46,10 +58,11 @@ export function win32DisableProcessedInput() {
|
|||
export function win32FlushInputBuffer() {
|
||||
if (process.platform !== "win32") return
|
||||
if (!process.stdin.isTTY) return
|
||||
if (!load()) return
|
||||
if (!k32) return
|
||||
|
||||
const handle = k32!.symbols.GetStdHandle(STD_INPUT_HANDLE)
|
||||
k32!.symbols.FlushConsoleInputBuffer(handle)
|
||||
const lib = k32
|
||||
const handle = lib.GetStdHandle(STD_INPUT_HANDLE)
|
||||
lib.FlushConsoleInputBuffer(handle)
|
||||
}
|
||||
|
||||
let unhook: (() => void) | undefined
|
||||
|
|
@ -68,23 +81,25 @@ let unhook: (() => void) | undefined
|
|||
export function win32InstallCtrlCGuard() {
|
||||
if (process.platform !== "win32") return
|
||||
if (!process.stdin.isTTY) return
|
||||
if (!load()) return
|
||||
if (!k32 || !mod) return
|
||||
if (unhook) return unhook
|
||||
const ptr = mod.ptr as Ptr
|
||||
const lib = k32
|
||||
|
||||
const stdin = process.stdin as any
|
||||
const original = stdin.setRawMode
|
||||
|
||||
const handle = k32!.symbols.GetStdHandle(STD_INPUT_HANDLE)
|
||||
const handle = lib.GetStdHandle(STD_INPUT_HANDLE)
|
||||
const buf = new Uint32Array(1)
|
||||
|
||||
if (k32!.symbols.GetConsoleMode(handle, ptr(buf)) === 0) return
|
||||
if (lib.GetConsoleMode(handle, ptr(buf)) === 0) return
|
||||
const initial = buf[0]!
|
||||
|
||||
const enforce = () => {
|
||||
if (k32!.symbols.GetConsoleMode(handle, ptr(buf)) === 0) return
|
||||
if (lib.GetConsoleMode(handle, ptr(buf)) === 0) return
|
||||
const mode = buf[0]!
|
||||
if ((mode & ENABLE_PROCESSED_INPUT) === 0) return
|
||||
k32!.symbols.SetConsoleMode(handle, mode & ~ENABLE_PROCESSED_INPUT)
|
||||
lib.SetConsoleMode(handle, mode & ~ENABLE_PROCESSED_INPUT)
|
||||
}
|
||||
|
||||
// Some runtimes can re-apply console modes on the next tick; enforce twice.
|
||||
|
|
@ -121,7 +136,7 @@ export function win32InstallCtrlCGuard() {
|
|||
stdin.setRawMode = original
|
||||
}
|
||||
|
||||
k32!.symbols.SetConsoleMode(handle, initial)
|
||||
lib.SetConsoleMode(handle, initial)
|
||||
unhook = undefined
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue