Golang函数类似于getchar

dem*_*emi 32 console go getchar

是否有类似getchar能够在控制台中处理标签按下的功能?我想在我的控制台应用程序中完成某种完成.

rpu*_*kar 20

C的getchar()例子:

#include <stdio.h>
void main()
{
    char ch;
    ch = getchar();
    printf("Input Char Is :%c",ch);
}
Run Code Online (Sandbox Code Playgroud)

去等效:

package main

import (
    "bufio"
    "fmt"
    "os"
)

func main() {

    reader := bufio.NewReader(os.Stdin)
    input, _ := reader.ReadString('\n')

    fmt.Printf("Input Char Is : %v", string([]byte(input)[0]))

    // fmt.Printf("You entered: %v", []byte(input))
}
Run Code Online (Sandbox Code Playgroud)

最后一条注释行只显示当你按下tab第一个元素时是U + 0009('CHARACTER TABULATION').

但是,根据您的需要(检测标签)C getchar()不适合,因为它要求用户按Enter键.你需要的是像@miku提到的ncurses的getch()/ readline/jLine.有了这些,你实际上等待一次击键.

所以你有多种选择:

  1. 使用ncurses/ readline绑定,例如https://code.google.com/p/goncurses/或类似https://github.com/nsf/termbox

  2. 滚动你自己的http://play.golang.org/p/plwBIIYiqG作为起点

  3. 用于os.Exec运行stty或jLine.

裁判:

https://groups.google.com/forum/?fromgroups=#!topic/golang-nuts/zhBE5MH4n-Q

https://groups.google.com/forum/?fromgroups=#!topic/golang-nuts/S9AO_kHktiY

https://groups.google.com/forum/?fromgroups=#!topic/golang-nuts/icMfYF8wJCk


bli*_*nry 14

假设您需要无缓冲输入(无需输入Enter),这可以在UNIX系统上完成工作:

package main

import (
    "fmt"
    "os"
    "os/exec"
)

func main() {
    // 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()
    // restore the echoing state when exiting
    defer exec.Command("stty", "-F", "/dev/tty", "echo").Run()

    var b []byte = make([]byte, 1)
    for {
        os.Stdin.Read(b)
        fmt.Println("I got the byte", b, "("+string(b)+")")
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这使终端在退出后处于非回显状态.添加`推迟exec.Command( "stty的", "F", "的/ dev/TTY", "回波")`可修复. (7认同)
  • 读取一个字节的开销(3个分叉)很糟糕. (6认同)
  • 当你只能使用 [`terminal.MakeRaw`](https://godoc.org/golang.org/x/crypto/ssh/terminal) 时,不要对 stty 执行效率低下、容易出错、不可移植等操作#MakeRaw) 来自`golang.org/x/crypto/ssh/terminal`。 (3认同)
  • defer exec.Command("stty", "-F", "/dev/tty", "echo").Run() 对我不起作用,我必须输入 'reset' :( (2认同)

Dav*_*e C 9

这里的其他答案建议如下:

\n
    \n
  • 使用cgo

    \n\n
  • \n
  • os.Execstty

    \n
      \n
    • 不便携
    • \n
    • 效率低下
    • \n
    • 容易出错
    • \n
    \n
  • \n
  • 使用使用的代码/dev/tty

    \n
      \n
    • 不便携
    • \n
    \n
  • \n
  • 使用 GNU readline 包

    \n
      \n
    • 如果它是 C readline 的包装器或者使用上述技术之一实现,则效率低下
    • \n
    • 否则还好
    • \n
    \n
  • \n
\n

然而,对于简单的情况,只需使用Go 项目子存储库中的包即可轻松完成。

\n

[编辑:以前这个答案使用的golang.org/x/crypto/ssh/terminal包已被弃用;它被移至golang.org/x/term. 代码/链接已适当更新。]

\n

基本上,使用\nterm.MakeRaw和\n term.Restore\n将标准输入设置为原始模式(检查错误,例如\xc2\xa0如果stdin不是终端);那么您可以直接从 读取字节os.Stdin,或者更有可能通过 a 读取字节bufio.Reader(以提高效率)。

\n

例如,这样的事情:

\n
package main\n\nimport (\n    "bufio"\n    "fmt"\n    "log"\n    "os"\n\n    "golang.org/x/term"\n)\n\nfunc main() {\n    // fd 0 is stdin\n    state, err := term.MakeRaw(0)\n    if err != nil {\n        log.Fatalln("setting stdin to raw:", err)\n    }\n    defer func() {\n        if err := term.Restore(0, state); err != nil {\n            log.Println("warning, failed to restore terminal:", err)\n        }\n    }()\n\n    in := bufio.NewReader(os.Stdin)\n    for {\n        r, _, err := in.ReadRune()\n        if err != nil {\n            log.Println("stdin:", err)\n            break\n        }\n        fmt.Printf("read rune %q\\r\\n", r)\n        if r == \'q\' {\n            break\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n


Sla*_*a V 7

谢谢Paul Rademacher - 这是有效的(至少在Mac上):

package main

import (
    "bytes"
    "fmt"

    "github.com/pkg/term"
)

func getch() []byte {
    t, _ := term.Open("/dev/tty")
    term.RawMode(t)
    bytes := make([]byte, 3)
    numRead, err := t.Read(bytes)
    t.Restore()
    t.Close()
    if err != nil {
        return nil
    }
    return bytes[0:numRead]
}

func main() {
    for {
        c := getch()
        switch {
        case bytes.Equal(c, []byte{3}):
            return
        case bytes.Equal(c, []byte{27, 91, 68}): // left
            fmt.Println("LEFT pressed")
        default:
            fmt.Println("Unknown pressed", c)
        }
    }
    return
}
Run Code Online (Sandbox Code Playgroud)

  • 使用“/dev/tty”是不可移植的。*永远不要*忽略错误!不要为每个“字符”将终端切换到/退出原始模式,不要为每个“字符”重新打开“/dev/tty”。这实际上并没有获取字符,而是最多三个字节。 (2认同)