The following script for AHK 2.0 is meant to do something to certain windows once, then ignore them while checking for new windows:
#SingleInstance Force
Persistent
SetTitleMatchMode "RegEx"
ids := []
Loop {
global ids
all := "ahk_exe ((msedge)|(chrome)|(Notepad)|(olk)|(explorer))\.exe"
beside := ""
for i, id in ids {
beside .= (i == 1 ? " ahk_id ^((?!" : "|") "(" id ")" (i == ids.Length ? ").)+$" : "")
}
MsgBox all beside
WinWait all beside
ids.push(WinGetID())
; Do something with the window here.
WinSetTransparent 217
for i, id in ids {
if(!WinExist("ahk_id " id)) {
ids.RemoveAt(i)
} else {
for n, nid in ids {
if(n > i && nid == id)
ids.RemoveAt(n)
}
}
}
}
Right now, it finds the foremost window (usually the Taskbar), then it finds no other window. The regular expression I'm using for the ahk_id
values matches anything not within the capture groups; the full statement would look something like this if it finds multiple windows: ahk_exe ((msedge)|(chrome)|(Notepad)|(olk)|(explorer))\.exe ahk_id ^((?!(66328)|(14420486)).)+$
.
Is there a better way to exclude a changing list of windows from WinWait
? I tried to use window groups and the ExcludeTitle
parameter, but I believe that parameter may really only be for titles rather than ahk_criteria
. Window groups also cannot be changed without reloading the script.
I just want to find new windows of certain executables, do something, then wait for new windows (not detecting the old windows). How might I accomplish that?
In this question, I needed to affect newly created windows only. Instead of using WinWait, I found a few references to an old example of a Shell Hook. This allows for the creation of a trigger which detects creation, destruction of, and changes to windows.
I have adapted the example for AutoHotkey 2.0:
#SingleInstance Force
Persistent
detector := Gui()
DllCall("RegisterShellHookWindow", "UInt",detector.Hwnd)
messenger := DllCall("RegisterWindowMessage", "Str","SHELLHOOK")
OnMessage(messenger, recipient)
recipient(message, id, *) {
if(message == 1) {
if(WinGetProcessName("ahk_id " id) == "YourExecutable.exe") {
; Do something with the window here.
WinSetTransparent(229, "ahk_id " id)
}
}
}
Concerning the nested if statements:
if(message == 1) {
if(WinGetProcessName("ahk_id " id) == "YourExecutable.exe") {
message == 1
), id
will contain the id of the window that was created. When message != 1
, id
may not contain a valid window id, so putting the checks in the same if statement may throw an error.message == 1
checks to see if the hook detected the creation of a window. For a list of the messages the hook can detect, see the link mentioned previously for Shell Hooks.WinGetProcessName("ahk_id " id) == "YourExecutable.exe"
, can be changed to anything you want to check concerning the window that was created. The title of the window that was created is ("ahk_id " id)
. Note that this may occasionally throw an error and not find a window in certain circumstances; I'm not sure why it does this, but, to solve this in my personal script, I put this if statement in a try block.For this example, I once again set the transparency of the window. I did so using the title of the window detected by the hook, as I mentioned just above: WinSetTransparent(229, "ahk_id " id)
.
I hope that this answer is as useful to you as it was for me!