Skip to content

Commit

Permalink
Open /dev/tty in non-blocking mode
Browse files Browse the repository at this point in the history
Resolves gdamore#452.
  • Loading branch information
tslocum committed Apr 25, 2021
1 parent 299cb41 commit 4f0563a
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 25 deletions.
7 changes: 3 additions & 4 deletions nonblock_bsd.go
Expand Up @@ -30,8 +30,7 @@ import (
// that loop. Normally we use VMIN 1 and VTIME 0, which ensures we pick up bytes when
// they come but don't spin burning cycles.
func (t *tScreen) nonBlocking(on bool) {
fd := int(os.Stdin.Fd())
tio, err := unix.IoctlGetTermios(fd, unix.TIOCGETA)
tio, err := unix.IoctlGetTermios(t.inFd, unix.TIOCGETA)
if err != nil {
return
}
Expand All @@ -44,7 +43,7 @@ func (t *tScreen) nonBlocking(on bool) {
tio.Cc[unix.VMIN] = 1
}

_ = syscall.SetNonblock(fd, on)
_ = syscall.SetNonblock(t.inFd, on)
// We want to set this *right now*.
_ = unix.IoctlSetTermios(fd, unix.TIOCSETA, tio)
_ = unix.IoctlSetTermios(t.inFd, unix.TIOCSETA, tio)
}
8 changes: 3 additions & 5 deletions nonblock_unix.go
Expand Up @@ -17,7 +17,6 @@
package tcell

import (
"os"
"syscall"

"golang.org/x/sys/unix"
Expand All @@ -32,8 +31,7 @@ import (
// that loop. Normally we use VMIN 1 and VTIME 0, which ensures we pick up bytes when
// they come but don't spin burning cycles.
func (t *tScreen) nonBlocking(on bool) {
fd := int(os.Stdin.Fd())
tio, err := unix.IoctlGetTermios(fd, unix.TCGETS)
tio, err := unix.IoctlGetTermios(t.inFd, unix.TCGETS)
if err != nil {
return
}
Expand All @@ -46,7 +44,7 @@ func (t *tScreen) nonBlocking(on bool) {
tio.Cc[unix.VMIN] = 1
}

_ = syscall.SetNonblock(fd, on)
_ = syscall.SetNonblock(t.inFd, on)
// We want to set this *right now*.
_ = unix.IoctlSetTermios(fd, unix.TCSETS, tio)
_ = unix.IoctlSetTermios(t.inFd, unix.TCSETS, tio)
}
24 changes: 17 additions & 7 deletions tscreen.go
Expand Up @@ -16,6 +16,7 @@ package tcell

import (
"bytes"
"errors"
"io"
"os"
"strconv"
Expand Down Expand Up @@ -82,6 +83,7 @@ type tScreen struct {
fini bool
cells CellBuffer
in *os.File
inFd int
out *os.File
buffering bool // true if we are collecting writes to buf instead of sending directly to out
buf bytes.Buffer
Expand Down Expand Up @@ -1484,20 +1486,29 @@ func (t *tScreen) mainLoop(stopQ chan struct{}) {
}

func (t *tScreen) inputLoop(stopQ chan struct{}) {

defer t.wg.Done()
var (
n int
err error
)
for {
select {
case <-stopQ:
return
default:
}

err = t.in.SetReadDeadline(time.Now().Add(250 * time.Millisecond))
if err != nil {
panic(err)
}

chunk := make([]byte, 128)
n, e := t.in.Read(chunk)
switch e {
case nil:
default:
_ = t.PostEvent(NewEventError(e))
n, err = t.in.Read(chunk)
if errors.Is(err, os.ErrDeadlineExceeded) {
continue
} else if err != nil {
_ = t.PostEvent(NewEventError(err))
return
}
if n > 0 {
Expand Down Expand Up @@ -1575,7 +1586,6 @@ func (t *tScreen) HasKey(k Key) bool {

func (t *tScreen) Resize(int, int, int, int) {}


func (t *tScreen) Suspend() error {
t.disengage()
return nil
Expand Down
22 changes: 13 additions & 9 deletions tscreen_unix.go
Expand Up @@ -34,10 +34,10 @@ func (t *tScreen) engage() error {
if t.stopQ != nil {
return errors.New("already engaged")
}
if _, err := term.MakeRaw(int(t.in.Fd())); err != nil {
if _, err := term.MakeRaw(t.inFd); err != nil {
return err
}
if w, h, err := term.GetSize(int(t.in.Fd())); err == nil && w != 0 && h != 0 {
if w, h, err := term.GetSize(t.inFd); err == nil && w != 0 && h != 0 {
t.cells.Resize(w, h)
}
stopQ := make(chan struct{})
Expand Down Expand Up @@ -93,7 +93,7 @@ func (t *tScreen) disengage() {
t.enablePasting(false)

// restore the termios that we were started with
_ = term.Restore(int(t.in.Fd()), t.saved)
_ = term.Restore(t.inFd, t.saved)

}

Expand All @@ -102,15 +102,19 @@ func (t *tScreen) disengage() {
// so that it can be restored when the application terminates.
func (t *tScreen) initialize() error {
var err error
t.out = os.Stdout
if t.in, err = os.Open("/dev/tty"); err != nil {
t.inFd, err = syscall.Open("/dev/tty", syscall.O_RDONLY|syscall.O_NONBLOCK, 0644)
if err != nil {
return err
}
t.in = os.NewFile(uintptr(t.inFd), "/dev/tty")

t.out = os.Stdout

t.saved, err = term.GetState(int(t.in.Fd()))
if err == nil {
return nil
t.saved, err = term.GetState(t.inFd)
if err != nil {
return err
}

return nil
}

Expand All @@ -123,7 +127,7 @@ func (t *tScreen) finalize() {

// getWinSize is called to obtain the terminal dimensions.
func (t *tScreen) getWinSize() (int, int, error) {
return term.GetSize(int(t.in.Fd()))
return term.GetSize(t.inFd)
}

// Beep emits a beep to the terminal.
Expand Down

0 comments on commit 4f0563a

Please sign in to comment.