#!/bin/sh #=============================================================================== # FILE: libcvautomation_funcs # # USAGE: . mosaic_testing_funcs # # DESCRIPTION: # # OPTIONS: --- # REQUIREMENTS: --- # BUGS: --- # NOTES: --- # AUTHOR: Bradlee Speice, bspeice@uncc.edu # ORGANIZATION: # CREATED: 06/19/2012 11:35:20 AM EDT # REVISION: --- #=============================================================================== #------------------------------------------------------------------------------- # This script file is meant to be sourced and then used for driving libcvautomation. # It provides access to a lot of common macros, like clicking # an area of the screen based on an image. #------------------------------------------------------------------------------- #------------------------------------------------------------------------------- # NOTE: Due to the way loops work in this script, you may NOT use spaces # in file names. #------------------------------------------------------------------------------- #Make sure all the programs we will need are in the right place CVAMATCH=`which cva-match` || echo "Could not find the cva-match program..." &>2 #Needed for image recognition CVAINPUT=`which cva-input` || echo "Could not find the cva-input program..." &>2 #Needed to manipulate mouse and keyboard INT_MAX=2147483647 #Some program-wide configs SEARCH_METHOD=0 #CV_TM_SQDIFF TOLERANCE=2250000 USE_SANE_TOLERANCE="" #Set to non-null to enable sane tolerance matching #ex: USE_SANE_TOLERANCE="yes" USE_CENTER="yes" #Set to null to disable center-of-image matching #ex: USE_CENTER="" USE_WAIT="yes" #Set to null to disable waiting before an action #ex: USE_WAIT="" TIMEOUT=5 #Quick trick to allow for easy redirection of output #OUTFILE=`mktemp`; echo "Logfile: " $OUTFILE OUTFILE=/dev/null #ERRFILE=`mktemp`; echo "Error file: " $ERRFILE ERRFILE=/dev/null out () { echo "`date`: $@" >> $OUTFILE } err () { echo "`date`: $@" >> $ERRFILE } #------------------------------------------------------------------------------- # Begin testing macros #------------------------------------------------------------------------------- #--- FUNCTION ---------------------------------------------------------------- # NAME: mouse_down # DESCRIPTION: Push the mouse button down, and leave it there. # PARAMETERS: # RETURNS: #------------------------------------------------------------------------------- mouse_down () { if [ -n "$1" ]; then eval $CVAINPUT -s 'mousedown "$1"' >> $OUTFILE else eval $CVAINPUT -s 'mousedown 1' >> $OUTFILE fi return $? } # ---------- end of function mouse_down ---------- #--- FUNCTION ---------------------------------------------------------------- # NAME: mouse_up # DESCRIPTION: Release a mouse button # PARAMETERS: # RETURNS: #------------------------------------------------------------------------------- mouse_up () { if [ -n "$1" ]; then eval $CVAINPUT -s 'mouseup "$1"' >> $OUTFILE else eval $CVAINPUT -s 'mouseup 1' >> $OUTFILE fi return $? } # ---------- end of function mouse_up ---------- #--- FUNCTION ---------------------------------------------------------------- # NAME: mouse_click # DESCRIPTION: Click the mouse where it is currently located # PARAMETERS: # RETURNS: #------------------------------------------------------------------------------- mouse_click () { if [ -n "$1" ]; then eval '$CVAINPUT -s "mouseclick \"$1\"" >> $OUTFILE' else eval '$CVAINPUT -s "mouseclick 1" >> $OUTFILE' fi return $? } # ---------- end of function mouse_click ---------- #--- FUNCTION ---------------------------------------------------------------- # NAME: mouse_click_xy # DESCRIPTION: Click a specific point on the screen # PARAMETERS: x-location, y-location # RETURNS: #------------------------------------------------------------------------------- mouse_click_xy () { if [ -z "$1" ]; then out "Did not specify an X location, assuming (0, 0)" X_LOC=0 Y_LOC=0 else X_LOC=$1 fi if [ -z "$2" ]; then out "Did not specify a Y location, assuming ($1, 0)" else Y_LOC=$2 fi out "mouse_click_xy: " $X_LOC $Y_LOC if [ -n "$3" ]; then eval '$CVAINPUT -s "mousexy $X_LOC $Y_LOC" -s "mouseclick $3" >> $OUTFILE' else eval '$CVAINPUT -s "mousexy $X_LOC $Y_LOC" -s "mouseclick 1" >> $OUTFILE' fi return $? } # ---------- end of function mouse_click_xy ---------- #--- FUNCTION ---------------------------------------------------------------- # NAME: mouse_click_rxy # DESCRIPTION: Click a point on the screen relative to where the mouse is at # PARAMETERS: X increment, Y increment # RETURNS: #------------------------------------------------------------------------------- mouse_click_rxy () { if [ -z "$1" ]; then out "Did not specify an X increment, assuming (0, 0)" X_INC=0 Y_INC=0 else X_INC=$1 fi if [ -z "$2" ]; then out "Did not specify a Y increment, assuming ($X_INC, 0)" else Y_INC=$2 fi out "mouse_click_rxy: " $1 $2 if [ -n "$3" ]; then eval '$CVAINPUT -s "mouserxy $1 $2" -s "mouseclick 1" >> $OUTFILE' else eval '$CVAINPUT -s "mouserxy $1 $2" -s "mouseclick 1" >> $OUTFILE' fi return $? } # ---------- end of function mouse_click_rxy ---------- #--- FUNCTION ---------------------------------------------------------------- # NAME: mouse_click_image # DESCRIPTION: Click a point based on a screenshot # PARAMETERS: Location of screenshot, optional index to use if multiple # matches are found # RETURNS: #------------------------------------------------------------------------------- mouse_click_image () { RETURN_CODE=255 COMMAND_LINE="" if [ -z "$1" ]; then err "Did not give a base image..." return 255 fi out "mouse_click_image: matching $@" if [ -n "$USE_CENTER" ]; then center="c" else center="" fi if [ -n "$USE_SANE_TOLERANCE" ]; then TOLERANCE_OPTION="-o" else TOLERANCE_OPTION="-t" fi if [ -z "$TOLERANCE" ]; then TOLERANCE=$INT_MAX fi if [ -n "$USE_WAIT" ]; then #Alternate between each image until a match is found, or we loop $TIMEOUT times #This is a bit weird, since we need to lower the TIMEOUT value for the "waitfor" #function, and then restore it at the end. OLD_TIMEOUT=$TIMEOUT TIMEOUT=1 #I don't like this syntax, but 'for loop in {1..$OLD_TIMEOUT}' doesn't work for loop in `seq 1 $OLD_TIMEOUT` do for x in "$@" do CVA_RETURN=`waitfor "$x"` if [ $CVA_RETURN -lt $RETURN_CODE ]; then RETURN_CODE=$CVA_RETURN fi if [ $CVA_RETURN -eq 0 ]; then #We found the image, click it TIMEOUT=$OLD_TIMEOUT eval "$CVAINPUT $TOLERANCE_OPTION $TOLERANCE --search-method $SEARCH_METHOD -s 'i${center}mouseclick \"$x\"' >> $OUTFILE" return $? fi done done #We'll get here if we don't find a match TIMEOUT=$OLD_TIMEOUT else eval "$CVAINPUT $TOLERANCE_OPTION $TOLERANCE --search-method $SEARCH_METHOD -s 'i${center}mouseclick \"$x\"' >> $OUTFILE" CVA_RETURN=$? if [ $CVA_RETURN -lt $RETURN_CODE ]; then RETURN_CODE=$CVA_RETURN fi fi return $RETURN_CODE } # ---------- end of function mouse_click_image ---------- #--- FUNCTION ---------------------------------------------------------------- # NAME: mouse_rightclick_image # DESCRIPTION: Exactly like click_i, but click the right mouse button # PARAMETERS: # RETURNS: #------------------------------------------------------------------------------- mouse_rightclick_image () { out "mouse_rightclick_image: $@" mouse_hover_image "$@" && click 3 } # ---------- end of function mouse_rightclick_image ---------- #--- FUNCTION ---------------------------------------------------------------- # NAME: mouse_doubleclick # DESCRIPTION: Click the mouse twice # PARAMETERS: # RETURNS: #------------------------------------------------------------------------------- mouse_doubleclick () { out "mouse_doubleclick: $1" if [ -n "$1" ]; then mouse_click "$1" && mouse_click "$1" else mouse_click && mouse_click fi } # ---------- end of function mouse_doubleclick ---------- #--- FUNCTION ---------------------------------------------------------------- # NAME: mouse_doubleclick_xy # DESCRIPTION: Click the mouse twice on a specific location # PARAMETERS: # RETURNS: #------------------------------------------------------------------------------- mouse_doubleclick_xy () { if [ -z "$1" ]; then err "Did not specify an X location, assuming (0, 0)" X_LOC=0 Y_LOC=0 else X_LOC=$1 fi if [ -z "$2" ]; then err "Did not specify a Y location, assuming ($1, 0)" else Y_LOC=$2 fi out "mouse_doubleclick_xy $X_LOC $Y_LOC" if [ -n "$3" ]; then mouse_click_xy "$X_LOC" "$Y_LOC" "$3" && mouse_click "$3" else mouse_click_xy "$X_LOC" "$Y_LOC" && mouse_click fi return $? } # ---------- end of function mouse_doubleclick_xy ---------- #--- FUNCTION ---------------------------------------------------------------- # NAME: mouse_doubleclick_rxy # DESCRIPTION: Click the mouse twice on a relative location # PARAMETERS: # RETURNS: #------------------------------------------------------------------------------- mouse_doubleclick_rxy () { if [ -z "$1" ]; then err "Did not specify an X increment, assuming (0, 0)" X_INC=0 Y_INC=0 else X_INC="$1" fi if [ -z "$2" ]; then err "Did not specify a Y increment, assuming ($X_INC, 0)" else Y_INC="$2" fi out "doubleclickr_xy: $X_INC $Y_INC" if [ -n "$3" ]; then mouse_clickr_xy "$X_INC" "$Y_INC" "$3" && mouse_click "$3" else mouse_clickr_xy "$1" "$2" && mouse_click fi return $? } # ---------- end of function mouse_doubleclick_rxy ---------- #--- FUNCTION ---------------------------------------------------------------- # NAME: mouse_doubleclick_image # DESCRIPTION: Double-click an image - moves to image first and then # executes a double-click to make sure that it is # compatible with multiple image arguments # PARAMETERS: # RETURNS: #------------------------------------------------------------------------------- mouse_doubleclick_image () { out "mouse_doubleclick_image: $@" mouse_hover_image "$@" && mouse_click && mouse_click } # ---------- end of function mouse_doubleclick_image ---------- #--- FUNCTION ---------------------------------------------------------------- # NAME: image_location # DESCRIPTION: Get the location of a subimage in root # PARAMETERS: PNG Filename of sub-image # RETURNS: "X_LOC,Y_LOC" #------------------------------------------------------------------------------- image_location () { COMMAND_LINE="" if [ -z "$1" ]; then err "Did not give a base image..." return 255 fi #Build the command line arguments for x in "$@" do COMMAND_LINE+="-s \"$x\" " done #Find our sub-image if [ -n "$USE_SANE_TOLERANCE" ]; then TOLERANCE_OPTION="-o" else TOLERANCE_OPTION="-t" fi if [ -z "$TOLERANCE" ]; then TOLERANCE=$INT_MAX fi if [ -n "$USE_CENTER" ]; then CENTER="--center" else CENTER="" fi MATCH=`$CVAMATCH $TOLERANCE_OPTION $TOLERANCE $CENTER --x-root $COMMAND_LINE` RETURN_CODE=$? out "$MATCH" MATCH=`echo $MATCH | head -n1` if [ x"$MATCH" == "x" ]; then err "Could not find a match between \"$@\" and the root window." return 255 fi IMAGE_NAME=`echo "$MATCH" | cut -d',' -f1` X_LOC=`echo "$MATCH" | cut -d',' -f2` Y_LOC=`echo "$MATCH" | cut -d',' -f3` out "image_location: \"$MATCH\" " "$X_LOC,$Y_LOC,$IMAGE_NAME" echo "$X_LOC,$Y_LOC" return $RETURN_CODE } # ---------- end of function image_location ---------- #--- FUNCTION ---------------------------------------------------------------- # NAME: mouse_hover_xy # DESCRIPTION: Move the mouse to location X Y # PARAMETERS: X_LOC, Y_LOC # RETURNS: #------------------------------------------------------------------------------- mouse_hover_xy () { if [ -z "$1" ]; then err "Did not provide an X location, assuming 0..." X_LOC=0 else X_LOC=$1 fi if [ -z "$2" ]; then err "Did not provide a Y location, assuming 0..." Y_LOC=0 else Y_LOC=$2 fi out "mouse_hover_xy: $X_LOC $Y_LOC" eval '$CVAINPUT -s "mousexy $X_LOC $Y_LOC" >> $OUTFILE' return $? } # ---------- end of function mouse_hover_xy ---------- #--- FUNCTION ---------------------------------------------------------------- # NAME: mouse_hover_rxy # DESCRIPTION: Move the mouse over X and up Y # PARAMETERS: # RETURNS: #------------------------------------------------------------------------------- mouse_hover_rxy () { if [ -z "$1" ]; then err "Did not provide an X increment, assuming 0..." X_INC=0 else X_INC=$1 fi if [ -z "$2" ]; then err "Did not provide a Y increment, assuming 0..." Y_INC=0 else Y_INC=$1 fi out "mouse_hover_rxy: $X_INC $Y_INC" eval '$CVAINPUT -s "mouserxy $X_INC $Y_INC" >> $OUTFILE' return $? } # ---------- end of function mouse_hover_rxy ---------- #--- FUNCTION ---------------------------------------------------------------- # NAME: mouse_hover_image # DESCRIPTION: Move the mouse to the center of image on root window # PARAMETERS: PNG File name # RETURNS: #------------------------------------------------------------------------------- mouse_hover_image () { RETURN_CODE=255 COMMAND_LINE="" if [ -z "$1" ]; then err "Did not give a base image." return 255 fi out "hover_i: $@" if [ -n "$USE_CENTER" ]; then center="c" else center="" fi if [ -n "$USE_SANE_TOLERANCE" ]; then TOLERANCE_OPTION="-o" else TOLERANCE_OPTION="-t" fi if [ -z "$TOLERANCE" ]; then TOLERANCE=$INT_MAX fi if [ -n "$USE_WAIT" ]; then #Alternate between each image until a match is found, or we loop $TIMEOUT times #This is a bit weird, since we need to lower the TIMEOUT value for the "waitfor" #function, and then restore it at the end. OLD_TIMEOUT=$TIMEOUT TIMEOUT=1 #I don't like this syntax, but 'for loop in {1..$OLD_TIMEOUT}' doesn't work for loop in `seq 1 $OLD_TIMEOUT` do for x in "$@" do CVA_RETURN=`waitfor "$x"` if [ $CVA_RETURN -lt $RETURN_CODE ]; then RETURN_CODE=$CVA_RETURN fi if [ $CVA_RETURN -eq 0 ]; then #We found the image, click it eval "$CVAINPUT $TOLERANCE_OPTION $TOLERANCE --search-method $SEARCH_METHOD -s '${center}mouseimage \"$x\"' >> $OUTFILE" TIMEOUT=$OLD_TIMEOUT return $? fi done done #We'll get here if we didn't find a match TIMEOUT=$OLD_TIMEOUT else eval "$CVAINPUT $TOLERANCE_OPTION $TOLERANCE --search-method $SEARCH_METHOD -s '${center}mouseimage \"$x\"' >> $OUTFILE" CVA_RETURN=$? if [ $CVA_RETURN -lt $RETURN_CODE ]; then RETURN_CODE=$CVA_RETURN fi fi return $RETURN_CODE } # ---------- end of function mouse_hover_image ---------- #--- FUNCTION ---------------------------------------------------------------- # NAME: mouse_jiggle # DESCRIPTION: Moves the mouse down-right 1 pixel, and then back - necessary # for activation some widgets # PARAMETERS: # RETURNS: #------------------------------------------------------------------------------- mouse_jiggle () { out "mouse_jiggle" eval '$CVAINPUT -s "mousejiggle" >> $OUTFILE' return $? } # ---------- end of function mouse_jiggle ---------- #--- FUNCTION ---------------------------------------------------------------- # NAME: mouse_scroll_up # DESCRIPTION: Scroll the mouse wheel up one # PARAMETERS: # RETURNS: #------------------------------------------------------------------------------- mouse_scroll_up () { out "mouse_scrollu" eval '$CVAINPUT -s "mousescrollu" >> $OUTFILE' return $? } # ---------- end of function mouse_scroll_up ---------- #--- FUNCTION ---------------------------------------------------------------- # NAME: mouse_scroll_down # DESCRIPTION: Scroll the mouse wheel down one # PARAMETERS: # RETURNS: #------------------------------------------------------------------------------- mouse_scroll_down () { out "mouse_scroll_down" eval '$CVAINPUT -s "mousescrolld" >> $OUTFILE' return $? } # ---------- end of function mouse_scroll_down ---------- #--- FUNCTION ---------------------------------------------------------------- # NAME: mouse_drag_n_drop # DESCRIPTION: Drag one image to another image # PARAMETERS: # RETURNS: #------------------------------------------------------------------------------- mouse_drag_n_drop () { if [ -z "$1" ]; then err "mouse_drag_n_drop: Did not give me an image to drag!" return 255 elif [ -z "$2" ]; then err "mouse_drag_n_drop: Did not give me an image to drag to!" return 255 fi #We have our images to find, hover over the first, mousedown, and then #hover over the other one, and mouseup. mouse_hover_image "$1" if [ $? -ne 0 ]; then err "mouse_drag_n_drop: Could not find image to drag!" else mouse_down 1 mouse_hover_image "$2" || err "mouse_drag_n_drop: Could not find image to drag to!" mouse_up fi } # ---------- end of function mouse_drag_n_drop ---------- #--- FUNCTION ---------------------------------------------------------------- # NAME: key_string # DESCRIPTION: Simulate pressing keys according to $1 # PARAMETERS: String of text as $1 # RETURNS: #------------------------------------------------------------------------------- key_string () { COMMAND_LINE="" if [ -z "$1" ]; then err "Did not give me a string to enter..." return 255 fi #We use $* instead of $@ because they expand a bit differently - # "$*" -> "$1 $2 $3" # "$@" -> "$1" "$2" "$3" COMMAND_LINE="-s 'keystring $*'" out "key_str: \"$*\"" eval "$CVAINPUT $COMMAND_LINE >> $OUTFILE" return $? } # ---------- end of function key_string ---------- #--- FUNCTION ---------------------------------------------------------------- # NAME: key_down # DESCRIPTION: Presses down a key - necessary for stuff like Alt-shortcuts # PARAMETERS: # RETURNS: #------------------------------------------------------------------------------- key_down () { if [ -z "$1" ]; then err "Did not give me a key to press down..." return 255 fi out "key_down: $1" eval '$CVAINPUT -s "keydown $1" >> $OUTFILE' return $? } # ---------- end of function key_down ---------- #--- FUNCTION ---------------------------------------------------------------- # NAME: key_up # DESCRIPTION: Lifts a key up - every key_down should have a key_up # PARAMETERS: # RETURNS: #------------------------------------------------------------------------------- key_up () { if [ -z "$1" ]; then err "Did not give me a key to release..." fi out "key_up: $1" eval "$CVAINPUT -s 'keyup $1' >> $OUTFILE" return $? } # ---------- end of function key_up ---------- #--- FUNCTION ---------------------------------------------------------------- # NAME: key_click # DESCRIPTION: Clicks a single key # PARAMETERS: # RETURNS: #------------------------------------------------------------------------------- key_click () { if [ -z "$1" ]; then err "Did not give me a key to press..." fi out "key_click: $1" eval "$CVAINPUT -s 'keyclick $1' >> $OUTFILE" return $? } # ---------- end of function key_press ---------- #--- FUNCTION ---------------------------------------------------------------- # NAME: wait_for # DESCRIPTION: Wait for an image to be displayed # PARAMETERS: # RETURNS: #------------------------------------------------------------------------------- wait_for () { if [ -z "$1" ]; then err "Did not give me an image to find..." fi out "wait_for: $1" if [ -n "$USE_SANE_TOLERANCE" ]; then if [ -z "$TOLERANCE" ]; then TOLERANCE=$INT_MAX fi eval '$CVAINPUT -o $TOLERANCE --search-method $SEARCH_METHOD --timeout $TIMEOUT -s "waitfor \"$1\"" >> $OUTFILE' else if [ -z "$TOLERANCE" ]; then TOLERANCE=$INT_MAX fi eval '$CVAINPUT -t $TOLERANCE --search-method $SEARCH_METHOD --timeout $TIMEOUT -s "waitfor \"$1\"" >> $OUTFILE' fi RETURN_CODE=$? echo $RETURN_CODE #We don't return here, but rather just pass the return code up - #This makes sure that if the user sets errexit, we don't abort because #multiple images were used, while still keeping the return code. } # ---------- end of function waitfor ---------- #--- FUNCTION ---------------------------------------------------------------- # NAME: notify # DESCRIPTION: Notify the user and pause # PARAMETERS: # RETURNS: #------------------------------------------------------------------------------- notify () { if [ -z "$1" ]; then #Not given any text to display, return an error return 255 fi if [ -n "$DISPLAY" ]; then which zenity &> /dev/null #If zenity isn't found, we don't want to go to a read prompt - #the user may not be running this from a terminal. if [ $? -eq 0 ]; then zenity --info --text="$@" fi else read -p "$@" fi } # ---------- end of function notify ----------