diff --git a/src/tui/light.go b/src/tui/light.go
index 574d161eb4b116b2d4f04c88f5016441027ea129..b9e90d689ca199fd3330c1eb73c29ca8c42f6bae 100644
--- a/src/tui/light.go
+++ b/src/tui/light.go
@@ -111,8 +111,10 @@ func (r *LightRenderer) defaultTheme() *ColorTheme {
 	return Default16
 }
 
-func stty(cmd string) string {
-	out, err := util.ExecCommand("stty " + cmd + " < /dev/tty").Output()
+func (r *LightRenderer) stty(cmd string) string {
+	proc := util.ExecCommand("stty " + cmd)
+	proc.Stdin = r.ttyin
+	out, err := proc.Output()
 	if err != nil {
 		// Not sure how to handle this
 		panic("stty " + cmd + ": " + err.Error())
@@ -164,8 +166,8 @@ func (r *LightRenderer) Init() {
 	}
 	r.escDelay = delay
 
-	r.ostty = stty("-g")
-	stty("raw")
+	r.ostty = r.stty("-g")
+	r.stty("raw")
 	r.updateTerminalSize()
 	initTheme(r.theme, r.defaultTheme(), r.forceBlack)
 
@@ -210,7 +212,7 @@ func (r *LightRenderer) origin() {
 }
 
 func (r *LightRenderer) updateTerminalSize() {
-	sizes := strings.Split(stty("size"), " ")
+	sizes := strings.Split(r.stty("size"), " ")
 	if len(sizes) < 2 {
 		r.width = defaultWidth
 		r.height = r.maxHeightFunc(defaultHeight)
@@ -220,14 +222,14 @@ func (r *LightRenderer) updateTerminalSize() {
 	}
 }
 
-func (r *LightRenderer) getch(nonblock bool) int {
+func (r *LightRenderer) getch(nonblock bool) (int, bool) {
 	b := make([]byte, 1)
 	util.SetNonblock(r.ttyin, nonblock)
 	_, err := r.ttyin.Read(b)
 	if err != nil {
-		return -1
+		return 0, false
 	}
-	return int(b[0])
+	return int(b[0]), true
 }
 
 func (r *LightRenderer) getBytes() []byte {
@@ -235,7 +237,11 @@ func (r *LightRenderer) getBytes() []byte {
 }
 
 func (r *LightRenderer) getBytesInternal(buffer []byte) []byte {
-	c := r.getch(false)
+	c, ok := r.getch(false)
+	if !ok {
+		r.Close()
+		errorExit()
+	}
 
 	retries := 0
 	if c == ESC {
@@ -244,8 +250,8 @@ func (r *LightRenderer) getBytesInternal(buffer []byte) []byte {
 	buffer = append(buffer, byte(c))
 
 	for {
-		c = r.getch(true)
-		if c == -1 {
+		c, ok = r.getch(true)
+		if !ok {
 			if retries > 0 {
 				retries--
 				time.Sleep(escPollInterval * time.Millisecond)
@@ -479,13 +485,13 @@ func (r *LightRenderer) mouseSequence(sz *int) Event {
 }
 
 func (r *LightRenderer) Pause() {
-	stty(fmt.Sprintf("%q", r.ostty))
+	r.stty(fmt.Sprintf("%q", r.ostty))
 	r.csi("?1049h")
 	r.flush()
 }
 
 func (r *LightRenderer) Resume() bool {
-	stty("raw")
+	r.stty("raw")
 	r.csi("?1049l")
 	r.flush()
 	// Should redraw
@@ -518,7 +524,7 @@ func (r *LightRenderer) Close() {
 		r.csi("A")
 	}
 	r.flush()
-	stty(fmt.Sprintf("%q", r.ostty))
+	r.stty(fmt.Sprintf("%q", r.ostty))
 }
 
 func (r *LightRenderer) MaxX() int {
diff --git a/src/tui/ncurses.go b/src/tui/ncurses.go
index b160692044e0f7b85546a67ec9b4962db82b265e..f6feefc6f67905405bff9dd516a85bdab99f16aa 100644
--- a/src/tui/ncurses.go
+++ b/src/tui/ncurses.go
@@ -110,12 +110,12 @@ func (r *FullscreenRenderer) Init() {
 	tty := C.c_tty()
 	if tty == nil {
 		fmt.Println("Failed to open /dev/tty")
-		os.Exit(2)
+		errorExit()
 	}
 	_screen = C.c_newterm(tty)
 	if _screen == nil {
 		fmt.Println("Invalid $TERM: " + os.Getenv("TERM"))
-		os.Exit(2)
+		errorExit()
 	}
 	C.set_term(_screen)
 	if r.mouse {
@@ -375,7 +375,9 @@ func (r *FullscreenRenderer) GetChar() Event {
 	c := C.getch()
 	switch c {
 	case C.ERR:
-		return Event{Invalid, 0, nil}
+		// Unexpected error from blocking read
+		r.Close()
+		errorExit()
 	case C.KEY_UP:
 		return Event{Up, 0, nil}
 	case C.KEY_DOWN:
diff --git a/src/tui/tcell.go b/src/tui/tcell.go
index 460bfd5bd01fbe04432a7a10400bb5de3ac5960a..b6f081921b04d36484107cad21e392d4460623a2 100644
--- a/src/tui/tcell.go
+++ b/src/tui/tcell.go
@@ -124,11 +124,11 @@ func (r *FullscreenRenderer) initScreen() {
 	s, e := tcell.NewScreen()
 	if e != nil {
 		fmt.Fprintf(os.Stderr, "%v\n", e)
-		os.Exit(2)
+		errorExit()
 	}
 	if e = s.Init(); e != nil {
 		fmt.Fprintf(os.Stderr, "%v\n", e)
-		os.Exit(2)
+		errorExit()
 	}
 	if r.mouse {
 		s.EnableMouse()
diff --git a/src/tui/tui.go b/src/tui/tui.go
index 11ac1e7d3e9e1a08c7a2046b8fe268bbefa85eac..eb504f8c2d3eabba4593ef3287bcc0bf4f4173da 100644
--- a/src/tui/tui.go
+++ b/src/tui/tui.go
@@ -1,6 +1,7 @@
 package tui
 
 import (
+	"os"
 	"strconv"
 	"time"
 )
@@ -275,6 +276,10 @@ func EmptyTheme() *ColorTheme {
 		Border:       colUndefined}
 }
 
+func errorExit() {
+	os.Exit(2)
+}
+
 func init() {
 	Default16 = &ColorTheme{
 		Fg:           colDefault,