How to set combination threshold in Autohotkey - autohotkey

There is a description of how to define a custom combination in AutoHotkey:
You can define a custom combination of two keys (except joystick
buttons) by using " & " between them. In the below example, you would
hold down Numpad0 then press the second key to trigger the hotkey:
Numpad0 & Numpad1::MsgBox "You pressed Numpad1 while holding down Numpad0."
Numpad0 & Numpad2::Run "Notepad"
But I couldn't find how to set the threshold. for example, I want Numpad0 & Numpad1 only to happen when user presses Numpad1 in less than 300ms after pressing Numpad0.

You could do something like this for example:
Numpad0::
if (!PressedAt)
PressedAt := A_TickCount
return
Numpad0 Up::PressedAt := 0
#If, A_TickCount - PressedAt < 300
Numpad1::MsgBox
#If
So use A_TickCount(docs) to compare times.
And the if-statement is there because of Windows' key repeat functionality. Without it, the PressedAt time would get set constantly while Numpad0 is held down.
Also, 0 is false, so we can conveniently use the PressedAt variable in the if-statement as well.
Could've also be done without a context sensitive hotkey for Numpad1, it just makes the key retain its original functionality.
If #If were to cause you trouble, you can switch over to a normal if-statement check inside the hotkey label.
And be sure to add the ~ prefix(docs) to the Numpad0 hotkey if you want.

Related

Remap keys in loops

Background: I'm trying to have a f-mode and d-mode which means if I press down the f key and press another key like i then nothing happens excepts a shortcut. let say it will send Up key instead of f and I.
Issue: how I can remap a pressed key (I in my example) to a shortcut (Up as example)?
Code:
d::
f::{
;...
loop{
if !GetKeyState("f","p") && !GetKeyState("d","p"){
break
}
if GetKeyState("i","p") {
OutputDebug "i"
send "{up}"
continue
}
; ...
}
}
Looks like you want to make a custom combination.
From the Docs:
You can define a custom combination of two keys (except joystick
buttons) by using " & " between them. In the below example, you would
hold down Numpad0 then press the second key to trigger the hotkey:
Numpad0 & Numpad1::MsgBox You pressed Numpad1 while holding down Numpad0.
Numpad0 & Numpad2::Run Notepad
But also note:
The prefix key loses its native function: In the above example,
Numpad0 becomes a prefix key; but this also causes Numpad0 to lose its
original/native function when it is pressed by itself. To avoid this,
a script may configure Numpad0 to perform a new action such as one of
the following:
Numpad0::WinMaximize A ; Maximize the active/foreground window.
Numpad0::Send {Numpad0} ; Make the release of Numpad0 produce a Numpad0 keystroke. See comment below.
This is to prevent holding down a key from spamming inputs while you wait to press the second part of a key combination. So essentially, your 'f' and 'd' keys will now perform their normal functions when you release them instead of initially pressing them down.
Anyways, the code would become:
f & i::
d & i::
Send {Up}
return
f::f
d::d

AHK script designed to toggle based on CapsLock Status always toggles on 'off' and I cannot change it to 'on'

(Note: Very new to scripting, borrowed some phrases from other scripts I've online.) I have Carpal Tunnel and play a video game that does not have any key-bind options not set to the F1-F0 keys so I want to rebind the F1-F4 keys to Z-V but only when capslock is enabled, to prevent being unable to type in chat windows and in other programs without closing the script. However, the script re-binds the basic keys to the f-keys ONLY when capslock is OFF, rather than allowing me to change it to ON. Not sure why.
I've tried 'hotfixing' it by rebinding it to Numlock, but when I moved to CapsLock changing 'OFF' to 'ON' did not keep the script from only rebinding the keys while CapsLock was OFF. Not sure why.
$Z::
GetKeyState, state, NumLock, T
if state = D ; NumLock is toggled ON
send, {z}
else
send, {F1}
Return
$X::
GetKeyState, state, NumLock, T
if state = D ; NumLock is toggled ON
send, {x}
else
send, {F2}
Return
etc...
etc...
I expected changing the value 'OFF' to 'ON' would result in the key rebinds only happening during the CapsLock status being toggled on.
Have you checked if you restarted the script after making changes? It's a very common mistake, not only among beginners. According to your example, your keys Z..V should behave as F1..F4 only when the NumLock is toggled off.
Given the nature of your script, you can consider to add the directive #SingleInstance Force which will automatically replace any older instance of your script by a new one each time you run the script again, making testing easier.
You can do conditional binding much easily with an #if directive, which makes the subsequent hotkeys and hotstring only effective when a condition is met.
To check the state of the CapsLock or NumLock keys you can also use the built-in function GetKeyState, which for toggle keys, such as CapsLock or NumLock, with the "T" mode returns either True or False based on the toggle state of the key.
Also, if you want to remap keys, you can simply write the target key's name at the right of the hotkey, which will completely bind the keys, on both Down and Up events. However, for this to work, you must specify your triggering keys as lowercase, since specifying uppercase would only trigger the remap when pressed the keys with the Shift key as well (the CapsLock would have no effect), and that is not your desired behaviour. [More on remapping keys]
Here is an example of what you could do:
#If GetKeyState("CapsLock", "T")
z::F1
x::F2
c::F3
v::F4
Note that, since key remapping always uses the keyboard hook (because it needs to register the Up events as well), there is no need to use the $ prefix in your hotkeys at all.
Nonetheless, you can automate your script even more if you use as condition for your hotkeys the currently active window and bind them to your game using the #IfWinActive directive.
However if there are also chats in the game, you might want to combine both conditions in a single #If, using the built-in function WinActive like this:
#If GetKeyState("CapsLock", "T") and WinActive("My Game Title")
z::F1
; ...
You can check how to narrow your search for the window by its title on the documentation for the WinTitle parameter.
If you want to improve your script even further, you could explore if there is any detectable change on the game window when the chat is active, such as if a certain control exists (you can check that as if it was another window using the WinExist function to check for a certain Window class.
To seek for such changes, you can use a script as the following (from the MouseGetPos documentation):
#Persistent
SetTimer, WatchCursor, 100
return
WatchCursor:
MouseGetPos, , , id, control
WinGetTitle, title, ahk_id %id%
WinGetClass, class, ahk_id %id%
ToolTip, ahk_id %id%`nahk_class %class%`n%title%`nControl: %control%
return
Which would allow you to see the window information of the windows below your mouse. You can use it to check for the name or class of the chat control by placing your mouse over it.
However, keep in mind that many games do not use Windows controls at all in their interfaces and rather just draw them on screen by themselves, so if you're trying this and can't progress much after a while you shouldn't waste too much time on it and rather enjoy playing with your CapsLock toggled binding.
Another tricky way to check if the chat is active is searching for an image on the screen or a pixel color using ImageSearch or much simpler PixelGetColor, but you can only do that if your game's interface is not very complex/animated.

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

Emulating Ctrl + Spacebar + AlphabeticalKey with Autohotkey

My problem :
^space & c::
send {F2}
send {Escape}
but it didn't work, how do I emulate Ctrl+Space + AlphabeticaklKey ?
As my previous speakers said, it can't be done easily. Here's my suggestion, it seems to work fine:
^space::
Loop {
if(GetKeyState("c")) {
break
}
if(!GetKeyState("CTRL") || !GetKeyState("SPACE")) {
return
}
Sleep, 50
}
msgbox, You have pressed CTRL+SPACE+C
return
The code is pretty self-explanatory. When CTRL + SPACE is pressed, it waits until either one of both is released or C is pressed. The latter triggers the actual functionality, otherwise it will return.
I actually don't like it very much, because theoretically it may fail in some cases (e.g. when CTRL + SPACE + C is pressed and released before the execution reaches the check for the state of C; although that seems very unlikely).
Update
There's also a way using #If. I recommend using that since it's more sophisticated and reliable. This is due to the fact that it doesn't need any loops:
#If GetKeyState("SPACE")
^c::Msgbox, You have pressed CTRL+SPACE+C
#If GetKeyState("c")
^space::Msgbox, You have pressed CTRL+SPACE+C
As far as I know, you can only combine two non-hotkey keys with the syntax:
space & c:: msgbox space and c
You can read it here
You can define a custom combination of two keys (except joystick
buttons) by using & between them. In the below example, you would hold
down Numpad0 then press the second key to trigger the hotkey:
Numpad0 & Numpad1::MsgBox You pressed Numpad1 while holding down
Numpad0. Numpad0 & Numpad2::Run Notepad
Trying to use control as well like in: space & c & control or space & ^c or any other combination will result in compile error.
My recommendation is that you don't combine that three keys together. Look for a pure hotkey combination or use another more or less useless key.
#!c:: windows + alt + c
AppsKey & c::
Remember that if you use a normal key as modificator, you have to remap it to itself to keep the original functionality, for example with the menu key (appskey):
AppsKey:: Send {Appskey}
AppsKey & c:: ;do what you want
There are actually a couple ways to get help. First of all the authors of this language have moved to a new domain ahkscript.org. It is always welcome to ask questions like these in our forum. I just happened to be digging through this site today and saw this by accident.
When you have more than one line of code after a hotkey you need to have a return follow it:
^space & c::
send {F2}
send {Escape}
return
Hope that helps

Eval / RegExp listen with Autohotkey

I think this must be possible but I can't find it in the documentation anywhere on autohotkey
I want to do something like:
[a-z0-9]::
SoundPlay, %A_WinDir%\Media\[\1].wav
SoundPlay *-1
i.e. listen for all keys a to z and 0-9 find the relevant wav file (a.wav etc..) and play it. If it can't be found Play a default sound.
Is this way out of AHK's league? Should I stick to doing this in python??!
Many thanks in advance
You can use the Hotkey Command to assign all possible hotkeys to the label.
The first loop here uses a trick with converting values to their ASCII codes, doing math, and converting them back to characters. The logic works like, "What is the 5th character after 'a'?" -- to which it replies 'f'.
#Persistent
Loop, 26
Hotkey, % Chr(Asc("a") + A_Index - 1), MyLabel
Loop, 10
Hotkey, % A_Index - 1, MyLabel
return
MyLabel:
MsgBox You pressed %A_ThisHotkey%
return
I'm not aware of a way to use a regex to specify the hotkey, but this is how I've done it in one of my scripts:
#::
a::
b::
c::
; (all other alpha keys...)
; Pass key on, if not in subscription list
If(in_edit_screen())
{
; Handle caps lock
If(GetKeyState("Capslock", "T"))
{
; Send uppercase letter
StringUpper key, A_ThisHotkey
Send %key%
}
Else
{
Send %A_ThisHotkey%
}
Return
}
; etc.
Return
This is part of a routine that's called whenever a certain window is focused, but the window in question has a few different modes; in one of those modes (indicated by the in_edit_screen flag), I want to just pass the keys through, while in another mode, I want the keys to do something special. A_ThisHotkey is the variable that tells the routine which key/key combination the user actually pressed.
Why not launch a script where you use:
Input, CI_KeyVar, I L1
and then read-out which key was pressed (variable = CI_KeyVar), do your thing (check if the ascii code falls between 0 and Z because this input will act on any input) and re-launch the script to wait for the next key press....
The way out would be to trigger on e.g. the esc key, so the script stops.