简体   繁体   English

Go 中的无缓冲输入管理器?

[英]Unbuffered input manager in Go?

I am creating a simple console-based game in Go.我正在用 Go 创建一个简单的基于控制台的游戏。 I want some way to accept unbuffered input (as in, you type in one key and it is immediately returned).我想要某种方式来接受无缓冲输入(例如,您输入一个键并立即返回)。 I started out with this code:我从这段代码开始:

func InitInput() {
  exec.Command("stty", "-f", "/dev/tty", "cbreak", "min", "1").Run()
  exec.Command("stty", "-f", "/dev/tty", "-echo").Run()
}
func StopInput() {
  exec.Command("stty", "-f", "/dev/tty", "echo").Run()
}
func GetInput() string {
  var b []byte = make([]byte, 1)
  for {
    os.Stdin.Read(b)
    return string(b)
  }
}

This was amazing, but it only works on a *nix-based os, and requires 3 functions.这太棒了,但它只适用于基于 *nix 的操作系统,并且需要 3 个函数。 Next, someone recommended this code for me:接下来,有人为我推荐了这段代码:

/*
// Works also for 64 bits
#ifdef _WIN32

// Lib for console management in windows
#include "conio.h"

#else

// Libs terminal management in Unix, Linux...
#include <stdio.h>
#include <unistd.h>
#include <termios.h>

// Implement reading a key pressed in terminal
char getch(){
    char ch = 0;
    struct termios old = {0};
    fflush(stdout);
    if( tcgetattr(0, &old) < 0 ) perror("tcsetattr()");
    old.c_lflag &= ~ICANON;
    old.c_lflag &= ~ECHO;
    old.c_cc[VMIN] = 1;
    old.c_cc[VTIME] = 0;
    if( tcsetattr(0, TCSANOW, &old) < 0 ) perror("tcsetattr ICANON");
    if( read(0, &ch,1) < 0 ) perror("read()");
    old.c_lflag |= ICANON;
    old.c_lflag |= ECHO;
    if(tcsetattr(0, TCSADRAIN, &old) < 0) perror("tcsetattr ~ICANON");
    return ch;
}
#endif
*/
import "C"

And then you only need 1 function:然后你只需要 1 个函数:

func GetInput() string {
    return string(byte(C.getch()))
}

This works perfectly, except that because of the way that cgo works, it is very slow which is not ideal for a game.这很完美,除了因为 cgo 的工作方式,它非常慢,这对于游戏来说并不理想。 Also, the original code for testing for a newline, if extras.GetInput() == "\\n" {} doesn't work anymore.此外,用于测试换行符的原始代码, if extras.GetInput() == "\\n" {}不再起作用。 Is there a way to get a single-character unbuffered input manager to work in Go without using a big, thick, external library?有没有办法让单字符无缓冲输入管理器在 Go 中工作而不使用大而厚的外部库?

I wrote some console handling from scratch sources, in C, Perl and PHP and was about to do one in Python.我从头开始用 C、Perl 和 PHP 编写了一些控制台处理,并准备用 Python 编写一个。

Then I discovered Go and I'm asking the same questions.然后我发现了 Go,我也在问同样的问题。 I agree with the author of the thread, we have to do the minimum.我同意该线程的作者,我们必须做到最低限度。 I haven't tried your code yet (The one which includes termio code).我还没有尝试过你的代码(包括 termio 代码的那个)。

There are many reasons why it may be slow:速度慢的原因有很多:

1 / You make a C call every time you hit a key: You may change this topology: first, you place the console in non-buffering mode and return the saved parameters to Golang. 1 / 每次击键时都会进行 C 调用:您可以更改此拓扑:首先,您将控制台置于非缓冲模式并将保存的参数返回给 Golang。

2/ You hit keys according to this code: 2/您根据此代码击键:

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)
    LOOP:
    for {
        os.Stdin.Read(b)
        var n uint8 = b[0]
        switch n {
        case 27, 113, 81 : fmt.Println("ESC, or 'q' or 'Q' was hitted!")
            break LOOP
        default:
            fmt.Printf("You typed : %d\n", n)
        }
    }
}

Then at last you restore console settings.然后最后你恢复控制台设置。

In this code : I use stty but I suppose I could replace it with 2 C routine calls.在这段代码中:我使用 stty 但我想我可以用 2 个 C 例程调用替换它。 Well, I need to try to implement this...好吧,我需要尝试实现这一点......

Also, a question: should we return a byte, a char a widechar?还有一个问题:我们应该返回一个字节,一个字符还是一个宽字符? This can be more complicated for sure.这肯定会更复杂。

Notice that you have also extended keys on keyboard and must read forward one or more bytes to get the whole sequence, but this is not a problem.请注意,您还扩展了键盘上的键,必须向前读取一个或多个字节才能获得整个序列,但这不是问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM