Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
542 views
in Technique[技术] by (71.8m points)

autohotkey - How to stop the current script?

I have this current script but it won't pause, even though i put a Pause script at F8 is there a way to stop the current loop?

F7::
Loop{
Send {1} ; Pressed 1
Send {-}
Send {-}
Send {-}
Send {-}
Send {2} ; Pressed 2
Send {-}
Send {-}
Send {-}
Send {-}
}
F8::Pause
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I don't know why exactly that doesn't work, I'll try to find out after this post and will edit that in if I find out. However, there are many things wrong (bad practice) in that script, so we'll be able to get you a working version easily.

Firtly, there is no need to use multiple send commands. Just put all the characters in one send command.

Secondly, there is no need to wrap those keys around a {}. That's only done when you want to escape keys that have special. For example wrapping ! in {} would send the literal ! key instead of the ALT key. (In AHK ! indicates the ALT modifier key)

Ok, so now your script looks like this

F7::
    Loop
        Send, 1----2----
return

F8::Pause

I also removed the braces around the loop, they're not needed for a one-liner. And added the return at the end of the hotkey, even though technically not needed here, but it kind of belongs there. With return you stop code execution, and that's how you end a non-one-liner hotkey statement (not needed for one-liners).
But in your case the code execution will never escape the loop, so it doesn't really matter.

But that the loop still doesn't get interrupted by your pause hotkey. If you were to use SendInput it would work. So just replace Send with SendInput.
It would also be very very very much faster at sending the keys and also more reliable. If it's too fast even, you could switch back to Send and tune the speed with SetKeyDelay.

Even better than using any way of sending those keys, would be setting the text to your clipboard and sending ctrl+v. Now that's fast and reliable. But maybe a bit excessive since your string to send is not that long. But if it gets longer, you'll surely want to do that.
Of course whether or not that works depends to what you're sending input to. Here's a minimal example for that:

Clipboard := "This is a long string that's going to be sent instantly by the use of pasting it in.`nThis is a long string that's going to be sent instantly by the use of pasting it in."
F7::SendInput, ^v

But still, all of this is bad practice because we're using a loop. And especially loop that's under a hotkey.


Now lets get onto some better ways of doing this. But first let me say that none of this make any actual difference in practice if your whole script is just those two hotkeys and nothing more. But still, for future reference, when you might make bigger and better scripts, I'd like to show some better ways of doing this.

Firstly, by pausing you just pause the whole script (so also all loops and timers, etc). But you never exit the loop. Always when you unpause, the loop will still be running there. Might not be desired.
You could make the loop include some condition under which to break the loop. Quick and minimal example of breaking the loop when a condition is met:

F7::
    BreakLoop := false
    Loop
    {
        if (BreakLoop) ;if true
            break
        ToolTip, % A_TickCount ;built in variable that holds the time, in ms, since our system was started
    }
return

F8::BreakLoop := true

But actually, even the usage of a loop can be bad practice. If we have a bigger script we'd want the loop to be something that's just running on the background. But a loop wont do that.
So, secondly, using a timer instead of a loop.
Basic example:

F7::SetTimer, OurTimersCallback, 0 ;0 as in execute timer every "0" ms (as fast as possible)
F8::SetTimer, OurTimersCallback, Off ;turn off

OurTimersCallback()
{
    ToolTip, % A_TickCount
}    

Sweet, but we can do even better. Lets use the same hotkey to toggle on/off, so we don't need two different hotkeys:

Toggle := true
F7::
    if (Toggle)
    {
        SetTimer, OurTimersCallback, 0
        Toggle := false
    }
    else
    {
        SetTimer, OurTimersCallback, Off
        Toggle := true
    }
return

OurTimersCallback()
{
    ToolTip, % A_TickCount
}

Nice, but believe it or not, we can do even better, though this part makes no difference in practice. But we can use a one-liner for the hotkey statement:

F7::SetTimer, OurTimersCallback, % (Toggle:=!Toggle) ? 0 : "Off"

OurTimersCallback()
{
    ToolTip, % A_TickCount
}

Phew, ok, well that's surely a bit confusing. Let me type out the explanation for what happens and why it works.
% ( ) ? <value> : <value> So what is this?
With % force the current parameter of command we are in the behave in expression syntax. So instead of interpreting what we type literally (as one string), it understand the cool stuff we're doing.
And then ( ) ? <value> : <value> is a ternary operator.
If the statement inside ( ) evaluates to true, we use the value that's before : (0 in our case), and if it evaluates to false, we use the value that's after : (the string Off in our case).

Toggle:=!Toggle The variable Toggle, like any variable, starts off with the default value of nothing, which evaluates to false in this example, so we'll just say Toggle starts off with the value false to keep things a bit more simple.

With := we assign an expression (simply said, a value (in this case)) to Toggle (if you don't already know the difference between = and :=, that's something you should learn, but that's an other thing)

!Toggle means the opposite of the value Toggle holds.
So opposite of false (the default value any variable holds at the beginning) is true

Ok, so now Toggle holds the value true.
And our ternary's statement, (Toggle:=!Toggle) is checking if the expression inside the brackets ( ) evaluates to true.
Well it did, so we choose the value for true in our ternary.

Next time around (when we hit F7 again), the variable Toggle already holds the value true.
Then we do the same stuff again. We assign !Toggle to Toggle. This time the opposite value is false, so the if statement evaluates to false, so we choose the value for false in our ternary instead.

And then when F7 is hit once again, we change the value of Toggle to its opposite again.
Toggle's value keeps changing between true, false, true, false, true,... and this is how we achieve a very nice, short, toggle.


Very long post, I hope someone learns something, or at least finds it interesting. Well, at least I enjoyed writing it.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...