diff --git a/Graphics/Vty/LLInput.hs b/Graphics/Vty/LLInput.hs
--- a/Graphics/Vty/LLInput.hs
+++ b/Graphics/Vty/LLInput.hs
@@ -1,4 +1,5 @@
 {-# OPTIONS_GHC -Wall #-}
+{-# LANGUAGE ForeignFunctionInterface #-}
 module Graphics.Vty.LLInput
     ( Key(..), Modifier(..), Button(..), Event(..), initTermInput ) where
 
@@ -12,6 +13,7 @@
 import Codec.Binary.UTF8.Generic (decode)
 
 import Control.Concurrent
+import Control.Exception
 import System.Posix.Signals.Exts
 import System.Posix.Signals
 import System.Posix.Terminal
@@ -46,36 +48,40 @@
 initTermInput :: IO (IO Event, IO ())
 initTermInput = do
   threadName "main"
-  kchan <- newEmptyMVar
+  eventChannel <- newChan
+  inputChannel <- newChan
   oattr <- getTerminalAttributes stdInput
   let nattr = foldl withoutMode oattr [StartStopOutput, KeyboardInterrupts,
                                        EnableEcho, ProcessInput]
   setTerminalAttributes stdInput nattr Immediately
+  set_term_timing
   terminal <- setupTermFromEnv 
 
-  let iothread :: MVar Event -> IO ()
-      iothread chn = threadName "kbd" >> loop [] where
-          loop kb = case (classify kb) of
-                      Prefix       -> do ch <- getInput
-                                         loop (kb ++ [ch])
-                      Invalid      -> loop ""
-                      MisPfx k m s -> putMVar chn (EvKey k m) >> loop s
-                      Valid k m    -> putMVar chn (EvKey k m) >> loop ""
-          getInput = do 
-              catch 
-                  (do
-                      setFdOption stdInput NonBlockingRead True
-                      (bytes, bytes_read) <- fdRead stdInput 1 
-                      if (bytes_read > 0)
-                          then return (head bytes)
-                          else do
-                              threadDelay 50000
-                              return '\xFFFE'
-                  )
-                  (\_ -> do
-                      threadDelay 50000
-                      return '\xFFFE')
-      
+  let inputToEventThread :: IO ()
+      inputToEventThread = threadName "input_to_event" >> loop [] 
+          where loop kb = case (classify kb) of
+                              Prefix       -> do c <- readChan inputChannel
+                                                 loop (kb ++ [c])
+                              Invalid      -> loop ""
+                              MisPfx k m s -> writeChan eventChannel (EvKey k m) >> loop s
+                              Valid k m    -> writeChan eventChannel (EvKey k m) >> loop ""
+      inputThread :: IO ()
+      inputThread = threadName "input" >> loop
+          where 
+              loop = do
+                  setFdOption stdInput NonBlockingRead False
+                  threadWaitRead stdInput
+                  setFdOption stdInput NonBlockingRead True
+                  try readAll 
+                  writeChan inputChannel '\xFFFE'
+                  loop
+              readAll = do
+                  (bytes, bytes_read) <- fdRead stdInput 1
+                  if bytes_read > 0
+                      then writeChan inputChannel (head bytes)
+                      else return ()
+                  readAll
+    
       compile :: [[([Char],(Key,[Modifier]))]] -> [Char] -> KClass
       compile lst = cl' where
           lst' = concat lst
@@ -162,18 +168,20 @@
              ("\ESC\^J",(KEnter,[MMeta])), ("\^J",(KEnter,[])) ] 
          ]
    
-  iothr <- forkIO $ iothread kchan
+  eventThreadId <- forkIO $ inputToEventThread
+  inputThreadId <- forkIO $ inputThread
   let pokeIO = (Catch $ do threadName "winch|cont"
                            let e = error "(getsize in input layer)"
                            setTerminalAttributes stdInput nattr Immediately
-                           putMVar kchan (EvResize e e))
+                           writeChan eventChannel (EvResize e e))
   installHandler windowChange pokeIO Nothing
   installHandler continueProcess pokeIO Nothing
-  let uninit = do killThread iothr
+  let uninit = do killThread eventThreadId
+                  killThread inputThreadId
                   installHandler windowChange Ignore Nothing
                   installHandler continueProcess Ignore Nothing
                   setTerminalAttributes stdInput oattr Immediately
-  return (takeMVar kchan, uninit)
+  return (readChan eventChannel, uninit)
 
 first :: (a -> b) -> (a,c) -> (b,c)
 first f (x,y) = (f x, y)
@@ -184,4 +192,6 @@
     | c < 0xE0 = 2
     | c < 0xF0 = 3
     | otherwise = 4
+
+foreign import ccall "set_term_timing" set_term_timing :: IO ()
 
diff --git a/cbits/set_term_timing.c b/cbits/set_term_timing.c
new file mode 100644
--- /dev/null
+++ b/cbits/set_term_timing.c
@@ -0,0 +1,14 @@
+#include <termios.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+void set_term_timing(void)
+{
+    struct termios trm;
+    tcgetattr(STDIN_FILENO, &trm);
+    trm.c_cc[VMIN] = 0;
+    trm.c_cc[VTIME] = 0;
+    tcsetattr(STDIN_FILENO, TCSANOW, &trm); 
+}
+
diff --git a/vty.cabal b/vty.cabal
--- a/vty.cabal
+++ b/vty.cabal
@@ -1,5 +1,5 @@
 Name:                vty
-Version:             3.1.0
+Version:             3.1.2
 License:             BSD3
 License-file:        LICENSE
 Author:              Stefan O'Rear
@@ -30,10 +30,11 @@
 
 Exposed-Modules:     Graphics.Vty
 C-Sources:           cbits/gwinsz.c
+                     cbits/set_term_timing.c
 Include-Dirs:        cbits
 Install-Includes:    gwinsz.h
 Other-Modules:       Graphics.Vty.Types, Graphics.Vty.Cursor, Graphics.Vty.LLInput
 
-ghc-options:         -funbox-strict-fields -Wall
-ghc-prof-options:    -funbox-strict-fields -auto-all -Wall
+ghc-options:         -funbox-strict-fields -Wall -threaded
+ghc-prof-options:    -funbox-strict-fields -auto-all -Wall -threaded
 
