x11-xinput-0.1.0.0: Graphics/X11/XInput/Foreign.chs
{-# LANGUAGE ForeignFunctionInterface, ScopedTypeVariables #-}
{-|
This module contains FFI imports and thin wrappers for them.
-}
module Graphics.X11.XInput.Foreign
(-- * XInput initialization
xinputVersion,
setEventMask,
-- * Wrappers for XInput calls
queryDevice,
grabDevice, ungrabDevice,
grabButton, ungrabButton,
grabKeycode, ungrabKeycode,
-- * FFI imports
xiQueryDevice,
xQueryExtension,
getEventData,
freeEventData
) where
#include <X11/Xlib.h>
#include <X11/extensions/XInput2.h>
import Control.Applicative
import Control.Monad
import Data.Bits
import Foreign.C
import Foreign.Ptr
import Foreign.Storable
import Foreign.Marshal.Alloc
import Foreign.Marshal.Array
import qualified Graphics.X11 as X11
import Graphics.X11.XInput.Types
import Graphics.X11.XInput.Parser
-- | Query list of devices
queryDevice :: X11.Display
-> SelectDevices -- ^ Which devices to list
-> IO [DeviceInfo]
queryDevice dpy devs = do
alloca $ \nptr -> do
dptr <- xiQueryDevice dpy (selectDevices devs) nptr
n <- peek nptr
let sz = {# sizeof XIDeviceInfo #}
offsets = take (fromIntegral n) [0, sz ..]
dptrs = map (plusPtr dptr) offsets
forM dptrs peekStruct
foreign import ccall "Foreign.chs.h XIQueryDevice"
xiQueryDevice :: X11.Display -> CInt -> Ptr CInt -> IO DeviceInfoPtr
foreign import ccall "Foreign.chs.h XQueryExtension"
xQueryExtension :: X11.Display -> CString -> Ptr CInt -> Ptr CInt -> Ptr CInt -> IO CInt
foreign import ccall "Foreign.chs.h XIQueryVersion"
xinputVersion :: X11.Display -> Ptr CInt -> Ptr CInt -> IO CInt
{# fun unsafe XGetEventData as getEventData {display2ptr `X11.Display',
castPtr `EventCookiePtr'} -> `Bool' #}
{# fun unsafe XFreeEventData as freeEventData {display2ptr `X11.Display',
castPtr `EventCookiePtr'} -> `()' #}
pokeAlloca :: Storable a => a -> (Ptr a -> IO b) -> IO b
pokeAlloca x f =
alloca $ \ptr -> do
poke ptr x
f ptr
{# fun unsafe XISelectEvents as selectEvents {display2ptr `X11.Display',
fromIntegral `X11.Window',
castPtr `EventMaskPtr',
`Int'} -> `()' #}
foreign import ccall unsafe "Foreign.chs.h XIGrabDevice"
xiGrabDevice :: X11.Display
-> DeviceID
-> X11.Window
-> X11.Time
-> X11.Cursor
-> X11.GrabMode
-> X11.GrabMode
-> CInt
-> EventMaskPtr
-> IO CInt
foreign import ccall unsafe "Foreign.chs.h XIUngrabDevice"
xiUngrabDevice :: X11.Display
-> DeviceID
-> X11.Time
-> IO X11.Status
foreign import ccall unsafe "Foreign.chs.h XIGrabButton"
xiGrabButton :: X11.Display
-> DeviceID
-> CInt
-> X11.Window
-> X11.Cursor
-> X11.GrabMode
-> X11.GrabMode
-> CInt
-> EventMaskPtr
-> CInt
-> GrabModifiersPtr
-> IO CInt
foreign import ccall unsafe "Foreign.chs.h XIUngrabButton"
xiUngrabButton :: X11.Display
-> DeviceID
-> X11.Button
-> X11.Window
-> CInt
-> GrabModifiersPtr
-> IO X11.Status
foreign import ccall unsafe "Foreign.chs.h XIGrabKeycode"
xiGrabKeycode :: X11.Display
-> DeviceID
-> X11.KeyCode
-> X11.Window
-> X11.GrabMode
-> X11.GrabMode
-> CInt
-> EventMaskPtr
-> CInt
-> GrabModifiersPtr
-> IO CInt
foreign import ccall unsafe "Foreign.chs.h XIUngrabKeycode"
xiUngrabKeycode :: X11.Display
-> DeviceID
-> X11.KeyCode
-> X11.Window
-> CInt
-> GrabModifiersPtr
-> IO X11.Status
grabDevice :: X11.Display
-> DeviceID
-> X11.Window
-> X11.Cursor
-> X11.GrabMode
-> X11.GrabMode
-> Bool
-> EventMask
-> IO X11.Status
grabDevice dpy dev win cursor
grab_mode paired_mode owner_events mask =
pokeAlloca mask $ \maskPtr ->
xiGrabDevice dpy dev win 0 cursor
grab_mode paired_mode
(fromBool owner_events)
maskPtr
ungrabDevice :: X11.Display
-> DeviceID
-> IO X11.Status
ungrabDevice dpy dev =
xiUngrabDevice dpy dev 0
grabButton :: X11.Display
-> SelectDevices
-> X11.Button
-> X11.Window
-> X11.Cursor
-> X11.GrabMode
-> X11.GrabMode
-> Bool
-> [EventType]
-> [GrabModifiers]
-> IO [GrabModifiers]
grabButton dpy dev btn win cursor
grab_mode paired_mode owner_events
events mods = do
let nMods = length mods
allocaArray nMods $ \modsPtr ->
withEventMask dpy win events $ \maskPtr -> do
pokeArray modsPtr mods
n <- xiGrabButton dpy (selectDevices dev)
(fromIntegral btn) win cursor
grab_mode paired_mode
(fromBool owner_events)
maskPtr
(fromIntegral nMods)
modsPtr
peekArray (fromIntegral n) modsPtr
ungrabButton :: X11.Display
-> SelectDevices
-> X11.Button
-> X11.Window
-> [GrabModifiers]
-> IO X11.Status
ungrabButton dpy dev btn win mods = do
let nMods = length mods
allocaArray nMods $ \modsPtr -> do
xiUngrabButton dpy (selectDevices dev)
(fromIntegral btn) win
(fromIntegral nMods)
modsPtr
grabKeycode :: X11.Display
-> SelectDevices
-> X11.KeyCode
-> X11.Window
-> X11.GrabMode
-> X11.GrabMode
-> Bool
-> [EventType]
-> [GrabModifiers]
-> IO [GrabModifiers]
grabKeycode dpy dev btn win
grab_mode paired_mode owner_events
events mods = do
let nMods = length mods
allocaArray nMods $ \modsPtr ->
withEventMask dpy win events $ \maskPtr -> do
pokeArray modsPtr mods
n <- xiGrabKeycode dpy (selectDevices dev)
(fromIntegral btn) win
grab_mode paired_mode
(fromBool owner_events)
maskPtr
(fromIntegral nMods)
modsPtr
peekArray (fromIntegral n) modsPtr
ungrabKeycode :: X11.Display
-> SelectDevices
-> X11.KeyCode
-> X11.Window
-> [GrabModifiers]
-> IO X11.Status
ungrabKeycode dpy dev btn win mods = do
let nMods = length mods
allocaArray nMods $ \modsPtr -> do
xiUngrabKeycode dpy (selectDevices dev)
(fromIntegral btn) win
(fromIntegral nMods)
modsPtr
addMask :: Ptr CUChar -> EventType -> IO ()
addMask ptr t = do
let event = eventType2int t
offset = fromIntegral $ event `shiftR` 3
mask = (1 `shiftL` (event .&. 7)) :: CUChar
value <- peekByteOff ptr offset :: IO CUChar
let newValue = value .|. mask
pokeByteOff ptr offset newValue
-- | Select XInput events.
setEventMask :: X11.Display
-> X11.Window
-> [EventType] -- ^ List of events to listen
-> IO ()
setEventMask dpy win list =
withEventMask dpy win list $ \maskptr ->
selectEvents dpy win maskptr 1
withEventMask :: X11.Display
-> X11.Window
-> [EventType]
-> (EventMaskPtr -> IO a)
-> IO a
withEventMask dpy win list callback = do
let len = (eventType2int XI_RawMotion + 7) `shiftR` 3
allocaBytes (fromIntegral len) $ \(maskptr :: EventMaskPtr) -> do
{# set XIEventMask.deviceid #} maskptr 0
{# set XIEventMask.mask_len #} maskptr len
allocaArray (fromIntegral len) $ \mask -> do
forM list $ addMask mask
{# set XIEventMask.mask #} maskptr mask
callback maskptr