Blame System/Console/ANSI/Windows/Foreign.hs

Packit fc89b4
{-# OPTIONS_HADDOCK hide #-}
Packit fc89b4
{-# LANGUAGE RankNTypes #-}
Packit fc89b4
{-# LANGUAGE DeriveDataTypeable #-}
Packit fc89b4
Packit fc89b4
-- | "System.Win32.Console" is really very impoverished, so I have had to do all the FFI myself.
Packit fc89b4
module System.Console.ANSI.Windows.Foreign (
Packit fc89b4
        -- Re-exports from Win32.Types
Packit fc89b4
        BOOL, WORD, DWORD, WCHAR, HANDLE, iNVALID_HANDLE_VALUE, nullHANDLE,
Packit fc89b4
        SHORT,
Packit fc89b4
Packit fc89b4
        -- 'Re-exports from System.Win32.Console.Extra'
Packit fc89b4
        INPUT_RECORD(..), INPUT_RECORD_EVENT(..), kEY_EVENT,
Packit fc89b4
        KEY_EVENT_RECORD(..), UNICODE_ASCII_CHAR (..), writeConsoleInput,
Packit fc89b4
        getNumberOfConsoleInputEvents, readConsoleInput,
Packit fc89b4
Packit fc89b4
        charToWCHAR, cWcharsToChars,
Packit fc89b4
Packit fc89b4
        COORD(..), SMALL_RECT(..), rect_top, rect_bottom, rect_left, rect_right, rect_width, rect_height,
Packit fc89b4
        CONSOLE_CURSOR_INFO(..), CONSOLE_SCREEN_BUFFER_INFO(..), CHAR_INFO(..),
Packit fc89b4
Packit fc89b4
        sTD_INPUT_HANDLE, sTD_OUTPUT_HANDLE, sTD_ERROR_HANDLE,
Packit fc89b4
Packit fc89b4
        eNABLE_VIRTUAL_TERMINAL_INPUT,
Packit fc89b4
        eNABLE_VIRTUAL_TERMINAL_PROCESSING,
Packit fc89b4
Packit fc89b4
        fOREGROUND_BLUE, fOREGROUND_GREEN, fOREGROUND_RED, fOREGROUND_INTENSITY, fOREGROUND_WHITE, fOREGROUND_INTENSE_WHITE,
Packit fc89b4
        bACKGROUND_BLUE, bACKGROUND_GREEN, bACKGROUND_RED, bACKGROUND_INTENSITY, bACKGROUND_WHITE, bACKGROUND_INTENSE_WHITE,
Packit fc89b4
        cOMMON_LVB_REVERSE_VIDEO, cOMMON_LVB_UNDERSCORE,
Packit fc89b4
Packit fc89b4
        getStdHandle,
Packit fc89b4
        getConsoleScreenBufferInfo,
Packit fc89b4
        getConsoleCursorInfo,
Packit fc89b4
        getConsoleMode,
Packit fc89b4
Packit fc89b4
        setConsoleTextAttribute,
Packit fc89b4
        setConsoleCursorPosition,
Packit fc89b4
        setConsoleCursorInfo,
Packit fc89b4
        setConsoleTitle,
Packit fc89b4
        setConsoleMode,
Packit fc89b4
Packit fc89b4
        fillConsoleOutputAttribute,
Packit fc89b4
        fillConsoleOutputCharacter,
Packit fc89b4
        scrollConsoleScreenBuffer,
Packit fc89b4
Packit fc89b4
        withTString, withHandleToHANDLE,
Packit fc89b4
Packit fc89b4
        ConsoleException(..)
Packit fc89b4
    ) where
Packit fc89b4
Packit fc89b4
import Foreign.C.Types
Packit fc89b4
import Foreign.Marshal
Packit fc89b4
import Foreign.Ptr
Packit fc89b4
import Foreign.Storable
Packit fc89b4
Packit fc89b4
import Data.Bits
Packit fc89b4
import Data.Char
Packit fc89b4
Packit fc89b4
import System.Win32.Types
Packit fc89b4
Packit fc89b4
import Control.Exception (Exception, throw)
Packit fc89b4
Packit fc89b4
#if __GLASGOW_HASKELL__ >= 612
Packit fc89b4
import Data.Typeable
Packit fc89b4
#endif
Packit fc89b4
Packit fc89b4
#if !MIN_VERSION_Win32(2,5,1)
Packit fc89b4
import Control.Concurrent.MVar
Packit fc89b4
import Foreign.StablePtr
Packit fc89b4
import Control.Exception (bracket)
Packit fc89b4
#if __GLASGOW_HASKELL__ >= 612
Packit fc89b4
import GHC.IO.Handle.Types (Handle(..), Handle__(..))
Packit fc89b4
import GHC.IO.FD (FD(..)) -- A wrapper around an Int32
Packit fc89b4
import Data.Typeable
Packit fc89b4
#else
Packit fc89b4
import GHC.IOBase (Handle(..), Handle__(..))
Packit fc89b4
import qualified GHC.IOBase as IOBase (FD) -- Just an Int32
Packit fc89b4
#endif
Packit fc89b4
#endif
Packit fc89b4
Packit fc89b4
#if defined(i386_HOST_ARCH)
Packit fc89b4
# define WINDOWS_CCONV stdcall
Packit fc89b4
#elif defined(x86_64_HOST_ARCH)
Packit fc89b4
# define WINDOWS_CCONV ccall
Packit fc89b4
#else
Packit fc89b4
# error Unknown mingw32 arch
Packit fc89b4
#endif
Packit fc89b4
Packit fc89b4
--import System.Console.ANSI.Windows.Foreign.Compat
Packit fc89b4
#if !MIN_VERSION_Win32(2,5,0)
Packit fc89b4
-- Some Windows types missing from System.Win32 prior version 2.5.0.0
Packit fc89b4
type SHORT = CShort
Packit fc89b4
#endif
Packit fc89b4
type WCHAR = CWchar
Packit fc89b4
Packit fc89b4
charToWCHAR :: Char -> WCHAR
Packit fc89b4
charToWCHAR char = fromIntegral (ord char)
Packit fc89b4
Packit fc89b4
Packit fc89b4
-- This is a FFI hack. Some of the API calls take a Coord, but that isn't a built-in FFI type so I can't
Packit fc89b4
-- use it directly. Instead, I use UNPACKED_COORD and marshal COORDs into this manually. Note that we CAN'T
Packit fc89b4
-- just use two SHORTs directly because they get expanded to 4 bytes each instead of just boing 2 lots of 2
Packit fc89b4
-- bytes by the stdcall convention, so linking fails.
Packit fc89b4
type UNPACKED_COORD = CInt
Packit fc89b4
Packit fc89b4
-- Field packing order determined experimentally: I couldn't immediately find a specification for Windows
Packit fc89b4
-- struct layout anywhere.
Packit fc89b4
unpackCOORD :: COORD -> UNPACKED_COORD
Packit fc89b4
unpackCOORD (COORD x y) = (fromIntegral y) `shiftL` (sizeOf x * 8) .|. (fromIntegral x)
Packit fc89b4
Packit fc89b4
Packit fc89b4
peekAndOffset :: Storable a => Ptr a -> IO (a, Ptr b)
Packit fc89b4
peekAndOffset ptr = do
Packit fc89b4
    item <- peek ptr
Packit fc89b4
    return (item, ptr `plusPtr` sizeOf item)
Packit fc89b4
Packit fc89b4
pokeAndOffset :: Storable a => Ptr a -> a -> IO (Ptr b)
Packit fc89b4
pokeAndOffset ptr item = do
Packit fc89b4
    poke ptr item
Packit fc89b4
    return (ptr `plusPtr` sizeOf item)
Packit fc89b4
Packit fc89b4
Packit fc89b4
data COORD = COORD {
Packit fc89b4
        coord_x :: SHORT,
Packit fc89b4
        coord_y :: SHORT
Packit fc89b4
    }
Packit fc89b4
    deriving (Read, Eq)
Packit fc89b4
Packit fc89b4
instance Show COORD where
Packit fc89b4
    show (COORD x y) = "(" ++ show x ++ ", " ++ show y ++ ")"
Packit fc89b4
Packit fc89b4
instance Storable COORD where
Packit fc89b4
    sizeOf ~(COORD x y) = sizeOf x + sizeOf y
Packit fc89b4
    alignment ~(COORD x _) = alignment x
Packit fc89b4
    peek ptr = do
Packit fc89b4
        let ptr' = castPtr ptr :: Ptr SHORT
Packit fc89b4
        x <- peekElemOff ptr' 0
Packit fc89b4
        y <- peekElemOff ptr' 1
Packit fc89b4
        return (COORD x y)
Packit fc89b4
    poke ptr (COORD x y) = do
Packit fc89b4
        let ptr' = castPtr ptr :: Ptr SHORT
Packit fc89b4
        pokeElemOff ptr' 0 x
Packit fc89b4
        pokeElemOff ptr' 1 y
Packit fc89b4
Packit fc89b4
Packit fc89b4
data SMALL_RECT = SMALL_RECT {
Packit fc89b4
        rect_top_left :: COORD,
Packit fc89b4
        rect_bottom_right :: COORD
Packit fc89b4
    }
Packit fc89b4
Packit fc89b4
rect_top, rect_left, rect_bottom, rect_right :: SMALL_RECT -> SHORT
Packit fc89b4
rect_top = coord_y . rect_top_left
Packit fc89b4
rect_left = coord_x . rect_top_left
Packit fc89b4
rect_bottom = coord_y . rect_bottom_right
Packit fc89b4
rect_right = coord_x . rect_bottom_right
Packit fc89b4
Packit fc89b4
rect_width, rect_height :: SMALL_RECT -> SHORT
Packit fc89b4
rect_width rect = rect_right rect - rect_left rect + 1
Packit fc89b4
rect_height rect = rect_bottom rect - rect_top rect + 1
Packit fc89b4
Packit fc89b4
instance Show SMALL_RECT where
Packit fc89b4
    show (SMALL_RECT tl br) = show tl ++ "-" ++ show br
Packit fc89b4
Packit fc89b4
instance Storable SMALL_RECT where
Packit fc89b4
    sizeOf ~(SMALL_RECT tl br) = sizeOf tl + sizeOf br
Packit fc89b4
    alignment ~(SMALL_RECT tl _) = alignment tl
Packit fc89b4
    peek ptr = do
Packit fc89b4
        let ptr' = castPtr ptr :: Ptr COORD
Packit fc89b4
        tl <- peekElemOff ptr' 0
Packit fc89b4
        br <- peekElemOff ptr' 1
Packit fc89b4
        return (SMALL_RECT tl br)
Packit fc89b4
    poke ptr (SMALL_RECT tl br) = do
Packit fc89b4
        let ptr' = castPtr ptr :: Ptr COORD
Packit fc89b4
        pokeElemOff ptr' 0 tl
Packit fc89b4
        pokeElemOff ptr' 1 br
Packit fc89b4
Packit fc89b4
Packit fc89b4
data CONSOLE_CURSOR_INFO = CONSOLE_CURSOR_INFO {
Packit fc89b4
        cci_cursor_size :: DWORD,
Packit fc89b4
        cci_cursor_visible :: BOOL
Packit fc89b4
    }
Packit fc89b4
    deriving (Show)
Packit fc89b4
Packit fc89b4
instance Storable CONSOLE_CURSOR_INFO where
Packit fc89b4
    sizeOf ~(CONSOLE_CURSOR_INFO size visible) = sizeOf size + sizeOf visible
Packit fc89b4
    alignment ~(CONSOLE_CURSOR_INFO size _) = alignment size
Packit fc89b4
    peek ptr = do
Packit fc89b4
        (size, ptr') <- peekAndOffset (castPtr ptr)
Packit fc89b4
        visible <- peek ptr'
Packit fc89b4
        return (CONSOLE_CURSOR_INFO size visible)
Packit fc89b4
    poke ptr (CONSOLE_CURSOR_INFO size visible) = do
Packit fc89b4
        ptr' <- pokeAndOffset (castPtr ptr) size
Packit fc89b4
        poke ptr' visible
Packit fc89b4
Packit fc89b4
Packit fc89b4
data CONSOLE_SCREEN_BUFFER_INFO = CONSOLE_SCREEN_BUFFER_INFO {
Packit fc89b4
        csbi_size :: COORD,
Packit fc89b4
        csbi_cursor_position :: COORD,
Packit fc89b4
        csbi_attributes :: WORD,
Packit fc89b4
        csbi_window :: SMALL_RECT,
Packit fc89b4
        csbi_maximum_window_size :: COORD
Packit fc89b4
    }
Packit fc89b4
    deriving (Show)
Packit fc89b4
Packit fc89b4
instance Storable CONSOLE_SCREEN_BUFFER_INFO where
Packit fc89b4
    sizeOf ~(CONSOLE_SCREEN_BUFFER_INFO size cursor_position attributes window maximum_window_size)
Packit fc89b4
      = sizeOf size + sizeOf cursor_position + sizeOf attributes + sizeOf window + sizeOf maximum_window_size
Packit fc89b4
    alignment ~(CONSOLE_SCREEN_BUFFER_INFO size _ _ _ _) = alignment size
Packit fc89b4
    peek ptr = do
Packit fc89b4
        (size, ptr1) <- peekAndOffset (castPtr ptr)
Packit fc89b4
        (cursor_position, ptr2) <- peekAndOffset ptr1
Packit fc89b4
        (attributes, ptr3) <- peekAndOffset ptr2
Packit fc89b4
        (window, ptr4) <- peekAndOffset ptr3
Packit fc89b4
        maximum_window_size <- peek ptr4
Packit fc89b4
        return (CONSOLE_SCREEN_BUFFER_INFO size cursor_position attributes window maximum_window_size)
Packit fc89b4
    poke ptr (CONSOLE_SCREEN_BUFFER_INFO size cursor_position attributes window maximum_window_size) = do
Packit fc89b4
        ptr1 <- pokeAndOffset (castPtr ptr) size
Packit fc89b4
        ptr2 <- pokeAndOffset ptr1 cursor_position
Packit fc89b4
        ptr3 <- pokeAndOffset ptr2 attributes
Packit fc89b4
        ptr4 <- pokeAndOffset ptr3 window
Packit fc89b4
        poke ptr4 maximum_window_size
Packit fc89b4
Packit fc89b4
Packit fc89b4
data CHAR_INFO = CHAR_INFO {
Packit fc89b4
        ci_char :: WCHAR,
Packit fc89b4
        ci_attributes :: WORD
Packit fc89b4
    }
Packit fc89b4
    deriving (Show)
Packit fc89b4
Packit fc89b4
instance Storable CHAR_INFO where
Packit fc89b4
    sizeOf ~(CHAR_INFO char attributes) = sizeOf char + sizeOf attributes
Packit fc89b4
    alignment ~(CHAR_INFO char _) = alignment char
Packit fc89b4
    peek ptr = do
Packit fc89b4
        (char, ptr') <- peekAndOffset (castPtr ptr)
Packit fc89b4
        attributes <- peek ptr'
Packit fc89b4
        return (CHAR_INFO char attributes)
Packit fc89b4
    poke ptr (CHAR_INFO char attributes) = do
Packit fc89b4
        ptr' <- pokeAndOffset (castPtr ptr) char
Packit fc89b4
        poke ptr' attributes
Packit fc89b4
Packit fc89b4
Packit fc89b4
eNABLE_VIRTUAL_TERMINAL_INPUT, eNABLE_VIRTUAL_TERMINAL_PROCESSING :: DWORD
Packit fc89b4
sTD_INPUT_HANDLE, sTD_OUTPUT_HANDLE, sTD_ERROR_HANDLE :: DWORD
Packit fc89b4
eNABLE_VIRTUAL_TERMINAL_INPUT = 512
Packit fc89b4
eNABLE_VIRTUAL_TERMINAL_PROCESSING = 4
Packit fc89b4
sTD_INPUT_HANDLE = -10
Packit fc89b4
sTD_OUTPUT_HANDLE = -11
Packit fc89b4
sTD_ERROR_HANDLE = -12
Packit fc89b4
Packit fc89b4
fOREGROUND_BLUE, fOREGROUND_GREEN, fOREGROUND_RED, fOREGROUND_INTENSITY,
Packit fc89b4
  bACKGROUND_BLUE, bACKGROUND_GREEN, bACKGROUND_RED, bACKGROUND_INTENSITY,
Packit fc89b4
  cOMMON_LVB_REVERSE_VIDEO, cOMMON_LVB_UNDERSCORE :: WORD
Packit fc89b4
fOREGROUND_BLUE = 0x1
Packit fc89b4
fOREGROUND_GREEN = 0x2
Packit fc89b4
fOREGROUND_RED = 0x4
Packit fc89b4
fOREGROUND_INTENSITY = 0x8
Packit fc89b4
bACKGROUND_BLUE = 0x10
Packit fc89b4
bACKGROUND_GREEN = 0x20
Packit fc89b4
bACKGROUND_RED= 0x40
Packit fc89b4
bACKGROUND_INTENSITY = 0x80
Packit fc89b4
cOMMON_LVB_REVERSE_VIDEO = 0x4000
Packit fc89b4
cOMMON_LVB_UNDERSCORE = 0x8000
Packit fc89b4
Packit fc89b4
fOREGROUND_WHITE, bACKGROUND_WHITE, fOREGROUND_INTENSE_WHITE, bACKGROUND_INTENSE_WHITE :: WORD
Packit fc89b4
fOREGROUND_WHITE = fOREGROUND_RED .|. fOREGROUND_GREEN .|. fOREGROUND_BLUE
Packit fc89b4
bACKGROUND_WHITE = bACKGROUND_RED .|. bACKGROUND_GREEN .|. bACKGROUND_BLUE
Packit fc89b4
fOREGROUND_INTENSE_WHITE = fOREGROUND_WHITE .|. fOREGROUND_INTENSITY
Packit fc89b4
bACKGROUND_INTENSE_WHITE = bACKGROUND_WHITE .|. bACKGROUND_INTENSITY
Packit fc89b4
Packit fc89b4
kEY_EVENT, mOUSE_EVENT, wINDOW_BUFFER_SIZE_EVENT, mENU_EVENT, fOCUS_EVENT :: WORD
Packit fc89b4
kEY_EVENT                =  1
Packit fc89b4
mOUSE_EVENT              =  2
Packit fc89b4
wINDOW_BUFFER_SIZE_EVENT =  4
Packit fc89b4
mENU_EVENT               =  8
Packit fc89b4
fOCUS_EVENT              = 16
Packit fc89b4
Packit fc89b4
foreign import WINDOWS_CCONV unsafe "windows.h GetStdHandle" getStdHandle :: DWORD -> IO HANDLE
Packit fc89b4
foreign import WINDOWS_CCONV unsafe "windows.h GetConsoleScreenBufferInfo" cGetConsoleScreenBufferInfo :: HANDLE -> Ptr CONSOLE_SCREEN_BUFFER_INFO -> IO BOOL
Packit fc89b4
foreign import WINDOWS_CCONV unsafe "windows.h GetConsoleCursorInfo" cGetConsoleCursorInfo :: HANDLE -> Ptr CONSOLE_CURSOR_INFO -> IO BOOL
Packit fc89b4
foreign import WINDOWS_CCONV unsafe "windows.h GetConsoleMode" cGetConsoleMode :: HANDLE -> Ptr DWORD -> IO BOOL
Packit fc89b4
Packit fc89b4
foreign import WINDOWS_CCONV unsafe "windows.h SetConsoleTextAttribute" cSetConsoleTextAttribute :: HANDLE -> WORD -> IO BOOL
Packit fc89b4
foreign import WINDOWS_CCONV unsafe "windows.h SetConsoleCursorPosition" cSetConsoleCursorPosition :: HANDLE -> UNPACKED_COORD -> IO BOOL
Packit fc89b4
foreign import WINDOWS_CCONV unsafe "windows.h SetConsoleCursorInfo" cSetConsoleCursorInfo :: HANDLE -> Ptr CONSOLE_CURSOR_INFO -> IO BOOL
Packit fc89b4
foreign import WINDOWS_CCONV unsafe "windows.h SetConsoleTitleW" cSetConsoleTitle :: LPCTSTR -> IO BOOL
Packit fc89b4
foreign import WINDOWS_CCONV unsafe "windows.h SetConsoleMode" cSetConsoleMode :: HANDLE -> DWORD -> IO BOOL
Packit fc89b4
Packit fc89b4
foreign import WINDOWS_CCONV unsafe "windows.h FillConsoleOutputAttribute" cFillConsoleOutputAttribute :: HANDLE -> WORD -> DWORD -> UNPACKED_COORD -> Ptr DWORD -> IO BOOL
Packit fc89b4
foreign import WINDOWS_CCONV unsafe "windows.h FillConsoleOutputCharacterW" cFillConsoleOutputCharacter :: HANDLE -> TCHAR -> DWORD -> UNPACKED_COORD -> Ptr DWORD -> IO BOOL
Packit fc89b4
foreign import WINDOWS_CCONV unsafe "windows.h ScrollConsoleScreenBufferW" cScrollConsoleScreenBuffer :: HANDLE -> Ptr SMALL_RECT -> Ptr SMALL_RECT -> UNPACKED_COORD -> Ptr CHAR_INFO -> IO BOOL
Packit fc89b4
Packit fc89b4
foreign import WINDOWS_CCONV unsafe "windows.h WriteConsoleInputW" cWriteConsoleInput :: HANDLE -> Ptr INPUT_RECORD -> DWORD -> LPDWORD -> IO BOOL
Packit fc89b4
foreign import WINDOWS_CCONV unsafe "windows.h GetNumberOfConsoleInputEvents" cGetNumberOfConsoleInputEvents :: HANDLE -> Ptr DWORD -> IO BOOL
Packit fc89b4
foreign import WINDOWS_CCONV unsafe "windows.h ReadConsoleInputW" cReadConsoleInput :: HANDLE -> Ptr INPUT_RECORD -> DWORD -> LPDWORD -> IO BOOL
Packit fc89b4
Packit fc89b4
data ConsoleException = ConsoleException !ErrCode deriving (Show, Eq, Typeable)
Packit fc89b4
Packit fc89b4
instance Exception ConsoleException
Packit fc89b4
Packit fc89b4
throwIfFalse :: IO Bool -> IO ()
Packit fc89b4
throwIfFalse action = do
Packit fc89b4
  succeeded <- action
Packit fc89b4
  if not succeeded
Packit fc89b4
    then getLastError >>= throw . ConsoleException -- TODO: Check if last error is zero for some instructable reason (?)
Packit fc89b4
    else return ()
Packit fc89b4
Packit fc89b4
getConsoleScreenBufferInfo :: HANDLE -> IO CONSOLE_SCREEN_BUFFER_INFO
Packit fc89b4
getConsoleScreenBufferInfo handle = alloca $ \ptr_console_screen_buffer_info -> do
Packit fc89b4
    throwIfFalse $ cGetConsoleScreenBufferInfo handle ptr_console_screen_buffer_info
Packit fc89b4
    peek ptr_console_screen_buffer_info
Packit fc89b4
Packit fc89b4
Packit fc89b4
getConsoleCursorInfo :: HANDLE -> IO CONSOLE_CURSOR_INFO
Packit fc89b4
getConsoleCursorInfo handle = alloca $ \ptr_console_cursor_info -> do
Packit fc89b4
    throwIfFalse $ cGetConsoleCursorInfo handle ptr_console_cursor_info
Packit fc89b4
    peek ptr_console_cursor_info
Packit fc89b4
Packit fc89b4
getConsoleMode :: HANDLE -> IO DWORD
Packit fc89b4
getConsoleMode handle = alloca $ \ptr_mode -> do
Packit fc89b4
    throwIfFalse $ cGetConsoleMode handle ptr_mode
Packit fc89b4
    peek ptr_mode
Packit fc89b4
Packit fc89b4
setConsoleTextAttribute :: HANDLE -> WORD -> IO ()
Packit fc89b4
setConsoleTextAttribute handle attributes = throwIfFalse $ cSetConsoleTextAttribute handle attributes
Packit fc89b4
Packit fc89b4
setConsoleCursorPosition :: HANDLE -> COORD -> IO ()
Packit fc89b4
setConsoleCursorPosition handle cursor_position = throwIfFalse $ cSetConsoleCursorPosition handle (unpackCOORD cursor_position)
Packit fc89b4
Packit fc89b4
setConsoleCursorInfo :: HANDLE -> CONSOLE_CURSOR_INFO -> IO ()
Packit fc89b4
setConsoleCursorInfo handle console_cursor_info = with console_cursor_info $ \ptr_console_cursor_info -> do
Packit fc89b4
    throwIfFalse $ cSetConsoleCursorInfo handle ptr_console_cursor_info
Packit fc89b4
Packit fc89b4
setConsoleTitle :: LPCTSTR -> IO ()
Packit fc89b4
setConsoleTitle title = throwIfFalse $ cSetConsoleTitle title
Packit fc89b4
Packit fc89b4
setConsoleMode :: HANDLE -> DWORD -> IO ()
Packit fc89b4
setConsoleMode handle attributes = throwIfFalse $ cSetConsoleMode handle attributes
Packit fc89b4
Packit fc89b4
Packit fc89b4
fillConsoleOutputAttribute :: HANDLE -> WORD -> DWORD -> COORD -> IO DWORD
Packit fc89b4
fillConsoleOutputAttribute handle attribute fill_length write_origin = alloca $ \ptr_chars_written -> do
Packit fc89b4
    throwIfFalse $ cFillConsoleOutputAttribute handle attribute fill_length (unpackCOORD write_origin) ptr_chars_written
Packit fc89b4
    peek ptr_chars_written
Packit fc89b4
Packit fc89b4
fillConsoleOutputCharacter :: HANDLE -> TCHAR -> DWORD -> COORD -> IO DWORD
Packit fc89b4
fillConsoleOutputCharacter handle char fill_length write_origin = alloca $ \ptr_chars_written -> do
Packit fc89b4
    throwIfFalse $ cFillConsoleOutputCharacter handle char fill_length (unpackCOORD write_origin) ptr_chars_written
Packit fc89b4
    peek ptr_chars_written
Packit fc89b4
Packit fc89b4
scrollConsoleScreenBuffer :: HANDLE -> SMALL_RECT -> Maybe SMALL_RECT -> COORD -> CHAR_INFO -> IO ()
Packit fc89b4
scrollConsoleScreenBuffer handle scroll_rectangle mb_clip_rectangle destination_origin fill
Packit fc89b4
  = with scroll_rectangle $ \ptr_scroll_rectangle ->
Packit fc89b4
    maybeWith with mb_clip_rectangle $ \ptr_clip_rectangle ->
Packit fc89b4
    with fill $ \ptr_fill ->
Packit fc89b4
    throwIfFalse $ cScrollConsoleScreenBuffer handle ptr_scroll_rectangle ptr_clip_rectangle (unpackCOORD destination_origin) ptr_fill
Packit fc89b4
Packit fc89b4
Packit fc89b4
#if !MIN_VERSION_Win32(2,5,1)
Packit fc89b4
-- | This bit is all highly dubious.  The problem is that we want to output ANSI to arbitrary Handles rather than forcing
Packit fc89b4
-- people to use stdout.  However, the Windows ANSI emulator needs a Windows HANDLE to work it's magic, so we need to be able
Packit fc89b4
-- to extract one of those from the Haskell Handle.
Packit fc89b4
--
Packit fc89b4
-- This code accomplishes this, albeit at the cost of only being compatible with GHC.
Packit fc89b4
-- withHandleToHANDLE was added in Win32-2.5.1.0
Packit fc89b4
withHandleToHANDLE :: Handle -> (HANDLE -> IO a) -> IO a
Packit fc89b4
withHandleToHANDLE haskell_handle action =
Packit fc89b4
    -- Create a stable pointer to the Handle. This prevents the garbage collector
Packit fc89b4
    -- getting to it while we are doing horrible manipulations with it, and hence
Packit fc89b4
    -- stops it being finalized (and closed).
Packit fc89b4
    withStablePtr haskell_handle $ const $ do
Packit fc89b4
        -- Grab the write handle variable from the Handle
Packit fc89b4
        let write_handle_mvar = case haskell_handle of
Packit fc89b4
                FileHandle _ handle_mvar     -> handle_mvar
Packit fc89b4
                DuplexHandle _ _ handle_mvar -> handle_mvar -- This is "write" MVar, we could also take the "read" one
Packit fc89b4
Packit fc89b4
        -- Get the FD from the algebraic data type
Packit fc89b4
#if __GLASGOW_HASKELL__ < 612
Packit fc89b4
        fd <- fmap haFD $ readMVar write_handle_mvar
Packit fc89b4
#else
Packit fc89b4
        --readMVar write_handle_mvar >>= \(Handle__ { haDevice = dev }) -> print (typeOf dev)
Packit fc89b4
        Just fd <- fmap (\(Handle__ { haDevice = dev }) -> fmap fdFD (cast dev)) $ readMVar write_handle_mvar
Packit fc89b4
#endif
Packit fc89b4
Packit fc89b4
        -- Finally, turn that (C-land) FD into a HANDLE using msvcrt
Packit fc89b4
        windows_handle <- cget_osfhandle fd
Packit fc89b4
Packit fc89b4
        -- Do what the user originally wanted
Packit fc89b4
        action windows_handle
Packit fc89b4
Packit fc89b4
-- This essential function comes from the C runtime system. It is certainly provided by msvcrt, and also seems to be provided by the mingw C library - hurrah!
Packit fc89b4
#if __GLASGOW_HASKELL__ >= 612
Packit fc89b4
foreign import WINDOWS_CCONV unsafe "_get_osfhandle" cget_osfhandle :: CInt -> IO HANDLE
Packit fc89b4
#else
Packit fc89b4
foreign import WINDOWS_CCONV unsafe "_get_osfhandle" cget_osfhandle :: IOBase.FD -> IO HANDLE
Packit fc89b4
#endif
Packit fc89b4
Packit fc89b4
-- withStablePtr was added in Win32-2.5.1.0
Packit fc89b4
withStablePtr :: a -> (StablePtr a -> IO b) -> IO b
Packit fc89b4
withStablePtr value = bracket (newStablePtr value) freeStablePtr
Packit fc89b4
#endif
Packit fc89b4
Packit fc89b4
-- The following is based on module System.Win32.Console.Extra from package
Packit fc89b4
-- Win32-console, cut down for the WCHAR version of writeConsoleInput.
Packit fc89b4
Packit fc89b4
writeConsoleInput :: HANDLE -> [INPUT_RECORD] -> IO DWORD
Packit fc89b4
writeConsoleInput hdl evs =
Packit fc89b4
    writeConsoleInputWith hdl $ \act -> withArrayLen evs $ \len ptr -> act (ptr, toEnum len)
Packit fc89b4
Packit fc89b4
writeConsoleInputWith :: HANDLE -> InputHandler (Ptr INPUT_RECORD, DWORD) -> IO DWORD
Packit fc89b4
writeConsoleInputWith hdl withBuffer =
Packit fc89b4
    returnWith_ $ \ptrN ->
Packit fc89b4
        withBuffer $ \(ptrBuf, len) ->
Packit fc89b4
            failIfFalse_ "WriteConsoleInputW" $ cWriteConsoleInput hdl ptrBuf len ptrN
Packit fc89b4
Packit fc89b4
returnWith_ :: Storable a => (Ptr a -> IO b) -> IO a
Packit fc89b4
returnWith_ act = alloca $ \ptr -> act ptr >> peek ptr
Packit fc89b4
Packit fc89b4
type InputHandler i = forall a. (i -> IO a) -> IO a
Packit fc89b4
Packit fc89b4
{-
Packit fc89b4
typedef union _UNICODE_ASCII_CHAR {
Packit fc89b4
    WCHAR UnicodeChar;
Packit fc89b4
    CHAR  AsciiChar;
Packit fc89b4
} UNICODE_ASCII_CHAR;
Packit fc89b4
-}
Packit fc89b4
newtype UNICODE_ASCII_CHAR   = UnicodeAsciiChar { unicodeAsciiChar :: WCHAR }
Packit fc89b4
                               deriving (Show, Read, Eq)
Packit fc89b4
Packit fc89b4
instance Storable UNICODE_ASCII_CHAR where
Packit fc89b4
    sizeOf _    = 2
Packit fc89b4
    alignment _ = 2
Packit fc89b4
    peek ptr = UnicodeAsciiChar <$> (`peekByteOff` 0) ptr
Packit fc89b4
    poke ptr val = case val of
Packit fc89b4
        UnicodeAsciiChar c -> (`pokeByteOff` 0) ptr c
Packit fc89b4
Packit fc89b4
{-
Packit fc89b4
typedef struct _KEY_EVENT_RECORD {
Packit fc89b4
	BOOL bKeyDown;
Packit fc89b4
	WORD wRepeatCount;
Packit fc89b4
	WORD wVirtualKeyCode;
Packit fc89b4
	WORD wVirtualScanCode;
Packit fc89b4
	union {
Packit fc89b4
		WCHAR UnicodeChar;
Packit fc89b4
		CHAR AsciiChar;
Packit fc89b4
	} uChar;
Packit fc89b4
	DWORD dwControlKeyState;
Packit fc89b4
}
Packit fc89b4
#ifdef __GNUC__
Packit fc89b4
/* gcc's alignment is not what win32 expects */
Packit fc89b4
 PACKED
Packit fc89b4
#endif
Packit fc89b4
KEY_EVENT_RECORD;
Packit fc89b4
-}
Packit fc89b4
data KEY_EVENT_RECORD = KEY_EVENT_RECORD {
Packit fc89b4
        keyEventKeyDown         :: BOOL,
Packit fc89b4
        keyEventRepeatCount     :: WORD,
Packit fc89b4
        keyEventVirtualKeyCode  :: WORD,
Packit fc89b4
        keyEventVirtualScanCode :: WORD,
Packit fc89b4
        keyEventChar            :: UNICODE_ASCII_CHAR,
Packit fc89b4
        keyEventControlKeystate :: DWORD
Packit fc89b4
    } deriving (Show, Read, Eq)
Packit fc89b4
Packit fc89b4
instance Storable KEY_EVENT_RECORD where
Packit fc89b4
    sizeOf _    = 16
Packit fc89b4
    alignment _ =  4
Packit fc89b4
    peek ptr = KEY_EVENT_RECORD <$> (`peekByteOff`  0) ptr
Packit fc89b4
                                <*> (`peekByteOff`  4) ptr
Packit fc89b4
                                <*> (`peekByteOff`  6) ptr
Packit fc89b4
                                <*> (`peekByteOff`  8) ptr
Packit fc89b4
                                <*> (`peekByteOff` 10) ptr
Packit fc89b4
                                <*> (`peekByteOff` 12) ptr
Packit fc89b4
    poke ptr val = do
Packit fc89b4
        (`pokeByteOff`  0) ptr $ keyEventKeyDown val
Packit fc89b4
        (`pokeByteOff`  4) ptr $ keyEventRepeatCount val
Packit fc89b4
        (`pokeByteOff`  6) ptr $ keyEventVirtualKeyCode val
Packit fc89b4
        (`pokeByteOff`  8) ptr $ keyEventVirtualScanCode val
Packit fc89b4
        (`pokeByteOff` 10) ptr $ keyEventChar val
Packit fc89b4
        (`pokeByteOff` 12) ptr $ keyEventControlKeystate val
Packit fc89b4
Packit fc89b4
{-
Packit fc89b4
typedef struct _MOUSE_EVENT_RECORD {
Packit fc89b4
	COORD dwMousePosition;
Packit fc89b4
	DWORD dwButtonState;
Packit fc89b4
	DWORD dwControlKeyState;
Packit fc89b4
	DWORD dwEventFlags;
Packit fc89b4
} MOUSE_EVENT_RECORD;
Packit fc89b4
-}
Packit fc89b4
data MOUSE_EVENT_RECORD = MOUSE_EVENT_RECORD {
Packit fc89b4
        mousePosition        :: COORD,
Packit fc89b4
        mouseButtonState     :: DWORD,
Packit fc89b4
        mouseControlKeyState :: DWORD,
Packit fc89b4
        mouseEventFlags      :: DWORD
Packit fc89b4
    } deriving (Show, Read, Eq)
Packit fc89b4
Packit fc89b4
instance Storable MOUSE_EVENT_RECORD where
Packit fc89b4
    sizeOf _    = 16
Packit fc89b4
    alignment _ =  4
Packit fc89b4
    peek ptr =
Packit fc89b4
        MOUSE_EVENT_RECORD <$> (`peekByteOff`  0) ptr
Packit fc89b4
                           <*> (`peekByteOff`  4) ptr
Packit fc89b4
                           <*> (`peekByteOff`  8) ptr
Packit fc89b4
                           <*> (`peekByteOff` 12) ptr
Packit fc89b4
    poke ptr val = do
Packit fc89b4
        (`pokeByteOff`  0) ptr $ mousePosition val
Packit fc89b4
        (`pokeByteOff`  4) ptr $ mouseButtonState val
Packit fc89b4
        (`pokeByteOff`  8) ptr $ mouseControlKeyState val
Packit fc89b4
        (`pokeByteOff` 12) ptr $ mouseEventFlags val
Packit fc89b4
Packit fc89b4
{-
Packit fc89b4
typedef struct _WINDOW_BUFFER_SIZE_RECORD {
Packit fc89b4
    COORD dwSize;
Packit fc89b4
} WINDOW_BUFFER_SIZE_RECORD;
Packit fc89b4
-}
Packit fc89b4
data WINDOW_BUFFER_SIZE_RECORD = WINDOW_BUFFER_SIZE_RECORD {
Packit fc89b4
        bufSizeNew :: COORD
Packit fc89b4
    } deriving (Show, Read, Eq)
Packit fc89b4
Packit fc89b4
instance Storable WINDOW_BUFFER_SIZE_RECORD where
Packit fc89b4
    sizeOf _    = 4
Packit fc89b4
    alignment _ = 4
Packit fc89b4
    peek ptr = WINDOW_BUFFER_SIZE_RECORD <$> (`peekByteOff` 0) ptr
Packit fc89b4
    poke ptr val = (`pokeByteOff` 0) ptr $ bufSizeNew val
Packit fc89b4
Packit fc89b4
{-
Packit fc89b4
typedef struct _MENU_EVENT_RECORD {
Packit fc89b4
    UINT dwCommandId;
Packit fc89b4
} MENU_EVENT_RECORD,*PMENU_EVENT_RECORD;
Packit fc89b4
-}
Packit fc89b4
data MENU_EVENT_RECORD = MENU_EVENT_RECORD {
Packit fc89b4
        menuCommandId :: UINT
Packit fc89b4
    } deriving (Show, Read, Eq)
Packit fc89b4
Packit fc89b4
instance Storable MENU_EVENT_RECORD where
Packit fc89b4
    sizeOf _    = 4
Packit fc89b4
    alignment _ = 4
Packit fc89b4
    peek ptr = MENU_EVENT_RECORD <$> (`peekByteOff` 0) ptr
Packit fc89b4
    poke ptr val = (`pokeByteOff` 0) ptr $ menuCommandId val
Packit fc89b4
Packit fc89b4
{-
Packit fc89b4
typedef struct _FOCUS_EVENT_RECORD { BOOL bSetFocus; } FOCUS_EVENT_RECORD;
Packit fc89b4
-}
Packit fc89b4
data FOCUS_EVENT_RECORD = FOCUS_EVENT_RECORD {
Packit fc89b4
        focusSetFocus :: BOOL
Packit fc89b4
    } deriving (Show, Read, Eq)
Packit fc89b4
Packit fc89b4
instance Storable FOCUS_EVENT_RECORD where
Packit fc89b4
    sizeOf _    = 4
Packit fc89b4
    alignment _ = 4
Packit fc89b4
    peek ptr = FOCUS_EVENT_RECORD <$> (`peekByteOff` 0) ptr
Packit fc89b4
    poke ptr val = (`pokeByteOff` 0) ptr $ focusSetFocus val
Packit fc89b4
Packit fc89b4
data INPUT_RECORD_EVENT
Packit fc89b4
    = InputKeyEvent KEY_EVENT_RECORD
Packit fc89b4
    | InputMouseEvent MOUSE_EVENT_RECORD
Packit fc89b4
    | InputWindowBufferSizeEvent WINDOW_BUFFER_SIZE_RECORD
Packit fc89b4
    | InputMenuEvent MENU_EVENT_RECORD
Packit fc89b4
    | InputFocusEvent FOCUS_EVENT_RECORD
Packit fc89b4
    deriving (Show, Read, Eq)
Packit fc89b4
Packit fc89b4
{-
Packit fc89b4
typedef struct _INPUT_RECORD {
Packit fc89b4
	WORD EventType;
Packit fc89b4
	union {
Packit fc89b4
		KEY_EVENT_RECORD KeyEvent;
Packit fc89b4
		MOUSE_EVENT_RECORD MouseEvent;
Packit fc89b4
		WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent;
Packit fc89b4
		MENU_EVENT_RECORD MenuEvent;
Packit fc89b4
		FOCUS_EVENT_RECORD FocusEvent;
Packit fc89b4
	} Event;
Packit fc89b4
} INPUT_RECORD,*PINPUT_RECORD;
Packit fc89b4
-}
Packit fc89b4
data INPUT_RECORD = INPUT_RECORD {
Packit fc89b4
        inputEventType :: WORD,
Packit fc89b4
        inputEvent     :: INPUT_RECORD_EVENT
Packit fc89b4
    } deriving (Show, Read, Eq)
Packit fc89b4
Packit fc89b4
instance Storable INPUT_RECORD where
Packit fc89b4
    sizeOf _    = 20
Packit fc89b4
    alignment _ =  4
Packit fc89b4
    peek ptr = do
Packit fc89b4
        evType <- (`peekByteOff` 0) ptr
Packit fc89b4
        event <- case evType of
Packit fc89b4
            _ | evType == kEY_EVENT
Packit fc89b4
                -> InputKeyEvent              <$> (`peekByteOff` 4) ptr
Packit fc89b4
            _ | evType == mOUSE_EVENT
Packit fc89b4
                -> InputMouseEvent            <$> (`peekByteOff` 4) ptr
Packit fc89b4
            _ | evType == wINDOW_BUFFER_SIZE_EVENT
Packit fc89b4
                -> InputWindowBufferSizeEvent <$> (`peekByteOff` 4) ptr
Packit fc89b4
            _ | evType == mENU_EVENT
Packit fc89b4
                -> InputMenuEvent             <$> (`peekByteOff` 4) ptr
Packit fc89b4
            _ | evType == fOCUS_EVENT
Packit fc89b4
                -> InputFocusEvent            <$> (`peekByteOff` 4) ptr
Packit fc89b4
            _ -> error $ "peek (INPUT_RECORD): Unknown event type " ++ show evType
Packit fc89b4
        return $ INPUT_RECORD evType event
Packit fc89b4
    poke ptr val = do
Packit fc89b4
        (`pokeByteOff` 0) ptr $ inputEventType val
Packit fc89b4
        case inputEvent val of
Packit fc89b4
            InputKeyEvent              ev -> (`pokeByteOff` 4) ptr ev
Packit fc89b4
            InputMouseEvent            ev -> (`pokeByteOff` 4) ptr ev
Packit fc89b4
            InputWindowBufferSizeEvent ev -> (`pokeByteOff` 4) ptr ev
Packit fc89b4
            InputMenuEvent             ev -> (`pokeByteOff` 4) ptr ev
Packit fc89b4
            InputFocusEvent            ev -> (`pokeByteOff` 4) ptr ev
Packit fc89b4
Packit fc89b4
-- The following is based on module System.Win32.Console.Extra from package
Packit fc89b4
-- Win32-console.
Packit fc89b4
Packit fc89b4
getNumberOfConsoleInputEvents :: HANDLE -> IO DWORD
Packit fc89b4
getNumberOfConsoleInputEvents hdl =
Packit fc89b4
    returnWith_ $ \ptrN ->
Packit fc89b4
        failIfFalse_ "GetNumberOfConsoleInputEvents" $ cGetNumberOfConsoleInputEvents hdl ptrN
Packit fc89b4
Packit fc89b4
-- The following is based on module System.Win32.Console.Extra from package
Packit fc89b4
-- Win32-console, cut down for the WCHAR version of readConsoleInput.
Packit fc89b4
Packit fc89b4
readConsoleInput :: HANDLE -> DWORD -> IO [INPUT_RECORD]
Packit fc89b4
readConsoleInput hdl len = readConsoleInputWith hdl len $ \(ptr, n) -> peekArray (fromEnum n) ptr
Packit fc89b4
Packit fc89b4
readConsoleInputWith :: HANDLE -> DWORD -> OutputHandler (Ptr INPUT_RECORD, DWORD)
Packit fc89b4
readConsoleInputWith hdl len handler =
Packit fc89b4
    allocaArray (fromEnum len) $ \ptrBuf ->
Packit fc89b4
        alloca $ \ptrN -> do
Packit fc89b4
            failIfFalse_ "ReadConsoleInputW" $ cReadConsoleInput hdl ptrBuf len ptrN
Packit fc89b4
            n <- peek ptrN
Packit fc89b4
            handler (ptrBuf, n)
Packit fc89b4
Packit fc89b4
type OutputHandler o = forall a. (o -> IO a) -> IO a
Packit fc89b4
Packit fc89b4
-- Replicated from module Foreign.C.String in package base because that module
Packit fc89b4
-- does not export the function.
Packit fc89b4
cWcharsToChars :: [CWchar] -> [Char]
Packit fc89b4
cWcharsToChars = map chr . fromUTF16 . map fromIntegral
Packit fc89b4
 where
Packit fc89b4
  fromUTF16 (c1:c2:wcs)
Packit fc89b4
    | 0xd800 <= c1 && c1 <= 0xdbff && 0xdc00 <= c2 && c2 <= 0xdfff =
Packit fc89b4
      ((c1 - 0xd800)*0x400 + (c2 - 0xdc00) + 0x10000) : fromUTF16 wcs
Packit fc89b4
  fromUTF16 (c:wcs) = c : fromUTF16 wcs
Packit fc89b4
  fromUTF16 [] = []