module Evdev.Stream ( allDevices, allEvents, makeDevices, readEvents, readEventsMany, ) where import Control.Exception import Control.Monad import System.IO.Error import RawFilePath.Directory (doesFileExist,listDirectory) import System.Posix.ByteString (RawFilePath) import System.Posix.FilePath (()) import Streamly import qualified Streamly.Prelude as S import Evdev -- | Read all events from a device. readEvents :: Device -> SerialT IO Event readEvents dev = S.repeatM $ nextEvent dev defaultReadFlags -- | Concurrently read events from multiple devices. readEventsMany :: IsStream t => AsyncT IO Device -> t IO (Device, Event) readEventsMany ds = asyncly $ do d <- ds S.map (d,) $ serially $ readEvents d -- | Create devices for all paths in the stream. -- | Will throw an exception if a path doesn't correspond to a valid input device. makeDevices :: IsStream t => t IO RawFilePath -> t IO Device makeDevices = S.mapM newDevice -- | All events on all valid devices (in /dev/input). allEvents :: IsStream t => t IO (Device, Event) allEvents = readEventsMany allDevices -- | All valid devices (in /dev/input). allDevices :: (IsStream t, Monad (t IO)) => t IO Device allDevices = let maybeNewDevice path = catchJust (guard . isIllegalOperation) (Just <$> newDevice path) (\() -> return Nothing) paths = S.filterM doesFileExist $ S.map (evdevDir ) $ S.fromFoldable =<< S.yieldM (listDirectory evdevDir) in S.mapMaybeM maybeNewDevice paths