Repository navigation
Expand file tree
/
Copy pathterminal_echo_linux.go
More file actions
64 lines (59 loc) · 1.97 KB
/
Copy pathterminal_echo_linux.go
File metadata and controls
64 lines (59 loc) · 1.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
//go:build linux
package main
import (
"os"
"os/signal"
"syscall"
"golang.org/x/sys/unix"
)
// disableInputProcessing puts the terminal into a mode where keypresses
// don't affect the display. Disables echo, canonical mode, and extended
// input processing (VDISCARD, VREPRINT) while keeping signal generation
// (Ctrl+C) enabled. Returns a function to restore the original state.
func disableInputProcessing() func() {
fd := int(os.Stdin.Fd())
termios, err := unix.IoctlGetTermios(fd, unix.TCGETS)
if err != nil {
return func() {}
}
old := *termios
// ECHO: don't echo keypresses
// ICANON: disable canonical mode (line buffering, control char processing)
// IEXTEN: disable extended input processing (VDISCARD=Ctrl-O, VREPRINT=Ctrl-R)
// Keep ISIG enabled so Ctrl+C still generates SIGINT
termios.Lflag &^= unix.ECHO | unix.ICANON | unix.IEXTEN
if err := unix.IoctlSetTermios(fd, unix.TCSETS, termios); err != nil {
return func() {}
}
return func() {
_ = unix.IoctlSetTermios(fd, unix.TCSETS, &old)
}
}
// handleSuspendResume handles Ctrl-Z (SIGTSTP) by restoring the terminal
// before suspending and re-applying settings on resume (SIGCONT).
// Holds displayMu across the suspend/resume cycle so the main loop
// cannot print while the terminal is being restored.
func handleSuspendResume(cleanup, setup, redraw func()) {
ch := make(chan os.Signal, 1)
signal.Notify(ch, syscall.SIGTSTP, syscall.SIGCONT)
go func() {
for sig := range ch {
switch sig {
case syscall.SIGTSTP:
// Lock display so no output races with suspend
displayMu.Lock()
cleanup()
// Re-send SIGTSTP with default handler to actually suspend.
// The lock stays held; the whole process is stopped by the OS.
signal.Reset(syscall.SIGTSTP)
_ = syscall.Kill(syscall.Getpid(), syscall.SIGTSTP)
case syscall.SIGCONT:
// Process resumed — re-apply terminal settings and redraw
setup()
redraw()
signal.Notify(ch, syscall.SIGTSTP)
displayMu.Unlock()
}
}
}()
}