如何在不进入 Golang 循环的情况下捕获按键

我有一个循环,其中一些事情根据它运行的状态(手动/自动/学习)发生。我现在希望能够通过按键盘上的伴随字母(“m”代表手动,“a”代表自动,“l”代表学习)让程序在这些状态之间切换。


所以要做到这一点,我需要能够在循环期间捕捉到按键并相应地更改变量状态。我现在有以下内容,它可以捕捉到一个按键,然后是一个输入:


ch := make(chan string)

go func(ch chan string) {

    reader := bufio.NewReader(os.Stdin)

    for {

        s, _ := reader.ReadString('\n')

        ch <- s

    }

}(ch)


for {

    select {

        case stdin, _ := <-ch:

            fmt.Println("Keys pressed:", stdin)

        default:

            fmt.Println("Working..")

    }

    time.Sleep(time.Second)

}

但我需要按下回车键这一事实是不可接受的。


有没有人知道一种非阻塞的方式来捕获普通字母(不是 SIGINT)的按键而无需事后按回车键?


holdtom
浏览 144回答 3
3回答

一只斗牛犬

在阅读 os.Stdin.Read() 并找到这个答案后,我创建了以下代码:package mainimport (    "fmt"    "os"    "time"    "os/exec")func main() {    ch := make(chan string)    go func(ch chan string) {        // disable input buffering        exec.Command("stty", "-F", "/dev/tty", "cbreak", "min", "1").Run()        // do not display entered characters on the screen        exec.Command("stty", "-F", "/dev/tty", "-echo").Run()        var b []byte = make([]byte, 1)        for {            os.Stdin.Read(b)            ch <- string(b)        }    }(ch)    for {        select {            case stdin, _ := <-ch:                fmt.Println("Keys pressed:", stdin)            default:                fmt.Println("Working..")        }        time.Sleep(time.Millisecond * 100)    }}这就像一个魅力。

跃然一笑

因为你正在使用ReadStringwhich 期望你给它的任何参数,在你的情况下 - 关键return。根据文档:ReadString 一直读取到输入中第一次出现 delim,返回一个包含数据的字符串,直到并包括分隔符。这意味着在您按下该键之前,该方法不会返回return。您可以改用常规的Read方法来读取您需要的字符。

江户川乱折腾

如果你想检查是否按下了某个键而不阻塞它所在的进程,你应该使用这样的东西:import (&nbsp; &nbsp;...&nbsp; &nbsp;"golang.org/x/sys/windows")var user32_dll&nbsp; = windows.NewLazyDLL("user32.dll")var GetKeyState = user32_dll.NewProc("GetKeyState")func wasESCKeyPressed() bool {&nbsp; &nbsp; r1, _, _ := GetKeyState.Call(27) // Call API to get ESC key state.&nbsp; &nbsp; return r1 == 65409&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// Code for KEY_UP event of ESC key.}func loop() {&nbsp; &nbsp; for {&nbsp; &nbsp; &nbsp; &nbsp;// Do something...&nbsp; &nbsp; &nbsp; &nbsp;if wasESCKeyPressed() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;break&nbsp; &nbsp; &nbsp; &nbsp;}&nbsp; &nbsp; &nbsp; &nbsp;// Do something...&nbsp; &nbsp; &nbsp; &nbsp;time.Sleep(time.Millisecond * 10)&nbsp; &nbsp; }}
打开App,查看更多内容
随时随地看视频慕课网APP