I am a newbie to Autohotkey, and I can't figure this out despite reading through this site and the official documentation.
I just want to have certain hotkeys work only with certain applications. So for example, if I press spacebar in a certain game I want it to send ` (grave), but if I'm not in that game I want spacebar to function normally. Everything I try seems to make spacebar do nothing when I'm not in game. I can try using an "else" statement to send the spacebar, but that just seems to make an infinite loop. Help!
EDIT: Thank you NbdNnm. Here's exactly what ended up working for me:
#IfWinActive League of Legends (TM) Client
Space:: `
#IfWinActive
Try this and make sure you have the latest version of AutoHotkey. Put the application process name in the strYourAppExeName variable and put your hotkey definitions in the #if block.
strYourAppExeName := "notepad.exe"
strYourMessage := "``(grave)"
#If WinActive("ahk_exe " strYourAppExeName)
Space::SendInput, % strYourMessage
#if
Related
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.
I am a newbie to Autohotkey, and I can't figure this out despite reading through this site and the official documentation.
I just want to have certain hotkeys work only with certain applications. So for example, if I press spacebar in a certain game I want it to send ` (grave), but if I'm not in that game I want spacebar to function normally. Everything I try seems to make spacebar do nothing when I'm not in game. I can try using an "else" statement to send the spacebar, but that just seems to make an infinite loop. Help!
EDIT: Thank you NbdNnm. Here's exactly what ended up working for me:
#IfWinActive League of Legends (TM) Client
Space:: `
#IfWinActive
Try this and make sure you have the latest version of AutoHotkey. Put the application process name in the strYourAppExeName variable and put your hotkey definitions in the #if block.
strYourAppExeName := "notepad.exe"
strYourMessage := "``(grave)"
#If WinActive("ahk_exe " strYourAppExeName)
Space::SendInput, % strYourMessage
#if
I've been using AHK in a very simple form for years, but multiple attempts at learning the more advanced functions has just resulted in confusion and frustration.
At the moment I'm trying to create a script that'll send the hotkey "CTRL + W" to Google Chrome when I hold the tilde key and left click inside the Google Chrome window. Whenever I trigger the script, it seems to close every single tab then the browser itself.
My script is below - what am I doing wrong?
#IfWinActive ahk_class Chrome_WidgetWin_1 ;Checks that the active window is Google Chrome.
` & LButton:: ;Tilde + Left Mouse Button
Send, ^+w ;Sends CTRL + W to the window.
return ;Ends the script.
Your script looks almost right. Try this. After you defined all the keys, you must "close" #ifwinactive ...
#IfWinActive, ahk_class Chrome_WidgetWin_1
` & LButton::Send, ^+w
#IfWinActive
Splitting the hotkey over multiple lines in not wrong, but in this case it can be done in one line. When you run into a problem like this. Try to isolate the issues. First ONLY try a bare ' & LButton::Send X to see if this works and be aware that you now loose the ` sign. Then try it with ^+w and when that works try it with #IfWinActive.
When you want to "restore" the tilde key, you could add this line:
~`::Return
The ~ will pass on the key data to the OS before executing the NOP (Return).
I'm testing AutoHotkeys as a way to block user's usage of Ctrl, Alt and Windows Key while an application is running. To do this, I compiled the code:
LAlt::return
RAlt::return
LControl::return
RControl::return
RWin::Return
LWin::Return
into an .exe using the compiler that comes with AutoHotkeys.
My problem is that normally when I close the .exe file (either by code using TerminateProcess(,) or manually) the keys are not released immediately. The Windows Key, for example, may take something like 10 seconds to be finely "unlocked" and become able to be used again, and for me this is unacceptable.
So I got two questions:
Is there a way to fix this problem? How can I make the keys to be released as soon as the .exe is closed?
Would there be any improvement if I tryed to get the same functionality by code? Or if I create the hooks by myself I would get the same problem I'm having with AutoHotkeys?
Thanks,
Momergil
AutoHotkey has a built-in command ExitApp for terminating your scripts.
This example makes Esc your termination hotkey:
Esc::ExitApp
It seems like the delay you are experiencing might be related to how long it's taking the process to close.
You could try making the hotkeys conditional with the #If command*
(i.e. they are only blocked when Flag = 1).
Then you can have the script quickly change the context just before ExitApp by using OnExit. The OnExit subroutine is called when the script exits by any means (except when it is killed by something like "End Task"). You can call a subroutine with a hotkey by using the GoSub command.
Flag := 1
OnExit, myExit
Esc::GoSub, myExit
#If Flag
LAlt::return
LCtrl::return
x::return
#If
myExit:
Flag := 0
Exitapp
* The #If command requires Autohotkey_L.
The other option that will be more verbose, but work for AHK basic, is the hotkey command.
Another option is to have AutoHotkey run the target application, and upon application exit, AutoHotkey exits as well. Here's an example with Notepad. When the user closes Notepad, the script gracefully exits.
RunWait, Notepad.exe
ExitApp ; Run after Notepad.exe closes
LAlt::return
RAlt::return
LControl::return
RControl::return
RWin::Return
LWin::Return
I would use winactive to disable these keys. In this example the modyfier keys are disabled for "Evernote". As soon as you switch to another program the keys are restored and when you switch back to Evernote the modifier keys are disabled again.
SetTitleMatchMode, 2 ; Find the string Evernote anywhere in the windows title
#ifWinActive Evernote
LAlt::return
RAlt::return
LControl::return
RControl::return
RWin::Return
LWin::Return
#ifWinActive
I want to remap alt+e when caps is on in autocad.
And when capslock is not on, alt+e should open menu edit.
I use script like this
<!e::
if(GetKeyState( "CAPSLOCK", "T" ))
{
SendInput erase{space}wp{space}
}
else
{
Send !e
}
When I turn on capslock, remap key is OK.
When I turn off capslockand alt+e, menu edit opened, but closed immediately.
Thanks.
You will want a $ at the beginning of your hotkey to prevent the endless loop that the !e in your else block will trigger. You will also want to add a Return at the end of the hotkey to prevent the script from continuing into what is below this hotkey.
$!e::
if GetKeyState( "CapsLock", "T" )
Sendinput, erase{space}wp{space}
else
Sendinput, !e
Return
(Brackets are only required when if/else blocks are more than one line.)
Beyond that, the likely issue is that it's an alt hotkey that is also set to send alt.
I say this is an issue because if you press and hold alt, it activates menus,
and then the script sends alt, which will be in conflict with that.
As Ricardo said, the ideal way to script this is with the #IF command (only included with AHK_L).
#If GetKeyState("CapsLock", "T") and WinActive("AutoCAD")
!e:: SendInput, erase{space}wp{space}
#If
Notice that you can add the WinActive() function to the #If command's expression.
Try it without that first, and also realize that the application's title needs to be exactly "AutoCAD" at all times for that to work. I would recommend finding AutoCad's ahk_class,
with AHK's window spy, instead of using the title.
If it still does not work, it is likely that AHK is sending faster than AutoCAD would like to receive.
Info on how to deal with that can be found here.
Try to change your else block to this:
Send, {ALTDOWN}e{ALTUP}
I do not rely on these symbols to send keystrokes in AutoHotKey.