x11-xinput-0.1.0.0: Graphics/X11/XInput/Parser.chs
{-# LANGUAGE TypeFamilies #-}
{-| Functions of this module perform parsing of XInput events structures. -}
module Graphics.X11.XInput.Parser where
#include <X11/Xlib.h>
#include <X11/extensions/XInput2.h>
import Control.Applicative
import Control.Monad
import qualified Data.Map as M
import Data.Bits
import Foreign.C
import Foreign.Ptr
import Foreign.Storable
import Foreign.Marshal.Alloc
import Foreign.Marshal.Array
import Text.Printf
import qualified Graphics.X11 as X11
import qualified Graphics.X11.Xlib.Extras as E
import Graphics.X11.XInput.Types
class Struct a where
type Pointer a
peekStruct :: Pointer a -> IO a
peekClasses :: Int -> Ptr a -> IO [GDeviceClass]
peekClasses n ptr = do
let ptr' = castPtr ptr :: Ptr GDeviceClassPtr
classesPtrs <- peekArray (fromIntegral n) ptr'
forM classesPtrs (peekStruct . castPtr)
checkByte :: CUChar -> [Int]
checkByte x = [i | i <- [0..7], x .&. (1 `shiftL` i) /= 0]
parseMask :: Mask -> [Int]
parseMask [] = []
parseMask [x] = checkByte x
parseMask list =
let x = last list
xs = init list
in map (+ 8) (checkByte x) ++ parseMask xs
peekMask :: (Ptr a -> IO CInt) -> (Ptr a -> IO (Ptr CUChar)) -> Ptr a -> IO [Int]
peekMask getLength getMask ptr = do
len <- trace "maskLen" $ getLength ptr
maskPtr <- trace "maskPtr" $ getMask ptr
mask <- trace "mask" $ peekArray (fromIntegral len) maskPtr
return $ parseMask mask
packMask :: [Int] -> X11.KeyMask
packMask list = foldr (.|.) 0 $ map (1 `shiftL`) list
instance Struct DeviceInfo where
type Pointer DeviceInfo = DeviceInfoPtr
peekStruct ptr = do
id <- {# get XIDeviceInfo->deviceid #} ptr
namePtr <- {# get XIDeviceInfo->name #} ptr
name <- peekCString namePtr
use <- int2deviceType <$> {# get XIDeviceInfo->use #} ptr
att <- {# get XIDeviceInfo->attachment #} ptr
on <- toBool <$> {# get XIDeviceInfo->enabled #} ptr
ncls <- fromIntegral <$> {# get XIDeviceInfo->num_classes #} ptr
clsptr <- {# get XIDeviceInfo->classes #} ptr
classes <- peekClasses ncls clsptr
return $ DeviceInfo id name use att on classes
instance Struct GDeviceClass where
type Pointer GDeviceClass = GDeviceClassPtr
peekStruct ptr = do
tp <- (toEnum . fromIntegral) <$> {# get XIAnyClassInfo->type #} ptr
src <- {# get XIAnyClassInfo->sourceid #} ptr
cls <- case tp of
XIButtonClass -> peekButtonClass ptr
XIKeyClass -> peekKeyClass ptr
XIValuatorClass -> peekValuatorClass ptr
return $ GDeviceClass tp (fromIntegral src) cls
instance Struct ButtonState where
type Pointer ButtonState = GDeviceClassPtr
peekStruct ptr = ButtonState
<$> peekMask ({# get XIButtonClassInfo->state.mask_len #})
({# get XIButtonClassInfo->state.mask #})
ptr
peekButtonClass :: GDeviceClassPtr -> IO DeviceClass
peekButtonClass ptr = do
n <- {# get XIButtonClassInfo->num_buttons #} ptr
labelsPtr <- {# get XIButtonClassInfo->labels #} ptr
labels <- peekArray (fromIntegral n) labelsPtr
st <- peekStruct ptr
return $ ButtonClass (fromIntegral n) (map fromIntegral labels) st
peekKeyClass :: GDeviceClassPtr -> IO DeviceClass
peekKeyClass ptr = do
n <- {# get XIKeyClassInfo->num_keycodes #} ptr
kptr <- {# get XIKeyClassInfo->keycodes #} ptr
keycodes <- peekArray (fromIntegral n) kptr
return $ KeyClass (fromIntegral n) (map fromIntegral keycodes)
peekValuatorClass :: GDeviceClassPtr -> IO DeviceClass
peekValuatorClass ptr = ValuatorClass
<$> (fromIntegral <$> {# get XIValuatorClassInfo->number #} ptr)
<*> (fromIntegral <$> {# get XIValuatorClassInfo->label #} ptr)
<*> (realToFrac <$> {# get XIValuatorClassInfo->min #} ptr)
<*> (realToFrac <$> {# get XIValuatorClassInfo->max #} ptr)
<*> (realToFrac <$> {# get XIValuatorClassInfo->value #} ptr)
<*> (fromIntegral <$> {# get XIValuatorClassInfo->resolution #} ptr)
<*> (fromIntegral <$> {# get XIValuatorClassInfo->mode #} ptr)
instance Struct Int where
type Pointer Int = Ptr CInt
peekStruct x = fromIntegral <$> peek x
get_event_type :: X11.XEventPtr -> IO X11.EventType
get_event_type ptr = fromIntegral <$> {# get XEvent->type #} ptr
get_event_extension :: X11.XEventPtr -> IO Opcode
get_event_extension ptr = {# get XGenericEvent->extension #} ptr
instance Struct EventCookie where
type Pointer EventCookie = EventCookiePtr
peekStruct xev = do
ev <- E.getEvent (castPtr xev)
ext <- {# get XGenericEventCookie->extension #} xev
et <- {# get XGenericEventCookie->evtype #} xev
cookie <- {# get XGenericEventCookie->cookie #} xev
dptr <- {# get XGenericEventCookie->data #} xev
cdata <- peekStruct (castPtr dptr)
return $ EventCookie {
ecEvent = ev,
ecExtension = ext,
ecType = int2eventType et,
ecCookie = cookie,
ecData = cdata }
getXGenericEventCookie :: X11.XEventPtr -> IO EventCookie
getXGenericEventCookie = peekStruct . castPtr
instance Struct Event where
type Pointer Event = EventPtr
peekStruct de = do
se <- toBool <$> {# get XIEvent->send_event #} de
dpy <- ptr2display <$> {# get XIEvent->display #} de
ext <- {# get XIDeviceEvent->extension #} de
evt <- int2eventType <$> {# get XIEvent->evtype #} de
dev <- {# get XIDeviceEvent->deviceid #} de
spec <- peekEventSpecific evt de
return $ Event se dpy ext evt dev spec
peekEventSpecific XI_PropertyEvent e = PropertyEvent
<$> (fromIntegral <$> {# get XIPropertyEvent->property #} e)
<*> {# get XIPropertyEvent->what #} e
peekEventSpecific XI_DeviceChanged e = do
reason <- {# get XIDeviceChangedEvent->reason #} e
ncls <- (fromIntegral <$> {# get XIDeviceChangedEvent->num_classes #} e)
clsPtr <- {# get XIDeviceChangedEvent->classes #} e
classes <- peekClasses ncls clsPtr
return $ DeviceChangedEvent reason classes
peekEventSpecific t e = GPointerEvent
<$> {# get XIDeviceEvent->sourceid #} e
<*> (fromIntegral <$> {# get XIDeviceEvent->detail #} e)
<*> (fromIntegral <$> {# get XIDeviceEvent->root #} e)
<*> (fromIntegral <$> {# get XIDeviceEvent->event #} e)
<*> (fromIntegral <$> {# get XIDeviceEvent->child #} e)
<*> {# get XIDeviceEvent->root_x #} e
<*> {# get XIDeviceEvent->root_y #} e
<*> {# get XIDeviceEvent->event_x #} e
<*> {# get XIDeviceEvent->event_y #} e
<*> trace "pointerEvent" (peekPointerEvent t e)
trace :: Show a => String -> IO a -> IO a
trace _ x = x
-- trace prefix action = do
-- result <- action
-- putStrLn $ prefix ++ ": " ++ show result
-- return result
peekPointerEvent XI_Enter e = EnterLeaveEvent
<$> {# get XIEnterEvent->mode #} e
<*> (toBool <$> {# get XIEnterEvent->focus #} e)
<*> (toBool <$> {# get XIEnterEvent->same_screen #} e)
<*> (ButtonState <$>
(peekMask ({# get XIEnterEvent->buttons.mask_len #})
({# get XIEnterEvent->buttons.mask #})
e ) )
<*> (ModifierState
<$> (fromIntegral <$> {# get XIEnterEvent->mods.base #} e)
<*> (fromIntegral <$> {# get XIEnterEvent->mods.latched #} e)
<*> (fromIntegral <$> {# get XIEnterEvent->mods.locked #} e)
<*> (fromIntegral <$> {# get XIEnterEvent->mods.effective #} e))
<*> (ModifierState
<$> (fromIntegral <$> {# get XIEnterEvent->group.base #} e)
<*> (fromIntegral <$> {# get XIEnterEvent->group.latched #} e)
<*> (fromIntegral <$> {# get XIEnterEvent->group.locked #} e)
<*> (fromIntegral <$> {# get XIEnterEvent->group.effective #} e))
peekPointerEvent XI_Leave e = peekPointerEvent XI_Enter e
peekPointerEvent XI_RawKeyPress e = peekRawEvent XI_RawKeyPress e
peekPointerEvent XI_RawKeyRelease e = peekRawEvent XI_RawKeyRelease e
peekPointerEvent t e = DeviceEvent
<$> trace "event type" (return t)
<*> trace "flags" ({# get XIDeviceEvent->flags #} e)
<*> trace "buttons" (ButtonState <$>
(peekMask ({# get XIDeviceEvent->buttons.mask_len #})
({# get XIDeviceEvent->buttons.mask #})
e ) )
<*> trace "valuators" (do
mask <- trace "mask" $ peekMask ({# get XIDeviceEvent->valuators.mask_len #})
({# get XIDeviceEvent->valuators.mask #})
e
valuesPtr <- trace "valuesPtr" $ {# get XIDeviceEvent->valuators.values #} e
values <- trace "values" $ peekArray (length mask) valuesPtr :: IO [CDouble]
let values' = map realToFrac values :: [Double]
return $ M.fromList $ zip mask values' )
<*> trace "mods" (ModifierState
<$> (fromIntegral <$> {# get XIDeviceEvent->mods.base #} e)
<*> (fromIntegral <$> {# get XIDeviceEvent->mods.latched #} e)
<*> (fromIntegral <$> {# get XIDeviceEvent->mods.locked #} e)
<*> (fromIntegral <$> {# get XIDeviceEvent->mods.effective #} e))
<*> trace "group" (ModifierState
<$> (fromIntegral <$> {# get XIDeviceEvent->group.base #} e)
<*> (fromIntegral <$> {# get XIDeviceEvent->group.latched #} e)
<*> (fromIntegral <$> {# get XIDeviceEvent->group.locked #} e)
<*> (fromIntegral <$> {# get XIDeviceEvent->group.effective #} e))
peekRawEvent t e = RawEvent
<$> trace "event type" (return t)
<*> trace "flags" ({# get XIRawEvent->flags #} e)
<*> trace "valuators" (do
mask <- trace "mask" $ peekMask ({# get XIRawEvent->valuators.mask_len #})
({# get XIRawEvent->valuators.mask #})
e
valuesPtr <- trace "valuesPtr" $ {# get XIRawEvent->valuators.values #} e
values <- trace "values" $ peekArray (length mask) valuesPtr :: IO [CDouble]
let values' = map realToFrac values :: [Double]
return $ M.fromList $ zip mask values' )