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