36

I want my app to show:

press any key to exit ...

And to exit when I press any key.

How can I achieve this?

Note: I have googled but all of what I've found needed to press Enter at the end. I want something like Console.ReadKey() in C#.

I am running MS Windows.

nik7
  • 806
  • 3
  • 12
  • 20
Kaveh Shahbazian
  • 13,088
  • 13
  • 80
  • 139
  • 3
    possible duplicate of [Golang function similar to getchar](http://stackoverflow.com/questions/14094190/golang-function-similar-to-getchar) – zzzz Mar 01 '13 at 13:46
  • 3
    @jnml No; this is not a duplicate. I've seen that question before and using the code provided in answer you still need to press enter at stdin. – Kaveh Shahbazian Mar 01 '13 at 13:54
  • The duplicity is solely about the question, not about any answer to it. – zzzz Mar 01 '13 at 14:02

7 Answers7

35

This is a minimal working example for those running a UNIX system:

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()

    var b []byte = make([]byte, 1)
    for {
        os.Stdin.Read(b)
        fmt.Println("I got the byte", b, "("+string(b)+")")
    }
}
blinry
  • 4,746
  • 4
  • 26
  • 31
14

termbox-go is a light-weight Go-native package which offers some rudimentary terminal control. Including the ability to get input in raw mode (read one character at a time without the default line-buffered behaviour).

It also has fairly ok compatibility across different systems.

And keyboard extends termbox-go to give some additional keyboard functionality like multi-key shortcuts and sequences.

jimt
  • 25,324
  • 8
  • 70
  • 60
10

go-termbox is very heavyweight. It wants to take over the entire terminal window. For example, it clears the screen on startup, which may not be what you want.

I put this together on OSX. Just a tiny getchar():

https://github.com/paulrademacher/climenu/blob/master/getchar.go

Paul Rademacher
  • 3,051
  • 1
  • 17
  • 9
10

You could use this library (mine): https://github.com/eiannone/keyboard

This is an example for getting a single keystroke:

char, _, err := keyboard.GetSingleKey()
if (err != nil) {
    panic(err)
}
fmt.Printf("You pressed: %q\r\n", char)
Emanuele
  • 617
  • 5
  • 16
  • great library. At least for windows, this solution is much better and to the point than others. – Ontropy Apr 18 '23 at 13:37
10

The package "golang.org/x/term" allows you to switch the stdin into raw mode to read each byte at a time.

package main

import (
    "fmt"
    "os"

    "golang.org/x/term"
)

func main() {
    // switch stdin into 'raw' mode
    oldState, err := term.MakeRaw(int(os.Stdin.Fd()))
    if err != nil {
        fmt.Println(err)
        return
    }
    defer term.Restore(int(os.Stdin.Fd()), oldState)

    b := make([]byte, 1)
    _, err = os.Stdin.Read(b)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Printf("the char %q was hit", string(b[0]))
}
Eurospoofer
  • 614
  • 10
  • 7
2

You can read a single key-press from a terminal in raw mode. Here is a package that should provide raw terminal mode to your program. Catch: it's Linux only.

zzzz
  • 87,403
  • 16
  • 175
  • 139
0

Try this - http://play.golang.org/p/kg-QirlucY.

Just read from the os.Stdin at the end of the func main

Dave C
  • 7,729
  • 4
  • 49
  • 65
alex
  • 2,178
  • 16
  • 14
  • 1
    This code demonstrates how to use `SetConsoleMode`. If want "Press Enter to continue", then `os.Stdin.Read([]byte{0})` is enough. – kbridge4096 Oct 04 '18 at 12:23