How can I make AutoHotKey script execute its function with multiple hotkeys? - autohotkey

LButton::
^LButton::
While GetKeyState("LButton","p"){
Send {LButton}
Sleep 20
}
return
This is my current script. What it does is when I hold the left mouse button it simulates pressing it repeatedly every 20 milliseconds. But, because in the game I use it with I often have to hold Alt down to crouch I need it to work with ^LButton. But for some reason, when holding alt+LButton it just acts normally i.e. it reverts to me holding down the left mouse button.
One thing I thought of is possibly adding
While GetKeyState("LButton","p") or GetKeyState("alt LButton","p"){
However I am lacking proper syntax to pass a modifier along with a button to the GetKeyState function.
I searched through the documents and did a bit of googling but it seems like the AHK forums have been inactive for around 5 years now. If anyone knows how to solve this issue your help would be appreciated!

#CherryDT Thanks for the quick response. I actually think I was just googling the wrong because I have solved it.
The trick is that with mouse buttons, you have to use a different syntax and also there is a precedence to the order in which the combination is pressed.
LButton::
Alt + LButton::
etc...
Again, thanks for the response :)

Related

AutoHotKey WinActive returns wrong value when changing window focus

In my AutoHotKey script I'm using #IfWinActive to detect if the Roblox window is in focus, and then press the number 1 button whenever left clicking the mouse, like this:
#IfWinActive, Roblox
LButton::
MouseClick, Left
SendInput, {1}
return
#IfWinActive
It works great, except for when I'm clicking out of the Roblox window back to another window. It still fires this code on the first click, resulting in it typing the number 1 into Notepad (or whatever window I switch focus to).
I figured that when I'm clicking on Notepad the focus is still on the Roblox window, which is why the code still fires. So I tried changing the code to this:
#IfWinActive, Roblox
LButton::
Sleep, 100
if WinActive("Roblox")
{
MouseClick, Left
SendInput, {1}
}
return
#IfWinActive
Assuming that by the time the Sleep finished the focus would have shifted to the Notepad window and If WinActive("Roblox") would return false, but it still returns true and types 1 into Notepad.
I also tried using StartTimer and a label, thinking that maybe the Sleep wasn't asynchronous, but that has the same problem as well.
Anybody know how to get around this issue? Thanks in advance!
The main problem in this case is that the hotkey is fired immediately after LButton is pressed down and the Roblox window is still active.
The only solution I see is to fire the hotkey upon release of the LButton using the tilde prefix (~) to prevent AHK from blocking the key-down/up events:
#IfWinActive, Roblox
~LButton Up:: SendInput, 1
#IfWinActive
There are a couple of ways we can achieve this. TL;DR for solution, check the yellow part of this post.
Firstly I'll address the problems in your code:
Usage of MouseClick over Click. Technically nothing wrong, but Click is said to be more reliable in some situations and easier to use. Looks cleaner as well.
Wrapping 1 in {} is not needed and does nothing for you here. In some cases you may even produce unwanted behavior by doing this. In a send command, {} is used to escape keys that have special meaning, or to define keys that you can't just type in. More about this from the documentation.
Having a somewhat of a bad WinTitle that you're matching against. Again, nothing technically wrong, but right now you match any window that starts with the word Roblox. Shouldn't be too hard accidentally match the wrong window.
A quick and a very effective solution would be matching against the process name of your Roblox window.
So #IfWinActive, ahk_exe Roblox.exe or in an if-statement if (WinActive("ahk_exe Roblox.exe")) (assuming that's the process' name, I have no idea)
For an absolutely fool proof way could match against the hwnd of the Roblox window. However, that's maybe a bit overkill and you couldn't really use it with #IfWinActive either. An example I'll write below will use this that though.
However, problems 1 and 2 can be entirely avoided by doing this neat way of remapping a key (remapping is pretty much what you're doing here).
~LButton::1
Ok, so why does that work?
key::key is just the syntax to easily do a basic remap, and with ~ we specify that the hotkey isn't consumed when it fires.
Cool, but now onto the actual problem you're having.
So what went wrong with the sleeping thing? Well since you're consuming the hotkey, all you're actually doing is firing the hotkey, waiting 100ms, then checking if Roblox is active. Well yes, it will still be active since nothing was ever done to switch focus away from it.
If you were to not consume the left clicking action, it would work, but it's definitely not a good idea. You do not want to sleep inside a hotkey statement. AHK does not have true multithreading and unless you would've specified a higher #MaxThreadsPerHotkey for your hotkey, all subsequent presses of the hotkey would be totally ignored for that 100ms.
So yes, with specifying a higher amount of threads that can run for that hotkey, it would kind of make this solution work, but it's still bad practice. We can come up with something better.
With timers you can avoid sleeping in the hotkey statement. Sounds like you tried the timers already, but I can't be sure it went right since code wasn't provided so I'll go over it:
#IfWinActive, ahk_exe Roblox.exe
~LButton::SetTimer, OurTimersCallbackLabel, -100 ;-100 specifies that it runs ONCE after 100ms has passed
#IfWinActive
OurTimersCallbackLabel:
if (WinActive("ahk_exe Roblox.exe"))
SendInput, 1
return
And now onto the real solution, to which #user3419297 seems to have beat me to, just as I'm writing this line of text.
Using the up event of your LButton press as the hotkey.
#IfWinActive, ahk_exe Roblox.exe
~LButton Up::SendInput, 1
#IfWinActive
This way the down event has already switched focus of the window and our hotkey wont even fire.
Note that here we unfortunately can't use the key::key way of remapping I described above.
Bonus:
Here's something that could be used if the up event of our keypress wouldn't be desirable, or somehow the window switching of the active window was delayed.
RobloxHwnd := WinExist("ahk_exe Roblox.exe")
#If, RobloxUnderMouse()
~LButton::1
#If
RobloxUnderMouse()
{
global RobloxHwnd ;specify that we're using the variable defined outside of this function scope
;could've also ran the code to get Roblox's hwnd here every time, but that would be wasteful
MouseGetPos, , , HwndUnderMouse ;we don't need the first two parameters
return RobloxHwnd == HwndUnderMouse ;are they the same hwnd? (return true or false)
}
Here we're first storing the hwnd of our Roblox to the variable RobloxHwnd.
Note that Roblox would need to be running before we run this script, and if you restart robox, script would need to be restarted as well.
So adding some way of updating the value of this variable on the fly would be good, maybe under some hotkey.
Then by using #If we're evaluating an expression (in our case, running a function and evaluating its return value) every time we're about to attempt to fire the hotkey. If the expression evaluates to true, we fire the hotkey.
Usage of #If is actually not recommended, and it is good practice to avoid using if at all possible. However, you wont encounter any problems in a script this small, so using #If is going to be very convenient here.
If you were to have a bigger script in which there's a lot of code running often, you'd be likely to run into problems.

Autohotkey. Hold two buttons and tap another to increase volume

I got stuck building an ahk shortcut script to increase / decrease Volume. The idea was to hold down LAlt+LShift and tap F12 to increase one step per tap.
The order in which LAlt and LShift are pressed shouldn't matter.
I came up with this so far:
!+::
While (GetKeyState("LShift","P")) and (GetKeyState("LAlt","P"))
{
F12::Send {Volume_Up}
}
Return
But somehow it increases the volume on holding LAlt and taping F12. LShift gets igronred..
What's wrong with that...
This
F12::Send {Volume_Up}
isn't a command, it's a hotkey assignment. You cannot use it within executable context. It is actually the short form for:
F12::
send {volume_up}
return
You wouldn't wanna have a return somewhere in between the lines which should be executed, would you.
As can be read in the documentation, you can only combine two Hotkeys for an action easily, like a & b::msgbox, you pressed a and b. E.g. for a,b AND c, you'd need some workaround like the crossed out, old answer below.
BUT you can add as many modifiers to your hotkey as you want. Modifiers are ! alt, + shift, # win and so on (please have a look # http://ahkscript.org/docs/Hotkeys.htm#Symbols).
So you can simply use
<!+F12::send {volume_up}
-
So, your aim is simply to have volume_up be fired when three Hotkeys are being pressed. You can achieve it like this:
#if getKeyState("LShift", "P")
*<!F12::send {volume_up}
#if
or
*<!F12::
if(getKeyState("LShift","P"))
send {volume_up}
return
For the meaning of * and < and other possible modifiers, see http://ahkscript.org/docs/Hotkeys.htm#Symbols
Your approach wasn't too bad. It would have worked if you had used the Hotkey command instead of an actual hotkey assignment. Still that would have been unneeded work

Loop autohotkey script moving mouse down each time

I am trying to automate my workflow using Autohotkey.
I want to move the mouse position down 200px each iteration at the two positions marked below; and apologies for the formatting.
EDIT: Thanks to the answer below I have learnt to think of other ways to make a repeating action. I ended up using TinyTask to solve this.
You can use a variable for the X coordinate and then use += 200 to add to the variables value. But it maybe simpler to use the keyboard to do it something like
send, {down 3}{F2}
Also autohotkey 1.1+ from http://ahkscript.org has COM built-in so that excel can be fully controled almost like vba

Alt HMC in Autohotkey

I am trying to remap a function key like F4 to do an ALT then press H + M + C.
Tried reading the docs but was not successful in getting my answer.
I actually thought this may work but it's not.
F4::!hmc
That was probably working, but AutoHotkey runs too fast for most applications to pick up on the macros. It looks like you want to manipulate Word or some sort of ribbon menu. Try this:
SetKeyDelay, 50 ; Increase this to increase the delay
F4::!mhc
You could also try switch our your ! for {Alt} and see if you get any improvements there. Let me know if this works for you.

autohotkey: 3 keys pressed together = hotkey?

language: Autohotkey on Win7
"Shift" plus "right mouse button" plus "mouse wheel up"
I want my hotkey to be holding those three keys simultaneously. I have tried the following without any success
+ & rbutton & wheelup::
send 6
+rbutton & wheelup::
send 6
shift & rbutton & wheelup::
send 6
I always get an error when I try to make this hotkey does anyone know how to do it?
I'm still a newbie but I'll try and help =].
It doesn't seem to work when you use a modifier key with two mouse buttons, so this is a way that kind of works:
+WheelUp::
KeyWait, RButton, D ; Waits for RButton to be pressed down.
MsgBox, This works!
Return
The problem is it clicks (or releases) the right mouse button once the hotkey has run. If you instead put it like so:
+RButton::
KeyWait, WheelUp, D
There will be another problem in that it will work fine for the first use of the hotkey, it will from then on work with only Shift + Right Mouse Button, because it's already waited for WheelUp to be pressed down (or rather scrolled up).
I mucked around for a little bit with GetKeyState and the like but still being new I can't find a way around it xD. These may be sufficient for what you need for now, otherwise better to wait for someone more knowledgeable to post.
With the information from your comment (hold Shift+right and spam WheelUp) following solution works fine. Use Shift + WheelUp and check if the right mosue button is down.
+WheelUp::
if (GetKeyState("RButton", "P"))
send 6
else
send +{WheelUp}
return
You could remove the else part and add a ~ modifier, but then Shift + WheelUp will be catched and blocked by AHK even if you dont press the right mouse button.