content: {- |
  Module      :  XMonad.Util.Paste
  Copyright   :  (C) 2008 Jérémy Bobbio, gwern
  License     :  BSD3
  
  Maintainer  :  none
  Stability   :  unstable
  Portability :  unportable
  
  A module for sending key presses to windows. This modules provides generalized
  and specialized functions for this task.
  -}
  
  module XMonad.Util.Paste ( -- * Usage
                             -- $usage
                             pasteSelection,
                             pasteString,
                             pasteChar,
                             sendKey,
                             sendKeyWindow,
                             noModMask
                           )
                             where
  
  import XMonad (io, theRoot, withDisplay, X ())
  import Graphics.X11
  import Graphics.X11.Xlib.Extras (none, setEventType, setKeyEvent)
  import Control.Monad.Reader (asks)
  import XMonad.Operations (withFocused)
  import Data.Char (isUpper)
  import Data.Maybe (listToMaybe)
  import XMonad.Util.XSelection (getSelection)
  import XMonad.Util.EZConfig (parseKey)
  import Text.ParserCombinators.ReadP (readP_to_S)
  
  {- $usage
  
  Import this module into your xmonad.hs as usual:
  
  > import XMonad.Util.Paste
  
  And use the functions. They all return 'X' (), and so are appropriate
  for use as keybindings. Example:
  
  >          , ((m,              xK_d), pasteString "foo bar") ]
  
  Don't expect too much of the functions; they probably don't work on complex
  texts.
  -}
  
  -- | Paste the current X mouse selection. Note that this uses 'getSelection' from
  --   "XMonad.Util.XSelection" and so is heir to its flaws.
  pasteSelection :: X ()
  pasteSelection = getSelection >>= pasteString
  
  -- | Send a string to the window which is currently focused. This function correctly
  -- handles capitalization. Warning: in dealing with capitalized characters, this assumes a QWERTY layout.
  pasteString :: String -> X ()
  pasteString = mapM_ (\x -> if isUpper x || x `elem` "~!@#$%^&*()_+{}|:\"<>?" then pasteChar shiftMask x else pasteChar noModMask x)
  
  {- | Send a character to the current window. This is more low-level.
     Remember that you must handle the case of capitalization appropriately.
     That is, from the window's perspective:
  
     > pasteChar mod2Mask 'F' ~> "f"
  
     You would want to do something like:
  
     > pasteChar shiftMask 'F'
  
     Note that this function makes use of 'stringToKeysym', and so will probably
     have trouble with any 'Char' outside ASCII.
  -}
  pasteChar :: KeyMask -> Char -> X ()
  pasteChar m c = sendKey m $ maybe (stringToKeysym [c]) fst
                  $ listToMaybe $ readP_to_S parseKey [c]
  
  sendKey :: KeyMask -> KeySym -> X ()
  sendKey = (withFocused .) . sendKeyWindow
  
  -- | The primitive. Allows you to send any combination of 'KeyMask' and 'KeySym' to any 'Window' you specify.
  sendKeyWindow :: KeyMask -> KeySym -> Window -> X ()
  sendKeyWindow mods key w = withDisplay $ \d -> do
                rootw <- asks theRoot
                keycode <- io $ keysymToKeycode d key
                io $ allocaXEvent $ \ev -> do
                    setEventType ev keyPress
                    setKeyEvent ev w rootw none mods keycode True
                    sendEvent d w True keyPressMask ev
                    setEventType ev keyRelease
                    sendEvent d w True keyReleaseMask ev
  