robot 1.1 → 1.2
raw patch · 5 files changed
+122/−24 lines, 5 files
Files
- Test/Robot.hs +35/−22
- Test/Robot/Internal.hs +2/−1
- examples/Jack.hs +46/−0
- examples/Vim.hs +38/−0
- robot.cabal +1/−1
Test/Robot.hs view
@@ -11,12 +11,9 @@ , module Test.Robot.Types -- * Doing things- -- ** Basic operations- , Pressable(press, release)+ , Pressable(press, release, hold) , moveBy , moveTo- -- ** Derived operations- , hold , tap -- * Miscellaneous@@ -33,6 +30,9 @@ import Test.Robot.Types +infixr 4 `hold` -- Allow e.g. xs ++ ys `hold` m++ -- | Represents things that can be pressed: either a key on a keyboard -- or a button on a mouse. class Pressable x where@@ -43,6 +43,19 @@ -- | Release a key or button. release :: x -> Robot () + -- | @hold x act@ holds down @x@ while executing @act@. It is+ -- equivalent to:+ --+ -- @+ -- press x >> act >> release x+ -- @+ --+ -- except @hold@ ensures that the argument is released in the event+ -- of an exception.+ --+ hold :: x -> Robot a -> Robot a+ hold = bracketRobot_ <$> press <*> release+ instance Pressable Key where press = keyboard True release = keyboard False@@ -51,7 +64,25 @@ press = button True release = button False +-- | Press items from left-to-right, but release from right-to-left.+--+-- This behavior ensures the following equivalence holds:+--+-- @+-- press xs >> act >> release xs+-- === xs \`hold\` act+-- === x1 \`hold\` x2 \`hold\` ... xn \`hold\` act+-- @+--+instance Pressable x => Pressable [x] where+ press = mapM_ press+ release = mapM_ release . reverse + hold = foldr (.) id . map hold+ --hold [] = id+ --hold (x:xs) = hold x . hold xs++ -- | Move the pointer by an offset. moveBy :: Int -> Int -> Robot () moveBy = motion True@@ -60,24 +91,6 @@ moveTo :: Int -> Int -> Robot () moveTo = motion False ---- | @hold x act@ holds down @x@ while executing @act@. It is equivalent--- to the code:------ @--- press x--- act--- release x--- @------ For example, you type some text in ALL CAPS using:------ @--- hold _Shift $ mapM_ tap [_D, _U, _C, _K, _S]--- @----hold :: Pressable x => x -> Robot a -> Robot a-hold = bracketRobot_ <$> press <*> release -- | Press the argument, then release it. tap :: Pressable x => x -> Robot ()
Test/Robot/Internal.hs view
@@ -68,7 +68,8 @@ keyboard :: Bool -> Key -> Robot () keyboard press key = mkRobot $ \(c, keymap) -> do case M.lookup (rawKey key) keymap of- Nothing -> error $ "Unknown keysym: " ++ show (rawKey key)+ Nothing -> error $ "keysym " ++ show (rawKey key)+ ++ " does not exist on keyboard layout" Just keycode -> X.keyboard c press keycode button :: Bool -> Button -> Robot ()
+ examples/Jack.hs view
@@ -0,0 +1,46 @@+-- | A simple typing automaton. Supports ASCII letters, spaces and newlines.++import Control.Applicative+import Control.Monad+import Control.Monad.IO.Class (liftIO)+import Data.Ratio ((%))+import System.Random (randomRIO)+import Test.Robot++main :: IO ()+main = runRobot . forever $ do+ typeText fudge "All work and no play makes Jack a dull boy\n"+ sleep . (% 5) =<< rand (1, 10)+ where+ -- This program is a horrible typist+ fudge = do+ sleep . (1 %) =<< rand (2, 10)+ roll <- rand (0, 100)+ when (roll `elem` [0..3]) $ tap _Space+ when (roll == 4) $ tap _Return++typeText+ :: Robot () -- ^ Action to perform between each key press+ -> String -- ^ Input string+ -> Robot ()+typeText pause = foldr combine (return ()) . map (tapShift . charToKey)+ where+ combine a b = a >> pause >> b++tapShift :: (Bool, Key) -> Robot ()+tapShift (False, k) = tap k+tapShift (True , k) = _Shift `hold` tap k++charToKey :: Char -> (Bool, Key)+charToKey c+ | 'A' <= c && c <= 'Z' = (True, k)+ | 'a' <= c && c <= 'z' = (False, k)+ | otherwise = (False, case c of+ ' ' -> _Space+ '\n' -> _Return+ _ -> error $ "key conversion not implemented for " ++ show c)+ where+ k = customKey $ fromIntegral (fromEnum c)++rand :: (Integer, Integer) -> Robot Integer+rand = liftIO . randomRIO
+ examples/Vim.hs view
@@ -0,0 +1,38 @@+-- | Do some funny things with the keyboard.++import Control.Monad (replicateM_)+import Test.Robot++main = runRobot $ do++ pause++ -- Let's open Vim!+ mapM_ t [_V, _I, _M]+ t _Return++ pause++ -- Enter some text...+ t _I; sleep 1+ _Shift `hold` do+ mapM_ t [_D, _U, _C, _K, _S]+ t _Escape++ pause++ -- Undo and redo+ replicateM_ 3 $ do+ t _U+ t [_Ctrl, _R] -- Alternatively: _Ctrl `hold` tap _R++ pause++ -- Quit+ _Shift `hold` do+ t _Z+ t _Q++ where+ t k = sleep 0.25 >> tap k+ pause = sleep 2
robot.cabal view
@@ -1,5 +1,5 @@ Name: robot-Version: 1.1+Version: 1.2 Synopsis: Simulate keyboard and mouse events Homepage: https://github.com/lfairy/robot License: OtherLicense