|
@@ -1,43 +1,62 @@
|
|
-// +build windows
|
|
|
|
-package editor
|
|
|
|
|
|
+package readline
|
|
|
|
|
|
import (
|
|
import (
|
|
"syscall"
|
|
"syscall"
|
|
"unsafe"
|
|
"unsafe"
|
|
)
|
|
)
|
|
|
|
|
|
-type State uint32
|
|
|
|
|
|
+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 kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
|
|
|
|
|
var (
|
|
var (
|
|
- procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
|
|
|
|
- procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
|
|
|
|
- procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
|
|
|
|
|
|
+ procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
|
|
|
|
+ procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
|
|
)
|
|
)
|
|
|
|
|
|
-// IsTerminal returns true if the given file descriptor is a terminal.
|
|
|
|
|
|
+type State struct {
|
|
|
|
+ mode uint32
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// IsTerminal checks if the given file descriptor is associated with a terminal
|
|
func IsTerminal(fd int) bool {
|
|
func IsTerminal(fd int) bool {
|
|
- var st uint32
|
|
|
|
- r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
|
|
|
|
- return r != 0 && e == 0
|
|
|
|
|
|
+ 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, err) {
|
|
|
|
- var state State
|
|
|
|
- _, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&state)), 0)
|
|
|
|
- if e != 0 {
|
|
|
|
- return 0, error(e)
|
|
|
|
- }
|
|
|
|
- raw := state &^ (enableEchoInput | enableProcessedInput | enableLineInput | enableProcessedOutput)
|
|
|
|
- _, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(raw), 0)
|
|
|
|
- if e != 0 {
|
|
|
|
- return nil, error(e)
|
|
|
|
- }
|
|
|
|
- return state, nil
|
|
|
|
|
|
+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
|
|
}
|
|
}
|
|
|
|
|
|
-func UnsetRawMode(fd int, state State) error {
|
|
|
|
- _, _, err := syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(state.mode), 0)
|
|
|
|
|
|
+func UnsetRawMode(fd int, state *State) error {
|
|
|
|
+ _, _, err := syscall.SyscallN(procSetConsoleMode.Addr(), uintptr(fd), uintptr(state.mode), 0)
|
|
return err
|
|
return err
|
|
}
|
|
}
|