Anton
Anton

Reputation: 3

AHK Click event while Toggled

I've found AHK codes that separately work "ok" but I need one inside another. So, I have:

1. The first rapidly fires click when you hold down the left mouse button:

~$LButton::
    While GetKeyState("LButton", "P"){
    Click
    Sleep .1  ;  milliseconds
    }
return

2. The second is a toggle script that sends the same left mouse button firing events but can be toggled on and off with a button press (F8 in this case)

toggle = 0
#MaxThreadsPerHotkey 2

F8::
    Toggle := !Toggle
    While Toggle{
        Click
        sleep 1
    }
return

What I need is: when I push F8 once, I want my left mouse button to fire click events rapidly while holding it. When I push F8 again it should do nothing. If it's important, I need those clicks while holding Ctrl in-game. I've read a bit about AHK and tried this code but it doesn't work any close to what I want:

toggle = 0
#MaxThreadsPerHotkey 2

F8::
    Toggle := !Toggle
    If Toggle{
~$LButton::
    While GetKeyState("LButton", "P"){
    Click
    Sleep .5  ;  milliseconds
    }
    }
return

This one gives me errors about missing "return" but I tried a lot of merging variations.

Also, I've read a lot about MaxThreads and still don't know why there should be 2 and what is it for.

Upvotes: 0

Views: 6026

Answers (1)

0x464e
0x464e

Reputation: 6489

Firstly, not sure what amount of time you're trying to give the Sleep commands, but decimal numbers wont work. Just whole numbers, and they're in milliseconds. .1 and .5 are likely interpreted as 0, not sure though. Also, the sleep command isn't as accurate as you may think it is. Read the remarks section in the documentation for more.

Secondly, you shouldn't loop inside hotkey labels. It's bad practice due to AHK not offering true multithreading.
Though, at the end of the day, it wont make any difference if this is all your script it.
For future reference if you want to start writing nicer and bigger scripts, I'll show you the usage of timers though. They should be used for this.

LButton::SetTimer, MyCoolFunction, 0 ;when LButton is clicked down start a timer with the shortest possible period
LButton Up::SetTimer, MyCoolFunction, Off ;when LButton is released, stop the timer

MyCoolFunction()
{
    Click
}

And same for your toggle version, you don't want to loop inside a hotkey label:

F8::
    toggle := !toggle
    if(toggle) ;if true
        SetTimer, MyCoolFunction, 0
    else
        SetTimer, MyCoolFunction, Off
return

MyCoolFunction()
{
    Click
}

And if you don't know what toggle := !toggle actually is, and want to know, you can read a previous answer of mine here. It also shows how you can compact that code down to just one line of code. And also explains why there's no need to define the variable toggle on top of your script (as you were doing).

And about #MaxThreadsPerHotkey2:
It's because AHK doesn't offer true multithreading. When you're looping side a hotkey definition, that hotkey is completely locked up. You can't run the hotkey again to stop the loop. Unless, you set the hotkey to use more threads (better to call them instances) than one.
That way you're able to launch the hotkey again and you're able to change the toggle variable's value so you can stop the loop.
But again, you shouldn't loop inside hotkeys. If you use a timer, like I showed above, you don't need to worry about this dirty workaround.


And then to the new code you want to create.
Well first about what went wrong in your attempt. I guess it was a good thought, but it's not even close. Hard to say what exactly is wrong in it, since it's not even close to working. I guess what I can say is that hotkey labels (hotkey::) are evaluated once when the script starts, and then never again. So you can't put them inside some runtime logic. The Hotkey command would be used for that.

Luckily your problem is actually much simple than that. You don't need to mess around with the Hotkey command.
All you're looking to do is toggle the hotkeys on/off. Suspend is used for that like so:
F8::Suspend
And now the script's hotkeys (and hotstrings) toggle on/off every time you press F8.

So here's your final script:

LButton::SetTimer, MyCoolFunction, 0 ;when LButton is clicked down start a timer with the shortest possible period
LButton Up::SetTimer, MyCoolFunction, Off ;when LButton is released, stop the timer

MyCoolFunction()
{
    Click
}

F8::
    Suspend
    SetTimer, MyCoolFunction, Off ;set the timer off just incase we hadn't released LButton before we hit F8
return

Upvotes: 1

Related Questions