@@ -24,6 +24,9 @@ import Control.Monad
24
24
import Control.Monad.Catch (MonadMask , handle , finally )
25
25
import Control.Concurrent.STM
26
26
import Control.Concurrent hiding (throwTo )
27
+ import Control.Concurrent.Async (runConcurrently , Concurrently (.. ))
28
+ import Control.Applicative ((<|>) )
29
+ import Data.Functor (($>) )
27
30
import Data.Maybe (catMaybes )
28
31
import System.Posix.Signals.Exts
29
32
import System.Posix.Types (Fd (.. ))
@@ -243,21 +246,33 @@ getEvent h baseMap = keyEventLoop $ do
243
246
return [KeyInput $ lexKeys baseMap cs]
244
247
245
248
-- Read at least one character of input, and more if immediately
246
- -- available. In particular the characters making up a control sequence
247
- -- will all be available at once, so they can be processed together
248
- -- (with Posix.lexKeys).
249
+ -- available. If an ESC character is seen, timeout mode is
250
+ -- activated to prevent control sequences from being broken across
251
+ -- getBlockofChars calls. A timeout of 20ms was shown to work
252
+ -- well with a 9600bps serial port.
249
253
getBlockOfChars :: Handle -> IO String
250
254
getBlockOfChars h = do
251
255
c <- hGetChar h
252
- loop [c]
253
- where
254
- loop cs = do
255
- isReady <- hReady h
256
- if not isReady
257
- then return $ reverse cs
258
- else do
259
- c <- hGetChar h
260
- loop (c: cs)
256
+ loop c [] False
257
+ where
258
+ loop :: Char -> String -> Bool -> IO String
259
+ loop c' cs' timeout' = do
260
+ let
261
+ timeout = timeout' || (c' == ' \ESC ' )
262
+ cs = (c': cs')
263
+ maybeC <- do
264
+ isReady <- hReady h
265
+ case (timeout, isReady) of
266
+ (_, True ) -> do -- fast new character case
267
+ Just <$> hGetChar h
268
+ (True , False ) -> -- wait up to 20ms for next char
269
+ runConcurrently $ Concurrently (Just <$> hGetChar h)
270
+ <|> Concurrently (threadDelay 20000 $> Nothing )
271
+ (False , False ) -> -- no new char and timeout mode has not been triggered
272
+ pure Nothing
273
+ case maybeC of
274
+ Just c -> loop c cs timeout
275
+ Nothing -> pure $ reverse cs
261
276
262
277
stdinTTYHandles , ttyHandles :: MaybeT IO Handles
263
278
stdinTTYHandles = do
0 commit comments