Jump to content

SleepUntil - Sleep until condition is met

Recommended Posts

Update 2017-04-21:

  1. Added a timeout
  2. My previous attempt of checking that the function is valid was not working. Added a 1 time function call before entering the While loop to test the function. Now sets error to $SLEEP_UNTIL_INVALID_CALL if the function supplied is does not exist or invalid arguments supplied
  3. Added an @Error value $SLEEP_UNTIL_TIMEOUT_REACHED, set when the condition was not met but timeout reached

Update 2017-04-25:

  1. Thanks to @jguinchfor letting me know about Execute(). Greatly simplified the loop (didn't know that Execute would execute a function call statement)
    Any strings passed to the SleepUntil() function need to be enclosed in " or ' (I.e', SleepUntil("ConsoleWrite('This is a test' & @LF)"))
  2. Adjusted SleepUntil() to use the Execute() function instead

Inspired by a very vague topic, and completely unnecessary, I had fun trying to making this up. A function that will sleep until the conditional statement, or function call statement, provided executes to the condition you want! I know, completely useless!!! It's pretty interesting actually. Instead of having to write multiple while loops per conditions, you just need to use SleepUntil and set your own condition.

Basic syntax:

SleepUntil("$iMyNumber = 100")

Will sleep until the variable in your script $iMyNumber is 100. All conditional operators are supported (=, <>, >=, <=, >, and <). Currently does not support multiple conditions (i.e., $iMyNumber > 100 and $iMyNumber < 1000).

More advanced syntax, using a value returned from a function call:

SleepUntil("TimerDiff(" & TimerInit() & ") > 5000")

Well check the value returned from TimerDiff using the value returned from TimerInit() and stop sleeping once it's > 5000 (5 seconds).

Anyways, better to show through the example.


#include <String.au3>
#include <Array.au3>
#include <GUIConstants.au3>
#include <GuiEdit.au3>
#include "SleepUntil.au3"

AutoItSetOption("GUICloseOnESC", 0)
Global $sName = "Test"
Global $bBool = True
Global $iInt = -1
Global $dDouble = 0.0

Global $sMsg = "Welcome," & @CRLF & _
            "The SleepUntil function can use a function to check against a condition or just a regular conditional statement. " & _
            "I.e. $iValue = 300" & @CRLF & "A basic conditional example would be" & @CRLF & @TAB & _
            "Global $bWaiting = True" & @CRLF & @TAB & _
            'SleepUntil("$bWaiting <> $bWaiting")' & @CRLF & _
            "This is a good example of having some kind of global flag where you want to wait until the user triggers the flag to not be true" & @CRLF & @CRLF & _
            "The first set of examples will use function calls to compare against the condition value." & @CRLF & _
            "First example calls GUIGetMsg using the with no arguments and sleeps until the value returned is " & _
            "$GUI_EVENT_CLOSE" & @CRLF & @CRLF & _
            "Syntax for the function call for SleepUntil is like normal:" & @CRLF & _
            'SleepUntil("FunctionName(Argument1, Argument2, ArgumnetN) (Condition Operator) Value' & @CRLF & _
            'Example (Where function call has arguments)' & @CRLF & @TAB & _
            'Global $iTimer = TimerInit()' & @CRLF & @TAB & _
            'SleepUntil("TimerDiff(" & $iTimer & ") >= 5000")' & @CRLF & @CRLF & _
            "Example (Where no arguments are needed for the function)" & @CRLF & @TAB & _
            'SleepUntil("GUIGetMsg() = $GUI_EVENT_CLOSE")' & @CRLF & @CRLF & _
            "The first example will start once you close this window!"

Global $hMain = GUICreate("Introduction", 800, 600, 0, 0, BitOR($WS_SIZEBOX, $WS_MAXIMIZEBOX, $WS_MINIMIZEBOX))
Global $edtEdit = GUICtrlCreateEdit($sMsg, 10, 10, 775, 555, $ES_MULTILINE)
GUICtrlSetBkColor($edtEdit, 0x1F1F1F)
GUICtrlSetColor($edtEdit, 0xF1F1F1)
GUICtrlSetFont($edtEdit, 11, 400, "", "Consolas")

_GUICtrlEdit_SetSel(GUICtrlGetHandle($edtEdit), 0, 0)

; Slep until person running this example script closes the GUI or it reaches the 30 second timeout
SleepUntil("GUIGetMsg() = $GUI_EVENT_CLOSE", 50, 30000)

MsgBox("", "Timer", "Starting the examples. The next sleep will last until 2 seconds have passed")

; Sleep until TimerDif(Timer Created) > 2000
ToolTip("Sleeping until 2 seconds has passed", 0, 0)

SleepUntil("TimerDiff(" & TimerInit() & ") >= 2000")

MsgBox("", "Timer", "2 Seconds has passed. Met condition and left sleep function")

; Sleep until the call to ConsoleWrite3Times is >= 3
ToolTip("Sleeping until the function ConsoleWrite3Times() as been called three times", 0, 0)
SleepUntil("ConsoleWrite3Times('This is a test!') >= 3", 500)

MsgBox("", "Print 3 Times", "Did ConsoleWrite 3 times. Met condition needed and left sleep function")

MsgBox("", "Next", "Next SleepUntil examples can be met by pressing the {F1} Key to trigger the conditions" & @CRLF & _
                    "Next example will sleep until $sName = InunoTaishou")

HotKeySet("{F1}", SetName)
; Sleep until user presses {F1} and changes $sName = InunoTaishou
ToolTip("$sName = " & $sName, 0, 0)
SleepUntil("$sName = 'InunoTaishou'", 100)

MsgBox("", $sName, "Name has been updated to " & $sName & ". Met condition needed and left sleep function" & @CRLF & _
                    "Next example will sleep until $bBool <> True")

; Sleep until user preses {F1} and $bBool <> True
ToolTip("$bBool = " & $bBool, 0, 0)
SleepUntil("$bBool <> " & $bBool, 100)

MsgBox("", $bBool, "Bool has been updated to " & $bBool & ". Met condition needed and left sleep function" & @CRLF & _
                    "Next example will sleep until $iInt > 0")

; Sleep until user presses {F1} and $iInt > 0
ToolTip("$iInt = " & $iInt, 0, 0)
SleepUntil("$iInt > 0", 100)

MsgBox("", $iInt, "Int has been updated to " & $iInt & ". Met condition needed and left sleep function" & @CRLF & _
                    "Next example will sleep until $dDouble = 99.99")

; Sleep until user presses {F1} and $dDouble = 99.99
ToolTip("$dDouble = " & $dDouble, 0, 0)
SleepUntil("$dDouble = 99.99", 100)

MsgBox("", $dDouble, "Double has been updated to " & $dDouble & ". Met condition needed and left sleep function" & @CRLF & _
                    "Next example will sleep until function Print is called with the msg provided")

Local $sMsgToPrint = InputBox("Message", "What message should be used for ConsoleWrite?", "This is a the default msg!")
SleepUntil("Print('" & $sMsgToPrint & "', " & InputBox("Times?", "How many times to print " & $sMsgToPrint & "?", 10) & ") = '" & $sMsgToPrint & "'")
MsgBox("", "Print", "Congrats! That's all the examples I have")

Func ConsoleWrite3Times($sMsg)
    Local Static $iPrint = 0
    $iPrint += 1
    ConsoleWrite("[" & $iPrint & "] " & $sMsg & @LF)
    Return $iPrint

Func Print($sMsg, $iTimes)
    If ($iTimes < 1) Then $iTimes = 1
    For $i = 1 to $iTimes
        ConsoleWrite($sMsg & @LF)
    Return $sMsg

Func SetName()
    $sName = "InunoTaishou"
    HotKeySet("{F1}", SetBool)
EndFunc   ;==>SetName

Func SetBool()
    $bBool = False
    HotKeySet("{F1}", SetInt)
EndFunc   ;==>SetBool

Func SetInt()
    $iInt = 100
    HotKeySet("{F1}", SetDouble)
EndFunc   ;==>SetInt

Func SetDouble()
    $dDouble = 99.99
EndFunc   ;==>SetDouble


#include <String.au3>

; #AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w- 4 -w 5 -w 6 -w- 7

; #CURRENT# =====================================================================================================================
; SleepUntil:               Sleeps until the condition statement supplied meets the requirements
; ===============================================================================================================================

; #FUNCTION# ====================================================================================================================
; Name ..........: SleepUntil
; Description ...: Sleeps until the condition supplied is met.
; Syntax ........: SleepUntil($sConditionStatement[, $iTime = 100[, $iTimeout = Default]])
; Parameters ....: $sConditionStatement     - String formatted condition statement
;                  $iTime                   - (Optional) Time (In Milliseconds) to sleep between each check of the condition
;                  $iTimeout                - (Optional) Timeout (In Milliseconds) to stop sleeping if condition not met
; Return values .: Success - Returns True when the condition is met
;                  Failure - Returns False and Sets the @Error flag
;                            -100 ($SLEEP_UNTIL_INVALID_EXECUTE): Function supplied does not exist or parameters supplied do not match
;                                                              the function called
;                            -101 ($SLEEP_UNTIL_TIMEOUT_REACHED): Timeout was reached but the condition was not met
; Author ........: InunoTaishou, jguinch for letting me know about Execute()
;                  Thanks jguinch! Greatly simplified the script
; Remarks .......: The $sConditionStatement parameter can be a simple $vVar = Value or can use the value returned from a function call
;                  to sleep.
;                  Proper syntax for a function call is a normal AutoIt function call: "MsgBox(0, 'Title', 'Message')"
; Example .......: Yes
; ===============================================================================================================================
Func SleepUntil($sConditionStatement, $iTime = 100, $iTimeout = Default)
    Local $iTimer = ($iTimeout ? TimerInit() : Null)
    While (Not Execute($sConditionStatement))
        If (@Error) Then Return SetError($SLEEP_UNTIL_INVALID_EXECUTE, 0, False)
        If ($iTimeout and TimerDiff($iTimer) >= $iTimeout) Then Return SetError($SLEEP_UNTIL_TIMEOUT_REACHED, 0, False)
    Return True
EndFunc   ;==>SleepUntil

Edit: Did a test call to the function to make sure it's valid. checking for the 0xDEAD and 0xBEEF errors inside the while loops wasn't working since the _EvalCondition was being called right after it.

Edit: Forgot about the _ that can be used in function calls. Added the _ to the StringRegExp

Edited by InunoTaishou
Link to post
Share on other sites

After looking at that same topic, I was almost inspired to do my own SleepUntil function, but figured it was hardly worth it really, as it would have just been milliseconds based. Many of us I am sure, have such things in some of our scripts/programs, as it is pretty simple to whip it up on the fly.

Your script though is something else altogether, so kudos to you for all that work and ingenuity. :thumbsup:

Thanks for sharing. :D

Make sure brain is in gear before opening mouth!
Remember, what is not said, can be just as important as what is said.


What is the Secret Key? Life is like a Donut

If I put effort into communication, I expect you to read properly & fully, or just not comment.
Ignoring those who try to divert conversation with irrelevancies.
If I'm intent on insulting you or being rude, I will be obvious, not ambiguous about it.
I'm only big and bad, to those who have an over-active imagination.

I may have the Artistic Liesense ;) to disagree with you. TheSaint's Toolbox (be advised many downloads are not working due to ISP screwup with my storage)


Link to post
Share on other sites

Thanks, it helped kill a couple of hours lol

I kind of want to redo the syntax and make it exactly like a regular autoit conditional statement. Like

SleepUntil("TimerDiff($iTimer) >= 2000 and Not $bRunning")

And I started doing this, but it got very complex. What if the conditional statement start with a variable instead of a function? How do I parse a string like that? I tried looking into how to make your own language to see how they execute something like this, but it looks very complex and time consuming. Maybe in the future.

I tried to make it a bit forgiving in the syntax too. I did mix function call syntax (Func = TimerDiff and Func: ConsoleWrite3Times). That should work for |Args = {Arg1}| and |Args: {Arg1}| or even just doing |{Arg1}, {Arg2}| That's why I went with the Regular Expression to capture the valid function characters (_a-zA-Z0-9). And then validate the function before going into the While loop.

Link to post
Share on other sites

Updated, added a timeout. Also noticed the way I was checking if the function (and arguments) was valid wasn't actually working. Changed it by doing a one time function call before entering the while loop.

New @Error values are $SLEEP_UNTIL_INVALID_CALL (Function doesn't exist or arguments supplied are incorrect) and $SLEEP_UNTIL_TIMEOUT_REACHED (timeout reached but the condition was not met)

Link to post
Share on other sites

Updated, thanks to @jguinch for letting me know the Execute() function can take a regular AutoIt expression and evaluate it! Simplified the SleepUntil function a lot. Will also allow me a much easier way to allow multiple conditions in a statement (condition1 and contidion2 or (condition3 and condition4)). When I decide to get around to doing that.... lol

Edited by InunoTaishou
Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By Vikramjeet
      I have a script that reads the last 7 lines of an active log file. By active I mean that the file is being written while the script runs. 
      How can I make the script to
      1- keep reading the last 7 lines till a specific text appears.
      2- Once the specific text appears, then get out of the loop and proceed to other tasks
      Thank You
    • By simonc8
      I have a script which executes sleep for a couple of hours then carries out instructions. Does the running AutoIt script prevent the computer from entering sleep mode during this time? If not, is there something I can add to the AutoIt script to keep the computer awake?
      Grateful for advice.
    • By mistersquirrle
      TL;DR: Anyway to bypass built in sleep on TrayGetMsg() and GUIGetMsg() ?
      I'm currently working on a project that does some heavy array/ GDI+ processing, which depending what I have it do can take between 4s - 1min. During this time, I'd like to have the Tray icon (mainly, possibly also the GUI) for the program be responsive, so that if someone wanted to change actions or exit the script during this, they can without closing the process.
      Currently I have my TrayGetMsg and GUIGetMsg captures in my main program loop, working great, and once I go into the array/ GDI+ functions I tried switching it to an AdlibRegister call, unregistering it once completed. The problem with this is that it's adding ~10-20% more time into those functions, which I'd like to avoid. As I understand it, and from the helpfile: "This function automatically idles the CPU when required so that it can be safely used in tight loops without hogging all the CPU." From what I've read/ seen/ tested, this adds a 10ms sleep into the calls. I would rather avoid that sleep all together.
      The array/ GDI+ function that I'm doing peg the CPU at 100% (for its core) anyways, so that's not a concern of mine. My only concern for this is speed (and having things be responsive to other actions).
      Here's an example:
      Local $iBlockSize = 20, $iWidth = 1920, $iHeight = 1080, $aBigArray[$iWidth * $iHeight], $iPercentDone, $sLastMsg Local $aSmallerArray[Int(Ceiling($iWidth / $iBlockSize)) * Int(Ceiling($iHeight / $iBlockSize))] Local $sAdlib[] = ["Registered: ", "UnRegistered: ", "Registered to _FakeTray: "], $timer, $iIndexLength = UBound($aBigArray) Local $ixBlocks = Int(Ceiling($iWidth / $iBlockSize)), $iBlockIndex, $iBlockX, $iBlockY For $j = 0 To 2 If $j = 0 Then AdlibRegister("_CheckTray", 100) ElseIf $j = 1 Then AdlibUnRegister("_CheckTray") ElseIf $j = 2 Then AdlibRegister("_FakeTray", 100) EndIf $timer = TimerInit() For $i = 0 To $iIndexLength - 1 ; Loop through $aBigArray $aBigArray[$i] = Random(1, 10, 1) $iPercentDone = Floor(($i / $iIndexLength * 100)) ; Hopefully quick maths to get progress If $sLastMsg <> "We are " & $iPercentDone & "% done" Then ; Check if we're on a new percent $sLastMsg = "We are " & $iPercentDone & "% done" ; If so, update the msg ToolTip($sLastMsg, 0, 0) ; And display the current progress EndIf $y = Floor($i / $iWidth) ; Convert index to Y coordinate $x = Floor($i - ($y * $iWidth)) ; Convert index to X coordinate $iBlockX = Floor($x / $iBlockSize) ; Convert X coord to xBlock coord $iBlockY = Floor($y / $iBlockSize) ; Convert Y coord to yBlock coord $iBlockIndex = Int($iBlockX + ($iBlockY * $ixBlocks)) ; Convert into a blockIndex ;~ If Mod($i, 10000) = 0 Then ;~ ConsoleWrite($iBlockIndex & " - " & $i & @CRLF) ;~ EndIf $aSmallerArray[$iBlockIndex] += Int($aBigArray[$i]) ; Add into $aSmallerArray Next ConsoleWrite("Time to run with Adlib" & $sAdlib[$j] & TimerDiff($timer) & @CRLF) Next Func _CheckTray() Switch TrayGetMsg() Case "Meow" Return Case "Woof" Return EndSwitch EndFunc ;==>_CheckTray Func _FakeTray() Local $sMeow = "Oink" Switch $sMeow Case "Meow" Return Case "Woof" Return EndSwitch EndFunc ;==>_FakeTray Exit On my system, this takes ~1 minute to run, output:
      Time to run with AdlibRegistered: 19649.335 Time to run with AdlibUnRegistered: 16264.4124 Time to run with AdlibRegistered to _FakeTray: 16860.1283 >Exit code: 0 Time: 53.92 As you can see, it's ~20.8% faster without the Adlib check, and ~16.5% faster using a (hopefully) reproduction of TrayGetMsg() without the built in sleep. These timings vary, but it's consistently much faster without the TrayGetMsg() sleep (unless it's just that slow). I've used the OnEventModes, and those also slow down performance, more so than just using the GetMsgs, so those are out (but effective, and pretty easy to use).
    • By naru
      I have script Like This :
      $var = Ping("www.google.com")
      If not @error Then
      WinActivate ( "testapp")
      ControlClick ( "testapp", "", "[Savetest]")
      ControlSend ( " :: Gujarat TPDS  - eFPS :: Version -  - [eFPS Bill]", "", "[NAME:btnSavebyFP]", "{enter}")
      WinWait(":: Aadhar/EID/Verification Number Entry ::")
      ControlClick(":: Aadhar/EID/Verification Number Entry ::", "", "[NAME:btnNext]")
      If WinExists ("Aadhar : Length Check") Then
         ControlClick("Aadhar : Length Check", "", "[CLASS:Button; INSTANCE:1]")
         ControlSend(":: Aadhar/EID/Verification Number Entry ::", "", "[NAME:txtAadharNumber]", "{backspace}")
         ControlSend(":: Aadhar/EID/Verification Number Entry ::", "", "[NAME:txtAadharNumber]", "^v")
         ControlClick(":: Aadhar/EID/Verification Number Entry ::", "", "[NAME:btnNext]")
         WinWait(" :: Barcoded Ration Card Members - Biometric Verification/Check Utility ::")
         ControlSend("[Class:WindowsForms10.Window.8.app.0.378734a]", "", "[NAME:PictureBox2]", "{tab} {enter}")
         RunWait("rasdial /disconnect", "", @SW_HIDE) ; Stop connect from start
         RunWait("rasdial Internet", "", @SW_HIDE) ; Connect again
      WinWait(" :: Barcoded Ration Card Members - Biometric Verification/Check Utility ::", "", 1)
      ControlSend("[Class:WindowsForms10.Window.8.app.0.378734a]", "", "[NAME:PictureBox2]", "{tab} {enter}")
      RunWait("rasdial /disconnect", "", @SW_HIDE) ; Stop connect from start
      RunWait("rasdial Internet", "", @SW_HIDE) ; Connect again
         #include <MsgBoxConstants.au3>
         MsgBox($MB_TOPMOST, "Connection Status", "Internet is not Connected")
    • By naru
      How can i add sleep command using internet speed.
      If my internet speed is 40-50Kbps then sleep for 5 seconds,
      If my internet speed is 30-40Kbps then sleep for 4 seconds,
      If my internet speed is 20-30Kbps then sleep for 3 seconds.

      *Sleep command used bitween my costom script, Example,
      RunWait("rasdial /disconnect", "", @SW_HIDE) ; Stop connect from start
      RunWait("rasdial Internet", "", @SW_HIDE) ; Connect again
  • Create New...