If you are going to use #Requires in a bug report, it would be prudent to correctly specify the applicable version (perhaps even
=2.1-alpha.9; but at least
2.1-).
In my testing, the issue never occurred with
1::,
^1:: or
RWin:: in place of
AppsKey::. I have that physical key remapped to RWin, but also tested with a key remapped to AppsKey, which allowed me to reproduce the issue. I do not see any difference in the frequency of the issue between v2.0.13 and v2.1-alpha.9 for
M.Show(), or between that and
M.Show(,, false). I was also unable to reproduce the issue with AppsKey while the Visual Studio debugger was attached.
In order for the menu to accept keyboard input or disappear when you click some other window, a window from the same thread must be active; otherwise the menu's message loop/window does not receive any input. AutoHotkey calls SetForegroundWindow
twice to activate its own window before showing the menu. The system is responsible for creating and positioning the actual menu window, and never provides the program with a handle to that window (with class #32768). For modeless menus, the system activates the menu window itself, or when the issue occurs, doesn't activate it.
With the modeless menu, the hotkey can be pressed even while the menu is visible to re-open it. In my testing, this never failed, presumably because the active window (the menu window) belongs to the script's process.
WinActivate (internally SetForegroundWindowEx) includes a number of hacks to fool the OS into letting us steal the focus. Working against the OS in this way is inherently unreliable. However, the menu code wasn't using these hacks, for reason noted in the source code:
// UPDATE: This is a problem because SetForegroundWindowEx() will restore the window if it's hidden,
// but restoring also shows the window if it's hidden. Could re-hide it... but the question here
// is can a minimized window be the foreground window? If not, how to explain why
// SetForegroundWindow() always seems to work for the purpose of the tray menu?
I'll add a parameter to SetForegroundWindowEx so that the menu code can use it. In my testing, this significantly increased reliability.
Actually, the window would normally never be minimized, since clicking the minimize button hides the window. But I digress.
The following can be used to troubleshoot these issues:
Code: Select all
OnMessage 0x117, Receive_WM_INITMENUPOPUP
Receive_WM_INITMENUPOPUP(*) {
MouseGetPos , &y
ToolTip WinGetClass(DllCall("GetForegroundWindow", "ptr")),, y - 30
; DetectHiddenWindows true
; if !WinActive("ahk_pid " ProcessExist())
; WinActivate A_ScriptHwnd
}
On failure, it can be seen that the script window was not active. This happens very predictably if you click away from the menu and then open it again. This could be a consequence of how the input loop for the menu works, or it could be the OS detecting that the process has stolen focus and then been dismissed by the user.
Another workaround is to explicitly activate one of the script's windows prior to showing the menu. This can be done for all menu popups by uncommenting the last few lines above, or it can be done by simply calling WinActivate before Show.