fix: Terminal emulation used by SSH sessions (#3473)

Fixes #3371
This commit is contained in:
Mathias Fredriksson
2022-09-12 19:27:51 +03:00
committed by GitHub
parent b4c29f34c3
commit 09da3858ce
15 changed files with 388 additions and 83 deletions
+32 -9
View File
@@ -1,5 +1,4 @@
//go:build windows
// +build windows
package pty
@@ -22,7 +21,12 @@ var (
)
// See: https://docs.microsoft.com/en-us/windows/console/creating-a-pseudoconsole-session
func newPty() (PTY, error) {
func newPty(opt ...Option) (PTY, error) {
var opts ptyOptions
for _, o := range opt {
o(&opts)
}
// We use the CreatePseudoConsole API which was introduced in build 17763
vsn := windows.RtlGetVersion()
if vsn.MajorVersion < 10 ||
@@ -32,30 +36,42 @@ func newPty() (PTY, error) {
return nil, xerrors.Errorf("pty not supported")
}
ptyWindows := &ptyWindows{}
pty := &ptyWindows{
opts: opts,
}
var err error
ptyWindows.inputRead, ptyWindows.inputWrite, err = os.Pipe()
pty.inputRead, pty.inputWrite, err = os.Pipe()
if err != nil {
return nil, err
}
ptyWindows.outputRead, ptyWindows.outputWrite, err = os.Pipe()
pty.outputRead, pty.outputWrite, err = os.Pipe()
if err != nil {
_ = pty.inputRead.Close()
_ = pty.inputWrite.Close()
return nil, err
}
consoleSize := uintptr(80) + (uintptr(80) << 16)
if opts.sshReq != nil {
consoleSize = uintptr(opts.sshReq.Window.Width) + (uintptr(opts.sshReq.Window.Height) << 16)
}
ret, _, err := procCreatePseudoConsole.Call(
consoleSize,
uintptr(ptyWindows.inputRead.Fd()),
uintptr(ptyWindows.outputWrite.Fd()),
uintptr(pty.inputRead.Fd()),
uintptr(pty.outputWrite.Fd()),
0,
uintptr(unsafe.Pointer(&ptyWindows.console)),
uintptr(unsafe.Pointer(&pty.console)),
)
if int32(ret) < 0 {
_ = pty.Close()
return nil, xerrors.Errorf("create pseudo console (%d): %w", int32(ret), err)
}
return ptyWindows, nil
return pty, nil
}
type ptyWindows struct {
opts ptyOptions
console windows.Handle
outputWrite *os.File
@@ -74,6 +90,13 @@ type windowsProcess struct {
proc *os.Process
}
// Name returns the TTY name on Windows.
//
// Not implemented.
func (p *ptyWindows) Name() string {
return ""
}
func (p *ptyWindows) Output() ReadWriter {
return ReadWriter{
Reader: p.outputRead,