Pause While loop by hotkey - while-loop

I want to pause an AutoIt script containing a While loop and some functions. But I am only able to close the script on HotKeySet(). How can I pause it?
The script checks for changes on a part of screen (x,y coordinates are set in a config file) and takes screenshots after playing an alert sound. It doesn't stop the While loop when pushing the pause button. But closing the program works. Here is my code:
Global $Paused, $counter = 0
HotKeySet("{1}", "TogglePause")
HotKeySet("{2}", "Terminate")
HotKeySet("{3}", "ShowMessage")
Init()
Start()
While 1
$counter +=1
ToolTip('Script is "Running"',0,0, $counter, 1)
Sleep(700)
Switch TrayGetMsg()
Case $resume
Start()
DisableAlert()
Case $exit
ExitLoop
Exit
EndSwitch
WEnd
//some of the functions
Func Start()
$ready = 0
$count = 0
$lastScreenshotNum = 0
TrayItemSetState($resume, $TRAY_DISABLE)
TraySetIcon("on.ico")
TakeScreenshot()
AdlibRegister(TakeScreenshot,2000)
EndFunc
Func Stop()
AdlibUnRegister(TakeScreenshot)
TraySetIcon("off.ico")
TrayItemSetState($resume, $TRAY_ENABLE)
EndFunc
Func TogglePause()
Stop()
$Paused = NOT $Paused
While $Paused
sleep(100)
ToolTip('Script is "Paused"',0,0, $counter, 1)
WEnd
ToolTip("")
EndFunc
Func Terminate()
Exit 0
EndFunc
Func ShowMessage()
MsgBox(4096,"","This is a message.")
EndFunc
Func EnableAlert()
SendMail()
Alert()
AdlibRegister(Alert,5000)
EndFunc
Func DisableAlert()
AdlibUnRegister(Alert)
EndFunc
Func Alert()
SoundPlay("alert.mp3")
EndFunc

I want to pause an Autoit script, containing a while1 loop and some functions. But I am only able to close the the script on HotKeySet. So how can i pause it?
"Pause" While -loops by running their instructions conditional to (key-toggled) states (untested, no error checking):
Global Const $g_sKeyQuit = 'q'
Global Const $g_sKeyPause = 'p'
Global Const $g_iDelay = 500
Global $g_bStateQuit = False
Global $g_bStatePause = False
Main()
Func Main()
HotKeySet($g_sKeyQuit, 'SwitchStateQuit')
HotKeySet($g_sKeyPause, 'SwitchStatePause')
While Not $g_bStateQuit
If Not $g_bStatePause Then YourCode()
Sleep($g_iDelay)
WEnd
Exit
EndFunc
Func YourCode()
Local Static $iCount = 0
$iCount += 1
ConsoleWrite($iCount & #LF)
EndFunc
Func SwitchStateQuit()
$g_bStateQuit = True
EndFunc
Func SwitchStatePause()
_SwitchVar($g_sKeyPause)
EndFunc
Func _SwitchVar(ByRef $bSwitch)
$bSwitch = Not $bSwitch
EndFunc
P pauses.
Q exits.
Change content of YourCode() as required.
Visual explanation (illustrating While -loop in Main()):
Loops and AdlibRegister() are different ways to accomplish the same (choose either one).
Use TimerDiff() if accurately timed repetition is required because simply adding Sleep() introduces time-drifts (disregards execution time, which is true for AdlibRegister() as well). As per documentation:
Note that other running processes often affect the timing accuracy and so pauses are likely to last for slightly longer than requested.

Related

Bind content with range to an key

I want to bind some variable textcontent to an specific key (example on key p)
For example:
First press on p: "hannes1"
second press on p: "hannes2"
third press on p: "hannes3"
And so on. Thanks for any help.
It isn't clear from your question if you want a fixed string hannes with a counter or "the next string from a list", so I added both options (available via p and P
; Global $aVars[3] = ["hannes1", "hannes2", "hannes3"]
HotKeySet("p", "_SendVarArray")
HotKeySet("P", "_sendvarCount")
While True
Sleep(25)
WEnd
Func _SendVarArray() ; write strings from an array; rotating
Local $aVars[3] = ["One", "Two", "Three"] ; define EITHER here as Local OR in main program as Global
Local Static $x = UBound($aVars) - 1 ; initial value for next line to be changed as start value '0'
$x = Mod($x + 1, UBound($aVars))
Send($aVars[$x])
EndFunc ;==>_SendVarArray
Func _SendVarCount()
Local Static $x = 0 ; 'Static' to remember value with next execution
$x += 1
Send("hannes" & $x)
EndFunc ;==>_SendVarCount
NOTE: an ordinary letter is a bad choice for a hotkey, because if a string you send() contains that letter, it will activate the hotkey function too (I kept it anyway, leaving it to you to find a better key(combination)).
The advantage of HotKeySet() is that your program can do other things while waiting for the hotkey being pressed.
Try this: Change the ConsoleWrite to Send if you want to send the keys to any application.
#include <Misc.au3>
#include <MsgBoxConstants.au3>
Local $hDLL = DllOpen("user32.dll")
Local $counter = 0
While 1
If _IsPressed("50", $hDLL) Then
; Wait until key is released.
While _IsPressed("50", $hDLL)
Sleep(25)
WEnd
ConsoleWrite("Hannes" & $counter & #CRLF)
$counter +=1
ElseIf _IsPressed("1B", $hDLL) Then
MsgBox($MB_SYSTEMMODAL, "_IsPressed", "The Esc Key was pressed, therefore we will close the application.")
ExitLoop
EndIf
Sleep(25)
WEnd
DllClose($hDLL)

Kotlin how do I stop the program with the response output on the screen?

I have an endless cycle going on. How do I stop the program to output the answer? The meaning of my program: reads all characters (including enter) and outputs the sum of only numbers.
fun main() {
fun StrToSum(str: String): Long {
var sum : Long = 0
var next = ""
for (symbol in str + " ") {
if (symbol == '-') {
if ((next != "-") && (next != "")) {
sum += next!!.toLong()
}
next = symbol.toString()
} else if (symbol.isDigit()) {
next += symbol
} else if (next != "") {
if (next != "-") {
sum += next!!.toLong()
}
next = ""
}
}
return sum
}
var string: String = ""
while (1<2) { //How stop it ?
var str = readLine()!!.toString()
string += " " + str
}
println (StrToSum(string)) //answer
}
maybe there is some kind of keyboard shortcut ? I work for IntelliJ from Jetbrains
You can terminate the currently running program, but that will kill it - it won't be able to output the answer. You need to code that handling as part of your design, so you enable the user to finish and print your result.
The usual way people do this is to have some kind of cancel input, like entering an x or something:
// while (true) is a typical way to create an infinite loop
while (true) {
var str = readLine()!!.toString()
// look for the cancel token, break out of the loop if you see it
if (str.lowercase() == "x") break
string += " " + str
}
If you don't want to do that (remember you can make the cancel token anything, like the word "cancel" if you like, and put a prompt on the screen telling the user to type it to finish) then you'd have to do something like detecting other keycodes like Ctrl+Z or whatever - and I'm not sure how you'd do that from a basic command-line program reading from standard input. Maybe someone knows some tricks you could use! It's not something I've ever had to do, so I can't help you there
edit If you're happy to just look for control characters like ^D in the lines of standard input, you could do this kind of thing
if (str.firstOrNull().code == 4) break // char value for ^D
But that still requires the user to press Enter after the Ctrl+D, so the line including that character can be sent from the terminal to standard input. That's just how it works, outside of the solutions in the discussion I linked which involve OS-level interaction or building a GUI so you have access to the raw keypresses.

foreach kotlin waiting for intervals to follow the flow

Can someone help me in the following:
I have a FOR and inside it I run some TIMERS
my intention is that initially it runs the TIMER for the first index and only after the timer is canceled does the method go to the next timer. my FOR would need to wait for the TIMER to be finalized.
for (i in 1..3) {
println("running for loop: $i")
val interval: Long = 60 * 1000 * 1 // 1 minute
val timer = Timer("timer: $i", true)
timer.schedule(100, interval) {
println("${LocalTime.now()} to loop: $i")
// some logic here do stop the timer
// if (something happens) timer.cancel()
}
}
my output
running for loop: 1
running for loop: 2
running for loop: 3
18:34:57.147132900 to loop: 2
18:34:57.147132900 to loop: 3
18:34:57.147132900 to loop: 1
18:35:57.137764800 to loop: 3
18:35:57.137764800 to loop: 2
18:35:57.137764800 to loop: 1
etc...
my output as I hope it will be
running for loop: 1
18:34:57.147132900 to loop: 1
18:35:57.147132900 to loop: 1
18:36:57.147132900 to loop: 1
18:37:57.147132900 to loop: 1
running for loop: 2
18:38:57.147132900 to loop: 2
18:39:57.147132900 to loop: 2
running for loop: 3
18:40:57.147132900 to loop: 3
18:41:57.147132900 to loop: 3
18:42:57.147132900 to loop: 3
I have a FOR and inside it I run some TIMERS
This statement is wrong, java.util.Timer is a utility class that can be used to schedule a thread to be executed at certain time in future.
timer.schedule(100, interval) {}
The above line does not block the for loop, the timer is scheduled to be run on the thread and the for loop continues to do next iteration.
You probably need a blocking solution for your purpose of executing them one by one
for (i in 1..3) {
println("running for loop: $i")
val interval: Long = 60 * 1000 * 1 // 1 minute
Thread.sleep(100)
var isRunning = true
while(isRunning) {
println("${LocalTime.now()} to loop: $i")
Thread.sleep(interval)
// some logic here do stop the timer
// if (something happens) isRunning = false
}
}
But probably it isn't the best practise since your thread is just blocked, you could use coroutines to do that without wasting your system resources by blocking threads:
fun main() = runBlocking {
launch {
for (i in 1..3) {
println("running for loop: $i")
val interval: Long = 60 * 1000 * 1 // 1 minute
delay(100)
var isRunning = true
while(isRunning) {
println("${LocalTime.now()} to loop: $i")
delay(interval)
// some logic here do stop the timer
// if (something happens) isRunning = false
}
}
}
// ...
// do sth in main without blocking, these all things run on same thread
// none of the code is blocked
}

Prevent default action on mouse click

I want MsgBox() on mouse click, but prevent natural behaviour of mouse click. That means if I click any links here on Stack Overflow my active page must remain the same.
#include <MsgBoxConstants.au3>
#Include <Misc.au3>
While 1
If _IsPressed(01) Then ShowAlert() ; 01 is for left mouse button
Sleep (100)
WEnd
Func ShowAlert()
MsgBox($MB_SYSTEMMODAL, "", "Test")
EndFunc
This should do the trick:
#include <Constants.au3>
#include <WinAPI.au3>
#include <WindowsConstants.au3>
Global Const $HC_ACTION = 0
Global $hStub_MouseProc = DllCallbackRegister("_MouseProc", "long", "int;wparam;lparam")
Global $hmod = _WinAPI_GetModuleHandle(0)
Global $hHook = _WinAPI_SetWindowsHookEx($WH_MOUSE_LL, DllCallbackGetPtr($hStub_MouseProc), $hmod)
HotKeySet('^+!e', '_ende') ; CTRL+SHIFT+ALT+E to exit.
OnAutoItExitRegister('ExitFunc')
While 1
Sleep(100)
WEnd
Func _ende()
Exit
EndFunc ;==>_ende
Func _MouseProc($nCode, $wParam, $lParam)
If $nCode < 0 Then
Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
EndIf
If $nCode = $HC_ACTION Then
Switch $wParam
Case 0x0201
ConsoleWrite('No Click!' & #CRLF)
Return -1
;~ Case $WM_MBUTTONUP
;~ Return _mouse_event($MOUSEEVENTF_RIGHTUP) ; Returns -1; mouse click will be ignored.
EndSwitch
EndIf
Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
EndFunc ;==>_MouseProc
Func ExitFunc()
_WinAPI_UnhookWindowsHookEx($hHook)
DllCallbackFree($hStub_MouseProc)
EndFunc ;==>ExitFunc
Func _mouse_event($dwFlags)
DllCall("user32", 'long', 'mouse_event', 'long', $dwFlags, 'long', 0, 'long', 0, 'long', 0, 'long', 0)
Return -1
EndFunc ;==>_mouse_event
… prevent it's natural behaviour in the same time …
As per MouseOnEvent UDF:
This UDF allows to set an events handler for Mouse device.
Example (using ConsoleWrite() as MsgBox() requires the blocked mouse-click in order to be closed):
#include "MouseOnEvent.au3"
Global Const $g_sKeyQuit = '{esc}'
Global Const $g_iDelay = 10
Global Const $g_bBlockInput = True
Global $g_bStateQuit = False
Main()
Func Main()
HotKeySet($g_sKeyQuit, 'Quit')
_MouseSetOnEvent($MOUSE_PRIMARYDOWN_EVENT, '_MousePrimaryDown_Event')
_MouseSetOnEvent($MOUSE_PRIMARYDBLCLK_EVENT, '_MousePrimaryDblclk_Event')
While Not $g_bStateQuit
Sleep($g_iDelay)
WEnd
Exit
EndFunc
Func Quit()
$g_bStateQuit = True
EndFunc
Func _MousePrimaryDown_Event()
ConsoleWrite('Detected $MOUSE_PRIMARYDOWN_EVENT' & #CRLF)
Return $g_bBlockInput ? $MOE_BLOCKDEFPROC : $MOE_RUNDEFPROC
EndFunc
Func _MousePrimaryDblclk_Event()
ConsoleWrite('Detected $MOUSE_PRIMARYDBLCLK_EVENT' & #CRLF)
Return $g_bBlockInput ? $MOE_BLOCKDEFPROC : $MOE_RUNDEFPROC
EndFunc
The UDF allows events to be registered to a specific window as well. It can either block or pass events after detection and includes example on how to restrict functionality to part(s) of a screen.

How to test a function's output (stdout/stderr) in unit tests

I have a simple function I want to test:
func (t *Thing) print(min_verbosity int, message string) {
if t.verbosity >= minv {
fmt.Print(message)
}
}
But how can I test what the function actually sends to standard output? Test::Output does what I want in Perl. I know I could write all my own boilerplate to do the same in Go (as described here):
orig = os.Stdout
r,w,_ = os.Pipe()
thing.print("Some message")
var buf bytes.Buffer
io.Copy(&buf, r)
w.Close()
os.Stdout = orig
if(buf.String() != "Some message") {
t.Error("Failure!")
}
But that's a lot of extra work for every single test. I'm hoping there's a more standard way, or perhaps an abstraction library to handle this.
One thing to also remember, there's nothing stopping you from writing functions to avoid the boilerplate.
For example I have a command line app that uses log and I wrote this function:
func captureOutput(f func()) string {
var buf bytes.Buffer
log.SetOutput(&buf)
f()
log.SetOutput(os.Stderr)
return buf.String()
}
Then used it like this:
output := captureOutput(func() {
client.RemoveCertificate("www.example.com")
})
assert.Equal(t, "removed certificate www.example.com\n", output)
Using this assert library: http://godoc.org/github.com/stretchr/testify/assert.
You can do one of three things. The first is to use Examples.
The package also runs and verifies example code. Example functions may include a concluding line comment that begins with "Output:" and is compared with the standard output of the function when the tests are run. (The comparison ignores leading and trailing space.) These are examples of an example:
func ExampleHello() {
fmt.Println("hello")
// Output: hello
}
The second (and more appropriate, IMO) is to use fake functions for your IO. In your code you do:
var myPrint = fmt.Print
func (t *Thing) print(min_verbosity int, message string) {
if t.verbosity >= minv {
myPrint(message) // N.B.
}
}
And in your tests:
func init() {
myPrint = fakePrint // fakePrint records everything it's supposed to print.
}
func Test...
The third is to use fmt.Fprintf with an io.Writer that is os.Stdout in production code, but bytes.Buffer in tests.
You could consider adding a return statement to your function to return the string that is actually printed out.
func (t *Thing) print(min_verbosity int, message string) string {
if t.verbosity >= minv {
fmt.Print(message)
return message
}
return ""
}
Now, your test could just check the returned string against an expected string (rather than the print out). Maybe a bit more in-line with Test Driven Development (TDD).
And, in your production code, nothing would need to change, since you don't have to assign the return value of a function if you don't need it.