    {-# LANGUAGE CPP #-}
    {- |
       Module      :  System.Win32.Console.CtrlHandler
       Copyright   :  2008-2013 Judah Jacobson, 2013 shelarcy
       License     :  BSD-style

       Maintainer  :  shelarcy@gmail.com
       Stability   :  Provisional
       Portability :  Non-portable (Win32 API)

       Set handlers of console Ctrl events.
    -}
    module System.Win32.Console.CtrlHandler
      ( CtrlEvent, Handler, PHANDLER_ROUTINE
      , withConsoleCtrlHandler
      , setConsoleCtrlHandler, c_SetConsoleCtrlHandler
      , mkHandler
      , cTRL_C_EVENT, cTRL_BREAK_EVENT
      ) where

    import Control.Exception    ( bracket )
    import Control.Monad        ( void )
    import Foreign.Ptr          ( FunPtr )
    import System.Win32.Console ( CtrlEvent, cTRL_C_EVENT, cTRL_BREAK_EVENT )
    import System.Win32.Types   ( BOOL, failIfFalse_ )

    #include "windows_cconv.h"

    type Handler = CtrlEvent -> IO BOOL
    -- type HandlerRoutine = Handler

    type PHANDLER_ROUTINE = FunPtr Handler

    withConsoleCtrlHandler :: Handler -> IO a -> IO a
    withConsoleCtrlHandler :: forall a. Handler -> IO a -> IO a
    withConsoleCtrlHandler Handler
    handler IO a
    io
      = IO PHANDLER_ROUTINE
    -> (PHANDLER_ROUTINE -> IO ())
    -> (PHANDLER_ROUTINE -> IO a)
    -> IO a
    forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
    bracket (do hd <- Handler -> IO PHANDLER_ROUTINE
    mkHandler Handler
    handler
                    -- don't fail if we can't set the Ctrl-C handler

                    -- for example, we might not be attached to a console?

                    void $ c_SetConsoleCtrlHandler hd True
                    return hd)
                (\PHANDLER_ROUTINE
    hd -> IO BOOL -> IO ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void (IO BOOL -> IO ()) -> IO BOOL -> IO ()
    forall a b. (a -> b) -> a -> b
    $ PHANDLER_ROUTINE -> BOOL -> IO BOOL
    c_SetConsoleCtrlHandler PHANDLER_ROUTINE
    hd BOOL
    False)
                ((PHANDLER_ROUTINE -> IO a) -> IO a)
    -> (PHANDLER_ROUTINE -> IO a) -> IO a
    forall a b. (a -> b) -> a -> b
    $ IO a -> PHANDLER_ROUTINE -> IO a
    forall a b. a -> b -> a
    const IO a
    io

    -- | This function isn't suitable when we want to set the cTRL_C_EVENT handler.

    -- If you want to set the cTRL_C_EVENT handler, use 'c_SetConsoleCtrlHandler' instead.

    setConsoleCtrlHandler :: PHANDLER_ROUTINE -> BOOL -> IO ()
    setConsoleCtrlHandler :: PHANDLER_ROUTINE -> BOOL -> IO ()
    setConsoleCtrlHandler PHANDLER_ROUTINE
    handler BOOL
    flag
      = String -> IO BOOL -> IO ()
    failIfFalse_ String
    "SetConsoleCtrlHandler"
          (IO BOOL -> IO ()) -> IO BOOL -> IO ()
    forall a b. (a -> b) -> a -> b
    $ PHANDLER_ROUTINE -> BOOL -> IO BOOL
    c_SetConsoleCtrlHandler PHANDLER_ROUTINE
    handler BOOL
    flag

    foreign import WINDOWS_CCONV "wrapper" mkHandler :: Handler -> IO PHANDLER_ROUTINE
    foreign import WINDOWS_CCONV "windows.h SetConsoleCtrlHandler"
      c_SetConsoleCtrlHandler :: PHANDLER_ROUTINE -> BOOL -> IO BOOL