diff --git a/platform/posix/src/System/Terminal/Platform.hsc b/platform/posix/src/System/Terminal/Platform.hsc index 9e36766..49004de 100644 --- a/platform/posix/src/System/Terminal/Platform.hsc +++ b/platform/posix/src/System/Terminal/Platform.hsc @@ -10,6 +10,7 @@ import Control.Concurrent import qualified Control.Concurrent.Async as A import Control.Concurrent.STM.TVar import Control.Concurrent.STM.TMVar +import Control.Concurrent.STM.TQueue import qualified Control.Exception as E import Control.Monad (forM_, void, when) import Control.Monad.Catch hiding (handle) @@ -61,7 +62,7 @@ withTerminal action = do mainThread <- liftIO myThreadId interrupt <- liftIO (newTVarIO False) windowChanged <- liftIO (newTVarIO False) - events <- liftIO newEmptyTMVarIO + events <- liftIO newTQueueIO cursorPosition <- liftIO newEmptyTMVarIO withTermiosSettings $ \termios-> withInterruptHandler (handleInterrupt mainThread interrupt) $ @@ -73,7 +74,7 @@ withTerminal action = do changed <- swapTVar windowChanged False if changed then pure (WindowEvent WindowSizeChanged) - else takeTMVar events + else readTQueue events , localInterrupt = swapTVar interrupt False >>= check >> pure Interrupt , localGetCursorPosition = do -- Empty the result variable. @@ -147,7 +148,7 @@ withInterruptHandler handler = bracket installHandler restoreHandler . const pure () withInputProcessing :: (MonadIO m, MonadMask m) => - Termios -> TMVar Position -> TMVar Event -> m a -> m a + Termios -> TMVar Position -> TQueue Event -> m a -> m a withInputProcessing termios cursorPosition events = bracket (liftIO $ A.async $ run decoder) (liftIO . A.cancel) . const where @@ -188,8 +189,8 @@ withInputProcessing termios cursorPosition events = -- The second one is not strictly required but a fail safe in order -- to never block in case the terminal sends a report without request. putTMVar cursorPosition pos <|> void (swapTMVar cursorPosition pos) - putTMVar events ev - ev -> atomically (putTMVar events ev) + writeTQueue events ev + ev -> atomically (writeTQueue events ev) -- The timeout duration has been choosen as a tradeoff between correctness -- (actual transmission or scheduling delays shall not be misinterpreted) and diff --git a/platform/windows/src/System/Terminal/Platform.hsc b/platform/windows/src/System/Terminal/Platform.hsc index 94a8750..773f9be 100644 --- a/platform/windows/src/System/Terminal/Platform.hsc +++ b/platform/windows/src/System/Terminal/Platform.hsc @@ -5,7 +5,7 @@ module System.Terminal.Platform import Control.Applicative ((<|>)) import Control.Concurrent (ThreadId, myThreadId, forkIO) -import Control.Concurrent.STM.TMVar +import Control.Concurrent.STM.TQueue import Control.Concurrent.STM.TVar (TVar, newTVarIO, readTVar, readTVarIO, swapTVar, writeTVar) import qualified Control.Exception as E import Control.Monad (forM_, when, unless) @@ -53,7 +53,7 @@ withTerminal action = do mainThread <- liftIO myThreadId interrupt <- liftIO (newTVarIO False) windowChanged <- liftIO (newTVarIO False) - events <- liftIO newEmptyTMVarIO + events <- liftIO newTQueueIO withConsoleModes $ withInputProcessing mainThread interrupt windowChanged events $ action $ LocalTerminal { localType = "xterm" -- They claim it behaves like xterm although this is certainly a bit ambituous. @@ -63,7 +63,7 @@ withTerminal action = do changed <- swapTVar windowChanged False if changed then pure (WindowEvent WindowSizeChanged) - else takeTMVar events + else readTQueue events } decoder0 :: Decoder @@ -143,7 +143,7 @@ putText text = do written <- peek ptrWritten when (written < len) (put (BS.drop (fromIntegral len * 2) bs) ptrWritten) -withInputProcessing :: (MonadIO m, MonadMask m) => ThreadId -> TVar Bool -> TVar Bool -> TMVar Event -> m a -> m a +withInputProcessing :: (MonadIO m, MonadMask m) => ThreadId -> TVar Bool -> TVar Bool -> TQueue Event -> m a -> m a withInputProcessing mainThread interrupt windowChanged events ma = do terminate <- liftIO (newTVarIO False) terminated <- liftIO (newTVarIO False) @@ -166,8 +166,7 @@ withInputProcessing mainThread interrupt windowChanged events ma = do shallTerminate <- readTVarIO terminate unless shallTerminate (waitForEvents decoder) pushEvent :: Event -> IO () - pushEvent ev = atomically do -- unblock when thread shall terminate - putTMVar events ev <|> (readTVar terminate >>= check) + pushEvent ev = atomically $ writeTQueue events ev waitForEvents :: Decoder -> IO () waitForEvents decoder = tryGetConsoleInputEvent >>= \case -- `tryGetConsoleInputEvent` is a blocking system call. It cannot be interrupted, but