This article was originally published on bmf-tech.com.
Introduction
Recently, I tried creating a terminal-based typing game using Go's x/term package. In this article, I will share the features of the x/term package and insights I gained during TUI application development.
As a practical TUI application using x/term, I am developing a git client tool called ggc, so please give it a star if you like it.
What is the x/term Package
x/term is one of Go's experimental packages that provides low-level functionalities for terminal operations. It was previously golang.org/x/crypto/ssh/terminal, but now it is an independent package as golang.org/x/term.
Main Features
- Getting terminal size
width, height, err := term.GetSize(int(os.Stdout.Fd()))
- Capturing low-level key inputs
oldState, err := term.MakeRaw(int(os.Stdin.Fd()))
if err != nil {
log.Fatal(err)
}
defer term.Restore(int(os.Stdin.Fd()), oldState)
- Controlling echo
- Controlling terminal modes
Using these features, you can create interactive TUI applications with cursor position control and immediate key input detection.
Implementing the Typing Game
1. Basic Design
The core features of the typing game are as follows:
- Displaying random English sentences
- Immediate key input detection
- Accuracy measurement
- Counting the number of mistakes
2. Managing Terminal State
The most important aspect when using x/term is managing the terminal state:
// Set terminal to raw mode
oldState, err := term.MakeRaw(int(os.Stdin.Fd()))
if err != nil {
log.Fatal(err)
}
// Restore original state upon program exit
defer term.Restore(int(os.Stdin.Fd()), oldState)
// Signal handling
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)
go func() {
<-sigCh
term.Restore(int(os.Stdin.Fd()), oldState)
os.Exit(0)
}()
3. Controlling Screen Display
Using ANSI escape sequences to control screen display:
// Hide cursor
fmt.Print("\033[?25l")
defer fmt.Print("\033[?25h") // Restore display on exit
// Clear screen
fmt.Print("\033[2J")
// Move cursor position (to x=10, y=5)
fmt.Printf("\033[%d;%dH", 5, 10)
4. Performance Optimization
Here are some points to ensure display stability:
- Controlling buffering
- Optimizing screen updates
- Asynchronous processing using goroutines
Implementation Points
1. Error Handling and Recovery
// Recovery process during panic
defer func() {
if r := recover(); r != nil {
term.Restore(int(os.Stdin.Fd()), oldState)
fmt.Printf("Recovered from panic: %v\n", r)
}
}()
2. Cross-Platform Support
var clear string
if runtime.GOOS == "windows" {
clear = "cls"
} else {
clear = "clear"
}
cmd := exec.Command(clear)
cmd.Stdout = os.Stdout
cmd.Run()
Conclusion
Developing TUI applications with x/term requires low-level control, but it offers a high degree of freedom. The typing game implementation example I created demonstrates basic patterns, but you can apply these to create various TUI applications.
Top comments (0)