I am creating a simple console-based game in 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. 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:
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. Also, the original code for testing for a newline, if extras.GetInput() == "\n" {}
doesn't work anymore. Is there a way to get a single-character unbuffered input manager to work in Go without using a big, thick, external library?