2023-10-30 20:18:12 +00:00
|
|
|
package readline
|
|
|
|
|
|
|
|
import (
|
|
|
|
"syscall"
|
|
|
|
"unsafe"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
enableLineInput = 2
|
|
|
|
enableWindowInput = 8
|
|
|
|
enableMouseInput = 16
|
|
|
|
enableInsertMode = 32
|
|
|
|
enableQuickEditMode = 64
|
|
|
|
enableExtendedFlags = 128
|
|
|
|
enableProcessedOutput = 1
|
|
|
|
enableWrapAtEolOutput = 2
|
|
|
|
enableAutoPosition = 256 // Cursor position is not affected by writing data to the console.
|
|
|
|
enableEchoInput = 4 // Characters are written to the console as they're read.
|
|
|
|
enableProcessedInput = 1 // Enables input processing (like recognizing Ctrl+C).
|
|
|
|
)
|
|
|
|
|
|
|
|
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
|
|
|
|
|
|
|
var (
|
|
|
|
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
|
|
|
|
procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
|
|
|
|
)
|
|
|
|
|
|
|
|
type State struct {
|
|
|
|
mode uint32
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsTerminal checks if the given file descriptor is associated with a terminal
|
|
|
|
func IsTerminal(fd int) bool {
|
|
|
|
var st uint32
|
|
|
|
r, _, e := syscall.SyscallN(procGetConsoleMode.Addr(), uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
|
|
|
|
// if the call succeeds and doesn't produce an error, it's a terminal
|
|
|
|
return r != 0 && e == 0
|
|
|
|
}
|
|
|
|
|
|
|
|
func SetRawMode(fd int) (*State, error) {
|
|
|
|
var st uint32
|
|
|
|
// retrieve the current mode of the terminal
|
|
|
|
_, _, e := syscall.SyscallN(procGetConsoleMode.Addr(), uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
|
|
|
|
if e != 0 {
|
|
|
|
return nil, error(e)
|
|
|
|
}
|
|
|
|
// modify the mode to set it to raw
|
|
|
|
raw := st &^ (enableEchoInput | enableProcessedInput | enableLineInput | enableProcessedOutput)
|
|
|
|
// apply the new mode to the terminal
|
|
|
|
_, _, e = syscall.SyscallN(procSetConsoleMode.Addr(), uintptr(fd), uintptr(raw), 0)
|
|
|
|
if e != 0 {
|
|
|
|
return nil, error(e)
|
|
|
|
}
|
|
|
|
// return the original state so that it can be restored later
|
|
|
|
return &State{st}, nil
|
|
|
|
}
|
|
|
|
|
2024-02-15 05:28:35 +00:00
|
|
|
func UnsetRawMode(fd int, state any) error {
|
|
|
|
s := state.(*State)
|
|
|
|
_, _, err := syscall.SyscallN(procSetConsoleMode.Addr(), uintptr(fd), uintptr(s.mode), 0)
|
2023-10-30 20:18:12 +00:00
|
|
|
return err
|
|
|
|
}
|