Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Windows through conpty #95

Open
hinshun opened this issue Apr 30, 2020 · 23 comments
Open

Support Windows through conpty #95

hinshun opened this issue Apr 30, 2020 · 23 comments

Comments

@hinshun
Copy link

hinshun commented Apr 30, 2020

Windows 10 gained support for psuedo-terminals with conpty: https://devblogs.microsoft.com/commandline/windows-command-line-introducing-the-windows-pseudo-console-conpty/

Prior art:

Would you be open to a PR?

@creack
Copy link
Owner

creack commented Apr 30, 2020 via email

@prabirshrestha
Copy link

Another option would be to use go-winpty but is based of winpty.dll.

You can also look at the source of portable-pty from rust that supports both winpty and conpty.

@virtuald
Copy link
Contributor

I noted in #50 that https://github.com/containerd/console has a console implementation for Windows. There's quite a bit of overlap with this library -- so it might be worth borrowing from that if someone were to open a PR.

@liuhaowen478
Copy link

Any update on this? Would be so great to see this happen

@mardukbp
Copy link

ActiveState implemented a Go library for conpty: termtest/conpty

@creack
Copy link
Owner

creack commented Nov 24, 2020

@mardukbp unfortunatelly termtest/conpty is based on CGO, which is not an option here as it would be a breaking change. We could consider it for a v2 though.

@virtuald This looks interesting indeed, but as I have 0 experience with windows, I have no idea what's going on there.. If someone want to create a PR, I'd be happy to bring it in, but I don't think I'll have time to do it myself anytime soon.

@liuhaowen478 We are looking for motived people to contribute :)

@mardukbp
Copy link

@creack How do you know that termtest/conpty is based on CGO? As far as I can tell, it uses the syscall and windows go packages. I could not find any reference to cgo in the code.

@creack
Copy link
Owner

creack commented Nov 25, 2020

As I have no experience with windows, I might be wrong and I didn't test it, but I saw this: https://github.com/ActiveState/termtest/blob/master/conpty/syscall_windows.go#L16

AFAIK, loading a plugin in go requires cgo (golang/go#19569)

@AlbinoDrought
Copy link

For what it's worth, here's what I get on a Windows machine:

User@Desktop MINGW64 ~/go/src
$ CGO_ENABLED=0 go get github.com/ActiveState/termtest

User@Desktop MINGW64 ~/go/src
$ cd github.com/ActiveState/termtest/conpty/cmd/example

User@Desktop MINGW64 ~/go/src/github.com/ActiveState/termtest/conpty/cmd/example (master)
$ CGO_ENABLED=0 go build

User@Desktop MINGW64 ~/go/src/github.com/ActiveState/termtest/conpty/cmd/example (master)
$ ./example.exe
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.

Try the new cross-platform PowerShell https://aka.ms/pscore6

PS C:\Users\User\Downloads> echo "hello world"
hello world
PS C:\Users\User\Downloads>
exit code was: 0

@mardukbp
Copy link

According to the Go Wiki loading a DLL with syscall does not require cgo.

AFAIK, loading a plugin in go requires cgo (golang/go#19569)

Yes, but termtest/conpty does not use go plugins.

I think this library is good to go! 😉

@ghost
Copy link

ghost commented Nov 30, 2020

Hi @creack , I have opened a pull request for windows conpty support (#109 ), but as noted as known issues there, I probably need some guidance to solve these issues since I am not a windows expert, any idea?

@creack
Copy link
Owner

creack commented Nov 30, 2020

@jeffreystoke I'll take a look this week, thanks for the pr!

@imbytecat
Copy link

Has there been any progress on the ConPTY support for Windows so far? I noticed that this PR is still not merged.

@creack
Copy link
Owner

creack commented Oct 13, 2021

Not yet. concerns about breaking change and overall usability issue. I haven't yet been able to get this to work on my windows machine.

@photostorm
Copy link

I think we fixed a lot of usability issues. I have tested it with powershell.

var f pty.Pty
var err error

f, err = pty.Start(exec.Command("powershell"))
if err != nil {
	return nil, err
}

@jherman
Copy link

jherman commented Oct 13, 2021

@photostorm How did you getting it working? I have the following code:

func main() {
	var f pty.Pty
	var err error

	f, err = pty.Start(exec.Command("cmd"))
	if err != nil {
		log.Fatal(err)
	}

	defer f.Close()

	h := f.Fd()

	oldState, err := term.MakeRaw(int(h))
	if err != nil {
		panic(err)
	}
	defer func() { _ = term.Restore(int(os.Stdin.Fd()), oldState) }() // Best effort.

	go func() { _, _ = io.Copy(f, os.Stdin) }()
	_, _ = io.Copy(os.Stdout, f)
}

output:

panic: The handle is invalid.

goroutine 1 [running]:
main.main()
        C:/repos/work/github.com/jeffreystoke/pty/test/test.go:69 +0x1eb
exit status 2

I can't seem to get a proper windows handle.

== EDIT:RESOLVED ==

I should have used os.Std.Fd() instead of f.Fd(). My bad. I have it working in Windows now.

@ghost
Copy link

ghost commented Oct 14, 2021

@jherman

Glad you have made it working, just comment for others may have the same issue:

term.MakeRaw

If you mean golang.org/x/sys/term.MakeRaw, that's meant for windows console, not conpty.

ref:

@ghost
Copy link

ghost commented Oct 14, 2021

@creack any chance to test it again? I'm pretty confident it works now.

@jherman
Copy link

jherman commented Oct 14, 2021

@jeffreystoke Thanks for the reply. I was able to make it work using the sample code in the readme, with only commenting out the section involving resize of the console. I still haven't found a good way to resize the console by listening for some event vs an inefficient polling for a size change.

I did find an issue with running interactive console UI's like FAR manager. You can't navigate or pretty much do anything with the function keys. This does work on the *nix bash sessions. Can you confirm if it's just me? If so, can you provide a working sample?

For those interested in the code I used:

package main

import (
	"io"
	"log"
	"os"
	"os/exec"

	"github.com/creack/pty"
	"golang.org/x/term"
)

func test() error {
	// Create arbitrary command.
	c := exec.Command("powershell")

	// Start the command with a pty.
	ptmx, err := pty.Start(c)
	if err != nil {
		return err
	}
	// Make sure to close the pty at the end.
	defer func() { _ = ptmx.Close() }() // Best effort.

	// Set stdin in raw mode.
	oldState, err := term.MakeRaw(int(os.Stdin.Fd()))
	if err != nil {
		panic(err)
	}
	defer func() { _ = term.Restore(int(os.Stdin.Fd()), oldState) }() // Best effort.

	// Copy stdin to the pty and the pty to stdout.
	// NOTE: The goroutine will keep reading until the next keystroke before returning.
	go func() { _, _ = io.Copy(ptmx, os.Stdin) }()
	_, _ = io.Copy(os.Stdout, ptmx)

	return nil
}

func main() {
	if err := test(); err != nil {
		log.Fatal(err)
	}
}

@ghost
Copy link

ghost commented Oct 14, 2021

@jherman

You can't navigate or pretty much do anything with the function keys.

Looks like a terminal escape sequence translation issue, result from my quick search suggests you should turn on
or off the translation depending on your terminal emulator implementation. (windows.SetConsoleMode(handle, state | windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING))

Ref: https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences

@photostorm
Copy link

@creack I know it been a couple months, but what are the tasks you would like done for windows support for it to be merge. I can continue PR.

@geekroscom
Copy link

Can I use it on Windows?

@kcmvp
Copy link

kcmvp commented May 20, 2024

any update on this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests