diff --git a/evdev/evdev.cabal b/evdev/evdev.cabal index 58409c8..e4c18f9 100644 --- a/evdev/evdev.cabal +++ b/evdev/evdev.cabal @@ -29,6 +29,7 @@ common common rawfilepath ^>= {1.0, 1.1}, time ^>= {1.9.3, 1.10, 1.11, 1.12, 1.13, 1.14}, unix ^>= 2.8, + udev, default-language: GHC2021 default-extensions: BlockArguments diff --git a/evdev/src/Evdev/Uinput.hs b/evdev/src/Evdev/Uinput.hs index c609767..5319ba9 100644 --- a/evdev/src/Evdev/Uinput.hs +++ b/evdev/src/Evdev/Uinput.hs @@ -32,6 +32,12 @@ import Evdev.Codes import qualified Evdev.LowLevel as LL import Util +import Control.Concurrent (newEmptyMVar, putMVar, readMVar, threadDelay) +import Control.Monad.Loops (untilM_) +import Data.Maybe (fromMaybe) +import GHC.Event qualified as Event +import System.UDev qualified as UDev + -- | A `uinput` device. newtype Device = Device LL.UDevice @@ -84,7 +90,30 @@ newDevice name DeviceOpts{..} = do LL.withAbsInfo absInfo $ \ptr -> enable ptr EvAbs [fromEnum' axis] - fmap Device $ cec $ LL.createFromDevice dev $ fromEnum' LL.UOMManaged + -- wait for device creation + mv <- newEmptyMVar + udev <- UDev.newUDev + monitor <- UDev.newFromNetlink udev UDev.UDevId + UDev.enableReceiving monitor + UDev.filterAddMatchSubsystemDevtype monitor "input" Nothing + UDev.enableReceiving monitor + fd <- UDev.getFd monitor + eventManager <- fromMaybe (error "not using GHC's threaded RTS") <$> Event.getSystemEventManager + fdKey <- + Event.registerFd + eventManager + (\_ _ -> traverse_ (putMVar mv) . UDev.getDevnode =<< UDev.receiveDevice monitor) + fd + Event.evtRead + Event.MultiShot + uinputDev <- fmap Device $ cec $ LL.createFromDevice dev $ fromEnum' LL.UOMManaged + deviceDevnode uinputDev >>= \case + Nothing -> pure () -- shouldn't generally happen - just return and hope for the best + Just devnode -> untilM_ (pure ()) $ (== devnode) <$> readMVar mv + Event.unregisterFd eventManager fdKey + UDev.freeUDev udev + threadDelay 100000 + pure uinputDev where cec :: CErrCall a => IO a -> IO (CErrCallRes a) cec = cErrCall "newDevice" ()