Blanco Verde
Blanco Verde

Reputation: 61

How to detect key press event

My purpose is to print string sequentially and when the user enter some character, we pause the process and read stdin content. I know it's possible to catch os.Interrupt signal but I don't how to catch event in stdin. I don't want to scan and wait user to enter text. The process is stopped when there is a keypress event.

My question: How detect event on stdin?

Here is current solution with your advice. Go routines not constitue an optimal solution because you can't manage them as threads. I currently continue working on this and keep you udpated.

func main() {
    quit := make(chan bool)

    scanner := bufio.NewScanner(os.Stdin)
    for scanner.Scan() {
        fmt.Println(scanner.Text())
        fmt.Println("-----------------")
        fmt.Println("Go routine running :", runtime.NumGoroutine())
        go func() {
             select {
                case <-quit:
                return
             default:
                fmt.Println("Text received and changed")
                fmt.Println("-----------------")
                for {
                    timer := time.NewTimer(time.Second * 1)
                    <-timer.C
                    fmt.Println(scanner.Text())
                }
            }

            fmt.Println("Routine closed")
        }()

    }
    if scanner.Err() != nil {
        quit <- false
    }
}

Otherwise if I follow your solution @varius :

func main() {
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
    for {
        timer := time.NewTimer(time.Second * 1)
        <-timer.C
        fmt.Println(scanner.Text())
    }
}
if scanner.Err() != nil {
 /*handle error*/
}
}

But I can't change the scan content while program running.

Upvotes: 6

Views: 13176

Answers (1)

KEINOS
KEINOS

Reputation: 1224

Don't know if it will answer your question but for those who want to determine a single keypress, without the enter key, like below:

$ go run . <enter>
Key press => a
Key press => b
Key press => c
Key press => d
Key press => e
... (ctrl+c)
signal: interrupt

The module github.com/mattn/go-tty by mattn might help.

package main

import (
    "fmt"
    "log"

    "github.com/mattn/go-tty"
)

func main() {
    tty, err := tty.Open()
    if err != nil {
        log.Fatal(err)
    }
    defer tty.Close()

    for {
        r, err := tty.ReadRune()
        if err != nil {
            log.Fatal(err)
        }
        fmt.Println("Key press => " + string(r))
    }
}
// go.mod
module sample/tty

go 1.16

require github.com/mattn/go-tty v0.0.3 // indirect
  • Tested on:
    • Intel Core i5, 2.7 GHz Dual-Core
    • macOS Catalina 10.15.7, Debian GNU/Linux 10 (buster), Alpine Linux v3.13

Upvotes: 8

Related Questions