1. Briefly
I don't understand, how I can use cycles from Loop multiple times without ending script.
2. Settings
I have a file SashaAutoScrolling.ahk, it content:
; First loop, Speed 1
#+1::
Loop
{
Send {WheelDown}
Sleep 3000
}
; Second loop, Speed 2
#+2::
Loop
{
Send {WheelDown}
Sleep 600
}
; Third loop, Speed 3
#+3::
Loop
{
Send {WheelDown}
Sleep 100
}
; Fourth loop, Speed Up
#+0::
Loop
{
Send {WheelUp}
Sleep 600
}
; Loop pause
; http://autohotkey.com/board/topic/95308-endless-loop-with-hotkey-pause/?p=600526
#p::Pause
; Exit script
#esc::ExitApp
3. Steps to reproduce
I open any pdf file in any PDF-viewer. I switch between «speeds»:
Shift+Super+3,
Shift+Super+0,
Shift+Super+2,
Shift+Super+3,
Shift+Super+0.
4. Actual behavior
If I run Shift+Super+3 and Shift+Super+0 first time
I can successful switch between «speeds».
If I run Shift+Super+3 and Shift+Super+0 second and next times,
I can't switch between «speeds».
5. Expected behavior
Successful switch between «speeds» unlimited number of times.
6. Not helped
Googling, searching in Stack Overflow and AutoHotkey forum.
7. Do not offer
Please, do not offer use third-party programs. Adobe Reader free version works as expected, but I can't read, use this program , for example, djvu or doc books.
Please, do not offer use built-in mouse auto scrolling. It uncomfortable, because is problematic quick choose exact comfortable «speed» for reading.
This code scrolls current window with simulated mouse wheel scrolls
Shift+Win+1, Shift+Win+2, etc... starts scrolling. If already scrolling, just updates sleep interval. esc exits
; globals:
; g_running : true while loop is active
; g_sleep : milliseconds to sleep between sending input event
; g_key : key to simulate
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; HOTKEY DEFINITIONS
#MaxThreadsPerHotkey 2
#+1:: scrollit(3000)
#+2:: scrollit(600)
#+3:: scrollit(300)
#+0:: scrollit(600,"WheelUp")
#MaxThreadsPerHotkey 1
Esc:: abort()
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; HELPER FUNCTIONS
; send wheeldown every _delay_ microseconds
; if called while loop is already active, just update delay and exit
;
scrollit(sleep, key="WheelDown")
{
global g_running
global g_sleep := sleep
global g_key := key
if g_running
return
g_running := true
while (g_running)
{
Send {%g_key%}
Sleep g_sleep
}
}
abort()
{
global g_running := false
}
Scrolls current window by simulating mouse wheel scroll when Shift+Win+1, Shift+Win+2, etc. pressed. esc exits loop
#+1:: scrollit(3000)
#+2:: scrollit(600)
#+3:: scrollit(300)
Esc:: abort()
scrollit(delay)
{
global abort := false
while (!abort)
{
Send {WheelDown}
Sleep delay
}
}
abort()
{
global abort := true
}
Your code doesn't work because by default there is only one thread per hotkey. When you do:
Loop
{
Send {WheelDown}
Sleep 100
}
You never return from this one thread so when you call it second time the hotkey will not fire and your program will continue looping in the current thread.
Jim U solved it by calling #MaxThreadsPerHotkey 2, this wouldn't have made your code work though because you don't return from your hotkey threads at all, Jim U doesn't return from the first thread only so 2 threads is enough for his solutoin to work.
An alternative solution is to use timers, the following will change the scrolling speed immediately, doesn't need any special directives and doesn't rely on Autohotkeys unique threading model.
#+1::callSetTimer(3000)
#+2::callSetTimer(600)
#+3::callSetTimer(100)
#+0::callSetTimer(600, "WheelUp")
Esc::SetTimer, scrollTimer, Off
callSetTimer(interval, key := "WheelDown") {
global currKey := key
SetTimer, scrollTimer, %interval%
scrollTimer:
send, {%currKey%}
return
}
Related
How can I achieve a loop like this:
foobar.each(function (model, j) {
// asynchrounous call etc. {in here bool get set to true}
// outside all asynchronous calls
// wait till bool is true, without stopping anything else except the loop to the top of
the _.each
})
I asked a similar question yesterday. But it got marked as a duplicate when it wasn't the same case. Their solution did not achieve the same thing. Also generator functions were suggested which looked like it would work. But I can't use them with ecmascript 5
I've tried busy loops and set time out but they don't seem to work either
I've also tried this:
goto();
function goto() {
if (foo === true) {
//return true; /*I've tried with and without the return because the loops
doesn't need a return*/
} else {
goto();
}
}
What happens with the goto() method is it breaks. Giving me the right results for the first iterations then execution seems to stop altogether. 'foo' always gets set to true in normal execution though.
What you could do is implement a foreach yourself, where you execute your condition, and then on success callback go to the next item (but meanwhile the rest of the code will keep running.
var iteration = 0 //count the iteration of your asynchronous process
//start looping
loop(iteration)
function loop(iteration){
var model = foobar[iteration];
//exit your loop when all iterations have finished (assuming all foobar items are not undefined)
if (foobar[iteration] === undefined){
return;
}
//do what you want
//on success callback
iteration++;
loop(iteration);
//end success callback
}
I'm using AngularsJS 1.1.3 with Internet Explorer 8.
In my code with a forloop which iterate through a high number items of an array, I have this error:
Stop running this script? A script on this page is causing internet
explorer to run slowly...?
I made a search on Internet and I found that I need to break the forloop cycle in many pieces.
I'm looking for a method which make a break (for example every 10 loops) ,
for who will suggest the setTimeout function, this one wait for some time before executing the function passed as argument, what I need is making a break, while looping inside the forloop iteration and then continue executing the forloop.
I added a screenshot for the error.
I found this function :
$scope.sleep=function(milliseconds) {
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) {
if ((new Date().getTime() - start) > milliseconds){
break;
}
}
}
And within my Forloop I added an If condition:
for(var i=0 ; i<tab.length ; i++) //tab has more than 50 elements
{
price=price+ tab[i];
total=total +tab[i].unitprice ;
if(i % 10 ==0 ) sleep(2000);
}
The problem with this code is that when the if evaluated a true an the sleep method is called, after that the excution doesn't go through the other items but leave the forloop, and I don't know why.
So i just started using autohotkey and i made this script to spam the trade chat in a game called path of exile, it works pretty well, but i cant get it to stop when i press f1 again, i've tried countles times, but the loop just won't stop
#MaxThreads 2
wintitle=Path of Exile
SetTitleMatchMode,2
DetectHiddenWindows,On
setkeydelay,2500,0
f1::
toggle:=!toggle
Loop
{
if toggle
controlsend,,{enter}{up}{enter}, %wintitle%
else
break
}
return
I think you're better off using SetTimer for this. Loops aren't very easy to work with when it comes to toggles.
i := 0
toggle := 0
F1::
toggle := !toggle
if (toggle) {
SetTimer, Timer_Spam, 10
} else {
SetTImer, Timer_Spam, Off
}
return
Timer_Spam:
TrayTip, Counter, %i%
i++
return
The reason why your loop isn't working is because once you enter the loop the program is stuck there, so to get out you need to work from inside the loop.
You can do this with GetKeyState(), but then you can't use the same key to toggle it on and off, as it'll toggle off as soon as you start it, unless you add Sleep commands in there, in which case it becomes unreliable instead.
You can however use a separate key to stop the loop, shown here.
toggle := 0
i := 0
F1::
toggle := !toggle
if (toggle) {
Loop {
if (GetKeyState("F2", "P")) {
toggle := !toggle
break
}
TrayTip, Counter, %i%
i++
}
}
return
But like I said above, SetTimer achieves the same result in a much more stable way. So I'd go with that.
use MaxThreadsPerHotkey
#MaxThreadsPerHotkey 2
wintitle=Path of Exile
SetTitleMatchMode,2
DetectHiddenWindows,On
setkeydelay,2500,0
return
f1::
toggle:=!toggle
Loop
{
if toggle
controlsend,,{enter}{up}{enter}, %wintitle%
else
break
}
return
This is the easiest approach I was able to do.
Start/stop toggle with key "2", sending "a" with 0.1 second delay.
#MaxThreadsPerHotkey 2
running := false
stop := false
~2::
if(!running) {
running := true
}
else {
stop := true
return
}
loop {
Send {a} ; example sending key "a"
if(stop) {
running := false
stop := false
break
}
Sleep, 100
}
return
My strategy is this,
Use this command:
v::
loop
{
click
if (GetKeyState("b")) {
break
}
}
return
(Its simple AutoClicker)
Working example with Loop command. Yet so simple.
#Persistent
#MaxThreadsPerHotkey 2
toggle := False
f1 UP::
toggle := !toggle
Loop {
If (!toggle) {
break
}
; Spam commands here
}
Return
This code does what you want:
#MaxThreads 2
wintitle=Path of Exile
SetTitleMatchMode,2
DetectHiddenWindows,On
setkeydelay,2500,0
return
F1::
Loop
{
CheckLButton1:
if (GetKeyState("F1"))
{
Goto, CheckLButton1
}
Docode:
controlsend,,{enter}{up}{enter}, %wintitle%
;ToolTip, 1
if (!(GetKeyState("F1")))
{
Goto, Docode
}
CheckLButton2:
if (!(GetKeyState("F1")))
{
return
}
else
{
Goto, CheckLButton2
}
}
return
If you need explanation, look here at my post: http://ahkscript.org/boards/viewtopic.php?f=5&t=4613#p26298
I am just learning Perl as a fourth language.
My wish is to use Parallel::ForkManager to speed up a foreach loop using an array whose members are taken from a text file.
Basically I am testing a .txt file of URLs, and wish to make it so that it will test multiple members of the array at once, not one at a time (five at a time in this instance) and without spamming the same URL inadvertently DoSing it.
Would something like this do the trick?
$limit = new Parallel::ForkManager(5);
foreach (#lines) {
$limit->start and next;
$lines = $_;
... do processing here ...
$limit->finish;
}
or would it be the equivalent of running that loop 5 times making a small multithreaded DoS script?
It isn't too clear from the documentation, but
A call to start will block in the parent process until there are fewer children running than the limit specified. Then it will return the (non-zero) child PID in the parent, and zero in the child
A child process can see all the data in the parent process as it was when the start was called. The data is presumably copy-on-write, as the child may modify it but the changes aren't reflected in any other process's workspace
The $pm->start and next idiom may seem a little obscure. Essentially it skips the rest of the loop if the start method returns a true value. I prefer something like my $pid = $fm->start; next if $pid; or the if construct in the code below. Both do the same thing, but I think more legibly
I recommend that you experiment with this simpler application, which uses a cache of five child threads to print the numbers from zero to nine.
use strict;
use warnings;
use Parallel::ForkManager;
STDOUT->autoflush;
my $fm = Parallel::ForkManager->new(5);
for my $i (0 .. 9) {
my $pid = $fm->start;
if ($pid == 0) {
print "$i\n";
sleep 2;
$fm->finish;
}
}
To test, use a safe local process like print or write to avoid spamming the URL's. Here's a working snippet from a program I wrote that uses the fork manager.
my $pm=new Parallel::ForkManager(20);
foreach $add (#adds){
$pm->start and next;
#if email is invalid move on
if (!defined(Email::Valid::Loose->address($add))){
writeaddr(*BADADDR, $add); #address is bad
$pm->finish;
}
#if email is valid get domain name
$is_valid = Email::Valid::Loose->address($add);
if ($is_valid =~ m/\#(.*)$/) {
$host = $1;
}
$is_valid="";
# perform dsn lookup to check domain
#mx=mx($resolver, $host);
if (#mx) {
writeaddr(*GOODADDR, $add); #address is good
}else{
writeaddr(*BADADDR, $add); #address is bad
}
$pm->finish;
}
This should be easy! I've checked out this thread, but it doesn't help.
I can't seem to break out of the loop using the hotkey. The idea is that you can start and stop the looping process with a single hotkey.
It seems like the value of timeron never gets into the the loop once it's begun.
Here is a sample script:
#singleinstance force
timeron = 0
return
!f7::
if(timeron){
timeron = 0
msgbox Okay, the loop is off.
}else{
timeron = 1 ;if this is not set to one, the loop will not begin
msgbox Turning on the loop.
gosub, STARTLOOPING
}
RETURN
STARTLOOPING:
;do this over and over
loop{
if(!timeron)
break
;now wait for the right length of time before continuing the loop
msgbox, The loop yet continues....
Sleep, 5000
if(!timeron)
break
}
RETURN
What am I missing here?
Since your !F7 never ends, a second press of !F7 is ignored.
Per default there is only one thread for each hotkey allowed at one time.
Add
#MaxThreadsPerHotkey 2
as a second line to your script then the second !F7 press can deactivate the loop.
Why don't you use timers instead? They allow your script to do other stuff in between timer runs, thus allowing hotkeys to interrupt them:
timeron := false
Exit
!F7::
if(timeron) {
timeron := false
SetTimer, MyTimer, Off
} else {
timeron := true
; Call GoSub once if you want the subroutine
; to fire immediately at the beginning
GoSub, MyTimer
; Then let the timer repeat it
SetTimer, MyTimer, 5000
}
return
MyTimer:
Msgbox, Looping like crazy!
return
You can always replace a loop's functionality with a timer. If you have some kind of for loop/counter, you can use global variables instead.