{-# LINE 1 "System/Linux/Input/Event.hsc" #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LINE 2 "System/Linux/Input/Event.hsc" #-}

module System.Linux.Input.Event ( -- * Events
                                  Event(..)
                                , hReadEvent
                                , KeyEventType(..)
                                , module System.Linux.Input.Event.Constants
                                ) where

import Data.Word
import Data.Int
import Data.ByteString as BS
import Data.ByteString.Internal
import Data.Time.Clock

import Foreign.Storable
import Foreign.Ptr
import Foreign.ForeignPtr
import Foreign.C.Types

import System.IO

import System.Linux.Input.Event.Constants


{-# LINE 26 "System/Linux/Input/Event.hsc" #-}

-- | An Event
data Event = SyncEvent { evTimestamp :: DiffTime
                       , evSyncCode :: SyncType }
           | KeyEvent  { evTimestamp :: DiffTime
                       , evKeyCode :: Key
                       , evKeyEventType :: KeyEventType }
           | RelEvent  { evTimestamp :: DiffTime
                       , evRelAxis :: RelAxis
                       , evValue :: Int32 }
           | AbsEvent  { evTimestamp :: DiffTime
                       , evAbsAxis :: AbsAxis
                       , evValue :: Int32 }
           | MscEvent  { evTimestamp :: DiffTime }
           | SwEvent   { evTimestamp :: DiffTime }
           | LedEvent  { evTimestamp :: DiffTime }
           | SndEvent  { evTimestamp :: DiffTime }
           | RepEvent  { evTimestamp :: DiffTime }
           | FfEvent   { evTimestamp :: DiffTime }
           | FfStatusEvent { evTimestamp :: DiffTime }
           deriving (Show, Eq)

data KeyEventType = Released | Depressed | Repeated
                  deriving (Show, Eq, Ord, Enum, Bounded)

instance Storable Event where
  sizeOf _ = ((24))
{-# LINE 53 "System/Linux/Input/Event.hsc" #-}
  alignment = sizeOf
  peek ptr = do let time = ((\hsc_ptr -> hsc_ptr `plusPtr` 0)) ptr
{-# LINE 55 "System/Linux/Input/Event.hsc" #-}
                sec <- ((\hsc_ptr -> peekByteOff hsc_ptr 0)) time
{-# LINE 56 "System/Linux/Input/Event.hsc" #-}
                usec <- ((\hsc_ptr -> peekByteOff hsc_ptr 8)) time
{-# LINE 57 "System/Linux/Input/Event.hsc" #-}
                _type <- ((\hsc_ptr -> peekByteOff hsc_ptr 16)) ptr :: IO Word16
{-# LINE 58 "System/Linux/Input/Event.hsc" #-}
                code <- ((\hsc_ptr -> peekByteOff hsc_ptr 18)) ptr :: IO Word16
{-# LINE 59 "System/Linux/Input/Event.hsc" #-}
                value <- ((\hsc_ptr -> peekByteOff hsc_ptr 20)) ptr :: IO Int32
{-# LINE 60 "System/Linux/Input/Event.hsc" #-}
                let t = 1000000000000*fromIntegral (sec::Int) + 1000000*fromIntegral (usec::Int)
                return $ case _type of
                     (0)     -> SyncEvent { evTimestamp = picosecondsToDiffTime t
{-# LINE 63 "System/Linux/Input/Event.hsc" #-}
                                                      , evSyncCode = SyncType code
                                                      }
                     (1)     -> KeyEvent { evTimestamp = picosecondsToDiffTime t
{-# LINE 66 "System/Linux/Input/Event.hsc" #-}
                                                     , evKeyCode = Key code
                                                     , evKeyEventType = toEnum (fromIntegral value)
                                                     }
                     (2)     -> RelEvent { evTimestamp = picosecondsToDiffTime t
{-# LINE 70 "System/Linux/Input/Event.hsc" #-}
                                                     , evRelAxis = RelAxis code
                                                     , evValue = value
                                                     }
                     (3)     -> AbsEvent { evTimestamp = picosecondsToDiffTime t
{-# LINE 74 "System/Linux/Input/Event.hsc" #-}
                                                     , evAbsAxis = AbsAxis code
                                                     , evValue = value
                                                     }
                     (4)     -> MscEvent { evTimestamp = picosecondsToDiffTime t }
{-# LINE 78 "System/Linux/Input/Event.hsc" #-}
                     (5)     -> SwEvent { evTimestamp = picosecondsToDiffTime t }
{-# LINE 79 "System/Linux/Input/Event.hsc" #-}
                     (17)     -> LedEvent { evTimestamp = picosecondsToDiffTime t }
{-# LINE 80 "System/Linux/Input/Event.hsc" #-}
                     (18)     -> SndEvent { evTimestamp = picosecondsToDiffTime t }
{-# LINE 81 "System/Linux/Input/Event.hsc" #-}
                     (20)     -> RepEvent { evTimestamp = picosecondsToDiffTime t }
{-# LINE 82 "System/Linux/Input/Event.hsc" #-}
                     (21)      -> FfEvent { evTimestamp = picosecondsToDiffTime t }
{-# LINE 83 "System/Linux/Input/Event.hsc" #-}
                     (23) -> FfStatusEvent { evTimestamp = picosecondsToDiffTime t }
{-# LINE 84 "System/Linux/Input/Event.hsc" #-}
                     otherwise  -> error $ "unknown event type: " ++ show _type

  poke = error "Storable(System.Linux.Input.Event): poke not supported"

-- | Read an event
hReadEvent :: Handle -> IO (Maybe Event)
hReadEvent h = do
    a <- hGet h $ sizeOf (undefined::Event)
    case a of
         _ | BS.null a  -> return Nothing
         _ | otherwise  -> getEvent a >>= return . Just

getEvent :: ByteString -> IO Event
getEvent bs = do
    let (fptr, off, len) = toForeignPtr bs
    withForeignPtr fptr $ peek . castPtr