Go语言执行showkey二进制文件时无法实时获取标准输出问题
解决思路
核心原因
showkey在输出到非终端(比如管道)时会启用块缓冲,而非终端环境下的行缓冲,导致它不会实时输出内容,直到缓冲区填满或进程结束才一次性输出。
方案一:用伪终端让showkey实时输出
通过创建伪终端(PTY)让showkey误以为自己输出到终端,从而启用行缓冲。可以使用Go的pty库实现:
首先安装依赖:
go get github.com/creack/pty
修改后的代码:
package main import ( "bufio" "fmt" "os/exec" "github.com/creack/pty" ) func main() { fmt.Println("Tracking Input!") cmd := exec.Command("/usr/bin/showkey", "-k") // 创建伪终端并启动命令 ptyFd, err := pty.Start(cmd) if err != nil { panic(err) } defer func() { _ = ptyFd.Close() }() scanner := bufio.NewScanner(ptyFd) for scanner.Scan() { m := scanner.Text() fmt.Println(m) } if err := cmd.Wait(); err != nil { panic(err) } }
方案二:直接读取输入设备(更推荐)
跳过showkey,直接读取Linux输入子系统的设备文件(比如/dev/input/event0,需要根据实际键盘设备调整),这样完全避免外部工具的缓冲问题,还能更精准获取按键的按下/释放事件。
可以用evdev库简化开发:
go get github.com/gvalkov/golang-evdev
示例代码(需root权限运行):
package main import ( "fmt" "log" "github.com/gvalkov/golang-evdev" ) func main() { // 列出所有输入设备,找到对应的键盘 devices, err := evdev.ListInputDevices() if err != nil { log.Fatal(err) } var kbd *evdev.InputDevice for _, dev := range devices { if dev.HasEventType(evdev.EV_KEY) { kbd = dev break } } if kbd == nil { log.Fatal("未找到键盘设备") } defer kbd.Close() fmt.Println("Tracking Input!") for { events, err := kbd.Read() if err != nil { log.Fatal(err) } for _, e := range events { if e.Type == evdev.EV_KEY { // 打印按键码和状态:1=按下,0=释放 fmt.Printf("按键码: %d, 状态: %d\n", e.Code, e.Value) } } } }
额外说明
- 方案一需要依赖第三方pty库,但改动原有代码较小;
- 方案二更原生,不需要依赖
showkey,还能直接获取按键的按下/释放状态,更适合你的GPIO控制场景; - 运行读取
/dev/input的程序需要root权限,可通过sudo ./your-program执行。
内容的提问来源于stack exchange,提问作者Xarus
相关产品推荐
相关产品推荐

