Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open /dev/tty in non-blocking mode #454

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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))
Copy link
Contributor

@hhirtz hhirtz Apr 27, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, 250ms feels like the delay I had.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This causes us to wake up every 250ms. Which is vile on some platforms. I was hoping to avoid period polling.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...Okay? What do you propose instead, considering the issues regarding suspend and resume (#452)?

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)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should not be necessary -- I believe os.Open() will do what you need, and you can call SetNonBlocking() if need be.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I already tried this (on Linux) to no effect.

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 {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a bug in the old code ... thanks for noticing it. :-)

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