| package termutil |
| |
| import ( |
| "errors" |
| "os" |
| "os/signal" |
| "sync" |
| ) |
| |
| var echoLocked bool |
| var echoLockMutex sync.Mutex |
| var errLocked = errors.New("terminal locked") |
| var autoTerminate = true |
| |
| // AutoTerminate enables or disables automatic terminate signal catching. |
| // It's needed to restore the terminal state after the pool was used. |
| // By default, it's enabled. |
| func AutoTerminate(enable bool) { |
| echoLockMutex.Lock() |
| defer echoLockMutex.Unlock() |
| autoTerminate = enable |
| } |
| |
| // RawModeOn switches terminal to raw mode |
| func RawModeOn() (quit chan struct{}, err error) { |
| echoLockMutex.Lock() |
| defer echoLockMutex.Unlock() |
| if echoLocked { |
| err = errLocked |
| return |
| } |
| if err = lockEcho(); err != nil { |
| return |
| } |
| echoLocked = true |
| quit = make(chan struct{}, 1) |
| go catchTerminate(quit) |
| return |
| } |
| |
| // RawModeOff restore previous terminal state |
| func RawModeOff() (err error) { |
| echoLockMutex.Lock() |
| defer echoLockMutex.Unlock() |
| if !echoLocked { |
| return |
| } |
| if err = unlockEcho(); err != nil { |
| return |
| } |
| echoLocked = false |
| return |
| } |
| |
| // listen exit signals and restore terminal state |
| func catchTerminate(quit chan struct{}) { |
| sig := make(chan os.Signal, 1) |
| if autoTerminate { |
| signal.Notify(sig, unlockSignals...) |
| defer signal.Stop(sig) |
| } |
| select { |
| case <-quit: |
| RawModeOff() |
| case <-sig: |
| RawModeOff() |
| } |
| } |