x11-xinput-0.1.0.0: Graphics/X11/XInput/Functions.hs
{-# LANGUAGE RecordWildCards #-}
{-| This module contains some higher-level functions,
- wrapping XInput calls. #-}
module Graphics.X11.XInput.Functions
(xinputInit,
xinputCheckVersion,
handleXCookie,
eventButton,
eventWindow,
eventKeyMask,
eventMousePos
) where
import Control.Applicative
import Control.Monad.Trans
import Foreign.C
import Foreign.Ptr
import Foreign.Storable
import Foreign.Marshal.Alloc
import Foreign.Marshal.Array
import qualified Graphics.X11 as X11
import qualified Graphics.X11.Xlib.Extras as E
import Graphics.X11.XInput.Types
import Graphics.X11.XInput.Foreign
import Graphics.X11.XInput.Parser
-- | Initialize XInput 2.0 extension.
xinputInit :: X11.Display -> IO XInputInitResult
xinputInit dpy = do
withCString "XInputExtension" $ \xinput ->
alloca $ \opcode ->
alloca $ \event ->
alloca $ \error -> do
result <- xQueryExtension dpy xinput opcode event error
if result /= 0
then do
xi_opcode <- peek opcode
mbVer <- xinputCheckVersion dpy
case mbVer of
Nothing -> return $ InitOK xi_opcode
Just (major, minor) -> return $ VersionMismatch major minor
else return NoXInput
xinputMajor, xinputMinor :: CInt
xinputMajor = 2
xinputMinor = 0
-- | Returns Nothing if XInput 2.0 is supported, or
-- Just (major, minor) if another version is supported
xinputCheckVersion :: X11.Display -> IO (Maybe (Int, Int))
xinputCheckVersion dpy = do
alloca $ \majorPtr ->
alloca $ \minorPtr -> do
poke majorPtr xinputMajor
poke minorPtr xinputMinor
result <- xinputVersion dpy majorPtr minorPtr
supportedMajor <- peek majorPtr
supportedMinor <- peek minorPtr
if result == 1
then return $ Just (fromIntegral supportedMajor, fromIntegral supportedMinor)
else return Nothing
-- | Handle usual X11 event or cookie event.
handleXCookie :: (MonadIO m) => X11.Display
-> Opcode -- ^ Extension identifier (one got from xinputInit)
-> X11.XEventPtr -- ^ Pointer to X11 event
-> (E.Event -> m a) -- ^ Handler for usual X11 event
-> (EventCookie -> m a) -- ^ Handler for X11 cookie event
-> m a
handleXCookie dpy xi_opcode xev evHandler cookieHandler = do
-- liftIO $ putStrLn "handling XCookie"
evtype <- liftIO $ get_event_type xev
ext <- liftIO $ get_event_extension xev
hasCookie <- liftIO $ getEventData dpy (castPtr xev)
result <- if (evtype == genericEvent) && (ext == xi_opcode) && hasCookie
then do
-- liftIO $ putStrLn "XInput event"
cookieHandler =<< (liftIO $ getXGenericEventCookie xev)
else evHandler =<< (liftIO $ E.getEvent xev)
liftIO $ freeEventData dpy (castPtr xev)
return result
-- | Shortcut to get button number or keycode
-- from keyboard or mouse event. Returns Nothing
-- if this is not mouse or keyboard event.
eventButton :: Event -> Maybe Int
eventButton (Event {..})
| (eType `elem` [XI_ButtonPress, XI_ButtonRelease,
XI_KeyPress, XI_KeyRelease]) =
case eSpecific of
GPointerEvent {peDetail = n} -> Just n
_ -> Nothing
| otherwise = Nothing
-- | Shortcut to get pointer position from event
eventMousePos :: Event -> Maybe (X11.Position, X11.Position)
eventMousePos (Event {..})
| (eType `elem` [XI_ButtonPress, XI_ButtonRelease,
XI_KeyPress, XI_KeyRelease,
XI_Enter, XI_Leave]) =
let x = round (peRootX eSpecific)
y = round (peRootY eSpecific)
in Just (x, y)
| otherwise = Nothing
-- | Shortcut to get event window.
-- Returns Nothing if this is not pointer-related event
eventWindow :: Event -> Maybe X11.Window
eventWindow e =
case eSpecific e of
GPointerEvent {peEvent = w} -> Just w
_ -> Nothing
-- | Shortcut to get keymask from event
eventKeyMask :: Event -> Maybe X11.KeyMask
eventKeyMask (Event {eSpecific = GPointerEvent {peSpecific = e}}) =
Just $ fromIntegral $ msBase $ peMods e
eventKeyMask _ = Nothing