Cadoiz
Cadoiz

Reputation: 1676

How to winwait for two or more different windows in AutoHotkey

Is it possible to WinWaitActive for two (or more) different window titles at the same time? I'm executing a command and there could be a successful VNC Window coming up or a dialog telling me that the connection failed.

run, vnc.cmd, , Hide , PID ;# Launch hidden
WinWait, TurboVNC info, ;# The Warning
MsgBox A
WinWait, VNC manager [Raw] - 99`%,
MsgBox B

So this minimal example obviously doesn't work if the VNC shows correctly, as B is never reached sequentially. So it was tried to combat this with timers, I thought they had separate threads:

run, vnc.cmd, , Hide , PID ;# Launch hidden
SetTimer, wait_for_graphical_vnc_own_thread, -1 ;# previously I had a 0 here, but that was not the problem's source

WinWait, TurboVNC info, ;# The Warning
MsgBox A
wait_for_graphical_vnc_own_thread:
WinWait, VNC manager [Raw] - 99`%, ;# Successful window
MsgBox B

Unfortunately, this does also not work, not even with another (second) timer for the warning. The next thing I tried was taken from this deprecated board:

Gui +LastFound 
hWnd := WinExist() 

DllCall( "RegisterShellHookWindow", UInt, hWnd ) 
MsgNum := DllCall( "RegisterWindowMessage", Str,"SHELLHOOK" ) 
OnMessage( MsgNum, "ShellMessage" ) 

Return ;                                                 // End of Auto-Execute Section // 

ShellMessage( wParam,lParam ) { 
  If ( wParam = 4 ) ;  HSHELL_WINDOWACTIVATED 
  { 
        WinGetTitle, Title, ahk_id %lParam% 
        MsgBox %Title% ;# Not even this is ever shown
    
        If InStr( Title, "TurboVNC info" ) {
            MsgBox A2
        }
        If InStr( Title, "VNC manager [Raw] - 99`%" ) {
            MsgBox B2
        } 
}

While I like the idea, it launches neither of the two. The author points to this board question on how to Hook on to Shell to receive its messages (archive link) for more details. The last idea comes from this answer to a question about AutoIt:

SetTitleMatchMode, RegEx 
WinWait, TurboVNC info|VNC manager [Raw] - 99`%, 
MsgBox C
;# I would then have a condition here to separate the two cases, but not even C gets shown

Upvotes: 0

Views: 2748

Answers (5)

lightproof
lightproof

Reputation: 101

Tried this and it worked properly:

#Persistent

Gui +LastFound
hWnd := WinExist()
DetectHiddenWindows, On

DllCall( "RegisterShellHookWindow", UInt,hWnd )
MsgNum := DllCall( "RegisterWindowMessage", Str,"SHELLHOOK" )
OnMessage( MsgNum, "ShellMessage" )
Return

ShellMessage( wParam,lParam )
{
    If ( wParam = 1 )   ; <-- correct wParam value
    {
        WinGetTitle, title, ahk_id %lParam%

        MsgBox, title = %title%     ; this shows properly now
        
        if InStr(title, "calc")
            MsgBox, This is Calculator
            
        if InStr(title, "notepad")
            MsgBox, This is Notepad
            
    }
}

Upvotes: 0

vadus
vadus

Reputation: 21

Set SetTitleMatchMode to RegEx [v1.0.45+] changes WinTitle, WinText, ExcludeTitle, and ExcludeText to accept regular expressions.

SetTitleMatchMode RegEx

    WinWaitActive, "TurboVNC info|VNC manager \[Raw\] - 99%", , 3 ; waiting one of two windows

    if ErrorLevel ;
    {
        MsgBox Non one of windows appeared
        return
    }

Upvotes: 1

T_Lube
T_Lube

Reputation: 331

Another solution for some one that doesn't feel they are up to learning regex:

#Persistent

 ; hotkey or other stuff...
currentWin := winWaitActives("ahk_id " . winActive("A"), 10
, "some win title"
, "some other wintitle"
, " and yet another win title")
Return ; end auto-execute section
 
 ; FUNCTION DEFINTION BELOW
winWaitActives(waitNotActiveTitle, waitSeconds, winWaitTitles*) { ; THE ASTERISK PROVIDES A VARIABLE NUMBER OF PARAMS TO THE FUNCTION
    
    ; THIS FIRST COMMAND GIVES A POSITIVE POINT TO START THE LOOP.
    winWaitNotActive, %waitNotActiveTitle%,, %waitSeconds%
   
    ; START LOOPING THROUGH THE TITLES UNTIL FOUND.
    for i, winTitle in winWaitTitles {
        if (winActive(winTitle)) {
            winGetActiveTitle, fullTitle
            Break
        }
    }    
    Return fullTitle
}

Upvotes: 2

Cadoiz
Cadoiz

Reputation: 1676

I found a workaround. Calling:

run, vnc_close_helper.ahk, PID_ch 

Actually runs in a separate thread. The helper script then contains the second WinWaitActive I need.

Upvotes: 0

0x464e
0x464e

Reputation: 6499

In normal AHK this is indeed not as easy as just running two WinWaitActive commands, because normal AHK is not multi threaded. You could do this in AHK_H, but that's a whole another thing.

In normal AHK, the shell hook implementation you found, works just fine.
You just need to account for the HSHELL_RUDEAPPACTIVATED message. This is the message that actually gets sent most of the time (I don't know why, it just is lol).

#NoEnv

DllCall("RegisterShellHookWindow", Ptr, A_ScriptHwnd)
MsgNum := DllCall("RegisterWindowMessage", Str, "SHELLHOOK")
OnMessage(MsgNum, "ShellMessage")
Return

ShellMessage(wParam, lParam) 
{ 
    static HSHELL_WINDOWACTIVATED := 0x04
         , HSHELL_HIGHBIT := 0x8000
         , HSHELL_RUDEAPPACTIVATED := HSHELL_WINDOWACTIVATED | HSHELL_HIGHBIT
    
    if (wParam == HSHELL_RUDEAPPACTIVATED || wParam == HSHELL_WINDOWACTIVATED)
    {
        WinGetTitle, title, % "ahk_id " lParam
        ToolTip, % (wParam == HSHELL_WINDOWACTIVATED ? "HSHELL_WINDOWACTIVATED" : "HSHELL_RUDEAPPACTIVATED") " message received!`nWindow activated: " title "`nHWND: " lParam
    }
}

Also, as a side note, this line of yours has incorrect syntax
If InStr( Title, "VNC manager [Raw] - 99`%" ).
You only need to escape such things in legacy syntax. Here you're using a function, which means you're in the modern expression syntax and you're explicitly specifying a string in " ". And the % character doesn't have any special meaning in a string, so there's nothing to escape there. So, long story short, remove `.


Also that RegEx approach would've worked, but this VNC manager [Raw] - 99% is not the RegEx you'd want.
[ ] has special meaning in RegEx (it's a character class), so you need to escape those characters.

SetTitleMatchMode, RegEx 

WinWaitActive, % "TurboVNC info|VNC manager \[Raw\] - 99%"
WinGetTitle, title, A
ToolTip, % title " activated!"

Upvotes: 2

Related Questions