xs/termmode_windows.go

114 lines
2.9 KiB
Go

//go:build windows
// +build windows
// Note the terminal manipulation functions herein are mostly stubs. They
// don't really do anything and the xs demo client depends on a wrapper
// script using the 'stty' tool to actually set the proper mode for
// password login and raw mode required, then restoring it upon logout/exit.
//
// mintty uses named pipes and ptys rather than Windows 'console'
// mode, and Go's x/crypto/ssh/terminal libs only work for the latter, so
// until some truly cross-platform terminal mode handling makes it into the
// go std lib I'm not going to jump through hoops trying to be cross-platform
// here; the wrapper does the bare minimum to make the client workable
// under MSYS+mintty which is what I use.
package xs
import (
"bufio"
"fmt"
"log"
"os"
"os/exec"
"os/signal"
)
type State struct {
}
// MakeRaw put the terminal connected to the given file descriptor into raw
// mode and returns the previous state of the terminal so that it can be
// restored.
func MakeRaw(f *os.File) (*State, error) {
cmd := exec.Command("stty", "-echo", "raw")
cmd.Stdin = f
err := cmd.Run()
if err != nil {
log.Fatal(err)
return &State{}, err
}
// MSYS2/CYGWIN: wintty needs CTRL-C caught
// ----------------------------------------
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, os.Kill)
go func() {
for sig := range c {
_ = sig
//fmt.Println(sig)
}
}()
// ----------------------------------------
return &State{}, nil
}
// GetState returns the current state of a terminal which may be useful to
// restore the terminal after a signal.
func GetState(f *os.File) (*State, error) {
return &State{}, nil
}
// Restore restores the terminal connected to the given file descriptor to a
// previous state.
func Restore(f *os.File, state *State) error {
cmd := exec.Command("stty", "sane")
cmd.Stdin = f
err := cmd.Run()
if err != nil {
log.Fatal(err)
return nil
}
return nil
}
// ReadPassword reads a line of input from a terminal without local echo. This
// is commonly used for inputting passwords and other sensitive data. The slice
// returned does not include the \n.
func ReadPassword(f *os.File) (pw []byte, err error) {
sttycmd, err := exec.LookPath("stty")
if err != nil {
return nil, err
} else {
//fmt.Printf("stty found at: %v\n", sttycmd)
cmdOff := exec.Command(sttycmd, "-echo")
cmdOff.Stdin = f //os.Stdin
cmdOff.Stdout = nil //os.Stdout
cmdOff.Stderr = nil //os.Stderr
err = cmdOff.Run()
if err != nil {
return nil, err
}
//fmt.Printf("Enter password:")
scanner := bufio.NewScanner(os.Stdin)
scanner.Scan()
err = scanner.Err()
if err != nil {
return nil, err
}
pw = scanner.Bytes()
fmt.Println()
cmdOn := exec.Command(sttycmd, "echo")
cmdOn.Stdin = f //os.Stdin
cmdOn.Stdout = nil //os.Stdout
cmdOn.Stderr = nil //os.Stderr
err = cmdOn.Run()
if err != nil {
return nil, err
}
}
return
}