Conditional Hotkeys without labels? Topic is solved

Get help with using AutoHotkey (v2 or newer) and its commands and hotkeys
User avatar
Coiler
Posts: 114
Joined: 29 Nov 2020, 09:06

Conditional Hotkeys without labels?

Post by Coiler » 30 Nov 2020, 16:16

Hello! I'm wondering if there is any way to create conditional hot-keys, similar to the Hotkey directive, without having to define external or secondary labels/functions for each key combination?

To better communicate what I'm asking for, take this example from the (V2) documentation that uses functions/labels:

Code: Select all

HotIfWinActive "ahk_class Notepad"
Hotkey "^!c", "MyFuncForNotepad"
HotIfWinActive "ahk_class WordPadClass"
Hotkey "^!c", "MyFuncForWordPad"
HotIfWinActive
Hotkey "^!c", "MyFuncForAllOtherWindows"
Notice how we have no idea what these hot keys are doing? The only way to figure that out would be search out each function and look at its execution code. For 3 variations of a hotkey, that's not a huge problem. But when you attempt something like this on a larger scale, with hundreds of remapped keys, it seems like it would get messy pretty quick.

I'm wondering why we can't simply do something like this instead?

Code: Select all

HotIfWinActive "ahk_class Notepad"
Hotkey "^!c", "^c" ; sends CTRL+C in notepad
HotIfWinActive "ahk_class WordPadClass"
Hotkey "^!c", "^+c" ; sends CTRL+SHIFT+C in WordPad
HotIfWinActive
Hotkey "^!c", "^+!c" ; sends CTRL+ALT+SHIFT+C in all other windows
Is something like this possible in V1 or V2 (either)? And if not, why not? Why do we need the labels or functions? It seems like they are just adding another layer of unnecessary complexity?

In my specific situation, I need to specify multiple conditions for each hotkey (which app is focused, and which custom joystick modifiers are down), and also have some of the conditions fall back on each other (or inherit from each other), so using #If (or #HotIf) will not work so well (will be difficult to allow app-specific remaps to inherit some keys from non-app-specific remaps).

Lastly, I read something about the "fat arrow" or => in the docs. I didn't completely understand it, but it almost seemed like some sort of function inlining. Would it be possible to use that here?

Really appreciate any help or advice with this!

User avatar
mikeyww
Posts: 27373
Joined: 09 Sep 2014, 18:38

Re: Conditional Hotkeys without labels?

Post by mikeyww » 30 Nov 2020, 16:23

I use v1. Of course, it's great to be able to put the label name into the Hotkey command, but yeah, it would sure be great, too, if an alternative to a label could be a single command. That would save some one-line subroutines and improve the general readability at the same time.

Perhaps this is a Suggestions item rather than a Help item.

swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: Conditional Hotkeys without labels?  Topic is solved

Post by swagfag » 30 Nov 2020, 16:50

Code: Select all

#Requires AutoHotkey v2.0-a122-f595abc2

MySimpleHotkey(hotkeyTrigger, whatToSend) {
    MyCustomSendFunc(ThisHotkey) { ; hotkey callbacks require at least one argument
        Send(whatToSend)
    }

    Hotkey(hotkeyTrigger, 'MyCustomSendFunc')
}

HotIfWinActive "ahk_class Notepad"
MySimpleHotkey "^!c", "^c" ; sends CTRL+C in notepad
HotIfWinActive "ahk_class WordPadClass"
MySimpleHotkey "^!c", "^+c" ; sends CTRL+SHIFT+C in WordPad
HotIfWinActive
MySimpleHotkey "^!c", "^+!c" ; sends CTRL+ALT+SHIFT+C in all other windows
alternatively, just

Code: Select all

MySimpleHotkey(hotkeyTrigger, whatToSend) => Hotkey(hotkeyTrigger, (ThisHotkey) => Send(whatToSend))
is also enough

User avatar
Coiler
Posts: 114
Joined: 29 Nov 2020, 09:06

Re: Conditional Hotkeys without labels?

Post by Coiler » 30 Nov 2020, 17:16

I just finished testing the lineHotKey "^N", (ThisHotkey) => MsgBox("you pressed " ThisHotkey) in V2, which seems to work. But I didn't realize I could wrap it into a custom function. That's a big advantage when I'll be creating so many of these (much easier to manage and update). Thank you!

Edit: Will your local function MyCustomSendFunc(ThisHotkey) generate unique code for each hotkey if MySimpleHotkey() is called many times with different input/output? Or would I need to write another wrapper function for each hotkey? I am trying to test this out, but still worried I may fool myself into thinking something is working when it is not.

CptRootBeard
Posts: 26
Joined: 16 Nov 2020, 14:47
Contact:

Re: Conditional Hotkeys without labels?

Post by CptRootBeard » 03 Dec 2020, 17:43

Coiler, don't overthink it. Consider this example:

Code: Select all

MyExampleFunction(firstName, lastName) {
    fullName := firstName . " " . lastName ;;Combine the first and last names
    Send(fullName) ;;Send fullName
}
You wouldn't expect fullName to hold onto its value from a previous call, would you?
It's a local variable, after all.

MyCustomSendFunc is, as you said, a local function.
Even though a particular Hotkey hangs onto the function that MyCustomSendFunc references, it forgets the "name" of the function after MySimpleHotkey returns.

Personally, I'm a fan of the fat arrow syntax Swag showed you, especially if you're worried about things like scope/namespace.
If you never even define MyCustomSendFunc by name, you don't have to worry about what it does/doesn't remember.

User avatar
Coiler
Posts: 114
Joined: 29 Nov 2020, 09:06

Re: Conditional Hotkeys without labels?

Post by Coiler » 08 Dec 2020, 20:53

Thank you for explaining that bit. I did not ask that question as well as I wanted to. I was mainly wondering if local functions were "generated" for each occurrence of the function call. Basically, I was wondering if each executed version of the function generated a unique version of the local function. But that seems doubtful.

I've learned a little while working with the Hotkey system, as far as variables go. It does keep track of local variables. But you have to be careful of global variables. Example:

Code: Select all

global g
MakeHotKey(key,a,b)
{
	Hotkey( key, (*) => Func(a,b,g) )
}
In this scenario, Func() is passed the current value of g each time the hotkey is pressed. The value that g had when MakeHotKey() was called is completely ignored and doesn't matter. So if you did something like this:

Code: Select all

g := "PhotoShop"
MakeHotKey( "x", 1, 2 )
MakeHotKey( "y", 3, 4 )

g := "Blender"
MakeHotKey( "x", 5, 6 )
MakeHotKey( "y", 7, 8 )
.. then all of your hotkeys would be set with g=="Blender" when they are tapped (unless you change it again after, then they will all reflect that value when tapped).

However, the opposite is true with locals. The local variable is recorded for every instance. So you can do this instead to make it work as expected:

Code: Select all

global g
MakeHotKey(key,a,b)
{
	current_g := g
	Hotkey( key, (*) => Func(a,b,current_g) )
}
So you can sort of control which values are linked and which are not by switching between globals and locals.

Post Reply

Return to “Ask for Help (v2)”