Golang中如何检测键盘按键按下
Golang中如何检测键盘按键按下 我正在尝试在连续循环运行时检测按键何时被按下。这个过程必须是非阻塞的,但到目前为止,我已经尝试了大约4个不同的库或建议,它们都是阻塞的!考虑到Go语言处理一些相对复杂的事情是多么容易,检测我按下Q键退出这样一个看似简单的任务竟然如此难以实现,这似乎令人难以置信。
PS. 回想80年代,我的Commodore VIC-20只用两行代码就能实现这个功能: get K$ if K$ = “Q” then end
1 回复
更多关于Golang中如何检测键盘按键按下的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Go中实现非阻塞键盘输入检测确实需要一些技巧,因为标准库没有直接提供这个功能。以下是几种有效的解决方案:
方案1:使用termbox-go库(推荐)
package main
import (
"fmt"
"github.com/nsf/termbox-go"
)
func main() {
err := termbox.Init()
if err != nil {
panic(err)
}
defer termbox.Close()
fmt.Println("按 Q 键退出...")
eventQueue := make(chan termbox.Event)
go func() {
for {
eventQueue <- termbox.PollEvent()
}
}()
for {
select {
case ev := <-eventQueue:
if ev.Type == termbox.EventKey {
if ev.Ch == 'q' || ev.Ch == 'Q' || ev.Key == termbox.KeyCtrlC {
fmt.Println("\n检测到退出按键")
return
}
fmt.Printf("按键: %c (Key: %v)\n", ev.Ch, ev.Key)
}
default:
// 非阻塞 - 这里可以执行其他任务
// fmt.Println("执行其他任务...")
// time.Sleep(100 * time.Millisecond)
}
}
}
方案2:使用golang.org/x/term(标准库扩展)
package main
import (
"fmt"
"os"
"syscall"
"time"
"golang.org/x/term"
)
func main() {
fmt.Println("按 Q 键退出...")
// 将终端设置为原始模式
oldState, err := term.MakeRaw(int(os.Stdin.Fd()))
if err != nil {
panic(err)
}
defer term.Restore(int(os.Stdin.Fd()), oldState)
for {
// 非阻塞读取
var buf [1]byte
n, err := syscall.Read(int(os.Stdin.Fd()), buf[:])
if err == nil && n > 0 {
key := buf[0]
if key == 'q' || key == 'Q' || key == 3 { // 3 = Ctrl+C
fmt.Println("\n检测到退出按键")
return
}
fmt.Printf("按键: %c\n", key)
}
// 执行其他任务
// fmt.Println("执行其他任务...")
time.Sleep(50 * time.Millisecond)
}
}
方案3:使用tcell库(功能更全面)
package main
import (
"fmt"
"github.com/gdamore/tcell/v2"
)
func main() {
screen, err := tcell.NewScreen()
if err != nil {
panic(err)
}
if err := screen.Init(); err != nil {
panic(err)
}
defer screen.Fini()
fmt.Println("按 Q 键退出...")
for {
ev := screen.PollEvent()
switch ev := ev.(type) {
case *tcell.EventKey:
if ev.Key() == tcell.KeyRune {
if ev.Rune() == 'q' || ev.Rune() == 'Q' {
fmt.Println("\n检测到退出按键")
return
}
fmt.Printf("按键: %c\n", ev.Rune())
} else if ev.Key() == tcell.KeyCtrlC {
fmt.Println("\n检测到Ctrl+C")
return
}
case *tcell.EventResize:
screen.Sync()
}
}
}
方案4:使用bufio.Scanner(简单但有限)
package main
import (
"bufio"
"fmt"
"os"
"time"
)
func main() {
fmt.Println("按 Q 键退出...")
scanner := bufio.NewScanner(os.Stdin)
// 使用goroutine非阻塞读取
inputChan := make(chan string)
go func() {
for scanner.Scan() {
inputChan <- scanner.Text()
}
}()
for {
select {
case input := <-inputChan:
if input == "q" || input == "Q" {
fmt.Println("检测到退出按键")
return
}
fmt.Printf("输入: %s\n", input)
default:
// 非阻塞执行其他任务
// fmt.Println("执行其他任务...")
time.Sleep(100 * time.Millisecond)
}
}
}
安装依赖
# termbox-go
go get github.com/nsf/termbox-go
# tcell
go get github.com/gdamore/tcell/v2
# x/term
go get golang.org/x/term
termbox-go 通常是最佳选择,因为它轻量且专门为终端UI设计。这些方案都提供了非阻塞的键盘输入检测,允许你在循环中同时处理其他任务,类似于你提到的BASIC代码的简单性。

