packages feed

Clipboard-2.0.0: System/Clipboard.hs

-- | Operations over the system clipboard.
--
-- Currently, this library only works for Windows.
-- For more information, see "Graphics.Win32.GDI.Clip"
-- or documentation for /GetClipboardData/ on MSDN.
module System.Clipboard
    (
      setClipboardString
    , getClipboardString 
    ) where

import System.Win32.Mem 
    (globalAlloc, globalLock, globalUnlock, copyMemory, gHND)
import Graphics.Win32.GDI.Clip 
    (openClipboard, closeClipboard, emptyClipboard, 
    getClipboardData, setClipboardData, cF_TEXT, isClipboardFormatAvailable)
import Foreign.C 
    (withCString, peekCString)
import Foreign.Ptr
    (castPtr, nullPtr)
import Data.List
    (genericLength)
import Control.Exception 
    (bracket_, bracket)
import Data.Maybe
    (isJust)

-- | Puts a string on the clipboard.
setClipboardString :: String -> IO ()
setClipboardString str = 
    withCString str $ \cstring -> do
    mem <- globalAlloc gHND strLen
    bracket (globalLock mem) globalUnlock $ \mem' -> do
        copyMemory mem' (castPtr cstring) strLen
        bracket_ (openClipboard nullPtr) closeClipboard $ do
            emptyClipboard
            setClipboardData cF_TEXT mem'
            return ()
  where
    strLen = genericLength str + 1

-- | Gets the contents of the clipboard as a 'String'.
-- Returns 'Nothing' if the clipboard content is not
-- of type 'cF_TEXT', i.e. it doesn't contain /textual/ data.
getClipboardString :: IO (Maybe String)
getClipboardString =  
    bracket_ (openClipboard nullPtr) closeClipboard $ do
        isFormatAvailable <- isClipboardFormatAvailable cF_TEXT
        if isFormatAvailable 
          then do
              handle <- getClipboardData cF_TEXT
              mem <- globalLock handle
              str <- peekCString (castPtr mem)
              globalUnlock mem
              return $ Just str
          else
              return Nothing

-- | Modifies the clipboard content.
-- If the clipboard has /textual/ data, this function modifies its content,
-- and return 'True'. Otherwise, it does nothing and return 'False'.
modifyClipboardString :: (String -> String) -> IO Bool
modifyClipboardString f = getClipboardString >>= return . isJust . fmap (setClipboardString . f)