linux-evdev-0.3: System/Linux/Input/Device.hsc
{-# LANGUAGE ForeignFunctionInterface #-}
module System.Linux.Input.Device (
getDeviceName
, getDeviceId
, InputId (..)
) where
import Prelude hiding (product)
import qualified Data.ByteString.Char8 as BSC
import qualified Data.ByteString.Unsafe as BSC
import Foreign
import Foreign.C
import System.IO (Handle)
import System.Posix.Types
import System.Posix.IO (handleToFd)
#include <linux/input.h>
foreign import ccall "ioctl" c_ioctl :: CInt -> CInt -> Ptr () -> IO CInt
c_ioctl' :: Fd -> CInt -> Ptr d -> IO ()
c_ioctl' f req p =
throwErrnoIfMinus1_ "ioctl" $
c_ioctl (fromIntegral f) req (castPtr p)
getDeviceName :: Handle -> IO BSC.ByteString
getDeviceName h = withFd h $ \f->do
BSC.takeWhile (/='\0') `fmap` ioctlBS f #{const EVIOCGNAME(0)} (BSC.replicate 255 '\0')
ioctlBS :: Fd -> Int -> BSC.ByteString -> IO BSC.ByteString
ioctlBS f req buf = do
BSC.unsafeUseAsCString buf $ \p -> do
print $ (sizedIoctl req $ BSC.length buf, #{const EVIOCGNAME(255)})
c_ioctl' f (sizedIoctl req $ BSC.length buf) p
return buf
-- | Sets the size of an ioctl request number
sizedIoctl :: Int -> Int -> CInt
sizedIoctl req size =
fromIntegral $ (req .&. complement (mask `shiftL` shift))
.|. ((mask .&. size) `shiftL` shift)
where
mask = #{const _IOC_SIZEMASK}
shift = #{const _IOC_SIZESHIFT}
data InputId = InputId { busType :: Word16
, vendor :: Word16
, product :: Word16
, version :: Word16
}
deriving (Ord, Eq, Show)
instance Storable InputId where
sizeOf _ = 8
alignment _ = 8
peek p = do
busType <- peekElemOff p' 0
vendor <- peekElemOff p' 1
product <- peekElemOff p' 2
version <- peekElemOff p' 3
return $ InputId busType vendor product version
where p' = castPtr p :: Ptr Word16
poke p i = do
pokeElemOff p' 0 $ busType i
pokeElemOff p' 1 $ vendor i
pokeElemOff p' 2 $ product i
pokeElemOff p' 3 $ version i
where p' = castPtr p :: Ptr Word16
-- | Invoke ioctl with a Storable argument
ioctlStorable :: Storable a => Fd -> Int -> a -> IO a
ioctlStorable f req a = alloca $ \p -> do
poke p a
c_ioctl' f (fromIntegral req) p
peek p
-- | Invoke ioctl with an uninitialized Storable argument
ioctlStorable' :: Storable a => Fd -> Int -> IO a
ioctlStorable' f req = alloca $ \p -> do
c_ioctl' f (fromIntegral req) p
peek p
withFd :: Handle -> (Fd -> IO a) -> IO a
withFd h action = handleToFd h >>= action
getDeviceId :: Handle -> IO InputId
getDeviceId h =
withFd h $ \f->ioctlStorable' f #{const EVIOCGID}