#include "SDL/SDL.h" #ifdef main #undef main #endif ----------------------------------------------------------------------------- -- | -- Module : Graphics.UI.SDL.Events -- Copyright : (c) David Himmelstrup 2005 -- License : BSD-like -- -- Maintainer : lemmih@gmail.com -- Stability : provisional -- Portability : portable -- ----------------------------------------------------------------------------- module Graphics.UI.SDL.Events ( Event (..) , SDLEvent (..) , UserEventID (..) , MouseButton (..) , Focus(..) , toSafePtr , tryFromSafePtr , fromSafePtr , typeOfSafePtr , enableKeyRepeat , enableUnicode , queryUnicodeState , getKeyName , getMouseState , getRelativeMouseState , getModState , setModState , tryPushEvent , pushEvent , pollEvent , waitEvent , waitEventBlocking , pumpEvents , enableEvent , queryEventState , getAppState ) where import Foreign (Int16, Word8, Word16, Word32, Ptr, Storable(poke, sizeOf, alignment, peekByteOff, pokeByteOff, peek), toBool, new, alloca) import Foreign.C (peekCString, CString, CInt) import System.IO.Unsafe (unsafePerformIO) import Data.Bits (Bits((.&.), shiftL)) import Control.Concurrent (threadDelay) import Prelude hiding (Enum(..)) import qualified Prelude (Enum(..)) import Foreign.StablePtr (newStablePtr,castStablePtrToPtr,castPtrToStablePtr,deRefStablePtr) import Data.Typeable (Typeable,typeOf,TypeRep) import Graphics.UI.SDL.Keysym (SDLKey, Modifier, Keysym) import Graphics.UI.SDL.Utilities (Enum(..), intToBool, toBitmask, fromBitmask, fromCInt) import Graphics.UI.SDL.General (unwrapBool, failWithError) import Graphics.UI.SDL.Video (Toggle(..), fromToggle) -- |Low level event structure keeping a one-to-one relation with the C event structure. data SDLEvent = SDLNoEvent | SDLActiveEvent | SDLKeyDown | SDLKeyUp | SDLMouseMotion | SDLMouseButtonDown | SDLMouseButtonUp | SDLJoyAxisMotion | SDLJoyBallMotion | SDLJoyHatMotion | SDLJoyButtonDown | SDLJoyButtonUp | SDLQuit | SDLSysWMEvent | SDLVideoResize | SDLVideoExpose | SDLUserEvent Word8 | SDLNumEvents deriving (Eq, Ord, Show) instance Bounded SDLEvent where minBound = SDLNoEvent maxBound = SDLNumEvents fromSDLEvent :: SDLEvent -> Word8 fromSDLEvent SDLNoEvent = #{const SDL_NOEVENT} fromSDLEvent SDLActiveEvent = #{const SDL_ACTIVEEVENT} fromSDLEvent SDLKeyDown = #{const SDL_KEYDOWN} fromSDLEvent SDLKeyUp = #{const SDL_KEYUP} fromSDLEvent SDLMouseMotion = #{const SDL_MOUSEMOTION} fromSDLEvent SDLMouseButtonDown = #{const SDL_MOUSEBUTTONDOWN} fromSDLEvent SDLMouseButtonUp = #{const SDL_MOUSEBUTTONUP} fromSDLEvent SDLJoyAxisMotion = #{const SDL_JOYAXISMOTION} fromSDLEvent SDLJoyBallMotion = #{const SDL_JOYBALLMOTION} fromSDLEvent SDLJoyHatMotion = #{const SDL_JOYHATMOTION} fromSDLEvent SDLJoyButtonDown = #{const SDL_JOYBUTTONDOWN} fromSDLEvent SDLJoyButtonUp = #{const SDL_JOYBUTTONUP} fromSDLEvent SDLQuit = #{const SDL_QUIT} fromSDLEvent SDLSysWMEvent = #{const SDL_SYSWMEVENT} fromSDLEvent SDLVideoResize = #{const SDL_VIDEORESIZE} fromSDLEvent SDLVideoExpose = #{const SDL_VIDEOEXPOSE} fromSDLEvent (SDLUserEvent n) = #{const SDL_USEREVENT} + n fromSDLEvent SDLNumEvents = #{const SDL_NUMEVENTS} toSDLEvent :: Word8 -> SDLEvent toSDLEvent #{const SDL_NOEVENT} = SDLNoEvent toSDLEvent #{const SDL_ACTIVEEVENT} = SDLActiveEvent toSDLEvent #{const SDL_KEYDOWN} = SDLKeyDown toSDLEvent #{const SDL_KEYUP} = SDLKeyUp toSDLEvent #{const SDL_MOUSEMOTION} = SDLMouseMotion toSDLEvent #{const SDL_MOUSEBUTTONDOWN} = SDLMouseButtonDown toSDLEvent #{const SDL_MOUSEBUTTONUP} = SDLMouseButtonUp toSDLEvent #{const SDL_JOYAXISMOTION} = SDLJoyAxisMotion toSDLEvent #{const SDL_JOYBALLMOTION} = SDLJoyBallMotion toSDLEvent #{const SDL_JOYHATMOTION} = SDLJoyHatMotion toSDLEvent #{const SDL_JOYBUTTONDOWN} = SDLJoyButtonDown toSDLEvent #{const SDL_JOYBUTTONUP} = SDLJoyButtonUp toSDLEvent #{const SDL_QUIT} = SDLQuit toSDLEvent #{const SDL_SYSWMEVENT} = SDLSysWMEvent toSDLEvent #{const SDL_VIDEORESIZE} = SDLVideoResize toSDLEvent #{const SDL_VIDEOEXPOSE} = SDLVideoExpose toSDLEvent n | n >= #{const SDL_USEREVENT} && n < #{const SDL_NUMEVENTS} = SDLUserEvent (n - #{const SDL_USEREVENT}) toSDLEvent _ = error "Graphics.UI.SDL.Events.toSDLEvent: bad argument" -- |High level event structure. data Event = NoEvent | GotFocus [Focus] | LostFocus [Focus] | KeyDown !Keysym | KeyUp !Keysym | MouseMotion !Word16 !Word16 !Int16 !Int16 | MouseButtonDown !Word16 !Word16 !MouseButton | MouseButtonUp !Word16 !Word16 !MouseButton | JoyAxisMotion !Word8 !Word8 !Int16 -- ^ device index, axis index, axis value. | JoyBallMotion !Word8 !Word8 !Int16 !Int16 -- ^ device index, trackball index, relative motion. | JoyHatMotion !Word8 !Word8 !Word8 -- ^ device index, hat index, hat position. | JoyButtonDown !Word8 !Word8 -- ^ device index, button index. | JoyButtonUp !Word8 !Word8 -- ^ device index, button index. | VideoResize !Int !Int -- ^ When @Resizable@ is passed as a flag to 'Graphics.UI.SDL.Video.setVideoMode' the user is -- allowed to resize the applications window. When the window is resized -- an @VideoResize@ is reported, with the new window width and height values. -- When an @VideoResize@ is recieved the window should be resized to the -- new dimensions using 'Graphics.UI.SDL.Video.setVideoMode'. | VideoExpose -- ^ A @VideoExpose@ event is triggered when the screen has been modified -- outside of the application, usually by the window manager and needs to be redrawn. | Quit | User !UserEventID !Int !(Ptr ()) !(Ptr ()) | Unknown deriving (Show,Eq) data MouseButton = ButtonLeft | ButtonMiddle | ButtonRight | ButtonWheelUp | ButtonWheelDown | ButtonUnknown !Word8 deriving (Show,Eq,Ord) instance Enum MouseButton Word8 where toEnum #{const SDL_BUTTON_LEFT} = ButtonLeft toEnum #{const SDL_BUTTON_MIDDLE} = ButtonMiddle toEnum #{const SDL_BUTTON_RIGHT} = ButtonRight toEnum #{const SDL_BUTTON_WHEELUP} = ButtonWheelUp toEnum #{const SDL_BUTTON_WHEELDOWN} = ButtonWheelDown toEnum n = ButtonUnknown (fromIntegral n) fromEnum ButtonLeft = #{const SDL_BUTTON_LEFT} fromEnum ButtonMiddle = #{const SDL_BUTTON_MIDDLE} fromEnum ButtonRight = #{const SDL_BUTTON_RIGHT} fromEnum ButtonWheelUp = #{const SDL_BUTTON_WHEELUP} fromEnum ButtonWheelDown = #{const SDL_BUTTON_WHEELDOWN} fromEnum (ButtonUnknown n) = fromIntegral n succ = toEnum . (+1) . fromEnum pred = toEnum . (subtract 1) . fromEnum enumFromTo = defEnumFromTo mouseButtonMask :: MouseButton -> Word8 mouseButtonMask ButtonLeft = #{const SDL_BUTTON(SDL_BUTTON_LEFT)} mouseButtonMask ButtonMiddle = #{const SDL_BUTTON(SDL_BUTTON_MIDDLE)} mouseButtonMask ButtonRight = #{const SDL_BUTTON(SDL_BUTTON_RIGHT)} mouseButtonMask ButtonWheelUp = #{const SDL_BUTTON(SDL_BUTTON_WHEELUP)} mouseButtonMask ButtonWheelDown = #{const SDL_BUTTON(SDL_BUTTON_WHEELDOWN)} mouseButtonMask (ButtonUnknown n) = 1 `shiftL` (fromIntegral n-1) allButtons :: [MouseButton] allButtons = [ButtonLeft ,ButtonMiddle ,ButtonRight ,ButtonWheelUp ,ButtonWheelDown ] defEnumFromTo :: (Enum a b, Ord a) => a -> a -> [a] defEnumFromTo x y | x > y = [] | x == y = [y] | otherwise = x : defEnumFromTo (succ x) y data Focus = MouseFocus | InputFocus | ApplicationFocus deriving (Show,Eq,Ord) instance Bounded Focus where minBound = MouseFocus maxBound = ApplicationFocus instance Enum Focus Word8 where fromEnum MouseFocus = #{const SDL_APPMOUSEFOCUS} fromEnum InputFocus = #{const SDL_APPINPUTFOCUS} fromEnum ApplicationFocus = #{const SDL_APPACTIVE} toEnum #{const SDL_APPMOUSEFOCUS} = MouseFocus toEnum #{const SDL_APPINPUTFOCUS} = InputFocus toEnum #{const SDL_APPACTIVE} = ApplicationFocus toEnum _ = error "Graphics.UI.SDL.Events.toEnum: bad argument" succ MouseFocus = InputFocus succ InputFocus = ApplicationFocus succ _ = error "Graphics.UI.SDL.Events.succ: bad argument" pred InputFocus = MouseFocus pred ApplicationFocus = InputFocus pred _ = error "Graphics.UI.SDL.Events.pred: bad argument" enumFromTo x y | x > y = [] | x == y = [y] | True = x : enumFromTo (succ x) y -- |Typed user events ranging from 0 to 7 data UserEventID = UID0 | UID1 | UID2 | UID3 | UID4 | UID5 | UID6 | UID7 deriving (Show,Eq,Prelude.Enum) -- |A safe pointer keeps the type of the object it was created from -- and checks it when it's deconstructed. type SafePtr = Ptr () -- |Constructs a safe pointer from an arbitrary value. toSafePtr :: (Typeable a) => a -> IO SafePtr toSafePtr val = do stablePtr <- newStablePtr (typeOf val,val) return (castStablePtrToPtr stablePtr) -- |Return the type of the object the safe pointer was created from. typeOfSafePtr :: SafePtr -> IO TypeRep typeOfSafePtr ptr = fmap fst (deRefStablePtr (castPtrToStablePtr ptr)) -- |Get object from a safe pointer. @Nothing@ on type mismatch. tryFromSafePtr :: (Typeable a) => SafePtr -> IO (Maybe a) tryFromSafePtr ptr = do (ty,val) <- deRefStablePtr (castPtrToStablePtr ptr) if ty == typeOf val then return (Just val) else return Nothing -- |Get object from a safe pointer. Throws an exception on type mismatch. fromSafePtr :: (Typeable a) => SafePtr -> IO a fromSafePtr ptr = do ret <- tryFromSafePtr ptr case ret of Nothing -> error "Graphics.UI.SDL.Events.fromSafePtr: invalid type." Just a -> return a toEventType :: UserEventID -> Word8 toEventType eid = fromIntegral (Prelude.fromEnum eid) fromEventType :: Word8 -> UserEventID fromEventType etype = Prelude.toEnum (fromIntegral etype) peekActiveEvent :: Ptr Event -> IO Event peekActiveEvent ptr = do gain <- fmap toBool ((#{peek SDL_ActiveEvent, gain} ptr) :: IO Word8) state <- #{peek SDL_ActiveEvent, state} ptr :: IO Word8 return $! (if gain then GotFocus else LostFocus) (fromBitmask state) peekKey :: (Keysym -> Event) -> Ptr Event -> IO Event peekKey mkEvent ptr = do keysym <- #{peek SDL_KeyboardEvent, keysym} ptr return $! mkEvent keysym peekMouseMotion :: Ptr Event -> IO Event peekMouseMotion ptr = do x <- #{peek SDL_MouseMotionEvent, x} ptr y <- #{peek SDL_MouseMotionEvent, y} ptr xrel <- #{peek SDL_MouseMotionEvent, xrel} ptr yrel <- #{peek SDL_MouseMotionEvent, yrel} ptr return $! MouseMotion x y xrel yrel peekMouse :: (Word16 -> Word16 -> MouseButton -> Event) -> Ptr Event -> IO Event peekMouse mkEvent ptr = do b <- #{peek SDL_MouseButtonEvent, button} ptr x <- #{peek SDL_MouseButtonEvent, x} ptr y <- #{peek SDL_MouseButtonEvent, y} ptr return $! mkEvent x y (toEnum (b::Word8)) peekJoyAxisMotion :: Ptr Event -> IO Event peekJoyAxisMotion ptr = do which <- #{peek SDL_JoyAxisEvent, which} ptr axis <- #{peek SDL_JoyAxisEvent, axis} ptr value <- #{peek SDL_JoyAxisEvent, value} ptr return $! JoyAxisMotion which axis value peekJoyBallMotion :: Ptr Event -> IO Event peekJoyBallMotion ptr = do which <- #{peek SDL_JoyBallEvent, which} ptr ball <- #{peek SDL_JoyBallEvent, ball} ptr xrel <- #{peek SDL_JoyBallEvent, xrel} ptr yrel <- #{peek SDL_JoyBallEvent, yrel} ptr return $! JoyBallMotion which ball xrel yrel peekJoyHatMotion :: Ptr Event -> IO Event peekJoyHatMotion ptr = do which <- #{peek SDL_JoyHatEvent, which} ptr hat <- #{peek SDL_JoyHatEvent, hat} ptr value <- #{peek SDL_JoyHatEvent, value} ptr return $! JoyHatMotion which hat value peekJoyButton :: (Word8 -> Word8 -> Event) -> Ptr Event -> IO Event peekJoyButton mkEvent ptr = do which <- #{peek SDL_JoyButtonEvent, which} ptr button <- #{peek SDL_JoyButtonEvent, button} ptr return $! mkEvent which button peekResize :: Ptr Event -> IO Event peekResize ptr = do w <- #{peek SDL_ResizeEvent, w} ptr h <- #{peek SDL_ResizeEvent, h} ptr return $! VideoResize (fromCInt w) (fromCInt h) peekUserEvent :: Ptr Event -> Word8 -> IO Event peekUserEvent ptr n = do code <- #{peek SDL_UserEvent, code} ptr data1 <- #{peek SDL_UserEvent, data1} ptr data2 <- #{peek SDL_UserEvent, data2} ptr return $ User (fromEventType n) (fromCInt code) data1 data2 getEventType :: Event -> Word8 getEventType = fromSDLEvent . eventToSDLEvent eventToSDLEvent :: Event -> SDLEvent eventToSDLEvent NoEvent = SDLNoEvent eventToSDLEvent (GotFocus _) = SDLActiveEvent eventToSDLEvent (LostFocus _) = SDLActiveEvent eventToSDLEvent (KeyDown _) = SDLKeyDown eventToSDLEvent (KeyUp _) = SDLKeyUp eventToSDLEvent (MouseMotion _ _ _ _) = SDLMouseMotion eventToSDLEvent (MouseButtonDown _ _ _) = SDLMouseButtonDown eventToSDLEvent (MouseButtonUp _ _ _) = SDLMouseButtonUp eventToSDLEvent (JoyAxisMotion _ _ _) = SDLJoyAxisMotion eventToSDLEvent (JoyBallMotion _ _ _ _) = SDLJoyBallMotion eventToSDLEvent (JoyHatMotion _ _ _) = SDLJoyHatMotion eventToSDLEvent (JoyButtonDown _ _) = SDLJoyButtonDown eventToSDLEvent (JoyButtonUp _ _) = SDLJoyButtonUp eventToSDLEvent Quit = SDLQuit eventToSDLEvent (VideoResize _ _) = SDLVideoResize eventToSDLEvent VideoExpose = SDLVideoExpose eventToSDLEvent (User uid _ _ _) = SDLUserEvent (toEventType uid) eventToSDLEvent _ = error "Graphics.UI.SDL.Events.eventToSDLEvent: bad argument" pokeActiveEvent :: Ptr Event -> Word8 -> [Focus] -> IO () pokeActiveEvent ptr gain focus = do #{poke SDL_ActiveEvent, gain} ptr gain #{poke SDL_ActiveEvent, state} ptr (toBitmask focus) pokeKey :: Ptr Event -> Word8 -> Keysym -> IO () pokeKey ptr state keysym = do #{poke SDL_KeyboardEvent, state} ptr state #{poke SDL_KeyboardEvent, keysym} ptr keysym pokeMouseMotion :: Ptr Event -> Word16 -> Word16 -> Int16 -> Int16 -> IO () pokeMouseMotion ptr x y xrel yrel = do #{poke SDL_MouseMotionEvent, x} ptr x #{poke SDL_MouseMotionEvent, y} ptr y #{poke SDL_MouseMotionEvent, xrel} ptr xrel #{poke SDL_MouseMotionEvent, yrel} ptr yrel pokeMouseButton :: Ptr Event -> Word8 -> Word16 -> Word16 -> MouseButton -> IO () pokeMouseButton ptr state x y b = do #{poke SDL_MouseButtonEvent, x} ptr x #{poke SDL_MouseButtonEvent, y} ptr y #{poke SDL_MouseButtonEvent, state} ptr state #{poke SDL_MouseButtonEvent, button} ptr (fromEnum b) pokeJoyAxisMotion :: Ptr Event -> Word8 -> Word8 -> Int16 -> IO () pokeJoyAxisMotion ptr which axis value = do #{poke SDL_JoyAxisEvent, which} ptr which #{poke SDL_JoyAxisEvent, axis} ptr axis #{poke SDL_JoyAxisEvent, value} ptr value pokeJoyBallMotion :: Ptr Event -> Word8 -> Word8 -> Int16 -> Int16 -> IO () pokeJoyBallMotion ptr which ball xrel yrel = do #{poke SDL_JoyBallEvent, which} ptr which #{poke SDL_JoyBallEvent, ball} ptr ball #{poke SDL_JoyBallEvent, xrel} ptr xrel #{poke SDL_JoyBallEvent, yrel} ptr yrel pokeJoyHatMotion :: Ptr Event -> Word8 -> Word8 -> Word8 -> IO () pokeJoyHatMotion ptr which hat value = do #{poke SDL_JoyHatEvent, which} ptr which #{poke SDL_JoyHatEvent, hat} ptr hat #{poke SDL_JoyHatEvent, value} ptr value pokeJoyButton :: Ptr Event -> Word8 -> Word8 -> Word8 -> IO () pokeJoyButton ptr which button state = do #{poke SDL_JoyButtonEvent, which} ptr which #{poke SDL_JoyButtonEvent, button} ptr button #{poke SDL_JoyButtonEvent, state} ptr state pokeResize :: Ptr Event -> Int -> Int -> IO () pokeResize ptr w h = do #{poke SDL_ResizeEvent, w} ptr w #{poke SDL_ResizeEvent, h} ptr h pokeUserEvent :: Ptr Event -> UserEventID -> Int -> Ptr () -> Ptr () -> IO () pokeUserEvent ptr _eventId code data1 data2 = do #{poke SDL_UserEvent, code} ptr code #{poke SDL_UserEvent, data1} ptr data1 #{poke SDL_UserEvent, data2} ptr data2 instance Storable Event where sizeOf = const (#{size SDL_Event}) alignment = const 4 poke ptr event = do pokeByteOff ptr 0 (getEventType event) case event of NoEvent -> return () GotFocus focus -> pokeActiveEvent ptr 1 focus LostFocus focus -> pokeActiveEvent ptr 0 focus KeyDown keysym -> pokeKey ptr #{const SDL_PRESSED} keysym KeyUp keysym -> pokeKey ptr #{const SDL_RELEASED} keysym MouseMotion x y xrel yrel -> pokeMouseMotion ptr x y xrel yrel MouseButtonDown x y b -> pokeMouseButton ptr #{const SDL_PRESSED} x y b MouseButtonUp x y b -> pokeMouseButton ptr #{const SDL_RELEASED} x y b JoyAxisMotion w a v -> pokeJoyAxisMotion ptr w a v JoyBallMotion w b x y -> pokeJoyBallMotion ptr w b x y JoyHatMotion w h v -> pokeJoyHatMotion ptr w h v JoyButtonDown w b -> pokeJoyButton ptr w b #{const SDL_PRESSED} JoyButtonUp w b -> pokeJoyButton ptr w b #{const SDL_RELEASED} Quit -> return () VideoResize w h -> pokeResize ptr w h VideoExpose -> return () User eventId c d1 d2 -> pokeUserEvent ptr eventId c d1 d2 e -> failWithError $ "Unhandled eventtype: " ++ show e peek ptr = do eventType <- peekByteOff ptr 0 case toSDLEvent eventType of SDLNoEvent -> return NoEvent SDLActiveEvent -> peekActiveEvent ptr SDLKeyDown -> peekKey KeyDown ptr SDLKeyUp -> peekKey KeyUp ptr SDLMouseMotion -> peekMouseMotion ptr SDLMouseButtonDown -> peekMouse MouseButtonDown ptr SDLMouseButtonUp -> peekMouse MouseButtonUp ptr SDLJoyAxisMotion -> peekJoyAxisMotion ptr SDLJoyBallMotion -> peekJoyBallMotion ptr SDLJoyHatMotion -> peekJoyHatMotion ptr SDLJoyButtonDown -> peekJoyButton JoyButtonDown ptr SDLJoyButtonUp -> peekJoyButton JoyButtonUp ptr SDLQuit -> return Quit -- SDLSysWMEvent SDLVideoResize -> peekResize ptr SDLVideoExpose -> return VideoExpose SDLUserEvent n -> peekUserEvent ptr n -- SDLNumEvents e -> failWithError $ "Unhandled eventtype: " ++ show e -- int SDL_EnableKeyRepeat(int delay, int interval); foreign import ccall unsafe "SDL_EnableKeyRepeat" sdlEnableKeyRepeat :: Int -> Int -> IO Int -- | Sets keyboard repeat rate. Returns @False@ on error. enableKeyRepeat :: Int -- ^ Initial delay. @0@ to disable. -> Int -- ^ Interval. -> IO Bool enableKeyRepeat delay interval = intToBool (-1) (sdlEnableKeyRepeat delay interval) -- int SDL_EnableUNICODE(int enable); foreign import ccall unsafe "SDL_EnableUNICODE" sdlEnableUnicode :: Int -> IO Int -- | Enables or disables unicode translation. enableUnicode :: Bool -> IO () enableUnicode enable = sdlEnableUnicode (fromToggle toggle) >> return () where toggle = case enable of True -> Enable False -> Disable -- | Returns the current state of unicode translation. See also 'enableUnicode'. queryUnicodeState :: IO Bool queryUnicodeState = fmap toBool (sdlEnableUnicode (fromToggle Query)) -- char *SDL_GetKeyName(SDLKey key); foreign import ccall unsafe "SDL_GetKeyName" sdlGetKeyName :: #{type SDLKey} -> IO CString -- | Gets the name of an SDL virtual keysym. getKeyName :: SDLKey -> String getKeyName key = unsafePerformIO $ sdlGetKeyName (fromEnum key) >>= peekCString -- SDLMod SDL_GetModState(void); foreign import ccall unsafe "SDL_GetModState" sdlGetModState :: IO #{type SDLMod} -- | Gets the state of modifier keys. getModState :: IO [Modifier] getModState = fmap fromBitmask sdlGetModState -- void SDL_SetModState(SDLMod modstate); foreign import ccall unsafe "SDL_SetModState" sdlSetModState :: #{type SDLMod} -> IO () -- | Sets the internal state of modifier keys. setModState :: [Modifier] -> IO () setModState = sdlSetModState . toBitmask mousePressed :: Word8 -> MouseButton -> Bool mousePressed mask b = mask .&. (mouseButtonMask b) /= 0 -- Uint8 SDL_GetMouseState(int *x, int *y); foreign import ccall "SDL_GetMouseState" sdlGetMouseState :: Ptr CInt -> Ptr CInt -> IO Word8 foreign import ccall "SDL_GetRelativeMouseState" sdlGetRelativeMouseState :: Ptr CInt -> Ptr CInt -> IO Word8 -- | Retrieves the current state of the mouse. Returns (X position, Y position, pressed buttons). getMouseState :: IO (Int, Int, [MouseButton]) getMouseState = mouseStateGetter sdlGetMouseState -- | Retrieve the current state of the mouse. Like 'getMouseState' except that X and Y are -- set to the change since last call to getRelativeMouseState. getRelativeMouseState :: IO (Int, Int, [MouseButton]) getRelativeMouseState = mouseStateGetter sdlGetRelativeMouseState mouseStateGetter :: (Ptr CInt -> Ptr CInt -> IO Word8) -> IO (Int, Int, [MouseButton]) mouseStateGetter getter = alloca $ \xPtr -> alloca $ \yPtr -> do ret <- getter xPtr yPtr [x,y] <- mapM peek [xPtr,yPtr] return (fromIntegral x,fromIntegral y ,filter (mousePressed ret) allButtons) -- int SDL_PollEvent(SDL_Event *event); foreign import ccall "SDL_PollEvent" sdlPollEvent :: Ptr Event -> IO Int -- | Polls for currently pending events. pollEvent :: IO Event pollEvent = alloca poll where poll ptr = do ret <- sdlPollEvent ptr case ret of 0 -> return NoEvent _ -> do event <- peek ptr case event of NoEvent -> poll ptr _ -> return event -- void SDL_PumpEvents(void); -- | Pumps the event loop, gathering events from the input devices. foreign import ccall unsafe "SDL_PumpEvents" pumpEvents :: IO () -- int SDL_PushEvent(SDL_Event *event); foreign import ccall unsafe "SDL_PushEvent" sdlPushEvent :: Ptr Event -> IO Int -- | Pushes an event onto the event queue. Returns @False@ on error. tryPushEvent :: Event -> IO Bool tryPushEvent event = new event >>= (fmap (0==) . sdlPushEvent) -- | Pushes an event onto the event queue. Throws an exception on error. pushEvent :: Event -> IO () pushEvent = unwrapBool "SDL_PushEvent" . tryPushEvent -- int SDL_WaitEvent(SDL_Event *event); foreign import ccall unsafe "SDL_WaitEvent" sdlWaitEvent :: Ptr Event -> IO Int -- | Waits indefinitely for the next available event. waitEvent :: IO Event waitEvent = loop where loop = do pumpEvents event <- pollEvent case event of NoEvent -> threadDelay 10 >> loop _ -> return event -- | Waits indefinitely for the next available event. Blocks Haskell threads. waitEventBlocking :: IO Event waitEventBlocking = alloca wait where wait ptr = do ret <- sdlWaitEvent ptr case ret of 0 -> failWithError "SDL_WaitEvent" _ -> do event <- peek ptr case event of NoEvent -> wait ptr _ -> return event -- Uint8 SDL_EventState(Uint8 type, int state); foreign import ccall unsafe "SDL_EventState" sdlEventState :: Word8 -> Int -> IO Word8 -- |Enable or disable events from being processed. enableEvent :: SDLEvent -> Bool -> IO () enableEvent event on = sdlEventState (fromSDLEvent event) (fromToggle state) >> return () where state | on = Enable | otherwise = Disable -- |Checks current state of a event. See also 'enableEvent'. queryEventState :: SDLEvent -> IO Bool queryEventState event = fmap (==1) (sdlEventState (fromSDLEvent event) (fromToggle Query)) -- Uint8 SDL_GetAppState(void); foreign import ccall unsafe "SDL_GetAppState" sdlGetAppState :: IO Word8 -- | Gets the state of the application. getAppState :: IO [Focus] getAppState = fmap fromBitmask sdlGetAppState