@@ -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,35 @@ 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 10ms is chosen to work well
242
+ -- down to 1200baud while still providing decent response times.
243
+
239
244
getBlockOfChars :: Handle -> IO String
240
245
getBlockOfChars h = do
241
246
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)
247
+ loop c [] False
248
+ where
249
+ loop :: Char -> String -> Bool -> IO String
250
+ loop c' cs' timeout' = do
251
+ let
252
+ timeout = timeout' || (c' == ' \ESC ' )
253
+ cs = (c': cs')
254
+ maybeC <- do
255
+ isReady <- hReady h
256
+ case (timeout, isReady) of
257
+ -- fast new character case
258
+ (_, True ) -> Just <$> hGetChar h
259
+ -- wait up to 10ms for next char
260
+ (True , False ) ->
261
+ runConcurrently $ Concurrently (Just <$> hGetChar h)
262
+ <|> Concurrently (threadDelay 10000 $> Nothing )
263
+ -- no new char and timeout mode has not been triggered
264
+ (False , False ) -> pure Nothing
265
+ case maybeC of
266
+ Just c -> loop c cs timeout
267
+ Nothing -> pure $ reverse cs
251
268
252
269
stdinTTYHandles , ttyHandles :: MaybeT IO Handles
253
270
stdinTTYHandles = do
0 commit comments