{-# LANGUAGE MultiWayIf #-}
module Mischief.SDL.Events
(
SDLEventsPlugin,
SDLMessage (..),
SDLWindow (..),
handleEvents,
)
where
import Control.Monad
import Control.Monad.IO.Class
import Data.Foldable
import Data.Primitive.Ptr
import Foreign (Storable (peek), castPtr)
import Mischief.ECS
import Mischief.ECS.App.Schedules (First)
import Mischief.ECS.Foreign as F
import Mischief.ECS.Messages (Message)
import Mischief.ECS.Messages qualified as Messages
import SDL3.Sys (destroyWindow)
import SDL3.Sys qualified as SDL3
import System.Exit
newtype SDLWindow = SDLWindow {SDLWindow -> Ptr SDL_Window
ptr :: Ptr SDL3.SDL_Window}
deriving anyclass (Typeable SDLWindow
[HookRel SDLWindow]
[Hook SDLWindow]
Set DefaultComponentType
IsExclusive (IsExclusiveRel SDLWindow)
(Typeable SDLWindow, IsExclusive (IsExclusiveRel SDLWindow)) =>
Set DefaultComponentType
-> [Hook SDLWindow]
-> [Hook SDLWindow]
-> [Hook SDLWindow]
-> [HookRel SDLWindow]
-> [HookRel SDLWindow]
-> [HookRel SDLWindow]
-> Component SDLWindow
forall c.
(Typeable c, IsExclusive (IsExclusiveRel c)) =>
Set DefaultComponentType
-> [Hook c]
-> [Hook c]
-> [Hook c]
-> [HookRel c]
-> [HookRel c]
-> [HookRel c]
-> Component c
$crequired :: Set DefaultComponentType
required :: Set DefaultComponentType
$conAdd :: [Hook SDLWindow]
onAdd :: [Hook SDLWindow]
$conSet :: [Hook SDLWindow]
onSet :: [Hook SDLWindow]
$conRemove :: [Hook SDLWindow]
onRemove :: [Hook SDLWindow]
$conAddRel :: [HookRel SDLWindow]
onAddRel :: [HookRel SDLWindow]
$conSetRel :: [HookRel SDLWindow]
onSetRel :: [HookRel SDLWindow]
$conRemoveRel :: [HookRel SDLWindow]
onRemoveRel :: [HookRel SDLWindow]
Component)
initSdl :: IO ()
initSdl :: IO ()
initSdl = do
version <- IO Int32
SDL3.getVersion
let (major, rest) = fromIntegral version `divMod` (1000000 :: Int)
(minor, micro) = rest `divMod` 1000
putStrLn
( "sdl3-raw: linked against SDL "
<> show major
<> "."
<> show minor
<> "."
<> show micro
)
ok <- SDL3.init SDL3.SDL_INIT_VIDEO
unless ok (die "SDL_Init")
data SDLMessage e = SDLMessage {forall e. SDLMessage e -> SDL_EventType
eventType :: SDL3.SDL_EventType, forall e. SDLMessage e -> e
event :: e}
deriving anyclass (Typeable (SDLMessage e)
Typeable (SDLMessage e) => Message (SDLMessage e)
forall e. Typeable e => Typeable (SDLMessage e)
forall {k} (m :: k). Typeable m => Message m
Message)
deriving stock (Int -> SDLMessage e -> String -> String
[SDLMessage e] -> String -> String
SDLMessage e -> String
(Int -> SDLMessage e -> String -> String)
-> (SDLMessage e -> String)
-> ([SDLMessage e] -> String -> String)
-> Show (SDLMessage e)
forall e. Show e => Int -> SDLMessage e -> String -> String
forall e. Show e => [SDLMessage e] -> String -> String
forall e. Show e => SDLMessage e -> String
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
$cshowsPrec :: forall e. Show e => Int -> SDLMessage e -> String -> String
showsPrec :: Int -> SDLMessage e -> String -> String
$cshow :: forall e. Show e => SDLMessage e -> String
show :: SDLMessage e -> String
$cshowList :: forall e. Show e => [SDLMessage e] -> String -> String
showList :: [SDLMessage e] -> String -> String
Show)
data SDLEventsPlugin
instance Plugin SDLEventsPlugin where
init :: System ()
init = do
IO () -> System ()
forall a. IO a -> System a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO ()
initSdl
System () -> SystemConfig
forall a. ToSystems a => a -> SystemConfig
systems System ()
handleEvents
SystemConfig -> (SystemConfig -> System ()) -> System ()
forall a b. a -> (a -> b) -> b
& forall sc. Schedule sc => SystemConfig -> System ()
forall {k} (sc :: k). Schedule sc => SystemConfig -> System ()
schedule @First
(System (), System ()) -> SystemConfig
forall a. ToSystems a => a -> SystemConfig
systems (System ()
handleQuit, System ()
handleWindowClose)
SystemConfig -> (SystemConfig -> SystemConfig) -> SystemConfig
forall a b. a -> (a -> b) -> b
& System () -> SystemConfig -> SystemConfig
forall a. ToSystems a => a -> SystemConfig -> SystemConfig
after System ()
handleEvents
SystemConfig -> (SystemConfig -> System ()) -> System ()
forall a b. a -> (a -> b) -> b
& forall sc. Schedule sc => SystemConfig -> System ()
forall {k} (sc :: k). Schedule sc => SystemConfig -> System ()
schedule @First
handleEvents :: System ()
handleEvents :: System ()
handleEvents = forall a b. Storable a => (Ptr a -> System b) -> System b
F.alloca @SDL3.SDL_Event ((Ptr SDL_Event -> System ()) -> System ())
-> (Ptr SDL_Event -> System ()) -> System ()
forall a b. (a -> b) -> a -> b
$ \Ptr SDL_Event
event -> do
pending <- IO Bool -> System Bool
forall a. IO a -> System a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Bool -> System Bool) -> IO Bool -> System Bool
forall a b. (a -> b) -> a -> b
$ Ptr SDL_Event -> IO Bool
SDL3.pollEvent Ptr SDL_Event
event
when pending $ do
e <- liftIO $ peek event
eventType <- liftIO $ peek (castPtr event :: Ptr SDL3.SDL_EventType)
handleEvent eventType e
handleEvents
handleEvent :: SDL3.SDL_EventType -> SDL3.SDL_Event -> System ()
handleEvent :: SDL_EventType -> SDL_Event -> System ()
handleEvent SDL_EventType
t SDL_Event
e = case SDL_EventType
t of
SDL_EventType
SDL3.SDL_EVENT_AUDIO_DEVICE_ADDED -> SDL_EventType -> SDL_AudioDeviceEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.adevice
SDL_EventType
SDL3.SDL_EVENT_AUDIO_DEVICE_FORMAT_CHANGED -> SDL_EventType -> SDL_AudioDeviceEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.adevice
SDL_EventType
SDL3.SDL_EVENT_AUDIO_DEVICE_REMOVED -> SDL_EventType -> SDL_AudioDeviceEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.adevice
SDL_EventType
SDL3.SDL_EVENT_DISPLAY_ADDED -> SDL_EventType -> SDL_DisplayEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.display
SDL_EventType
SDL3.SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED -> SDL_EventType -> SDL_DisplayEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.display
SDL_EventType
SDL3.SDL_EVENT_DISPLAY_CURRENT_MODE_CHANGED -> SDL_EventType -> SDL_DisplayEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.display
SDL_EventType
SDL3.SDL_EVENT_DISPLAY_DESKTOP_MODE_CHANGED -> SDL_EventType -> SDL_DisplayEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.display
SDL_EventType
SDL3.SDL_EVENT_DISPLAY_FIRST -> SDL_EventType -> SDL_DisplayEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.display
SDL_EventType
SDL3.SDL_EVENT_DISPLAY_LAST -> SDL_EventType -> SDL_DisplayEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.display
SDL_EventType
SDL3.SDL_EVENT_DISPLAY_MOVED -> SDL_EventType -> SDL_DisplayEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.display
SDL_EventType
SDL3.SDL_EVENT_DISPLAY_ORIENTATION -> SDL_EventType -> SDL_DisplayEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.display
SDL_EventType
SDL3.SDL_EVENT_DISPLAY_REMOVED -> SDL_EventType -> SDL_DisplayEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.display
SDL_EventType
SDL3.SDL_EVENT_DISPLAY_USABLE_BOUNDS_CHANGED -> SDL_EventType -> SDL_DisplayEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.display
SDL_EventType
SDL3.SDL_EVENT_KEYBOARD_ADDED -> SDL_EventType -> SDL_KeyboardDeviceEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.kdevice
SDL_EventType
SDL3.SDL_EVENT_KEYBOARD_REMOVED -> SDL_EventType -> SDL_KeyboardDeviceEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.kdevice
SDL_EventType
SDL3.SDL_EVENT_KEY_DOWN -> SDL_EventType -> SDL_KeyboardEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.key
SDL_EventType
SDL3.SDL_EVENT_KEY_UP -> SDL_EventType -> SDL_KeyboardEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.key
SDL_EventType
SDL3.SDL_EVENT_MOUSE_ADDED -> SDL_EventType -> SDL_MouseDeviceEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.mdevice
SDL_EventType
SDL3.SDL_EVENT_MOUSE_REMOVED -> SDL_EventType -> SDL_MouseDeviceEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.mdevice
SDL_EventType
SDL3.SDL_EVENT_MOUSE_MOTION -> SDL_EventType -> SDL_MouseMotionEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.motion
SDL_EventType
SDL3.SDL_EVENT_MOUSE_BUTTON_DOWN -> SDL_EventType -> SDL_MouseButtonEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.button
SDL_EventType
SDL3.SDL_EVENT_MOUSE_BUTTON_UP -> SDL_EventType -> SDL_MouseButtonEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.button
SDL_EventType
SDL3.SDL_EVENT_MOUSE_WHEEL -> SDL_EventType -> SDL_MouseWheelEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.wheel
SDL_EventType
SDL3.SDL_EVENT_QUIT -> SDL_EventType -> SDL_QuitEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.quit
SDL_EventType
SDL3.SDL_EVENT_TEXT_INPUT -> SDL_EventType -> SDL_TextInputEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.text
SDL_EventType
SDL3.SDL_EVENT_USER -> SDL_EventType -> SDL_UserEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.user
SDL_EventType
SDL3.SDL_EVENT_WINDOW_CLOSE_REQUESTED -> SDL_EventType -> SDL_WindowEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.window
SDL_EventType
SDL3.SDL_EVENT_WINDOW_DESTROYED -> SDL_EventType -> SDL_WindowEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.window
SDL_EventType
SDL3.SDL_EVENT_WINDOW_DISPLAY_CHANGED -> SDL_EventType -> SDL_WindowEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.window
SDL_EventType
SDL3.SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED -> SDL_EventType -> SDL_WindowEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.window
SDL_EventType
SDL3.SDL_EVENT_WINDOW_ENTER_FULLSCREEN -> SDL_EventType -> SDL_WindowEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.window
SDL_EventType
SDL3.SDL_EVENT_WINDOW_EXPOSED -> SDL_EventType -> SDL_WindowEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.window
SDL_EventType
SDL3.SDL_EVENT_WINDOW_FIRST -> SDL_EventType -> SDL_WindowEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.window
SDL_EventType
SDL3.SDL_EVENT_WINDOW_FOCUS_GAINED -> SDL_EventType -> SDL_WindowEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.window
SDL_EventType
SDL3.SDL_EVENT_WINDOW_FOCUS_LOST -> SDL_EventType -> SDL_WindowEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.window
SDL_EventType
SDL3.SDL_EVENT_WINDOW_HDR_STATE_CHANGED -> SDL_EventType -> SDL_WindowEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.window
SDL_EventType
SDL3.SDL_EVENT_WINDOW_HIDDEN -> SDL_EventType -> SDL_WindowEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.window
SDL_EventType
SDL3.SDL_EVENT_WINDOW_HIT_TEST -> SDL_EventType -> SDL_WindowEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.window
SDL_EventType
SDL3.SDL_EVENT_WINDOW_ICCPROF_CHANGED -> SDL_EventType -> SDL_WindowEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.window
SDL_EventType
SDL3.SDL_EVENT_WINDOW_LAST -> SDL_EventType -> SDL_WindowEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.window
SDL_EventType
SDL3.SDL_EVENT_WINDOW_LEAVE_FULLSCREEN -> SDL_EventType -> SDL_WindowEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.window
SDL_EventType
SDL3.SDL_EVENT_WINDOW_MAXIMIZED -> SDL_EventType -> SDL_WindowEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.window
SDL_EventType
SDL3.SDL_EVENT_WINDOW_METAL_VIEW_RESIZED -> SDL_EventType -> SDL_WindowEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.window
SDL_EventType
SDL3.SDL_EVENT_WINDOW_MINIMIZED -> SDL_EventType -> SDL_WindowEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.window
SDL_EventType
SDL3.SDL_EVENT_WINDOW_MOUSE_ENTER -> SDL_EventType -> SDL_WindowEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.window
SDL_EventType
SDL3.SDL_EVENT_WINDOW_MOUSE_LEAVE -> SDL_EventType -> SDL_WindowEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.window
SDL_EventType
SDL3.SDL_EVENT_WINDOW_MOVED -> SDL_EventType -> SDL_WindowEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.window
SDL_EventType
SDL3.SDL_EVENT_WINDOW_OCCLUDED -> SDL_EventType -> SDL_WindowEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.window
SDL_EventType
SDL3.SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED -> SDL_EventType -> SDL_WindowEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.window
SDL_EventType
SDL3.SDL_EVENT_WINDOW_RESIZED -> SDL_EventType -> SDL_WindowEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.window
SDL_EventType
SDL3.SDL_EVENT_WINDOW_RESTORED -> SDL_EventType -> SDL_WindowEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.window
SDL_EventType
SDL3.SDL_EVENT_WINDOW_SAFE_AREA_CHANGED -> SDL_EventType -> SDL_WindowEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.window
SDL_EventType
SDL3.SDL_EVENT_WINDOW_SHOWN -> SDL_EventType -> SDL_WindowEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.window
SDL_EventType
t -> SDL_EventType -> SDL_CommonEvent -> System ()
forall {e}. Typeable e => SDL_EventType -> e -> System ()
s SDL_EventType
t SDL_Event
e.common
where
s :: SDL_EventType -> e -> System ()
s SDL_EventType
t e
a = SDLMessage e -> System ()
forall m. Message m => m -> System ()
Messages.write (SDLMessage e -> System ()) -> SDLMessage e -> System ()
forall a b. (a -> b) -> a -> b
$ SDL_EventType -> e -> SDLMessage e
forall e. SDL_EventType -> e -> SDLMessage e
SDLMessage SDL_EventType
t e
a
handleQuit :: System ()
handleQuit :: System ()
handleQuit = do
messages <- forall m. Message m => System [m]
Messages.read @(SDLMessage SDL3.SDL_QuitEvent)
unless (null messages) $ liftIO exitSuccess
handleWindowClose :: System ()
handleWindowClose :: System ()
handleWindowClose = do
messages <- (SDLMessage SDL_WindowEvent -> Bool)
-> [SDLMessage SDL_WindowEvent] -> [SDLMessage SDL_WindowEvent]
forall a. (a -> Bool) -> [a] -> [a]
filter (\(SDLMessage SDL_EventType
t SDL_WindowEvent
_) -> SDL_EventType
t SDL_EventType -> SDL_EventType -> Bool
forall a. Eq a => a -> a -> Bool
== SDL_EventType
SDL3.SDL_EVENT_WINDOW_CLOSE_REQUESTED) ([SDLMessage SDL_WindowEvent] -> [SDLMessage SDL_WindowEvent])
-> System [SDLMessage SDL_WindowEvent]
-> System [SDLMessage SDL_WindowEvent]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall m. Message m => System [m]
Messages.read @(SDLMessage SDL3.SDL_WindowEvent)
for_ messages $ \(SDLMessage SDL_EventType
_ SDL3.SDL_WindowEvent {SDL_WindowID
windowID :: SDL_WindowID
windowID :: SDL_WindowEvent -> SDL_WindowID
windowID}) -> do
window <- IO (Ptr SDL_Window) -> System (Ptr SDL_Window)
forall a. IO a -> System a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Ptr SDL_Window) -> System (Ptr SDL_Window))
-> IO (Ptr SDL_Window) -> System (Ptr SDL_Window)
forall a b. (a -> b) -> a -> b
$ SDL_WindowID -> IO (Ptr SDL_Window)
SDL3.getWindowFromID SDL_WindowID
windowID
unless (window == nullPtr) $ do
liftIO $ destroyWindow window
a <-
[q|(Entity, SDLWindow) / With SDLWindow|]
& qfilter (\(Entity
_, SDLWindow Ptr SDL_Window
p) -> Ptr SDL_Window
p Ptr SDL_Window -> Ptr SDL_Window -> Bool
forall a. Eq a => a -> a -> Bool
== Ptr SDL_Window
window)
& qmap fst
& single
traverse_ despawn a