Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

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

How to disable ENABLE_LINE_INPUT in ConPTY? How to call GetConsoleMode for a PseudoConsole? #13201

Closed
lonnywong opened this issue May 30, 2022 · 3 comments
Labels
Issue-Question For questions or discussion Needs-Tag-Fix Doesn't match tag requirements Needs-Triage It's a new issue that the core contributor team needs to triage at the next triage meeting Product-Conpty For console issues specifically related to conpty

Comments

@lonnywong
Copy link
Contributor

Windows Terminal version

1.12.10982.0

Windows build number

10.0.19043.0

Other Software

https://github.com/UserExistsError/conpty v0.1.0

Is it similar to https://stackoverflow.com/a/11439517/7696611 ?

Steps to reproduce

  • go run conptytest.go
package main

import (
        "bufio"
        "context"
        "fmt"
        "strings"

        "github.com/UserExistsError/conpty"
)

func main() {
        cpty, err := conpty.Start("python3 -c \"import sys; s = sys.stdin.readline(); print(len(s))\"")
        if err != nil {
                fmt.Printf("Failed to spawn a pty:  %v", err)
                return
        }
        defer cpty.Close()

        go func() {
                cpty.Write([]byte(strings.Repeat("A", 3000) + "\r\n"))

                scanner := bufio.NewScanner(cpty)
                for scanner.Scan() {
                        // Should output 3001.
                        // But output 511 in cmd, output 2510 in MSYS2.
                        fmt.Printf("Output: %s\n", scanner.Text())
                }
                if err := scanner.Err(); err != nil {
                        fmt.Println(err)
                }
        }()

        if _, err := cpty.Wait(context.Background()); err != nil {
                fmt.Printf("Error: %v", err)
        }
}

Expected Behavior

Output: 3001

Actual Behavior

Output: 511

@lonnywong lonnywong added the Issue-Bug It either shouldn't be doing this or needs an investigation. label May 30, 2022
@ghost ghost added Needs-Triage It's a new issue that the core contributor team needs to triage at the next triage meeting Needs-Tag-Fix Doesn't match tag requirements labels May 30, 2022
@lonnywong lonnywong changed the title How to disable the input buffer of ConPTY? How to disable ENABLE_LINE_INPUT in ConPTY? May 31, 2022
@lonnywong
Copy link
Contributor Author

If disable ENABLE_LINE_INPUT in the child process, it works.

But I can't change the child process to disable ENABLE_LINE_INPUT.

Is there a way to disable ENABLE_LINE_INPUT in ConPTY?

  • go build readline.go
package main

import (
	"bufio"
	"fmt"
	"os"

	"golang.org/x/sys/windows"
)

func main() {
	var st uint32
	if err := windows.GetConsoleMode(windows.Handle(os.Stdin.Fd()), &st); err != nil {
		fmt.Println(err)
		return
	}

	// disable ENABLE_LINE_INPUT
	raw := st &^ (windows.ENABLE_ECHO_INPUT | windows.ENABLE_LINE_INPUT)
	fmt.Printf("st: %#x, raw: %#x\n", st, raw)

	if err := windows.SetConsoleMode(windows.Handle(os.Stdin.Fd()), raw); err != nil {
		fmt.Println(err)
		return
	}

	// reset console mode
	defer func() {
		if err := windows.SetConsoleMode(windows.Handle(os.Stdin.Fd()), st); err != nil {
			fmt.Println(err)
			return
		}
	}()

	// read line
	line, err := bufio.NewReader(os.Stdin).ReadBytes('\r')
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Printf("\nLength: %d\r\n", len(line))
}
  • go run conptytest.go
package main

import (
	"bufio"
	"context"
	"fmt"
	"strings"
	"time"

	"github.com/UserExistsError/conpty"
)

func main() {
	cpty, err := conpty.Start("readline.exe") // The child process have to disable ENABLE_LINE_INPUT first
	if err != nil {
		fmt.Printf("Failed to spawn a pty:  %v", err)
		return
	}
	defer cpty.Close()

	go func() {
		time.Sleep(1 * time.Second) // Wait the child process disable ENABLE_LINE_INPUT first
		cpty.Write([]byte(strings.Repeat("A", 5000) + "\r\n"))

		scanner := bufio.NewScanner(cpty)
		for scanner.Scan() {
			fmt.Println(scanner.Text())
		}
		if err := scanner.Err(); err != nil {
			fmt.Println(err)
		}
	}()

	if _, err := cpty.Wait(context.Background()); err != nil {
		fmt.Printf("Error: %v", err)
	}
}

@lonnywong lonnywong changed the title How to disable ENABLE_LINE_INPUT in ConPTY? How to disable ENABLE_LINE_INPUT in ConPTY? How to call GetConsoleMode for a PseudoConsole? May 31, 2022
@zadjii-msft zadjii-msft added the Product-Conpty For console issues specifically related to conpty label Jun 6, 2022
@zadjii-msft
Copy link
Member

But I can't change the child process to disable ENABLE_LINE_INPUT.

Huh. I think you might be stuck here then. I don't think we provide any sort of way to call the console APIs on a conpty you create. There might be some trickery possible. You might be able to attach some other helper disable-line-input.exe to the same conpty, which just calls that API, and have it magically work. IIRC input mode is a global state, so multiple attached clients can mess with each other's state. But, I'd also caution that's definitely a hack and one we're intending to fix (#4954)

@zadjii-msft zadjii-msft added Issue-Question For questions or discussion and removed Issue-Bug It either shouldn't be doing this or needs an investigation. labels Jun 9, 2022
@lonnywong
Copy link
Contributor Author

But I can't change the child process to disable ENABLE_LINE_INPUT.

Huh. I think you might be stuck here then. I don't think we provide any sort of way to call the console APIs on a conpty you create. There might be some trickery possible. You might be able to attach some other helper disable-line-input.exe to the same conpty, which just calls that API, and have it magically work. IIRC input mode is a global state, so multiple attached clients can mess with each other's state. But, I'd also caution that's definitely a hack and one we're intending to fix (#4954)

Thanks for your help.

I tried it before, it works.

I disabled the ENABLE_LINE_INPUT and create a ssh process.
But the /usr/bin/ssh in MSYS2 still can't read all the input from ConPTY.
Looks like it's another issue.

Btw, the C:\Windows\System32\OpenSSH\ssh.exe works good.

@microsoft microsoft locked and limited conversation to collaborators Jun 9, 2022
@zadjii-msft zadjii-msft converted this issue into discussion #13257 Jun 9, 2022

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
Issue-Question For questions or discussion Needs-Tag-Fix Doesn't match tag requirements Needs-Triage It's a new issue that the core contributor team needs to triage at the next triage meeting Product-Conpty For console issues specifically related to conpty
Projects
None yet
Development

No branches or pull requests

2 participants