Jump to content


Photo

BUG: Sending keystrokes from within #If condition


  • Please log in to reply
6 replies to this topic

#1 Scoox

Scoox
  • Members
  • 116 posts

Posted 15 May 2012 - 02:09 AM

I've spent quite a while scratching my head over this one and I think I've managed to narrow it down. It's either a bug or me being stupid. Hopefully it's the latter! Thanks in advance :D

The following code consistently reproduces the bug. Before you run it, try to predict the behaviour of this script, then fire the 1 an 2 hotkeys and see how what you see tallies up with what you expected.

;Autohotkey_L v1.1.07.03

#SingleInstance Force
#NoEnv

1::MsgBox ONE

#If Function()
2::MsgBox TWO ;oops!
#If

Function()
{
	Send a ;I've randomly chosen to send 'a'
	Return True
}


#2 Guests

  • Guests

Posted 15 May 2012 - 02:39 AM

Just don't do it.

When the key combination which forms a hotkey is pressed, the #If expression is evaluated to determine if the hotkey should activate. The system may not respond to keyboard input until expression evaluation completes or times out.



#3 engunneer

engunneer
  • Fellows
  • 9162 posts

Posted 15 May 2012 - 09:53 PM

it looks like your issue is that it didn't block the 2 being sent? or that the order (2a vs a2) is unpredictable?

#4 Scoox

Scoox
  • Members
  • 116 posts

Posted 16 May 2012 - 03:34 AM

Thanks for replying guys. This code may seem trivial but in the context of my script a section of code that caused this problem was required. There are other way to achieve the same but if this is a bug it'd be nice to have it fixed, hence my post.

What I was expecting to see is the "ONE" msgbox every time I press 1, and the "TWO" msgbox every time I press 2. Apart for the small delay after pressing 2 (which may be explained by the fact that "the system may become unrepsonsive..." as stated in the help file), I found that after pressing 2 if I subsequently press 1 the corresponding "ONE" message box won't pop up again unless I reload the script.

Also I wasn't expecting for the character '2' to be typed at all.

#5 Lexikos

Lexikos
  • Administrators
  • 8832 posts

Posted 17 May 2012 - 12:21 AM

I believe this is due to the nature of the keyboard hook and #if. The keyboard and mouse hooks run on a separate thread to the main program. When a relevant key event is received, the hook thread sends a message to the main thread, requesting evaluation of #if. The hook thread waits until either expression evaluation completes and the message handler returns, or #ifTimeout (default 1000ms) is reached.

I'm not sure exactly what happens when you try to send keystrokes while the hook is waiting, but it is definitely not designed to work the way you expect. Don't do it.

Aside from that,

Due to a design quirk of AutoHotkey, #If expressions may be evaluated twice under certain circumstances. For this reason, #If expressions should be designed to have no side-effects.

Sending keystrokes is one example of a side-effect.

I found that after pressing 2 if I subsequently press 1 the corresponding "ONE" message box won't pop up again unless I reload the script.

I believe this is due to the nature of "threads" and #MaxThreadsPerHotkey, and has nothing to do with #if.

#6 Scoox

Scoox
  • Members
  • 116 posts

Posted 19 May 2012 - 08:32 AM

Thanks for clarifying, Lexikos.

In my script #MaxThreads and #MaxThreadsPerHotkey are both unspecified, so default values should be in place (10 and 1 threads respectively). Does this mean that the 1:: thread is still running? I don't see how this could be.

Originally what I wanted to do was write a context-sensitive hotkey based on the currently active window. Since the hotkey is triggered by LButton & g, and clicking gives focus to the window under the mouse, this saves one step (first activating the window by clicking and then launching the command). The problem is with Explorer. In Explorer, when you click on a file icon rather than the white are around it, that is the SysListView321 control, the window does not take focus until you release the mouse button. Initially I was sending {LButton Up} from within the #If statement, but this didn't work. I have now found a better way to do this.

;Determines whether hovered window belongs to previously defined ahk_group
HoverWinGroupIs(GroupName) ;e.g. ahk_group Explorer
{
	MouseGetPos,,, HoverWinID
	Return WinExist(" ahk_id " . HoverWinID . " " . GroupName) ;note multiple criteria
}
Up until today I wasn't aware of this, but the fact is that several "ahk_" parameters can be combined into one WinTitle string. This information is actually in the help file, but the example given (and in fact most examples I have seen) follow the format My file.txt ahk_class Notepad (note just one instance of ahk_). Today it crossed my mind that this might work and it did, and finally I was able to write the above function. I am sure this is no news to a lot of you, but this knowledge has opened a lot of new possibilities for me so I want to share it with the community.

#7 Lexikos

Lexikos
  • Administrators
  • 8832 posts

Posted 19 May 2012 - 11:27 AM

Does this mean that the 1:: thread is still running? I don't see how this could be.

Perhaps this will help to clarify:
MsgBox Press 1
1::
MsgBox A) Press 2
MsgBox D)
ListLines
return
2::
MsgBox B) Close MsgBox A
MsgBox C) Observe that MsgBox D hasn't appeared yet
return
This behaviour is explained by the page I linked to earlier: "threads".