packages feed

astrds-0.1: src/UInputUtils.hs

module UInputUtils where

import qualified Graphics.UI.SDL as SDL
import Data.Word

import Options
import Debug

import UInputInterface

standardUInputEngine :: Options -> UInputEngine
standardUInputEngine opts = UInputEngine (updateUInput opts)
                                         (waitForAnyKey minWait)

-- clean up the event queue
cleanUpEventQueue :: IO ()
cleanUpEventQueue  = do 
                      event <- SDL.pollEvent
                      case event of
                        SDL.NoEvent -> return ()
                        _           -> cleanUpEventQueue

-- | Wait a specificed number of milliseconds, then wait for any key
-- (or joystick button) being pressed and return the pressed key.
waitForAnyKey :: Int -> IO UInput
waitForAnyKey t =
  do
    SDL.delay (fromIntegral t)
    cleanUpEventQueue
    waitForAnyKey'

-- | Wait for a key (or joystick button) being pressed.
waitForAnyKey' :: IO UInput
waitForAnyKey' =
  do
    event  <- SDL.pollEvent
    case event of
         SDL.KeyUp k         -> return $ addKey (sdlKeyToKey k)   noInput
         SDL.JoyButtonUp _ x -> return $ addKey (joystickToKey x) noInput
         _                   -> waitForAnyKey'


-- Reminder:
-- InputHandler :: UInput -> IO UInput

updateUInput :: Options -> InputHandler
updateUInput opts ui = do 
                        -- joystick handling
                        ui' <- updateJoystick opts ui
                        processEvents opts ui'

-- TODO: This could theoretically lead into an infinite loop
-- if processing an event takes longer than producing one
processEvents :: Options -> InputHandler
processEvents opts ui =
  do
    event <- SDL.pollEvent 
    -- key handling
    case event of
      SDL.JoyButtonDown x y -> processEvents opts (processJoyButtonDown x y ui)
      SDL.JoyButtonUp   x y -> processEvents opts (processJoyButtonUp x y ui) 
      SDL.KeyDown k         -> processEvents opts (processKeyDown k ui)
      SDL.KeyUp k           -> processEvents opts (processKeyUp k ui)
      SDL.NoEvent           -> return ui
      e                     -> do
                                debug_msg opts (show e)
                                return ui     

updateJoystick :: Options -> InputHandler
updateJoystick opts ui 
  = do
      let mj = joystick opts
      case mj of
        Nothing -> return ui
        Just j  -> do
                    SDL.update
                    cs <- mapM (SDL.getAxis j) [0..1]
                    let [x,y] = map ( (\ x -> if abs x < 0.05 then 0 else x)
                                    . (\ x -> x - 1) . (* 2) . (/ (2^16 - 1))
                                    . (+ (2^15)) . fromIntegral
                                    )
                                    cs
                    debug_msg opts (show (x,y))
                    return (ui { axes = (x,y) })


processKeyDown :: SDL.Keysym -> UInput -> UInput 
processKeyDown = addKey . sdlKeyToKey

processKeyUp :: SDL.Keysym -> UInput -> UInput 
processKeyUp = removeKey . sdlKeyToKey

processJoyButtonDown :: Word8 -> Word8 -> UInput -> UInput
processJoyButtonDown _ = addKey . joystickToKey

processJoyButtonUp :: Word8 -> Word8 -> UInput -> UInput
processJoyButtonUp   _ _ = id -- has to be changed if more keys are added!

-- | Convert joystick buttons into abstract keys.
joystickToKey :: Word8 -> Key
joystickToKey x | x == fromIntegral joystick_QUIT  = KQuit
                | otherwise                        = KUnknown

-- | Convert actual keys into abstract keys
-- (i.e., for changing game controls redefine this function).
sdlKeyToKey :: SDL.Keysym -> Key
sdlKeyToKey k = case SDL.symKey k of
                  SDL.SDLK_UP     -> KUp
                  SDL.SDLK_DOWN   -> KDown
                  SDL.SDLK_RIGHT  -> KRight
                  SDL.SDLK_LEFT   -> KLeft
                  SDL.SDLK_q      -> KQuit
                  _               -> KUnknown