Help configuring Hotkey, If with BoundFunc Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
doubledave22
Posts: 343
Joined: 08 Jun 2019, 17:36

Help configuring Hotkey, If with BoundFunc

04 May 2021, 17:27

Is there a way to use the return value of a function as arguments for a Hotkey, If [, Expression]?

This is a crude example:

Code: Select all


#If Value := Test()
#If

Test()
{
	return 15
}

Test_Handler(arg)
{
	msgbox, % arg
}

^t::
	Hotkey, If, Value := Test()
	fn := Func("Test_Handler").Bind(Value)
	Hotkey,F11,% fn, on UseErrorLevel	
return
I know that I can set Value to global in Test_Handler but that can lead to problems if "Value" is changed and some Test_Handler calls are queued up. I'd like to send exact arguments to Test_Handler that are returned from the Test() function (ideally this will be an object). Can anyone point me in the right direction?
teadrinker
Posts: 4326
Joined: 29 Mar 2015, 09:41
Contact:

Re: Help configuring Hotkey, If with BoundFunc

04 May 2021, 18:10

Code: Select all

#If % test_fn
#If

Test(Obj)
{
	return Obj[1] := 15
}

Test_Handler(arg)
{
	msgbox, % arg[1]
}

^t::
MyFunc() {
   static Obj := []
        , test_fn := Func("Test").Bind(Obj)
        , fn := Func("Test_Handler").Bind(Obj)
   Hotkey, If, % test_fn
   Hotkey, F11, % fn, On
}
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: Help configuring Hotkey, If with BoundFunc

04 May 2021, 21:00

doubledave22 wrote:
04 May 2021, 17:27
can lead to problems if "Value" is changed and some Test_Handler calls are queued up. I'd like to send exact arguments to Test_Handler that are returned from the Test() function (ideally this will be an object)
the above approach doesnt protect against this. it's basically the same as using a global variable, except it just uses objects instead. depending on circumstances and the script's contents, ahk may call into ur condition at times u wouldnt normally expect it to. so, if that happens and the hotkey procedure is still running currently, it could potentially start working with different data halfway through.

to avoid this, in ur condition function, ud have to bundle whatever data u want passed to the hotkey procedure(eg Context, create new object) and redefine the hotkey procedure, binding that object to it. that way if the hotkey procedure ends up executing(due to the condition returning true), it is guaranteed to have its own context independent of that of other potentially queued procedures(or other things/threads running, interrupting the execution and potentially changing stuff)
doubledave22
Posts: 343
Joined: 08 Jun 2019, 17:36

Re: Help configuring Hotkey, If with BoundFunc

04 May 2021, 21:28

Thanks! This is good to know that teadrinkers solution, although awesome will lead to the same problem. I have no idea how to implement what you said but I will give it a try nonetheless. Much appreciated!
lexikos
Posts: 9583
Joined: 30 Sep 2013, 04:07
Contact:

Re: Help configuring Hotkey, If with BoundFunc

04 May 2021, 23:13

teadrinker wrote:
04 May 2021, 18:10
#If % test_fn
What is it that you think this will do?

"Hotkey if" has two different modes: one which accepts a string which is literally matched against an existing expression, and one which takes a function object.

The directive above would make hotkeys active if test_fn contains a non-empty, non-zero value. You would refer to it with Hotkey If, test_fn or Hotkey If, % "test_fn".

The percent sign with #If is redundant and not intentionally supported.
teadrinker
Posts: 4326
Joined: 29 Mar 2015, 09:41
Contact:

Re: Help configuring Hotkey, If with BoundFunc

05 May 2021, 01:02

@lexikos, thanks, got it.
can lead to problems if "Value" is changed and some Test_Handler calls are queued up
Yeah, my example can be changed like this:

Code: Select all

Test(Obj)
{
   static val := 3
   --val
   if val
      Obj.Push(val)
   return val
}

Test_Handler(arg)
{
   Critical
   Sleep, 2000
   ToolTip, % arg.RemoveAt(1)
}

^t::
MyFunc() {
   static Obj := []
        , test_fn := Func("Test").Bind(Obj)
        , fn := Func("Test_Handler").Bind(Obj)
   Hotkey, If, % test_fn
   Hotkey, F11, % fn, On
}
Press Ctrl + T and then F11 trice.
Last edited by teadrinker on 05 May 2021, 05:59, edited 1 time in total.
lexikos
Posts: 9583
Joined: 30 Sep 2013, 04:07
Contact:

Re: Help configuring Hotkey, If with BoundFunc

05 May 2021, 05:56

@teadrinker, you missed the main points of my post. Just remove #If test_fn. It is irrelevant.
doubledave22
Posts: 343
Joined: 08 Jun 2019, 17:36

Re: Help configuring Hotkey, If with BoundFunc

05 May 2021, 11:06

Thanks guys!

How'd I do?

Code: Select all


Test(Obj)
{
	static testvar1 := 0
	
	testvar1++
	Sleep, 500
	val := {1: testvar1, 2: a_thishotkey}
	Obj.Push(val)
	return 1
}


Test_Handler(arg)
{
	Critical
	output := arg.RemoveAt(1)
	ToolTip, % output.1 " and " output.2
}

^t::
MyFunc() {
   static Obj := {}
        , test_fn := Func("Test").Bind(Obj)
        , fn := Func("Test_Handler").Bind(Obj)
   Hotkey, If, % test_fn
   Hotkey, F11, % fn, On
   Hotkey, F10, % fn, On
}

I held down F10 and then hit F11 and it seems to have outputted correctly (output.2 didn't get overwritten halfway through)
Spoiler
doubledave22
Posts: 343
Joined: 08 Jun 2019, 17:36

Re: Help configuring Hotkey, If with BoundFunc

07 May 2021, 11:35

@teadrinker So ultimately the solution you presented worked great until there was a small hiccup where Obj.Push(val) was called and and arg.RemoveAt(1) was not called for whatever reason. This put all hotkeys on a "hotkey delay" meaning now the 2nd key in our Obj was the current hotkey but arg.RemoveAt(1) was now processing the previous hotkey instead.

To reiterate exactly what I need is the output (ideally an object) of my hotkey, if, % FunctionObject (when evaluating to true) to be sent as arguments to my Hotkey, KeyName [, Label, Options] with the label here being another FunctionObject. Your method was nearly perfect except for the fatal flaw seen above. Perhaps this is what @swagfag was referencing.

"to avoid this, in ur condition function, ud have to bundle whatever data u want passed to the hotkey procedure(eg Context, create new object) and redefine the hotkey procedure, binding that object to it. that way if the hotkey procedure ends up executing(due to the condition returning true), it is guaranteed to have its own context independent of that of other potentially queued procedures(or other things/threads running, interrupting the execution and potentially changing stuff)"

If you have any spare time to produce a very crude example of this I'd be very grateful.
lexikos
Posts: 9583
Joined: 30 Sep 2013, 04:07
Contact:

Re: Help configuring Hotkey, If with BoundFunc  Topic is solved

07 May 2021, 21:48

N.B.
Note: Scripts should not assume that the expression is only evaluated when the key is pressed (see below).
Source: #If - Syntax & Usage | AutoHotkey
Evaluation of the #If (and it returning true) does not necessarily mean that the hotkey is being fired, and even if it is, the hotkey's subroutine might not be called; for instance, if #MaxThreadsPerHotkey prevents it.


This is how you can "bundle whatever data u want passed to the hotkey procedure(eg Context, create new object) and redefine the hotkey procedure".

Code: Select all

#If Test()
F11::MsgBox Something went wrong.

Test() {
    static count := 0
    Hotkey If, Test()
    fn := Func("Test_Handler").Bind({n: ++count})
    Hotkey F11, % fn
    return true
}

Test_Handler(context) {
    MsgBox % context.n
}
Unlike the queue approach, if the hotkey doesn't fire, the context for that particular call is not used by the next hotkey, or at all. If the same hotkey eventually executes, it would be after Test has been called again and replaced the previous context.

However, if there is already a hotkey message buffered for execution when #If is evaluated for the same hotkey, the new context will replace whatever context should have been associated with the buffered message. In effect, it is the same as having a global variable for each hotkey variant.
doubledave22
Posts: 343
Joined: 08 Jun 2019, 17:36

Re: Help configuring Hotkey, If with BoundFunc

08 May 2021, 10:56

Works like a charm thank you everyone!!!!

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: No registered users and 341 guests