How can Sikuli be used to wait for a button for a long time, with perhaps some maintenance task in between? - automation

I have a webpage where I am waiting for a button to appear, and when it appears I would like to click it. The button is on a timer and may take as long as an hour to appear. Also, if the button takes longer than a certain length of time to appear, I'd like to move the mouse (otherwise the website will log me out automatically).
So, to wait for a button to appear I devised this Sikuli script:
button = "button.png"
while(1):
if exists(button):
print("found it")
click(button)
break
else:
print("wait longer")
wait(button,30*60)
# do a regular task
print "all done!"
The above does not seem to be functional. If the button is on screen, the script will find it... However, if it has to wait it will simply time out quickly with a FindFailed exception (on the click() even though the button does not exist on screen). I considered writing a handler, but seems like overkill.
What am I doing wrong and what is the best way to wait a long period for a visual event like this?

Some other thoughts for you...
while(1):
wait(Button, 30*60) # This will spinlock for 30 minutes for the button to appear
if exists(Button):
hover(Button) # Debug statement allowing user to see what Sikuli has matched to
click (Button)
else:
mouseMove(Location(50,100))
mouseMove(Location(50,200))
Links:
wait
mouse movement link
Location

Maybe Sikuli recognizes something that looks quite your button, and tries to click it.
If you right click in the IDE your button pattern, you can fine tune the tolerance level for recognition. Try to cut the image exactly around your button and increase the value to be more precise.
I suggest you to read this tutorial
http://doc.sikuli.org/tutorials/surveillance/surveillance.html
and to set up a event handler to manage your button when it appears
http://doc.sikuli.org/region.html#Region.onAppear
http://doc.sikuli.org/region.html#observingvisualeventsinaregion
It is not much code to write.
You can get a nice example with full source code in Sikuli's Blog here
http://sikuli.org/blog/2011/08/15/sikuli-plays-angry-birds-on-google-games/
I think you can just set up your handlers and go with
observe(FOREVER)

If you want sikuli to do stuff while your waiting for an image i would use the onAppear(pic, function) and observe(FOREVER, true) methods this is how it works
event = Sikuli.event
def function(event):
click(yourButton.png)
onAppear(picYourWaitingFor.png, function)
observe(FOREVER, true)
basically what this does is onAppear will continuously scan the screen for picYourWaitingFor.png. sikuli continues execution after words so it's scanning while its working. on the appearance of said pic it will jump to the function you put down as the second parameter of onAppear.

I have this same issue as described. Its not about waiting forever. And Observe won't work either, because that does watch forever. Think about wanting to check for event only for a certain period of time say 60 seconds. If it doesn't occur, move on. This could be happening in a specific series of events. If the image doesn't appear in the 60 seconds, move on to do another series.
wait(image,60)
...will crash after 60 seconds if it doesn't find the image, which isn't what is wanted at all in my case.
So I did something like this:
attempt = 1
count=0
while attempt:
if exists(image):
attempt=0
else:
count=count+1
if count>60:
attempt=0
else:
wait(1)
Probably a better way and doesn't give an exact time, but approach doesn't crash the script.
You could also try: except it.. Should be shorter.

Related

Send vs SendInput Problems

I've tried many variations of a script whose purpose is to send rapid clicks when either mouse button is held down. In my own script I have both left and right click loops but here is the simplest version I tried:
SetKeyDelay, -1
$RButton::
While GetKeyState("RButton", "P") {
Send, {RButton}
}
Returm
When using this, I get about 20 clicks per second. However, I would like to achieve 30 or so. What I infer from this, is that the send command has a 50 ms delay (1000ms/20 clicks). I would also like to use the {Blind} modifier but that slows it down even more (to about 16 clicks per second).
The obvious answer I think is to use SendInput, and I was able to achieve desired clicks per second using SendInput. However, it came with undesirable side effects. Namely, the key buffering is very unwanted in my use case. In addition, no matter if I used a while loop with GetKeyState or a Button up configuration with SetTimer and Gosub, the right click and left click loops would get stuck occasionally (interference?). The loops getting stuck was not a problem with Send as I'm able to put the loops for each mouse button in separate scripts. When I do that with SendInput, it lowers the clicks per second drastically.
I have also tried SendPlay and SendEvent to no success. Also, I tried using V2 although most of my testing has been in 1.1.35.00.
I don't think it is CPU or memory related as SendInput is able to hit the clicks per second goal of 30 and both CPU and memory stay at about 60%. I could be wrong here though. I also don't think the application I am using is restricting the click rate for the same reason of it being able to register 30 with SendInput.
I greatly appreciate anyone who takes the time to read this! Happy Holidays!
Expecting about 30 clicks per second with both right and left mouse buttons being held down.
I've tried:
Send, SendInput, SendPlay, SendEvent
#MaxThreadsPerHotkey, 2 #SingleInstance Force
SetKeyDelay, -1 SetBatchLines, -1
While loop with GetKeyState as condition and also tried SetTimer and Gosub with individual functions
V2 and 1.1.35.00.
Resulted always in a maximum of 16 clicks per second with Send
With SendInput, user keystrokes sent while clicking were always buffered, which was undesired. As well as the loops getting stuck occassionally

Pyautogui automation - Identify waiting time issue

I am trying to automate a task with pyautogui. After a click program starts loading for few second and this time varies every time. Th script has to wait for that time to perform next operation/click. I was thinking to take the screenshot but in screenshot mouse cursor is not showing and loading is shown on the cursor itself. what could be the best possible way to identify this loading time and stop the script for that seconds before performing next instructions.
You provided vague details, but I'll try to provide a way given what I understood.
So basically when you click, a program starts loading, and you want to find out when the program finished loading so you can execute the next part of the script?
If the program was gui based, I'm pretty sure, there are pixel changes before loading and after loading, you could for example use pyautogui.pixelMatchesColor(x, y, (R, G, B)) on a loop, to check whether a pixel in the program has changed, this could mean that the program finished loading.

Sikuli click is not effect

I'm using SikulixIDE 1.1.0 to write a script playing Yugioh game (run on Windows 10 x64).
See the main screen:
I start the game manually and then run the script as below:
switchApp("Yu-Gi-Oh! PC")
click("1477213591920.png")
My expectation is that the link named "DUEL MODE" is clicked to go to the next screen. The cursor always moves to that link, but sometimes it works, sometimes does not.
I check the log and see that Sikuli has sent click command but for some reason, the game not accept it. This is the log:
[log] App.focus: [8020:Yu-Gi-Oh!]
[log] CLICK on L(687,488)#S(0)[0,0 1366x768]
I've already tried:
doubleClick instead of click
sleep a few seconds
hover and click
But all do not work, neither.
I would expect that some of the things you have tried will help but if that's not the case you will need to identify whether the button was actually triggered or not. To do that you have to capture the next screen or any part of it that uniquely identifies it. Then you will use it a loop with a predefined number of attempts and some wait time between them and click more than once if the click didn't work. So generally something like that (pseudo code):
attempts = 3
for attempt in attempts:
click(button)
if (nextScreen is available):
break
sleep(time)
I know it's been a while but I ran into a similar problem recently.
The image was found but the click didn't work.
I'm also working on Windows 10 x86_64.
The solution was simply to execute the program as administrator.
Don't know why but now it's working..
I also had to use the double click instead of simple click for some patterns.
In adition to Eugene S Answers, if you are using SikuliX, you can try to Run in Slow Motion. Also, if the image have some effects (like brightness), you can try to use Pattern inside of exists():
if exists(Pattern("DualMode.png").similar(0.6), time_in_seconds):
click(Pattern("DualMode.png").similar(0.6))
By default, the similar() value is 0.8, so if the image have some effect and for example, the color change every second, you can set a lower value between 0 and 1.
PS: Don't forget to put the pattern inside if exists and click, because if you don't put inside of click(), could throw an Image not found error message.

Mouse button hotkeys only work once, not continual

I need to make an AutoHotkey script that performs some action when and while the mouse button is pressed, then finishes when the mouse button is released.
For (a very simplified) example:
LButton::
MouseGetPos x,y
MsgBox %x%-%y%
LButton Up::MsgBox Foobar
Replacing the LButton with a keyboard key (e.g., LWin) makes it work correctly and moving the mouse cursor updates as expected while the key is held down, but using the mouse button only performs the LButton action one time. I need the hotkey action to continue occurring until the button is no longer being held.
After a bunch of query-term tweaking, I found a page that gives sample scripts for autofire.
I wasn’t sure that was what I wanted (even though it made sense) because as I said, the sample script already works just fine for keys, but I gave it a shot anyway. I tweaked the sample a bit and now it works as desired. (Actually, it is very similar to a solution I had already been using, but now it absorbs the button event, which solves the underlying problem that I led me to trying the aforementioned script.)
Hopefully I picked good keywords in this post so that anyone else who finds themselves in the same situation can find the/a solution faster than I did.
#SingleInstance,force
CoordMode, Mouse, Screen
LButton::
While GetKeyState("LButton","p") {
MouseGetPos x,y
Tooltip %x%/%y%
Sleep 75
}
return
LButton Up::
Tooltip Foobar
return

What is alternative of "QDDisplayWaitCursor"?

I am trying to display wait cursor (spinning rainbow wheel) by using "QDDisplayWaitCursor" function, but I get a warning that "QDDisplayWaitCursor" is deprecated, however everything runs fine but I would like to replace it with proper alternative of this function but I didnt find any google result and also in apple docs.
The best thing to do is to use something else1:
The spinning wait cursor is displayed automatically by
the window server when an application
cannot handle all of the events it
receives. If an application does not
respond for about 2 to 4 seconds, the
spinning wait cursor appears. You
should try to avoid situations in your
application in which the spinning wait
cursor will be displayed.
Instead use progress indicators, in a window- or application-modal way if neccessary.